问题
What i have: I display errors in the editor as a red underline and als in the problems view. I use markers for that, but also create annotations by this code:
@TextEditorScoped
public class ErrorHighlighter {
private final IAnnotationModel annotationModel;
private String content = "";
private final Set<Annotation> annotations = Sets.newConcurrentHashSet();
private static final String ERRORMARKERID = "org.eclipse.rwth.syntaxerror";
private static final String WARNINGMARKERID = "org.eclipse.rwth.syntaxwarning";
@Inject
public ErrorHighlighter(@Nullable IAnnotationModel annotationModel, IStorage storage,
ObservableModelStates observableModelStates) {
this.annotationModel = annotationModel;
if (annotationModel != null) {
observableModelStates.getModelStates().stream()
.filter(modelState -> modelState.getStorage().equals(storage))
.forEach(this::acceptModelState);
observableModelStates.addStorageObserver(storage, this::acceptModelState);
}
}
public void acceptModelState(ModelState modelState) {
for (Annotation annotation : annotations) {
annotationModel.removeAnnotation(annotation);
annotations.remove(annotation);
}
IMarker[] problems = null;
int depth = IResource.DEPTH_INFINITE;
IFile file = Misc.getEditorInput(modelState.getStorage()).getAdapter(IFile.class);
try { //Remove all problem Markers when rebuilding the Model
problems = file.findMarkers(ERRORMARKERID, true, depth);
for(IMarker m: problems){
m.delete();
}
problems = file.findMarkers(WARNINGMARKERID, true, depth);
for(IMarker m: problems){
m.delete();
}
} catch (CoreException e) {
e.printStackTrace();
}
try {
content = IOUtils.toString(modelState.getStorage().getContents(), "UTF-8");
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
displaySyntaxErrors(modelState);
displayAdditionalErrors(modelState);
}
private void displaySyntaxErrors(ModelState modelState) {
ImmutableMultimap<Interval, String> syntaxErrors = modelState.getSyntaxErrors();
for (Interval interval: syntaxErrors.keys()) {
for (String message : syntaxErrors.get(interval)) {
Display.getDefault().asyncExec(() -> displayError(interval, message));
}
}
}
private void displayAdditionalErrors(ModelState modelState) {
Multimap<Interval, String> additionalErrors = modelState.getAdditionalErrors();
for (Interval interval: additionalErrors.keys()) {
for (String message : additionalErrors.get(interval)) {
Display.getDefault().asyncExec(() -> displayError(interval, message));
}
}
}
private void displayError(Interval interval, String message) {
int startIndex = interval.a;
int stopIndex = interval.b + 1;
Annotation annotation = null;
// Annotation annotation =
// new Annotation("org.eclipse.ui.workbench.texteditor.error", false, message);
// annotations.add(annotation);
// annotationModel.addAnnotation(annotation, new Position(startIndex, stopIndex - startIndex));
IMarker marker = null;
try { //create Marker to display Syntax Errors in Problems View
IFile file = (IFile) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getEditorInput().getAdapter(IFile.class);
if (file != null) {
if(message.charAt(message.length()-1) == 'W'){
marker = file.createMarker(WARNINGMARKERID);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
} else {
marker = file.createMarker(ERRORMARKERID);
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
}
marker.setAttribute(IMarker.MESSAGE, message);
marker.setAttribute(IMarker.CHAR_START, startIndex);
marker.setAttribute(IMarker.CHAR_END, stopIndex);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
int lineNumber = 0;
if(!content.isEmpty() && content.length()>=stopIndex){ //Convert StartIndex to Line Number
String[] lines = content.substring(0, stopIndex).split("\r\n|\r|\n");
lineNumber = lines.length;
}
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
}
} catch (CoreException e) {
e.printStackTrace();
}
IMarker[] problems = null;
int depth = IResource.DEPTH_INFINITE;
IFile file = (IFile) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getEditorInput().getAdapter(IFile.class);
try { //Remove all problem Markers when rebuilding the Model
problems = file.findMarkers(ERRORMARKERID, true, depth);
for(IMarker m: problems){
for(IMarker n: problems){
if(MarkerUtilities.getCharStart(m) == MarkerUtilities.getCharStart(n) && m != n && MarkerUtilities.getMessage(m).equals(MarkerUtilities.getMessage(n))){
m.delete();
}
}
}
} catch (CoreException e) {
e.printStackTrace();
}
if(marker != null){
Annotation a = new MarkerAnnotation(marker);
annotations.add(a);
annotationModel.addAnnotation(a, new Position(startIndex, stopIndex - startIndex));
}
}
}
In my SourceViewerConfiguration I overwrite getTextHover and getAnnotationHover with this code:
@Override
public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) {
return new DefaultAnnotationHover(true);
}
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
return new DefaultTextHover(sourceViewer);
}
I also overwrite getQuickAssistAssistant with this code:
public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
IQuickAssistAssistant quickAssist = new QuickAssistAssistant();
quickAssist.setQuickAssistProcessor(new TFQuickAssistProcessor());
quickAssist.setInformationControlCreator(getInformationControlCreator(sourceViewer));
return quickAssist;
}
With this i can right klick on errors in the code and select QuickFix, which will result in a Box appearing, which displays my Quick Fix Proposals.
What I want: How do I make this Box appear whenever I hover above the error? Thanks in advance
回答1:
To answer my own question:
I replaced the getTextHover method by this one:
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
return new AbstractAnnotationHover(true) {
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
IAnnotationModel model = ((SourceViewer) textViewer).getAnnotationModel();
@SuppressWarnings("unchecked")
Iterator<Annotation> parent =
((IAnnotationModelExtension2)model).getAnnotationIterator(hoverRegion.getOffset(),
hoverRegion.getLength(), true, true);
Iterator<?> iter = new JavaAnnotationIterator(parent, false);
Annotation annotation = null;
Position position = null;
while (iter.hasNext()) {
Annotation a = (Annotation) iter.next();
Position p = model.getPosition(a);
annotation = a;
position = p;
}
return new AnnotationInfo(annotation, position, textViewer) {
public ICompletionProposal[] getCompletionProposals() {
ICompletionProposal proposal1 = null;
IMarkerResolution [] resolutions = null;
ICompletionProposal [] com = null;
if (annotation instanceof MarkerAnnotation) {
resolutions = new ErrorResolution().getResolutions(((MarkerAnnotation) annotation).getMarker());
if(resolutions.length != 0){
proposal1 = new MarkerResolutionProposal(resolutions[0],
((MarkerAnnotation) annotation).getMarker());
return new ICompletionProposal[] { proposal1 };
}
}
return com ;
}
};
}
};
}
which will result in a hovering box appearing over the errors offering a quick fix. Hope this helps!
回答2:
The selected answer solved my problem, but I also needed to provide textual hover help in addition to the problem resolution proposals. Different hover implementations are needed for textual help and problem resolution proposals.
Here's my implementation of a delegating Hover control, which calls the JDT Annotation hover control if the user is hovering over a problem marker and a resolution proposal is available. Otherwise, it calls an ITextHover implementation which provides textual help if available.
This is loosely based on the JDT implementation of BestMatchHover, which is how the JDT delegates to different Hovers by checking configured hovers in turn and using the first one which returns information. I had some trouble getting the proper presentation from the selected hover, and the JDT implementation was helpful in showing how to provide the appropriate implementations of IInformationControlCreator.
/**
* This class provides a TextHover implementation which delegates to one of two different kinds of
* TextHovers, depending on the current hover contents.
*
* If the mouse is hovering over text for which
* a problem was detected by the parser and a resolution proposal is available, presentation of the
* hover info will be delegated to the JDT Hover control which presents the problem description and
* Hyperlinks for the available proposals. Otherwise an ITextHover implementation will provide textual
* hover help..
*
* The JDT Hover implementation is non-API, and could therefore break in future RCP versions.
*/
public class DelegatingTextHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 {
private ICompletionProposal[] proposals = new ICompletionProposal[0];
protected IRegion currentHoverRegion;
//Provides help info as text
private ITextHover helpHover = new ITextHover() {
@Override
public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
return DelegatingTextHover.this.getHoverRegion(textViewer, offset);
}
@Override
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
String hoverHelp = ...
return hoverHelp;
};
@SuppressWarnings("restriction")
private AbstractAnnotationHover quickFixHover = new AbstractAnnotationHover(true) {
@Override
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
return null;
}
@Override
public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
return DelegatingTextHover.this.getHoverRegion(textViewer, offset);
}
@Override
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
currentHoverRegion = hoverRegion;
IMarker marker = ((MarkerResolutionProposal) proposals[0]).getMarker();
String msg;
try {
msg = (String) marker.getAttribute(IMarker.MESSAGE);
} catch (CoreException e) {
msg = "Parsing Error";
}
return new AnnotationInfo(new Annotation(IMarker.PROBLEM, true, msg),
new Position(hoverRegion.getOffset(), msg.length()),
textViewer) {
@Override
public ICompletionProposal[] getCompletionProposals() {
return proposals;
}
};
}
@Override
public IInformationControlCreator getHoverControlCreator() {
// if we're using the annotation hover, delegate to superclass. Otherwise, use the default
if (hoveringOverProblemAnnotation(currentHoverRegion)) {
return super.getHoverControlCreator();
}
return new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(Shell shell) {
return new DefaultInformationControl(shell, true);
}
};
}
};
@SuppressWarnings({ "restriction", "deprecation" })
@Override
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
proposals = ...
if (hoveringOverProblemAnnotation(hoverRegion)) {
return quickFixHover.getHoverInfo2(textViewer, hoverRegion);
}
currentHoverRegion = hoverRegion;
return helpHover.getHoverInfo(textViewer, hoverRegion);
}
@SuppressWarnings("restriction")
@Override
public IInformationControlCreator getHoverControlCreator() {
if (hoveringOverProblemAnnotation(currentHoverRegion)) {
return quickFixHover.getHoverControlCreator();
}
return null;
}
public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
Point selection= textViewer.getSelectedRange();
if (selection.x <= offset && offset < selection.x + selection.y)
return new Region(selection.x, selection.y);
return new Region(offset, 0);
}
@Override
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
return null;
}
public boolean hoveringOverProblemAnnotation(IRegion hoverRegion) {
List<Point> ranges = new ArrayList<>();
for (ICompletionProposal proposal : proposals) {
//MarkerResolutionProposal is an implementation of ICompletionProposal which wraps a Marker
if (proposal instanceof MarkerResolutionProposal) {
MarkerResolutionProposal markerProposal = (MarkerResolutionProposal) proposal;
IMarker marker = markerProposal.getMarker();
try {
Integer begin = (Integer) marker.getAttribute(IMarker.CHAR_START);
Integer end = (Integer) marker.getAttribute(IMarker.CHAR_END);
ranges.add(new Point(begin, end));
} catch (CoreException e) {
//PASS
}
}
}
boolean found = false;
for (Point p : ranges) {
if (hoverRegion.getOffset() >= p.x && hoverRegion.getOffset() <= p.y) {
found = true;
}
}
return proposals.length > 0 && found;
}
}
来源:https://stackoverflow.com/questions/37587545/eclipse-plugin-implement-quick-fix-proposals-on-hovering-over-errors