Browse Source

A bunch more Lucene work

* Only list user-accessible repositories
* Syntax-highlight matched blob fragments
* Improve look and layout of search results
tags/v0.9.0
James Moger 12 years ago
parent
commit
6722961db1

+ 15
- 9
resources/gitblit.css View File

@@ -267,7 +267,7 @@ img.gravatar {
}
div.searchResult {
padding:5px;
padding: 10px 5px 10px 5px;
}
div.searchResult .summary {
@@ -300,18 +300,24 @@ div.searchResult .highlight {
padding: 0 2px;
}
div.searchResult .ellipses {
font-family: sans-serif;
font-size: 9px;
font-weight: normal;
background-color: #eee;
border: 1px solid #ccc;
padding: 0 3px;
margin: 0px;
div.searchResult .ellipses {
padding-left:25px;
color: #aaa;
}
div.searchResult pre {
margin: 1px 0px;
border: 0px;
}
div.searchResult .text {
border-left: 5px solid #EEEEEE;
padding: 0 0 0 15px;
}
div.searchResult ol {
margin-bottom: 0px !important;
}
div.header, div.commitHeader, table.repositories th {

+ 47
- 14
src/com/gitblit/utils/LuceneUtils.java View File

@@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -903,7 +904,8 @@ public class LuceneUtils {
Document doc = searcher.doc(docId);
SearchResult result = createSearchResult(doc, hits[i].score);
String content = doc.get(FIELD_CONTENT);
result.fragment = getHighlightedFragment(analyzer, query, content);
result.fragment = getHighlightedFragment(analyzer, query, content, result);
results.add(result);
}
} catch (Exception e) {
@@ -913,28 +915,44 @@ public class LuceneUtils {
}
private static String getHighlightedFragment(Analyzer analyzer, Query query,
String content) throws IOException, InvalidTokenOffsetsException {
content = content == null ? "":StringUtils.escapeForHtml(content, false);
String content, SearchResult result) throws IOException, InvalidTokenOffsetsException {
content = content == null ? "":StringUtils.escapeForHtml(content, false);
TokenStream stream = TokenSources.getTokenStream("content", content, analyzer);
QueryScorer scorer = new QueryScorer(query, "content");
Fragmenter fragmenter = new SimpleSpanFragmenter(scorer, 150);
SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<span class=\"highlight\">", "</span>");
Highlighter highlighter = new Highlighter(formatter, scorer);
Fragmenter fragmenter;
if (ObjectType.commit == result.type) {
fragmenter = new SimpleSpanFragmenter(scorer, 1024);
} else {
fragmenter = new SimpleSpanFragmenter(scorer, 150);
}
// use an artificial delimiter for the token
String termTag = "<!--[";
String termTagEnd = "]-->";
SimpleHTMLFormatter formatter = new SimpleHTMLFormatter(termTag, termTagEnd);
Highlighter highlighter = new Highlighter(formatter, scorer);
highlighter.setTextFragmenter(fragmenter);
String [] fragments = highlighter.getBestFragments(stream, content, 5);
if (ArrayUtils.isEmpty(fragments)) {
return content;
}
if (fragments.length == 1) {
return "<pre>" + fragments[0] + "</pre>";
if (ObjectType.blob == result.type) {
return "";
}
return "<pre class=\"text\">" + content + "</pre>";
}
StringBuilder sb = new StringBuilder();
for (int i = 0, len = fragments.length; i < len; i++) {
String fragment = fragments[i].trim();
sb.append("<pre>");
sb.append(fragment);
String fragment = fragments[i];
// resurrect the raw fragment from removing the artificial delimiters
String raw = fragment.replace(termTag, "").replace(termTagEnd, "");
sb.append(getPreTag(result, raw, content));
// replace the artificial delimiter with html tags
String html = fragment.replace(termTag, "<span class=\"highlight\">").replace(termTagEnd, "</span>");
sb.append(html);
sb.append("</pre>");
if (i < len - 1) {
sb.append("<span class=\"ellipses\">...</span><br/>");
@@ -942,6 +960,21 @@ public class LuceneUtils {
}
return sb.toString();
}
private static String getPreTag(SearchResult result, String fragment, String content) {
String pre = "<pre class=\"text\">";
if (ObjectType.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;
}
/**
* Close all the index writers and searchers

+ 7
- 0
src/com/gitblit/utils/StringUtils.java View File

@@ -485,4 +485,11 @@ public class StringUtils {
}
return value;
}
public static int countLines(String value) {
if (isEmpty(value)) {
return 0;
}
return value.split("\n").length;
}
}

+ 14
- 6
src/com/gitblit/wicket/pages/LucenePage.html View File

@@ -3,8 +3,17 @@
xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
xml:lang="en"
lang="en">
<body onload="document.getElementById('fragment').focus();">
<!-- contribute google-code-prettify resources to the page header -->
<wicket:head>
<wicket:link>
<link href="prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="prettify/prettify.js"></script>
</wicket:link>
</wicket:head>
<wicket:extend>
<body onload="document.getElementById('query').focus(); prettyPrint();">
<div class="pageTitle">
<h2><wicket:message key="gb.search"></wicket:message></h2>
</div>
@@ -17,7 +26,7 @@
<div class="span9">
<div>
<h3><wicket:message key="gb.query"></wicket:message></h3>
<input class="span8" wicket:id="query" placeholder="enter search text"></input>
<input class="span8" id="query" wicket:id="query" placeholder="enter search text"></input>
<button class="btn btn-primary" type="submit" value="Search"><wicket:message key="gb.search"></wicket:message></button>
</div>
<div style="margin-top:10px;">
@@ -45,12 +54,11 @@
<div><i wicket:id="type"></i><span class="summary" wicket:id="summary"></span></div>
<div class="body">
<div class="fragment" wicket:id="fragment"></div>
<span class="author" wicket:id="author"></span> committed to <span class="repository" wicket:id="repository"></span>:<span class="branch" wicket:id="branch"></span><br/>
<span class="date" wicket:id="date"></span>
<hr/>
<div><span class="author" wicket:id="author"></span> <span class="date" ><wicket:message key="gb.authored"></wicket:message> <span class="date" wicket:id="date"></span></span></div>
<span class="repository" wicket:id="repository"></span>:<span class="branch" wicket:id="branch"></span>
</div>
</div>
</div>
</wicket:extend>
</body>
</wicket:extend>
</html>

+ 13
- 2
src/com/gitblit/wicket/pages/LucenePage.java View File

@@ -32,10 +32,14 @@ import org.eclipse.jgit.lib.Repository;
import com.gitblit.Constants.SearchType;
import com.gitblit.GitBlit;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.SearchResult;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.LuceneUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.GitBlitWebSession;
import com.gitblit.wicket.StringChoiceRenderer;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.LinkPanel;
@@ -110,7 +114,14 @@ public class LucenePage extends RootPage {
setResponsePage(LucenePage.class, params);
}
};
ListMultipleChoice<String> selections = new ListMultipleChoice<String>("repositories", repositoriesModel, GitBlit.self().getRepositoryList());
UserModel user = GitBlitWebSession.get().getUser();
List<String> availableRepositories = new ArrayList<String>();
for (RepositoryModel model : GitBlit.self().getRepositoryModels(user)) {
availableRepositories.add(model.name);
}
ListMultipleChoice<String> selections = new ListMultipleChoice<String>("repositories",
repositoriesModel, availableRepositories, new StringChoiceRenderer());
selections.setMaxRows(10);
form.add(selections);
form.add(new TextField<String>("query", queryModel));
@@ -153,7 +164,7 @@ public class LucenePage extends RootPage {
item.add(new LinkPanel("repository", null, sr.repository, SummaryPage.class, WicketUtils.newRepositoryParameter(sr.repository)));
item.add(new LinkPanel("branch", "branch", StringUtils.getRelativePath(Constants.R_HEADS, sr.branch), LogPage.class, WicketUtils.newObjectParameter(sr.repository, sr.branch)));
item.add(new Label("author", sr.author));
item.add(WicketUtils.createTimestampLabel("date", sr.date, getTimeZone()));
item.add(WicketUtils.createDatestampLabel("date", sr.date, getTimeZone()));
}
};
add(resultsView.setVisible(results.size() > 0));

Loading…
Cancel
Save