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

[ZEN-4820] [WIP] Make Quick Fixes available with mouse interactions #504

Open
wants to merge 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class Messages extends NLS {
public static String outline_proposal_project;
public static String outline_proposal_workspace;

public static String quick_fix_hover_single_quick_fix;
public static String quick_fix_hover_multiple_quick_fixes;

static {
NLS.initializeMessages(BUNDLE_NAME, Messages.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package com.reprezen.swagedit.core.assist;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -61,6 +62,12 @@ public String getErrorMessage() {
return errorMessage;
}

protected Stream<MarkerResolutionProposal> getMarkerResolution(IMarker marker, ISourceViewer viewer) {
return generators.stream() //
.flatMap(generator -> Stream.of(generator.getResolutions(marker))) //
.map(resolution -> new MarkerResolutionProposal(marker, resolution, viewer));
}

@Override
public boolean canFix(Annotation annotation) {
if (annotation.isMarkedDeleted()) {
Expand All @@ -87,11 +94,13 @@ public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationC
return new ICompletionProposal[0];
}

List<MarkerResolutionProposal> result = markers.stream() //
.flatMap(e -> generators.stream()
.flatMap(generator -> Stream.of(generator.getResolutions(e))
.map(m -> new MarkerResolutionProposal(e, m, invocationContext.getSourceViewer()))))
.collect(Collectors.toList());
Collection<MarkerResolutionProposal> result = markers.stream() //
.flatMap(marker -> getMarkerResolution(marker, invocationContext.getSourceViewer())) //
// This is how we return only distinct values.
// Without it we would have multiple quickfixes for the example preferences when multiple markers are
// on the same line.
.collect(Collectors.toMap(proposal -> proposal.getDisplayString(), proposal -> proposal, (u, v) -> u)) //
.values();

return result.toArray(new ICompletionProposal[result.size()]);
}
Expand Down Expand Up @@ -194,7 +203,6 @@ public IContextInformation getContextInformation() {
}
return null;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ContentAssistant;
Expand All @@ -32,12 +33,15 @@
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.reconciler.MonoReconciler;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.widgets.Shell;

import com.reprezen.swagedit.core.assist.JsonContentAssistProcessor;
import com.reprezen.swagedit.core.assist.JsonQuickAssistProcessor;
import com.reprezen.swagedit.core.editor.outline.QuickOutline;
import com.reprezen.swagedit.core.hover.ProblemAnnotationHover;
import com.reprezen.swagedit.core.hover.ProblemTextHover;
import com.reprezen.swagedit.core.schema.CompositeSchema;

public abstract class JsonSourceViewerConfiguration extends YEditSourceViewerConfiguration {
Expand Down Expand Up @@ -75,6 +79,16 @@ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
return ca;
}

@Override
public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) {
return new ProblemAnnotationHover(sourceViewer);
}

@Override
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
return new ProblemTextHover(sourceViewer);
}

protected abstract JsonContentAssistProcessor createContentAssistProcessor(ContentAssistant ca);

@Override
Expand Down Expand Up @@ -103,11 +117,6 @@ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
return new IHyperlinkDetector[] { new URLHyperlinkDetector() };
}

@Override
public IInformationPresenter getInformationPresenter(ISourceViewer sourceViewer) {
return super.getInformationPresenter(sourceViewer);
}

