Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/search uhighlighter #2732

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 51 additions & 97 deletions opengrok-indexer/src/main/java/org/opengrok/indexer/search/Hit.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* portions copyright 2005 Trond Norbye. All rights reserved.
* Use is subject to license terms.
* Portions Copyright (c) 2019, Chris Fraire <cfraire@me.com>.
*/
package org.opengrok.indexer.search;

Expand All @@ -31,16 +32,16 @@
*
* @author Trond Norbye
*/
public class Hit implements Comparable<Hit> {
public class Hit {
/**
* Holds value of property filename.
*/
private String filename;
private final String filename;

/**
* Holds value of property directory.
*/
private String directory;
private final String directory;

/**
* Holds value of property line.
Expand All @@ -65,17 +66,29 @@ public class Hit implements Comparable<Hit> {
/**
* path relative to source root.
*/
private String path;
private final String path;

/**
* Creates a new instance of Hit.
* A phrase match's left offset (inclusive) within the line.
*/
public Hit() {
this(null, null, null, false, false);
private Integer left;

/**
* A phrase match's right offset (exclusive) within the line.
*/
private Integer right;

/**
* Creates a new, possibly-defined instance.
*
* @param filename The name of the file this hit represents
*/
public Hit(String filename) {
this(filename, null, null, false, false);
}

/**
* Creates a new instance of Hit.
* Creates a new, possibly-defined instance.
*
* @param filename The name of the file this hit represents
* @param line The line containing the match
Expand All @@ -88,115 +101,55 @@ public Hit(String filename, String line, String lineno, boolean binary, boolean
File file = new File(filename);
this.path = filename;
this.filename = file.getName();
this.directory = file.getParent();
if (directory == null) {
final String parent = file.getParent();
if (parent == null) {
directory = "";
} else {
directory = parent;
}
} else {
this.path = "";
this.filename = "";
this.directory = "";
}
this.line = line;
this.lineno = lineno;
this.binary = binary;
this.alt = alt;
}

/**
* Getter for property filename.
*
* @return Value of property filename.
*/
public String getFilename() {
return this.filename;
}

/**
* Getter for property path.
*
* @return Value of property path.
*/
public String getPath() {
return this.path;
}

/**
* Getter for property directory.
*
* @return Value of property directory
*/
public String getDirectory() {
return this.directory;
}

/**
* Setter for property filename.
*
* @param filename New value of property filename.
*/
public void setFilename(String filename) {
this.filename = filename;
}

/**
* Getter for property line.
*
* @return Value of property line.
*/
public String getLine() {
return this.line;
}

/**
* Setter for property line.
*
* @param line New value of property line.
*/
public void setLine(String line) {
this.line = line;
}

/**
* Getter for property line no.
*
* @return Value of property line no.
*/
public String getLineno() {
return this.lineno;
}

/**
* Setter for property line no.
*
* @param lineno New value of property line no.
*/
public void setLineno(String lineno) {
this.lineno = lineno;
}

/**
* Compare this object to another hit (in order to implement the comparable interface).
*
* @param o The object to compare this object with
*
* @return the result of a toString().compareTo() of the filename
*/
@Override
public int compareTo(Hit o) throws ClassCastException {
return filename.compareTo(o.filename);
}

/**
* Getter for property binary.
*
* @return Value of property binary.
*/
public boolean isBinary() {
return this.binary;
}

/**
* Setter for property binary.
*
* @param binary New value of property binary.
*/
public void setBinary(boolean binary) {
this.binary = binary;
}
Expand All @@ -206,19 +159,11 @@ public void setBinary(boolean binary) {
*/
private String tag;

/**
* Getter for property tag.
* @return Value of property tag.
*/
public String getTag() {

return this.tag;
}

/**
* Setter for property tag.
* @param tag New value of property tag.
*/
public void setTag(String tag) {

this.tag = tag;
Expand All @@ -233,21 +178,30 @@ public boolean getAlt() {
}

/**
* Check if two objects are equal. Only consider the {@code filename} field
* to match the return value of the {@link #compareTo(Hit)} method.
* @param o the object to compare with
* @return true if the filenames are equal
* Gets the left line offset (inclusive) of a phrase match.
*/
@Override
public boolean equals(Object o) {
if (o instanceof Hit) {
return compareTo((Hit) o) == 0;
}
return false;
public Integer getLeft() {
return this.left;
}

@Override
public int hashCode() {
return filename.hashCode();
/**
* Sets the left line offset (inclusive) of a phrase match.
*/
public void setLeft(Integer left) {
this.left = left;
}

/**
* Gets the right line offset (exclusive) of a phrase match.
*/
public Integer getRight() {
return this.right;
}

/**
* Sets the right line offset (exclusive) of a phrase match.
*/
public void setRight(Integer right) {
this.right = right;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/

/*
* Copyright (c) 2018-2019, Chris Fraire <cfraire@me.com>.
*/

package org.opengrok.indexer.search;

import org.apache.lucene.search.uhighlight.Passage;
import org.apache.lucene.search.uhighlight.PassageFormatter;
import org.opengrok.indexer.analysis.Definitions;
import org.opengrok.indexer.search.context.ContextArgs;
import org.opengrok.indexer.search.context.LineHighlight;
import org.opengrok.indexer.search.context.PassageConverter;
import org.opengrok.indexer.search.context.PhraseHighlight;
import org.opengrok.indexer.util.SourceSplitter;
import org.opengrok.indexer.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.regex.Matcher;

/**
* Represents a subclass of {@link PassageFormatter} that uses
* {@link PassageConverter} to produce {@link Hit} instances.
*/
public class HitFormatter extends SearchFormatterBase {

private String filename;

/**
* Initializes a formatter for the specified arguments.
*/
public HitFormatter() {
super(new PassageConverter(new ContextArgs((short) 0, Short.MAX_VALUE)));
}

/**
* Gets the source code file name, including optional path.
* @return the full path or {@code null}
*/
public String getFilename() {
return filename;
}

/**
* Sets the source code file name.
* @param value the file name to use
*/
public void setFilename(String value) {
this.filename = value;
}

/**
* Splits {@code originalText} using {@link SourceSplitter}, converts
* passages using {@link PassageConverter}, and formats for returning hits
* through the search API.
* @param passages a required instance
* @param originalText a required instance
* @return a defined list of {@link Hit} instances, which might be empty
*/
@Override
public Object format(Passage[] passages, String originalText) {

updateOriginalText(originalText);

SortedMap<Integer, LineHighlight> lines = cvt.convert(passages, splitter);
List<Hit> res = new ArrayList<>();
for (LineHighlight lhi : lines.values()) {
final int lineOffset = lhi.getLineno();

String line = splitter.getLine(lineOffset);
Matcher eolMatcher = StringUtils.STANDARD_EOL.matcher(line);
if (eolMatcher.find()) {
line = line.substring(0, eolMatcher.start());
}

for (int i = 0; i < lhi.countMarkups(); ++i) {
marks.clear();
PhraseHighlight phi = lhi.getMarkup(i);
checkIfMark(line, phi);

Hit hit = new Hit(filename);
// `binary' is false
hit.setLine(line);
hit.setLineno(String.valueOf(lineOffset + 1)); // to 1-offset
hit.setLeft(phi.getLineStart());
hit.setRight(phi.getLineEnd());

if (defs != null) {
// N.b. use ctags 1-offset vs 0-offset.
List<Definitions.Tag> lineTags = defs.getTags(lineOffset + 1);
if (lineTags != null) {
Definitions.Tag pickedTag = findTagForMark(lineTags, marks);
if (pickedTag != null) {
hit.setTag(pickedTag.type);
}
}
}

res.add(hit);
}
}

return res;
}
}
Loading