Bug 574248: [SourceEditor] Add common command support for quick assist
proposals
- Add command definition, handler and keybinding for quick assist
Rename in File
- Update icon for linked rename actions/proposals
Change-Id: I4bd582dd0db9f04534bd08e6dca230065ff173e2
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename.png
new file mode 100644
index 0000000..502d932
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename@2x.png
new file mode 100644
index 0000000..1d02a84
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/linked_rename@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/text-linked_rename.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/text-linked_rename.png
deleted file mode 100644
index 083e4cc..0000000
--- a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/text-linked_rename.png
+++ /dev/null
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/plugin.properties b/ltk/org.eclipse.statet.ltk.ui/plugin.properties
index a8f5dfb..f2a1970 100644
--- a/ltk/org.eclipse.statet.ltk.ui/plugin.properties
+++ b/ltk/org.eclipse.statet.ltk.ui/plugin.properties
@@ -67,6 +67,8 @@
commands_CorrectLineWrap_description= Corrects the line wrap of current line/selected lines
commands_ToggleReportProblemWhenTyping_name= Toggle Report Problems as you type
commands_ToggleReportProblemWhenTyping_description= Toggles the activation of reporting problems as you type in editors of current type
+commands_QuickAssistRenameInFile_name= Quick Assist - Rename in File
+commands_QuickAssistRenameInFile_description= Links all references for a local rename in the current file
commands_RefactorRenameInWorkspace_name= Rename in Workspace...
commands_RefactorRenameInWorkspace_description= Renames the selected identifier in the workspace
commands_RefactorRenameInSelectedRegion_name= Rename in Selected Region...
diff --git a/ltk/org.eclipse.statet.ltk.ui/plugin.xml b/ltk/org.eclipse.statet.ltk.ui/plugin.xml
index 0c0d6dd..a27d0db 100644
--- a/ltk/org.eclipse.statet.ltk.ui/plugin.xml
+++ b/ltk/org.eclipse.statet.ltk.ui/plugin.xml
@@ -217,8 +217,15 @@
id="org.eclipse.statet.ltk.commands.ToggleLiveReportProblems"
categoryId="org.eclipse.statet.workbench.commandCategorys.Source"
name="%commands_ToggleReportProblemWhenTyping_name"
- description="%commands_ToggleReportProblemWhenTyping_description"
- />
+ description="%commands_ToggleReportProblemWhenTyping_description"/>
+
+ <!-- quick assist -->
+ <command
+ id="org.eclipse.statet.ltk.commands.QuickAssistRenameInFile"
+ categoryId="org.eclipse.statet.workbench.commandCategorys.Source"
+ name="%commands_QuickAssistRenameInFile_name"
+ description="%commands_QuickAssistRenameInFile_description"/>
+
<!-- refactor -->
<command
id="org.eclipse.statet.ltk.commands.RefactorRenameInWorkspace"
@@ -249,12 +256,13 @@
disabledIcon="icons/tool_16_d/mark-occurrences.png" />
<image
commandId="org.eclipse.statet.workbench.commands.CopyElementName"
- icon="icons/tool_16/copy-name.png">
- </image>
+ icon="icons/tool_16/copy-name.png"/>
<image
commandId="org.eclipse.statet.workbench.commands.OpenSearchDialog"
- icon="icons/tool_16/search.gif">
- </image>
+ icon="icons/tool_16/search.gif"/>
+ <image
+ commandId="org.eclipse.statet.ltk.commands.QuickAssistRenameInFile"
+ icon="icons/obj_16/linked_rename.png"/>
</extension>
<extension
@@ -413,8 +421,14 @@
commandId="org.eclipse.ui.edit.text.showInformation"
contextId="org.eclipse.statet.workbench.contexts.StructuredElementViewer"
schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
- sequence="F2">
- </key>
+ sequence="F2"/>
+
+ <key
+ commandId="org.eclipse.statet.ltk.commands.QuickAssistRenameInFile"
+ contextId="org.eclipse.statet.workbench.contexts.TextEditor"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"
+ sequence="M1+2 R"/>
+
<key
commandId="org.eclipse.statet.ltk.commands.RefactorRenameInWorkspace"
contextId="org.eclipse.statet.workbench.contexts.TextEditor"
@@ -508,6 +522,18 @@
</with>
</activeWhen>
</handler>
+ <handler
+ commandId="org.eclipse.statet.ltk.commands.QuickAssistRenameInFile">
+ <class class="org.eclipse.statet.ltk.ui.sourceediting.actions.QuickAssistCommandHandler"/>
+ <activeWhen>
+ <with
+ variable="activePart">
+ <instanceof
+ value="org.eclipse.statet.ltk.ui.sourceediting.SourceEditor1">
+ </instanceof>
+ </with>
+ </activeWhen>
+ </handler>
</extension>
<extension
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
index e9f1c92..9f6ae25 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
@@ -138,7 +138,7 @@
util.register(LtkUI.OBJ_TEXT_TEMPLATE_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-template.png"); //$NON-NLS-1$
util.register(LtkUI.OBJ_TEXT_AT_TAG_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-at_tag.png"); //$NON-NLS-1$
- util.register(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-linked_rename.png"); //$NON-NLS-1$
+ util.register(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID, ImageRegistryUtil.T_OBJ, "linked_rename.png"); //$NON-NLS-1$
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkActions.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkActions.java
index d7c913c..76981c3 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkActions.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkActions.java
@@ -176,6 +176,15 @@
"org.eclipse.statet.ltk.commands.CorrectLineWrap"; //$NON-NLS-1$
+ /**
+ * ID of command 'Quick Assist - Rename in File'.
+ *
+ * Value: @value
+ */
+ public static final String QUICK_ASSIST_RENAME_IN_FILE=
+ "org.eclipse.statet.ltk.commands.QuickAssistRenameInFile";
+
+
//--Search--
/**
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractOpenDeclarationHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractOpenDeclarationHandler.java
index 2826f8b..7ac4ede 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractOpenDeclarationHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractOpenDeclarationHandler.java
@@ -20,7 +20,6 @@
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.osgi.util.NLS;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
@@ -42,19 +41,14 @@
@Override
- public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
- final SourceEditor editor= getSourceEditor(event.getApplicationContext());
- if (editor == null || !isSupported(editor)) {
- return null;
- }
-
+ protected @Nullable Object execute(final SourceEditor editor, final ExecutionEvent event)
+ throws ExecutionException {
final ITextSelection selection= (ITextSelection)editor.getViewer().getSelection();
if (execute(editor,
JFaceTextRegion.newByStartLength(selection.getOffset(), selection.getLength())) ) {
return null;
}
- Display.getCurrent().beep();
- return null;
+ return ACTION_NOT_AVAILABLE;
}
protected abstract boolean execute(SourceEditor editor, TextRegion selection);
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractSourceEditorHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractSourceEditorHandler.java
index 7eca4e9..a6399e2 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractSourceEditorHandler.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/AbstractSourceEditorHandler.java
@@ -17,7 +17,10 @@
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
@@ -33,6 +36,10 @@
public abstract class AbstractSourceEditorHandler extends AbstractHandler {
+ protected static final Object ACTION_NOT_AVAILABLE= new Object();
+ protected static final Object DOCUMENT_NOT_EDITABLE= new Object();
+
+
private final @Nullable SourceEditor editor;
@@ -63,22 +70,57 @@
return null;
}
- protected boolean isSupported(final SourceEditor sourceEditor) {
- final SourceViewer viewer= sourceEditor.getViewer();
- return (UIAccess.isOkToUse(viewer) && viewer.getDocument() != null);
+ protected boolean isSupported(final SourceEditor editor) {
+ final SourceViewer viewer= editor.getViewer();
+ return (UIAccess.isOkToUse(viewer)
+ && viewer.getDocument() != null );
+ }
+
+ protected boolean isEditAction() {
+ return false;
}
@Override
public void setEnabled(@Nullable final Object evaluationContext) {
final SourceEditor editor= getSourceEditor(evaluationContext);
- if (editor == null || !isSupported(editor)) {
- setBaseEnabled(false);
- return;
- }
-
- setBaseEnabled(true);
+ setBaseEnabled(editor != null && isSupported(editor)
+ && (!isEditAction() || editor.isEditable(false)) );
}
+ @Override
+ public @Nullable Object execute(final ExecutionEvent event) throws ExecutionException {
+ final SourceEditor editor= getSourceEditor(event.getApplicationContext());
+ if (!(editor != null && isSupported(editor)
+ && (!isEditAction() || editor.isEditable(false)) )) {
+ return null;
+ }
+
+ final Object result= execute(editor, event);
+ if (result == ACTION_NOT_AVAILABLE) {
+ onActionNotAvailable();
+ return null;
+ }
+ if (result == DOCUMENT_NOT_EDITABLE) {
+ onDocumentNotEditable();
+ return null;
+ }
+ return result;
+ }
+
+ protected @Nullable Object execute(final SourceEditor editor,
+ final ExecutionEvent event) throws ExecutionException {
+ return null;
+ }
+
+
+ protected void onActionNotAvailable() {
+ Display.getCurrent().beep();
+ }
+
+ protected void onDocumentNotEditable() {
+ onActionNotAvailable();
+ }
+
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/QuickAssistCommandHandler.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/QuickAssistCommandHandler.java
new file mode 100644
index 0000000..0f3336d
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/actions/QuickAssistCommandHandler.java
@@ -0,0 +1,105 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting.actions;
+
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.isNull;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullLateInit;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
+import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
+import org.eclipse.swt.graphics.Point;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor;
+import org.eclipse.statet.ltk.ui.sourceediting.assist.AssistProposal;
+import org.eclipse.statet.ltk.ui.sourceediting.assist.QuickAssistProcessorCommandExtension;
+
+
+@NonNullByDefault
+public class QuickAssistCommandHandler extends AbstractSourceEditorHandler
+ implements IExecutableExtension {
+
+
+ private String commandId;
+
+
+ public QuickAssistCommandHandler(final String commandId) {
+ this.commandId= commandId;
+ }
+
+ public QuickAssistCommandHandler() {
+ this.commandId= nonNullLateInit();
+ }
+
+ @Override
+ public void setInitializationData(final IConfigurationElement config,
+ final String propertyName, @Nullable final Object data) throws CoreException {
+ if (isNull(this.commandId)) {
+ this.commandId= nonNullAssert(config.getAttribute("commandId")).intern(); //$NON-NLS-1$
+ }
+ }
+
+
+ @Override
+ protected boolean isEditAction() {
+ return true;
+ }
+
+
+ @Override
+ protected @Nullable Object execute(final SourceEditor editor,
+ final ExecutionEvent event) throws ExecutionException {
+ final var processor= getProcessor(editor);
+ if (processor == null) {
+ return ACTION_NOT_AVAILABLE;
+ }
+ final var document= nonNullAssert(editor.getViewer().getDocument());
+ final var invocationContext= editor.getViewer().getQuickAssistInvocationContext();
+ final AssistProposal proposal= processor.findQuickAssist(invocationContext, this.commandId);
+ if (proposal == null) {
+ return ACTION_NOT_AVAILABLE;
+ }
+
+ if (isEditAction() && !editor.isEditable(true)) {
+ return DOCUMENT_NOT_EDITABLE;
+ }
+ proposal.apply(editor.getViewer(), (char)0, 0, invocationContext.getOffset());
+ final Point selection= proposal.getSelection(document);
+ if (selection != null) {
+ editor.selectAndReveal(selection.x, selection.y);
+ }
+ return null;
+ }
+
+ private @Nullable QuickAssistProcessorCommandExtension getProcessor(final SourceEditor editor) {
+ final IQuickAssistAssistant assistant= editor.getViewer().getQuickAssistAssistant();
+ if (assistant != null) {
+ final IQuickAssistProcessor processor= assistant.getQuickAssistProcessor();
+ if (processor instanceof QuickAssistProcessorCommandExtension) {
+ return (QuickAssistProcessorCommandExtension)processor;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CommandAssistProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CommandAssistProposal.java
index c8d4526..d5a1cc6 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CommandAssistProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/CommandAssistProposal.java
@@ -14,6 +14,10 @@
package org.eclipse.statet.ltk.ui.sourceediting.assist;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
+import static org.eclipse.statet.ecommons.ui.actions.UIActions.NO_COMMAND_ID;
+
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.text.DocumentEvent;
@@ -27,6 +31,8 @@
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
+import org.eclipse.statet.jcommons.text.core.BasicTextRegion;
+import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.text.ui.DefaultBrowserInformationInput;
import org.eclipse.statet.ecommons.ui.workbench.WorkbenchUIUtils;
@@ -35,8 +41,79 @@
@NonNullByDefault
-public abstract class CommandAssistProposal implements AssistProposal, CommandAccess,
- ICompletionProposalExtension5, ICompletionProposalExtension6 {
+public abstract class CommandAssistProposal<TContext extends AssistInvocationContext>
+ implements AssistProposal, CommandAccess, ICompletionProposalExtension5, ICompletionProposalExtension6 {
+
+
+ public static class ProposalParameters<TContext extends AssistInvocationContext> {
+
+
+ public final TContext context;
+
+ public final String commandId;
+
+ public final String label;
+ public final @Nullable String description;
+
+ public int relevance;
+
+
+ public ProposalParameters(final TContext context, final String commandId,
+ final String label, final @Nullable String description,
+ final int relevance) {
+ this.context= nonNullAssert(context);
+ this.commandId= nonNullAssert(commandId);
+ this.label= nonNullAssert(label);
+ this.description= description;
+ this.relevance= relevance;
+ }
+
+
+ }
+
+
+ protected static class ApplyData {
+
+
+ private @Nullable TextRegion selectionToSet;
+
+ private @Nullable IContextInformation contextInformation;
+
+
+ public ApplyData() {
+ }
+
+
+ public void setSelection(final TextRegion region) {
+ this.selectionToSet= region;
+ }
+
+ public void setSelection(final int offset) {
+ this.selectionToSet= new BasicTextRegion(offset, offset);
+ }
+
+ public void setSelection(final int offset, final int length) {
+ assert (length >= 0);
+ this.selectionToSet= new BasicTextRegion(offset, offset + length);
+ }
+
+ public void clearSelection() {
+ this.selectionToSet= null;
+ }
+
+ public @Nullable TextRegion getSelection() {
+ return this.selectionToSet;
+ }
+
+ public void setContextInformation(final IContextInformation info) {
+ this.contextInformation= info;
+ }
+
+ public @Nullable IContextInformation getContextInformation() {
+ return this.contextInformation;
+ }
+
+ }
protected static StyledString addAcceleratorStyled(final String message,
@@ -51,29 +128,35 @@
}
- private final AssistInvocationContext context;
+ private final TContext context;
private final String commandId;
- private String label;
- private String description;
+ private final String label;
+ private final @Nullable String description;
- private int relevance;
+ private final int relevance;
+
+ private @Nullable ApplyData applyData;
- protected CommandAssistProposal(final AssistInvocationContext invocationContext,
- final String commandId) {
- this.context= invocationContext;
- this.commandId= commandId;
+ public CommandAssistProposal(final ProposalParameters<TContext> parameters) {
+ this.context= parameters.context;
+ this.commandId= parameters.commandId;
+ this.label= parameters.label;
+ this.description= parameters.description;
+ this.relevance= parameters.relevance;
}
- public CommandAssistProposal(final AssistInvocationContext invocationContext,
- final String commandId,
- final String label, final String description) {
- this(invocationContext, commandId);
+ @SuppressWarnings("null")
+ protected CommandAssistProposal(final TContext invocationContext, final String commandId,
+ final String label, final @Nullable String description) {
+ this.context= nonNullAssert(invocationContext);
+ this.commandId= nonNullAssert(commandId);
this.label= label;
this.description= description;
+ this.relevance= 0;
}
@@ -82,39 +165,21 @@
return this.commandId;
}
- protected AssistInvocationContext getInvocationContext() {
+ protected final TContext getInvocationContext() {
return this.context;
}
-
- protected void setLabel(final String label) {
- this.label= label;
+ protected final ApplyData getApplyData() {
+ ApplyData applyData= this.applyData;
+ if (applyData == null) {
+ applyData= createApplyData();
+ this.applyData= applyData;
+ }
+ return applyData;
}
- protected void setDescription(final String description) {
- this.description= description;
- }
-
- protected void setRelevance(final int relevance) {
- this.relevance= relevance;
- }
-
-
- @Override
- public boolean validate(final IDocument document, final int offset,
- final @Nullable DocumentEvent event) {
- return false;
- }
-
-
- @Override
- public void apply(final IDocument document) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @Nullable Point getSelection(final IDocument document) {
- return null;
+ protected ApplyData createApplyData() {
+ return new ApplyData();
}
@@ -128,6 +193,12 @@
return this.label;
}
+
+ @Override
+ public @Nullable Image getImage() {
+ return null;
+ }
+
@Override
public String getDisplayString() {
return this.label;
@@ -135,12 +206,16 @@
@Override
public StyledString getStyledDisplayString() {
- return addAcceleratorStyled(getDisplayString(), WorkbenchUIUtils.getBestKeyBinding(this.commandId));
+ return addAcceleratorStyled(getDisplayString(), (this.commandId != NO_COMMAND_ID) ?
+ WorkbenchUIUtils.getBestKeyBinding(this.commandId) :
+ null );
}
+
@Override
- public @Nullable Image getImage() {
- return null;
+ public boolean validate(final IDocument document, final int offset,
+ final @Nullable DocumentEvent event) {
+ return false;
}
@Override
@@ -160,6 +235,23 @@
@Override
+ public void apply(final IDocument document) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public @Nullable Point getSelection(final IDocument document) {
+ final var applyData= this.applyData;
+ if (applyData != null) {
+ final TextRegion selection= applyData.getSelection();
+ if (selection != null) {
+ return new Point(selection.getStartOffset(), selection.getLength());
+ }
+ }
+ return null;
+ }
+
+ @Override
public @Nullable IContextInformation getContextInformation() {
return null;
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
index b8a993f..0909a87 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
@@ -14,11 +14,8 @@
package org.eclipse.statet.ltk.ui.sourceediting.assist;
-import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
-
import static org.eclipse.statet.ltk.ui.LtkUI.BUNDLE_ID;
-import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.BadLocationException;
@@ -26,8 +23,6 @@
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
-import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
-import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.link.LinkedModeModel;
import org.eclipse.jface.text.link.LinkedModeUI;
import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags;
@@ -45,16 +40,14 @@
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.TextRegion;
-import org.eclipse.statet.ecommons.text.ui.DefaultBrowserInformationInput;
-
import org.eclipse.statet.ltk.ui.LtkUI;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.TextEditToolSynchronizer;
@NonNullByDefault
-public abstract class LinkedNamesAssistProposal implements AssistProposal,
- ICompletionProposalExtension5 {
+public abstract class LinkedNamesAssistProposal<TContext extends AssistInvocationContext>
+ extends CommandAssistProposal<TContext> {
/**
@@ -97,25 +90,17 @@
}
- private final AssistInvocationContext context;
-
- private String label;
- private @Nullable String description;
- private int relevance;
-
private @Nullable String valueSuggestion;
- @SuppressWarnings("null")
- public LinkedNamesAssistProposal(final AssistInvocationContext invocationContext) {
- this.context= nonNullAssert(invocationContext);
+ public LinkedNamesAssistProposal(final ProposalParameters<TContext> parameters) {
+ super(parameters);
}
- protected void init(final String label, final @Nullable String description, final int relevance) {
- this.label= nonNullAssert(label);
- this.description= description;
- this.relevance= relevance;
+ @Override
+ public Image getImage() {
+ return LtkUI.getUIResources().getImage(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID);
}
@@ -125,8 +110,10 @@
return false;
}
+
@Override
- public void apply(final ITextViewer viewer, final char trigger, final int stateMask, final int offset) {
+ public void apply(final ITextViewer viewer, final char trigger, final int stateMask,
+ final int offset) {
try {
// by default full word is selected by linked model ui
// instead we want to keep the original selection by default
@@ -151,7 +138,7 @@
model.addGroup(group);
model.forceInstall();
- { final SourceEditor editor= this.context.getEditor();
+ { final SourceEditor editor= getInvocationContext().getEditor();
final TextEditToolSynchronizer synchronizer;
if (editor != null && (synchronizer= editor.getTextEditToolSynchronizer()) != null) {
synchronizer.install(model);
@@ -202,7 +189,7 @@
final @Nullable Position position, final int idx) throws BadLocationException {
if (position != null) {
group.addPosition(new LinkedPosition(document, position.getOffset(), position.getLength(), idx));
- return idx+1;
+ return idx + 1;
}
return idx;
}
@@ -211,64 +198,10 @@
final @Nullable TextRegion position, final int idx) throws BadLocationException {
if (position != null) {
group.addPosition(new LinkedPosition(document, position.getStartOffset(), position.getLength(), idx));
- return idx+1;
+ return idx + 1;
}
return idx;
}
- @Override
- public void apply(final IDocument document) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @Nullable Point getSelection(final IDocument document) {
- return null;
- }
-
-
- @Override
- public int getRelevance() {
- return this.relevance;
- }
-
- @Override
- public String getSortingString() {
- return this.label;
- }
-
-
- @Override
- public String getDisplayString() {
- return this.label;
- }
-
- @Override
- public Image getImage() {
- return LtkUI.getUIResources().getImage(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID);
- }
-
-
- @Override
- public @Nullable String getAdditionalProposalInfo() {
- return this.description;
- }
-
- @Override
- public @Nullable Object getAdditionalProposalInfo(final IProgressMonitor monitor) {
- final var description= this.description;
- if (description == null) {
- return null;
- }
- return new DefaultBrowserInformationInput(getDisplayString(),
- description, DefaultBrowserInformationInput.FORMAT_TEXT_INPUT );
- }
-
-
- @Override
- public @Nullable IContextInformation getContextInformation() {
- return null;
- }
-
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/MultiContentSectionQuickAssistProcessor.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/MultiContentSectionQuickAssistProcessor.java
index 5ec7093..7ddc202 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/MultiContentSectionQuickAssistProcessor.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/MultiContentSectionQuickAssistProcessor.java
@@ -14,13 +14,21 @@
package org.eclipse.statet.ltk.ui.sourceediting.assist;
+import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
+
import java.util.IdentityHashMap;
import java.util.Map;
+import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+import org.eclipse.statet.jcommons.lang.NonNull;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.text.core.sections.DocContentSections;
@@ -34,7 +42,9 @@
*
* @see DocContentSections
*/
-public class MultiContentSectionQuickAssistProcessor implements IQuickAssistProcessor {
+@NonNullByDefault
+public class MultiContentSectionQuickAssistProcessor
+ implements IQuickAssistProcessor, QuickAssistProcessorCommandExtension {
private static final Object NULL= new Object();
@@ -44,14 +54,11 @@
private final Map<String, Object> processors= new IdentityHashMap<>(8);
- private String errorMessage;
+ private @Nullable String errorMessage;
public MultiContentSectionQuickAssistProcessor(final DocContentSections sections) {
- if (sections == null) {
- throw new NullPointerException("sections"); //$NON-NLS-1$
- }
- this.sections= sections;
+ this.sections= nonNullAssert(sections);
}
@@ -62,7 +69,7 @@
this.processors.put(sectionType, (processor != null) ? processor : NULL);
}
- protected final IQuickAssistProcessor getProcessor(final String sectionType) {
+ protected final @Nullable IQuickAssistProcessor getProcessor(final String sectionType) {
if (sectionType == DocContentSections.ERROR) {
return null;
}
@@ -83,10 +90,19 @@
return (processor != NULL) ? (IQuickAssistProcessor) processor : null;
}
- protected IQuickAssistProcessor createProcessor(final String sectionType) {
+ protected @Nullable IQuickAssistProcessor createProcessor(final String sectionType) {
return null;
}
+ public @Nullable IQuickAssistProcessor getProcessor(final IQuickAssistInvocationContext invocationContext) {
+ final ISourceViewer sourceViewer= invocationContext.getSourceViewer();
+ final IDocument document;
+ if (sourceViewer == null || (document= sourceViewer.getDocument()) == null) {
+ return null;
+ }
+ return getProcessor(this.sections.getType(document, invocationContext.getOffset()));
+ }
+
@Override
public boolean canFix(final Annotation annotation) {
@@ -98,11 +114,12 @@
return false;
}
+
@Override
- public ICompletionProposal[] computeQuickAssistProposals(final IQuickAssistInvocationContext invocationContext) {
+ public @NonNull ICompletionProposal @Nullable [] computeQuickAssistProposals(
+ final IQuickAssistInvocationContext invocationContext) {
this.errorMessage= null;
- final IQuickAssistProcessor processor= getProcessor(
- this.sections.getType(invocationContext.getSourceViewer().getDocument(), invocationContext.getOffset() ));
+ final IQuickAssistProcessor processor= getProcessor(invocationContext);
if (processor != null) {
try {
return processor.computeQuickAssistProposals(invocationContext);
@@ -115,8 +132,21 @@
}
@Override
- public String getErrorMessage() {
+ public @Nullable String getErrorMessage() {
return this.errorMessage;
}
+
+ @Override
+ public @Nullable AssistProposal findQuickAssist(
+ final IQuickAssistInvocationContext invocationContext,
+ final String commandId) {
+ final IQuickAssistProcessor processor= getProcessor(invocationContext);
+ if (processor instanceof QuickAssistProcessorCommandExtension) {
+ return ((QuickAssistProcessorCommandExtension)processor)
+ .findQuickAssist(invocationContext, commandId);
+ }
+ return null;
+ }
+
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessor.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessor.java
index dd0a8b3..5ab21e8 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessor.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessor.java
@@ -35,18 +35,19 @@
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
-import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.texteditor.spelling.SpellingAnnotation;
import org.eclipse.ui.texteditor.spelling.SpellingProblem;
+import org.eclipse.statet.jcommons.lang.NonNull;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ecommons.text.core.util.TextUtils;
import org.eclipse.statet.ltk.model.core.ModelManager;
+import org.eclipse.statet.ltk.ui.sourceediting.CommandAccess;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor;
@@ -54,7 +55,8 @@
* LTK quick assistant processor.
*/
@NonNullByDefault
-public class QuickAssistProcessor implements IQuickAssistProcessor {
+public class QuickAssistProcessor
+ implements IQuickAssistProcessor, QuickAssistProcessorCommandExtension {
private static class SpellingProposal implements AssistProposal {
@@ -74,7 +76,7 @@
final Method method= this.proposal.getClass().getMethod("getRelevance"); //$NON-NLS-1$
final Object value= method.invoke(this.proposal);
if (value instanceof Integer) {
- return ((Integer) value).intValue();
+ return ((Integer)value).intValue();
}
}
catch (final Exception e) {
@@ -102,14 +104,14 @@
@Override
public void selected(final ITextViewer viewer, final boolean smartToggle) {
if (this.proposal instanceof ICompletionProposalExtension2) {
- ((ICompletionProposalExtension2) this.proposal).selected(viewer, smartToggle);
+ ((ICompletionProposalExtension2)this.proposal).selected(viewer, smartToggle);
}
}
@Override
public void unselected(final ITextViewer viewer) {
if (this.proposal instanceof ICompletionProposalExtension2) {
- ((ICompletionProposalExtension2) this.proposal).unselected(viewer);
+ ((ICompletionProposalExtension2)this.proposal).unselected(viewer);
}
}
@@ -122,7 +124,7 @@
@Override
public boolean validate(final IDocument document, final int offset, final DocumentEvent event) {
if (this.proposal instanceof ICompletionProposalExtension2) {
- return ((ICompletionProposalExtension2) this.proposal).validate(document, offset, event);
+ return ((ICompletionProposalExtension2)this.proposal).validate(document, offset, event);
}
return false;
}
@@ -136,7 +138,7 @@
@Override
public void apply(final ITextViewer viewer, final char trigger, final int stateMask, final int offset) {
if (this.proposal instanceof ICompletionProposalExtension2) {
- ((ICompletionProposalExtension2) this.proposal).apply(viewer, trigger, stateMask, offset);
+ ((ICompletionProposalExtension2)this.proposal).apply(viewer, trigger, stateMask, offset);
}
else {
this.proposal.apply(viewer.getDocument());
@@ -209,7 +211,8 @@
@Override
- public ICompletionProposal @Nullable [] computeQuickAssistProposals(final IQuickAssistInvocationContext invocationContext) {
+ public @NonNull ICompletionProposal @Nullable [] computeQuickAssistProposals(
+ final IQuickAssistInvocationContext invocationContext) {
this.errorMessage= null;
final SubMonitor m= SubMonitor.convert(null, 3 + 10 + 1);
@@ -223,13 +226,9 @@
if (context == null) {
return null;
}
- final ISourceViewer viewer= context.getSourceViewer();
- if (viewer == null) {
- return null;
- }
final AssistProposalCollector proposals= new AssistProposalCollector();
- final IAnnotationModel model= viewer.getAnnotationModel();
+ final IAnnotationModel model= context.getSourceViewer().getAnnotationModel();
if (model != null) {
addAnnotationProposals(context, proposals, model);
m.worked(5);
@@ -260,7 +259,7 @@
* @param monitor a progress monitor
* @return the list of filtered and sorted proposals, ready for display
*/
- protected AssistProposal[] filterAndSortCompletionProposals(
+ protected @NonNull AssistProposal[] filterAndSortCompletionProposals(
final AssistProposalCollector proposals,
final AssistInvocationContext context, final IProgressMonitor monitor) {
final AssistProposal[] array= proposals.toArray();
@@ -271,10 +270,10 @@
}
- protected boolean isMatchingPosition(final Position pos, final int offset) {
+ protected boolean isMatchingPosition(final @Nullable Position pos, final int offset) {
return (pos != null)
&& (offset >= pos.getOffset())
- && (offset <= pos.getOffset()+pos.getLength());
+ && (offset <= pos.getOffset() + pos.getLength());
}
private void addAnnotationProposals(final IQuickAssistInvocationContext invocationContext,
@@ -292,8 +291,8 @@
continue;
}
if (annotation instanceof SpellingAnnotation) {
- final SpellingProblem problem= ((SpellingAnnotation) annotation).getSpellingProblem();
- final ICompletionProposal[] annotationProposals= problem.getProposals(invocationContext);
+ final SpellingProblem problem= ((SpellingAnnotation)annotation).getSpellingProblem();
+ final var annotationProposals= problem.getProposals(invocationContext);
if (annotationProposals != null && annotationProposals.length > 0) {
for (int i= 0; i < annotationProposals.length; i++) {
proposals.add(new SpellingProposal(annotationProposals[i]));
@@ -304,7 +303,7 @@
}
}
- protected void addModelAssistProposals(final AssistInvocationContext context,
+ protected void addModelAssistProposals(final AssistInvocationContext invocationContext,
final AssistProposalCollector proposals, final IProgressMonitor monitor) {
}
@@ -313,4 +312,24 @@
return this.errorMessage;
}
+
+ @Override
+ public @Nullable AssistProposal findQuickAssist(
+ final IQuickAssistInvocationContext invocationContext,
+ final String commandId) {
+ final var proposals= computeQuickAssistProposals(invocationContext);
+ if (proposals == null) {
+ return null;
+ }
+ for (final var proposal : proposals) {
+ if (proposal instanceof AssistProposal
+ && proposal instanceof CommandAccess
+ && ((CommandAccess)proposal).getCommandId().equals(commandId) ) {
+ return (AssistProposal)proposal;
+ }
+ }
+ return null;
+ }
+
+
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessorCommandExtension.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessorCommandExtension.java
new file mode 100644
index 0000000..626dcbf
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/QuickAssistProcessorCommandExtension.java
@@ -0,0 +1,31 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink and others.
+ #
+ # This program and the accompanying materials are made available under the
+ # terms of the Eclipse Public License 2.0 which is available at
+ # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting.assist;
+
+import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
+import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+
+@NonNullByDefault
+public interface QuickAssistProcessorCommandExtension extends IQuickAssistProcessor {
+
+
+ @Nullable AssistProposal findQuickAssist(IQuickAssistInvocationContext context,
+ String commandId);
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/SourceProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/SourceProposal.java
index 1bd71f7..e6faf0f 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/SourceProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/SourceProposal.java
@@ -112,6 +112,7 @@
}
+
protected static class ApplyData {