mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-07-04 07:49:00 +02:00
Fix display of ellipsis in search fragments (#1896)
Display ellipsis as an indicator that there is more content before or behind a search result fragment only if there really is more content.
This commit is contained in:
committed by
GitHub
parent
1118ddd146
commit
11673e6d07
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.search;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ContentFragment {
|
||||
private final String fragment;
|
||||
private final boolean matchesContentStart;
|
||||
private final boolean matchesContentEnd;
|
||||
|
||||
ContentFragment(String fragment) {
|
||||
this(fragment, false, false);
|
||||
}
|
||||
|
||||
ContentFragment(String fragment, boolean matchesContentStart, boolean matchesContentEnd) {
|
||||
this.fragment = fragment;
|
||||
this.matchesContentStart = matchesContentStart;
|
||||
this.matchesContentEnd = matchesContentEnd;
|
||||
}
|
||||
}
|
||||
@@ -70,25 +70,32 @@ public final class LuceneHighlighter {
|
||||
return field.isHighlighted() && queriedFields.contains(field.getName());
|
||||
}
|
||||
|
||||
public String[] highlight(String fieldName, Indexed.Analyzer fieldAnalyzer, String value) throws InvalidTokenOffsetsException, IOException {
|
||||
public ContentFragment[] highlight(String fieldName, Indexed.Analyzer fieldAnalyzer, String value) throws InvalidTokenOffsetsException, IOException {
|
||||
String[] fragments = highlighter.getBestFragments(analyzer, fieldName, value, MAX_NUM_FRAGMENTS);
|
||||
if (fieldAnalyzer == Indexed.Analyzer.CODE) {
|
||||
fragments = keepWholeLine(value, fragments);
|
||||
return keepWholeLine(value, fragments);
|
||||
}
|
||||
return Arrays.stream(fragments)
|
||||
.toArray(String[]::new);
|
||||
return Arrays.stream(fragments).map(ContentFragment::new)
|
||||
.toArray(ContentFragment[]::new);
|
||||
}
|
||||
|
||||
private String[] keepWholeLine(String content, String[] fragments) {
|
||||
private ContentFragment[] keepWholeLine(String content, String[] fragments) {
|
||||
return Arrays.stream(fragments)
|
||||
.map(fragment -> keepWholeLine(content, fragment))
|
||||
.toArray(String[]::new);
|
||||
.toArray(ContentFragment[]::new);
|
||||
}
|
||||
|
||||
private String keepWholeLine(String content, String fragment) {
|
||||
private ContentFragment keepWholeLine(String content, String fragment) {
|
||||
boolean matchesContentStart = false;
|
||||
boolean matchesContentEnd = false;
|
||||
|
||||
String raw = fragment.replace(PRE_TAG, "").replace(POST_TAG, "");
|
||||
int index = content.indexOf(raw);
|
||||
|
||||
if (index == 0) {
|
||||
matchesContentStart = true;
|
||||
}
|
||||
|
||||
int start = content.lastIndexOf('\n', index);
|
||||
|
||||
String snippet;
|
||||
@@ -109,9 +116,10 @@ public final class LuceneHighlighter {
|
||||
int end = content.indexOf('\n', index + raw.length());
|
||||
if (end < 0) {
|
||||
end = content.length();
|
||||
matchesContentEnd = true;
|
||||
}
|
||||
|
||||
return snippet + content.substring(index + raw.length(), end) + "\n";
|
||||
return new ContentFragment(snippet + content.substring(index + raw.length(), end) + (matchesContentEnd ? "" : "\n"), matchesContentStart, matchesContentEnd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -75,9 +76,11 @@ public class QueryResultFactory {
|
||||
Object value = field.value(document);
|
||||
if (value != null) {
|
||||
if (highlighter.isHighlightable(field)) {
|
||||
String[] fragments = createFragments(field, value.toString());
|
||||
ContentFragment[] fragments = createFragments(field, value.toString());
|
||||
if (fragments.length > 0) {
|
||||
return of(new Hit.HighlightedField(fragments));
|
||||
boolean firstFragmentMatchesContentStart = fragments[0].isMatchesContentStart();
|
||||
boolean lastFragmentMatchesContentEnd = fragments[fragments.length - 1].isMatchesContentEnd();
|
||||
return of(new Hit.HighlightedField(Arrays.stream(fragments).map(ContentFragment::getFragment).toArray(String[]::new), firstFragmentMatchesContentStart, lastFragmentMatchesContentEnd));
|
||||
}
|
||||
}
|
||||
return of(new Hit.ValueField(value));
|
||||
@@ -85,7 +88,7 @@ public class QueryResultFactory {
|
||||
return empty();
|
||||
}
|
||||
|
||||
private String[] createFragments(LuceneSearchableField field, String value) throws InvalidTokenOffsetsException, IOException {
|
||||
private ContentFragment[] createFragments(LuceneSearchableField field, String value) throws InvalidTokenOffsetsException, IOException {
|
||||
return highlighter.highlight(field.getName(), field.getAnalyzer(), value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user