James Moger
2012-03-21 12c31ef28e1396f652f6f80f84480c0833182150
Restore the leading hunk of the first line of a fragment

Also correctly determine the line number of a fragment.
2 files modified
121 ■■■■■ changed files
src/com/gitblit/LuceneExecutor.java 95 ●●●●● patch | view | raw | blame | history
src/com/gitblit/utils/StringUtils.java 26 ●●●●● patch | view | raw | blame | history
src/com/gitblit/LuceneExecutor.java
@@ -1114,17 +1114,14 @@
     */
    private String getHighlightedFragment(Analyzer analyzer, Query query,
            String content, SearchResult result) throws IOException, InvalidTokenOffsetsException {
        content = content == null ? "":StringUtils.escapeForHtml(content, false);
        if (content == null) {
            content = "";
        }
        int fragmentLength = SearchObjectType.commit == result.type ? 512 : 150;
        QueryScorer scorer = new QueryScorer(query, "content");
        Fragmenter fragmenter;
        // TODO improve the fragmenter - hopefully on line breaks
        if (SearchObjectType.commit == result.type) {
            fragmenter = new SimpleSpanFragmenter(scorer, 1024);
        } else {
            fragmenter = new SimpleSpanFragmenter(scorer, 150);
        }
        Fragmenter fragmenter = new SimpleSpanFragmenter(scorer, fragmentLength);
        // use an artificial delimiter for the token
        String termTag = "<!--[";
@@ -1132,22 +1129,64 @@
        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(termTag, termTagEnd);
        Highlighter highlighter = new Highlighter(formatter, scorer);        
        highlighter.setTextFragmenter(fragmenter);
        String [] fragments = highlighter.getBestFragments(analyzer, "content", content, 3);
        if (ArrayUtils.isEmpty(fragments)) {
            if (SearchObjectType.blob  == result.type) {
                return "";
            }
            return "<pre class=\"text\">" + content + "</pre>";
            // clip commit message
            String fragment = content;
            if (fragment.length() > fragmentLength) {
                fragment = fragment.substring(0, fragmentLength) + "...";
            }
            return "<pre class=\"text\">" + StringUtils.escapeForHtml(fragment, true) + "</pre>";
        }
        int contentPos = 0;
        StringBuilder sb = new StringBuilder();
        for (int i = 0, len = fragments.length; i < len; i++) {
            String fragment = fragments[i];
            String tag = "<pre class=\"text\">";
            // resurrect the raw fragment from removing the artificial delimiters
            String raw = fragment.replace(termTag, "").replace(termTagEnd, "");
            sb.append(getPreTag(result, raw, content));
            String raw = fragment.replace(termTag, "").replace(termTagEnd, "");
            // determine position of the raw fragment in the content
            int pos = content.indexOf(raw, contentPos);
            // restore complete first line of fragment
            int c = pos;
            while (c > 0) {
                c--;
                if (content.charAt(c) == '\n') {
                    break;
                }
            }
            if (c > 0) {
                // inject leading chunk of first fragment line
                fragment = content.substring(c + 1, pos) + fragment;
            }
            if (SearchObjectType.blob  == result.type) {
                // count lines as offset into the content for this fragment
                int line = StringUtils.countLines(content.substring(0, pos));
                // create fragment tag with line number and language
                String lang = "";
                String ext = StringUtils.getFileExtension(result.path).toLowerCase();
                if (!StringUtils.isEmpty(ext)) {
                    // maintain leading space!
                    lang = " lang-" + ext;
                }
                tag = MessageFormat.format("<pre class=\"prettyprint linenums:{0,number,0}{1}\">", line, lang);
                // update offset into content
                contentPos = pos + raw.length() + 1;
            }
            
            sb.append(tag);
            // replace the artificial delimiter with html tags
            String html = fragment.replace(termTag, "<span class=\"highlight\">").replace(termTagEnd, "</span>");
            sb.append(html);
@@ -1157,31 +1196,7 @@
            }
        }
        return sb.toString();
    }
    /**
     * Returns the appropriate tag for a fragment. Commit messages are visually
     * differentiated from blob fragments.
     *
     * @param result
     * @param fragment
     * @param content
     * @return an html tag appropriate for the fragment
     */
    private String getPreTag(SearchResult result, String fragment, String content) {
        String pre = "<pre class=\"text\">";
        if (SearchObjectType.blob  == result.type) {
            int line = StringUtils.countLines(content.substring(0, content.indexOf(fragment)));
            int lastDot = result.path.lastIndexOf('.');
            if (lastDot > -1) {
                String ext = result.path.substring(lastDot + 1).toLowerCase();
                pre = MessageFormat.format("<pre class=\"prettyprint linenums:{0,number,0} lang-{1}\">", line, ext);
            } else {
                pre = MessageFormat.format("<pre class=\"prettyprint linenums:{0,number,0}\">", line);
            }
        }
        return pre;
    }
    }
    
    /**
     * Simple class to track the results of an index update. 
src/com/gitblit/utils/StringUtils.java
@@ -479,6 +479,12 @@
        return "#" + rs + gs + bs;
    }
    
    /**
     * Strips a trailing ".git" from the value.
     *
     * @param value
     * @return a stripped value or the original value if .git is not found
     */
    public static String stripDotGit(String value) {
        if (value.toLowerCase().endsWith(".git")) {
            return value.substring(0, value.length() - 4);
@@ -486,10 +492,30 @@
        return value;
    }
    
    /**
     * Count the number of lines in a string.
     *
     * @param value
     * @return the line count
     */
    public static int countLines(String value) {
        if (isEmpty(value)) {
            return 0;
        }
        return value.split("\n").length;
    }
    /**
     * Returns the file extension of a path.
     *
     * @param path
     * @return a blank string or a file extension
     */
    public static String getFileExtension(String path) {
        int lastDot = path.lastIndexOf('.');
        if (lastDot > -1) {
            return path.substring(lastDot + 1);
        }
        return "";
    }
}