public void setEditor(JsonEditor editor) {
this.editor = editor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.reprezen.swagedit.core.validation.Markers;
import com.reprezen.swagedit.core.validation.SwaggerError;
import com.reprezen.swagedit.core.validation.SwaggerErrorFactory;
import com.reprezen.swagedit.core.validation.Validator;

public class ValidationOperation implements IWorkspaceRunnable {
Expand All @@ -39,6 +40,8 @@ public class ValidationOperation implements IWorkspaceRunnable {
private final boolean parseFileContents;
private final JsonEditor editor;

private final SwaggerErrorFactory factory = new SwaggerErrorFactory();

public ValidationOperation(Validator validator, JsonEditor editor, boolean parseFileContents) {
this.editor = editor;
this.validator = validator;
Expand Down Expand Up @@ -100,11 +103,11 @@ public void run(IProgressMonitor monitor) throws CoreException {
protected void validateYaml(IFile file, JsonDocument document) {
if (document.getYamlError() instanceof YAMLException) {
Markers.addMarker(editor, file, //
SwaggerError.newYamlError((YAMLException) document.getYamlError()));
factory.newYamlError(document, (YAMLException) document.getYamlError()));
}
if (document.getJsonError() instanceof JsonProcessingException) {
Markers.addMarker(editor, file, //
SwaggerError.newJsonError((JsonProcessingException) document.getJsonError()));
factory.newJsonError((JsonProcessingException) document.getJsonError()));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.reprezen.swagedit.core.hover;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IInformationControlExtension4;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ILineDiffInfo;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.editors.text.EditorsUI;

public class AbstractProblemHover {

private final ISourceViewer sourceViewer;

public AbstractProblemHover(ISourceViewer sourceViewer) {
this.sourceViewer = sourceViewer;
}

protected ISourceViewer getSourceViewer() {
return sourceViewer;
}

protected boolean isLineDiffInfo(Annotation annotation) {
return annotation instanceof ILineDiffInfo;
}

protected IAnnotationModel getAnnotationModel() {
return sourceViewer.getAnnotationModel();
}

protected IDocument getDocument() {
return sourceViewer.getDocument();
}

private boolean isHandled(Annotation annotation) {
return true;
}

private IInformationControlCreator presenterControlCreator;
private HoverControlCreator hoverControlCreator;

private static final class PresenterControlCreator extends AbstractReusableInformationControlCreator {

@Override
public IInformationControl doCreateInformationControl(Shell parent) {
// DIFF: do not show toolbar in hover, no configuration supported (2)
// return new AnnotationInformationControl(parent, new ToolBarManager(SWT.FLAT));
return new QuickFixInformationControl(parent, true);
}
}

private static final class HoverControlCreator extends AbstractReusableInformationControlCreator {
private final IInformationControlCreator presenterControlCreator;

public HoverControlCreator(IInformationControlCreator presenterControlCreator) {
this.presenterControlCreator = presenterControlCreator;
}

@Override
public IInformationControl doCreateInformationControl(Shell parent) {
return new QuickFixInformationControl(parent, EditorsUI.getTooltipAffordanceString()) {

@Override
public IInformationControlCreator getInformationPresenterControlCreator() {
return presenterControlCreator;
}
};
}

@Override
public boolean canReuse(IInformationControl control) {
if (!super.canReuse(control))
return false;

if (control instanceof IInformationControlExtension4)
((IInformationControlExtension4) control).setStatusText(EditorsUI.getTooltipAffordanceString());

return true;
}
}

public IInformationControlCreator getHoverControlCreator() {
if (hoverControlCreator == null)
hoverControlCreator = new HoverControlCreator(getInformationPresenterControlCreator());
return hoverControlCreator;
}

public IInformationControlCreator getInformationPresenterControlCreator() {
if (presenterControlCreator == null)
presenterControlCreator = new PresenterControlCreator();
return presenterControlCreator;
}

public List<Annotation> getAnnotations(final int lineNumber, final int offset) {
if (getAnnotationModel() == null) {
return Collections.emptyList();
}

final Iterator<?> iterator = getAnnotationModel().getAnnotationIterator();
List<Annotation> result = new ArrayList<>();
while (iterator.hasNext()) {
final Annotation annotation = (Annotation) iterator.next();
if (isHandled(annotation)) {
Position position = getAnnotationModel().getPosition(annotation);
if (position != null) {
final int start = position.getOffset();
final int end = start + position.getLength();

if (offset > 0 && !(start <= offset && offset <= end)) {
continue;
}
try {
int startLine = getDocument().getLineOfOffset(start);
if (lineNumber != startLine) {
continue;
}
} catch (final Exception x) {
continue;
}
if (!isLineDiffInfo(annotation)) {
result.add(annotation);
}
}
}
}
return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.reprezen.swagedit.core.hover;

import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.source.Annotation;

public class AnnotationInfo {
public final Annotation annotation;
public final Position position;
public final ITextViewer viewer;
public final ICompletionProposal[] proposals;

public AnnotationInfo(Annotation annotation, Position position, ITextViewer textViewer,
ICompletionProposal[] proposals) {
this.annotation = annotation;
this.position = position;
this.viewer = textViewer;
this.proposals = proposals;
}

public ICompletionProposal[] getCompletionProposals() {
return proposals;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.reprezen.swagedit.core.hover;

import java.util.List;

import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationHover;
import org.eclipse.jface.text.source.IAnnotationHoverExtension;
import org.eclipse.jface.text.source.IAnnotationHoverExtension2;
import org.eclipse.jface.text.source.ILineRange;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.LineRange;

public class ProblemAnnotationHover extends AbstractProblemHover
implements IAnnotationHover, IAnnotationHoverExtension, IAnnotationHoverExtension2 {

public ProblemAnnotationHover(ISourceViewer sourceViewer) {
super(sourceViewer);
}

@Override
public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
return null;
}

@Override
public boolean canHandleMouseWheel() {
return false;
}

@Override
public boolean canHandleMouseCursor() {
return false;
}

@Override
public Object getHoverInfo(ISourceViewer sourceViewer, ILineRange lineRange, int visibleNumberOfLines) {
List<Annotation> annotations = getAnnotations(lineRange.getStartLine(), -1);

AnnotationInfo result = annotations.stream() //
.filter(ann -> ann.getText() != null) //
.map(ann -> {
Position position = getAnnotationModel().getPosition(ann);
return new AnnotationInfo(ann, position, sourceViewer, new ICompletionProposal[] {});
}) //
// We return only one marker to avoid UI complexities
.findFirst() //
.orElse(null);

return result;
}

@Override
public ILineRange getHoverLineRange(ISourceViewer viewer, int lineNumber) {
return new LineRange(lineNumber, 1);
}

}
Loading