diffLines = new ArrayList<>();
@@ -137,7 +137,7 @@ public static void assertSymbolStream(Class extends JFlexSymbolMatcher> klass,
count = 0;
for (String token : tokens) {
- // 1-based offset to accord with line #
+ // 1-based index to accord with line #
if (count >= expectedTokens.size()) {
printTokens(tokens);
assertTrue(count < expectedTokens.size(), "too many tokens at term" + (1 + count) + ": " + token);
diff --git a/opengrok-indexer/src/test/java/org/opengrok/indexer/web/SearchHelperTest.java b/opengrok-indexer/src/test/java/org/opengrok/indexer/web/SearchHelperTest.java
index e9fdc041a88..a0ddad7e3f2 100644
--- a/opengrok-indexer/src/test/java/org/opengrok/indexer/web/SearchHelperTest.java
+++ b/opengrok-indexer/src/test/java/org/opengrok/indexer/web/SearchHelperTest.java
@@ -82,7 +82,7 @@ private SearchHelper getSearchHelper(String searchTerm) {
env.getDataRootFile(), env.getSourceRootFile(),
env.getHitsPerPage(), null,
new QueryBuilder().setFreetext(searchTerm), false,
- env.getUrlPrefix(), false, false);
+ null, env.getUrlPrefix(), false, false);
assertNotSame(0, sh.getBuilder().getSize());
return sh;
@@ -93,7 +93,7 @@ private SearchHelper getSearchHelperPath(String searchTerm) {
env.getDataRootFile(), env.getSourceRootFile(),
env.getHitsPerPage(), null,
new QueryBuilder().setPath(searchTerm), false,
- env.getUrlPrefix(), false, false);
+ null, env.getUrlPrefix(), false, false);
assertNotSame(0, sh.getBuilder().getSize());
return sh;
diff --git a/opengrok-web/src/main/java/org/opengrok/web/PageConfig.java b/opengrok-web/src/main/java/org/opengrok/web/PageConfig.java
index b8a211a2ac4..8dd586ce81d 100644
--- a/opengrok-web/src/main/java/org/opengrok/web/PageConfig.java
+++ b/opengrok-web/src/main/java/org/opengrok/web/PageConfig.java
@@ -83,6 +83,7 @@
import org.opengrok.indexer.index.IndexDatabase;
import org.opengrok.indexer.logger.LoggerFactory;
import org.opengrok.indexer.search.QueryBuilder;
+import org.opengrok.indexer.search.context.ContextArgs;
import org.opengrok.indexer.util.IOUtils;
import org.opengrok.indexer.util.LineBreaker;
import org.opengrok.indexer.util.TandemPath;
@@ -1565,6 +1566,7 @@ public SearchHelper prepareInternalSearch(SortOrder sortOrder) {
String xrValue = req.getParameter(QueryParameters.NO_REDIRECT_PARAM);
return new SearchHelper(getSearchStart(), sortOrder, getDataRoot(), new File(getSourceRootPath()),
getSearchMaxItems(), getEftarReader(), getQueryBuilder(), getPrefix() == Prefix.SEARCH_R,
+ getLimitedContextArgs(),
req.getContextPath(), getPrefix() == Prefix.SEARCH_R || getPrefix() == Prefix.SEARCH_P,
xrValue != null && !xrValue.isEmpty());
}
@@ -1851,7 +1853,7 @@ public boolean evaluateMatchOffset() {
breaker.reset(streamSource, in -> ExpandTabsReader.wrap(in, getProject()));
int matchLine = breaker.findLineIndex(matchOffset);
if (matchLine >= 0) {
- // Convert to 1-based offset to accord with OpenGrok line number.
+ // Convert to 1-based index to accord with OpenGrok line number.
fragmentIdentifier = String.valueOf(matchLine + 1);
return true;
}
@@ -1864,4 +1866,59 @@ public boolean evaluateMatchOffset() {
}
return false;
}
+
+ /**
+ * Gets context settings as specified by the user if available or else using
+ * the configured defaults -- but also bound by
+ * {@link ContextArgs#MAX_CONTEXT_SURROUND}.
+ * @return a defined instance
+ */
+ public ContextArgs getLimitedContextArgs() {
+ int userContextSurround = getIntParam(QueryParameters.CONTEXT_SURROUND_PARAM, -1);
+ short contextSurround;
+ if (userContextSurround < 0) {
+ contextSurround = env.getContextSurround();
+ } else {
+ contextSurround = userContextSurround <= Short.MAX_VALUE ?
+ (short) userContextSurround : Short.MAX_VALUE;
+ }
+
+ if (contextSurround < 0) {
+ contextSurround = 0;
+ } else if (contextSurround > ContextArgs.MAX_CONTEXT_SURROUND) {
+ contextSurround = ContextArgs.MAX_CONTEXT_SURROUND;
+ }
+
+ short scaledContextLimit = scaleContextLimit(contextSurround, env.getContextLimit());
+ return new ContextArgs(contextSurround, scaledContextLimit);
+ }
+
+ private short scaleContextLimit(short contextSurround, short contextLimit) {
+ if (contextSurround <= 0) {
+ return contextLimit;
+ }
+ /*
+ * I experimentally arrived at formula below which scales the
+ * surrounding context at a slowing rate until then growing linearly
+ * when sizing for roughly a single match with its large context. I've
+ * actually decided to cap the maximum surrounding context (elsewhere),
+ * so the max() is probably not transformative -- but leaving it
+ * doesn't hurt in case the cap is lifted.
+ *
+ * E.g. for contextLimit=10, the scaled limit as contextSurround grows:
+ * 1 -> 15 2 -> 18 3 -> 20 4 -> 21
+ * ...
+ * 10 -> 25 11 -> 25 12 -> 26
+ * 13 -> 27 [max() is transformative.]
+ * 14 -> 29 [max() is transformative.]
+ * ...
+ */
+ double scale = 1 + Math.log10(3 * contextSurround);
+ long limit = Math.round(scale * contextLimit);
+ limit = Math.max(limit, 2 * contextSurround + 1);
+ if (limit > Short.MAX_VALUE) {
+ return Short.MAX_VALUE;
+ }
+ return (short) limit;
+ }
}
diff --git a/opengrok-web/src/main/webapp/default/print-1.0.2.css b/opengrok-web/src/main/webapp/default/print-1.1.0.css
similarity index 91%
rename from opengrok-web/src/main/webapp/default/print-1.0.2.css
rename to opengrok-web/src/main/webapp/default/print-1.1.0.css
index c37db045d72..890fbf7ab08 100644
--- a/opengrok-web/src/main/webapp/default/print-1.0.2.css
+++ b/opengrok-web/src/main/webapp/default/print-1.1.0.css
@@ -187,14 +187,13 @@ input.submit { /* start search button */
}
/* ############### end of header ############## */
-
/* ############### start of content ############## */
+
#content {
position: static;
overflow-x: hidden;
}
-
/* *** help page *** */
#help h4 {
font-style: italic;
@@ -216,13 +215,22 @@ input.submit { /* start search button */
/* *** more page ***/
#more {
- line-height: 1.25em;
+ line-height: 1.5em;
}
#more b { /* highlight matches */
background-color: #e5e5e5;
}
+#more .ovl, #results .ovl {
+ /*
+ * overline non-consecutive, contextual, "more" line contents or search-
+ * result line contents
+ */
+ border-style: dotted none none none;
+ border-width: 1px;
+ display: block;
+}
/* *** history page *** */
table#revisions {
@@ -259,6 +267,10 @@ table#revisions {
text-align: center;
}
+.rev-message-hidden {
+ display: none;
+}
+
.rssbadge { /* RSS/XML Feed on history page */
text-align: right;
margin: 1ex 0;
@@ -320,19 +332,41 @@ table#dirlist { /* the "Name" column */
border-collapse: collapse;
}
+table#dirlist thead tr:nth-child(1) {
+ height: 22px;
+}
+
#dirlist .r, #dirlist .p {
padding: 0;
margin: 0 0 0 1em;
}
-#dirlist td:nth-child(n+2) { /* all but the first column */
+#dirlist td:nth-child(n+3) { /* all but the first 2 columns */
padding-right: 1em;
}
-#dirlist tbody td:nth-child(4) {
+#dirlist tbody td:nth-child(5) {
text-align: right; /* CSS3 may allow " " (single space char) */
}
+#dirlist td.q { /* 2nd column: H A D */
+ white-space: nowrap;
+ font-size: small;
+ padding-left: 16px;
+ width: 3em;
+}
+
+#dirlist td.numlines { /* 5th column: #Lines */
+ text-align: right; /* CSS3 may allow " " (single space char) */
+}
+
+#dirlist td.loc { /* 6th column: LOC */
+ text-align: right; /* CSS3 may allow " " (single space char) */
+}
+
+span.simplified-path {
+ color: #888;
+}
/* file display */
#src {
@@ -365,6 +399,12 @@ table#dirlist { /* the "Name" column */
color: #000;
}
+/* highlight line number with anchor */
+#src a.l:target, #src a.hl:target {
+ background: orange;
+ color:yellow;
+}
+
.blame .r { /* revision number "column" (annotation) */
text-align: right;
}
@@ -373,6 +413,10 @@ table#dirlist { /* the "Name" column */
text-align: center;
}
+.most_recent_revision {
+ font-weight: bold;
+}
+
/* source code highlighting - see org/opengrok/analysis/$lang/*Xref.lex */
#src .n { /* numbers/label */ color: #a52a2a; }
#src .s { /* strings */ color: green; }
@@ -504,10 +548,6 @@ a.xsr { /* subroutine */ color: #00f; font-weight: bold;
}
/* ############### end of footer ############## */
-.important-note {
- display: none;
-}
-
/* *** scopes *** */
span.scope-head {
@@ -537,3 +577,7 @@ span.scope-signature {
div#scope {
display: none;
}
+
+.important-note {
+ display: none;
+}
diff --git a/opengrok-web/src/main/webapp/default/style-1.0.4.css b/opengrok-web/src/main/webapp/default/style-1.1.0.css
similarity index 96%
rename from opengrok-web/src/main/webapp/default/style-1.0.4.css
rename to opengrok-web/src/main/webapp/default/style-1.1.0.css
index 81ee3061054..93303a7fa9c 100644
--- a/opengrok-web/src/main/webapp/default/style-1.0.4.css
+++ b/opengrok-web/src/main/webapp/default/style-1.1.0.css
@@ -104,6 +104,11 @@ button:hover, button:active, .btn:hover, .btn:active {
label {
}
+label.sch {
+ /* Surrounding context chooser */
+ font-size: small;
+}
+
.pre { /* the diff content */
white-space: pre-wrap;
font-family: monospace;
@@ -500,13 +505,40 @@ html.history #content{
/* *** more page ***/
#more {
- line-height: 1.25em;
+ line-height: 1.5em;
}
#more b { /* highlight matches */
background-color: #ffff99;
}
+#more .ovl, #results .ovl {
+ /*
+ * overline non-consecutive, contextual, "more" line contents or search-
+ * result line contents.
+ */
+ border-style: dotted none none none;
+ border-width: 1px;
+ display: block;
+ white-space: pre;
+ /* Safari work-around re word-wrap when white-space: pre is used. */
+ word-wrap: normal;
+}
+
+#more .xovl, #results .xovl {
+ /*
+ * Applies for contextual search result line contents that are not #ovl.
+ * Technically #more is already in a but avoiding a missing style.
+ */
+ white-space: pre;
+ /* Safari work-around re word-wrap when white-space: pre is used. */
+ word-wrap: normal;
+}
+
+#more .ovl b, #results .ovl b, #more .xovl b, #results .xovl b {
+ /* highlight matches when surrounding context is shown. */
+ background-color: #ffff99;
+}
/* *** history page *** */
table#revisions {
diff --git a/opengrok-web/src/main/webapp/httpheader.jspf b/opengrok-web/src/main/webapp/httpheader.jspf
index 4e96c7f95a3..708890ab902 100644
--- a/opengrok-web/src/main/webapp/httpheader.jspf
+++ b/opengrok-web/src/main/webapp/httpheader.jspf
@@ -45,8 +45,8 @@ org.opengrok.web.Scripts"
PageConfig cfg = PageConfig.get(request);
String styleDir = cfg.getCssDir();
String ctxPath = request.getContextPath();
- String dstyle = styleDir + '/' + "style-1.0.4.min.css";
- String pstyle = styleDir + '/' + "print-1.0.2.min.css";
+ String dstyle = styleDir + '/' + "style-1.1.0.min.css";
+ String pstyle = styleDir + '/' + "print-1.1.0.min.css";
String mstyle = styleDir + '/' + "mandoc-1.0.0.min.css";
%>
Project(s)
- <%
SortedSet pRequested = new TreeSet<>(cfg.getRequestedProjects());
@@ -126,15 +127,15 @@ document.domReady.push(function() { domReadyMenu(); });
- select all
- invert selection
- clear
@@ -148,7 +149,7 @@ document.domReady.push(function() { domReadyMenu(); });
Full Search
-
@@ -156,7 +157,7 @@ document.domReady.push(function() { domReadyMenu(); });
Definition
-
@@ -164,7 +165,7 @@ document.domReady.push(function() { domReadyMenu(); });
Symbol
-
@@ -172,7 +173,7 @@ document.domReady.push(function() { domReadyMenu(); });
File Path
-
@@ -183,7 +184,7 @@ document.domReady.push(function() { domReadyMenu(); });
History
-
@@ -193,7 +194,7 @@ document.domReady.push(function() { domReadyMenu(); });
%>
Type
- <%
String selection = queryParams.getType();
%>
@@ -216,18 +217,25 @@ document.domReady.push(function() { domReadyMenu(); });
-
-
-
-
+
+
+ context
+
-
+ <%-- filled with javascript --%>
diff --git a/opengrok-web/src/main/webapp/minisearch.jspf b/opengrok-web/src/main/webapp/minisearch.jspf
index daf1a0e6eb7..d8196fb9243 100644
--- a/opengrok-web/src/main/webapp/minisearch.jspf
+++ b/opengrok-web/src/main/webapp/minisearch.jspf
@@ -21,10 +21,12 @@ Portions Copyright (c) 2020, Chris Fraire .
--%>
<%@ page session="false" errorPage="error.jsp" import="
org.opengrok.indexer.configuration.Project,
+org.opengrok.indexer.search.context.ContextArgs,
org.opengrok.web.PageConfig,
org.opengrok.indexer.web.Prefix,
org.opengrok.indexer.web.QueryParameters,
-org.opengrok.indexer.web.Util"%><%
+org.opengrok.indexer.web.Util"%>
+<%
/* ---------------------- minisearch.jspf start --------------------- */
{
PageConfig cfg = PageConfig.get(request);
@@ -98,10 +100,20 @@ org.opengrok.indexer.web.Util"%><%
}
%>
- <%
+
+
+
+
+ context
+ <%
Project proj = cfg.getProject();
String[] vals = cfg.getSearchOnlyIn();
- %>
+
+ /> current directory
<%
diff --git a/opengrok-web/src/main/webapp/more.jsp b/opengrok-web/src/main/webapp/more.jsp
index 14f8cf33020..d22a047617a 100644
--- a/opengrok-web/src/main/webapp/more.jsp
+++ b/opengrok-web/src/main/webapp/more.jsp
@@ -1,6 +1,4 @@
<%--
-$Id$
-
CDDL HEADER START
The contents of this file are subject to the terms of the
@@ -84,14 +82,14 @@ file="mast.jsp"
Query tquery = qbuilder.build();
if (tquery != null) {
%>Lines Matching <%= tquery %>
-
+
<%
String xrefPrefix = request.getContextPath() + Prefix.XREF_P;
boolean didPresentNew = false;
if (docId >= 0) {
- didPresentNew = searchHelper.getSourceContext().getContext2(env,
- searchHelper.getSearcher(), docId, out, xrefPrefix, null, false,
- tabSize);
+ didPresentNew = searchHelper.getSourceContext().getContext2(
+ searchHelper.getSearcher(), docId, out, xrefPrefix, null,
+ searchHelper.getUnlimitedContextArgs(), tabSize);
}
if (!didPresentNew) {
/**
diff --git a/opengrok-web/src/main/webapp/search.jsp b/opengrok-web/src/main/webapp/search.jsp
index 6d8e60286a7..06d80b5f6b3 100644
--- a/opengrok-web/src/main/webapp/search.jsp
+++ b/opengrok-web/src/main/webapp/search.jsp
@@ -19,10 +19,8 @@ CDDL HEADER END
Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
Portions Copyright 2011 Jens Elkner.
Portions Copyright (c) 2017-2018, 2020, Chris Fraire .
-
--%>
<%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
-<%@page import="jakarta.servlet.http.HttpServletResponse"%>
<%@page session="false" errorPage="error.jsp" import="
org.apache.lucene.queryparser.classic.QueryParser,
org.opengrok.indexer.search.Results,
@@ -32,11 +30,12 @@ org.opengrok.indexer.web.SearchHelper,
org.opengrok.indexer.web.SortOrder,
org.opengrok.indexer.web.Suggestion,
-java.util.List"
+java.nio.charset.StandardCharsets,
+java.util.List,
+jakarta.servlet.http.Cookie,
+jakarta.servlet.http.HttpServletRequest,
+jakarta.servlet.http.HttpServletResponse"
%>
-<%@ page import="jakarta.servlet.http.HttpServletRequest" %>
-<%@ page import="jakarta.servlet.http.Cookie" %>
-<%@ page import="java.nio.charset.StandardCharsets" %>
<%
{
PageConfig cfg = PageConfig.get(request);