Chromium Code Reviews| Index: editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/dart/DartServerProposal.java |
| diff --git a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/dart/DartServerProposal.java b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/dart/DartServerProposal.java |
| index 8770763537247031410f1486a8b0976428a28e47..09a8b9cb499eaa3214c321e8373ae95f802bcb69 100644 |
| --- a/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/dart/DartServerProposal.java |
| +++ b/editor/tools/plugins/com.google.dart.tools.ui/src/com/google/dart/tools/ui/internal/text/dart/DartServerProposal.java |
| @@ -95,6 +95,7 @@ import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.URL; |
| +import java.util.List; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| @@ -154,14 +155,41 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| private Image image; |
| - /** Offset needed when the proposal is applied */ |
| + /** |
| + * The offset into {@link replacementString} where the cursor should be placed if the proposal is |
| + * accepted. Computed by computeReplacement(). |
| + */ |
| private int selectionOffset = 0; |
| /** |
| + * The length of text that should be selected if the proposal is accepted. Computed by |
| + * computeReplacement(). |
| + */ |
| + private int selectionLength = 0; |
| + |
| + /** |
| * The {@link IInformationControlCreator} for documentation. |
| */ |
| private IInformationControlCreator informationControlCreator; |
| + /** |
| + * The replacement string, or null if it has not yet been computed. Computed by |
| + * computeReplacement(). |
| + */ |
| + private String replacementString = null; |
| + |
| + /** |
| + * If the completion is a method call with at least one argument, offsets within replacementString |
| + * of the arguments. Otherwise null. Computed by computeReplacement(). |
| + */ |
| + private int[] argumentOffsets = null; |
| + |
| + /** |
| + * If the completion is a method call with at least one argument, the lengths of the arguments. |
| + * Otherwise null. Computed by computeReplacement(). |
|
danrubel
2015/01/06 23:49:36
I recommend dropping the "Computed by ..." from al
Paul Berry
2015/01/07 15:39:14
Whoops, that was supposed to be computeCompletion(
|
| + */ |
| + private int[] argumentLengths = null; |
| + |
| public DartServerProposal(DartServerProposalCollector collector, CompletionSuggestion suggestion) { |
| this.collector = collector; |
| this.suggestion = suggestion; |
| @@ -197,7 +225,6 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| */ |
| if (replacementLength == 0 && trigger == '.') { |
| doc.replace(offset, 0, Character.toString(trigger)); |
| - selectionOffset = 1; |
| return; |
| } |
| /* |
| @@ -211,31 +238,18 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| * Insert the suggestion |
| */ |
| doc.replace(replacementOffset, replacementLength, completion); |
| - selectionOffset = completion.length(); |
| /* |
| * If the suggestion has parameters, initiate entering parameters |
| */ |
| - int newOffset = replacementOffset + completion.length(); |
| - String param = getParamString(); |
| - if (param != null) { |
| - doc.replace(newOffset, 0, "()"); |
| - ++newOffset; |
| - ++selectionOffset; |
| - if (param.length() == 2) { // param is "()" |
| - ++selectionOffset; |
| - return; |
| - } |
| - LinkedPositionGroup group = new LinkedPositionGroup(); |
| - group.addPosition(new LinkedPosition(doc, newOffset, 0, LinkedPositionGroup.NO_STOP)); |
| - |
| + if (argumentLengths != null) { |
| + // Set up linked position groups for the arguments. |
| LinkedModeModel model = new LinkedModeModel(); |
| - model.addGroup(group); |
| + buildLinkedModeModel(model, doc, replacementOffset); |
| model.forceInstall(); |
| LinkedModeUI ui = new EditorLinkedModeUI(model, viewer); |
| - ui.setSimpleMode(true); |
| ui.setExitPolicy(new ExitPolicy(')', doc, viewer)); |
| - ui.setExitPosition(viewer, newOffset + 1, 0, Integer.MAX_VALUE); |
| + ui.setExitPosition(viewer, replacementOffset + completion.length(), 0, Integer.MAX_VALUE); |
| ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER); |
| ui.enter(); |
| return; |
| @@ -244,8 +258,12 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| * Insert the trigger character typed if it is not enter or null |
| */ |
| if (trigger != '\0' && trigger != '\n') { |
| - doc.replace(newOffset, 0, Character.toString(trigger)); |
| + doc.replace( |
| + replacementOffset + selectionOffset, |
| + selectionLength, |
| + Character.toString(trigger)); |
| ++selectionOffset; |
| + selectionLength = 0; |
| return; |
| } |
| } catch (BadLocationException e) { |
| @@ -373,7 +391,8 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| @Override |
| public Point getSelection(IDocument document) { |
| - return new Point(collector.getReplacementOffset() + selectionOffset, 0); |
| + computeCompletion(); |
| + return new Point(collector.getReplacementOffset() + selectionOffset, selectionLength); |
| } |
| @Override |
| @@ -430,6 +449,64 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| || CharOperation.camelCaseMatch(pattern, 0, pattern.length, name, 0, name.length, false); |
| } |
| + protected void buildLinkedModeModel(LinkedModeModel model, IDocument document, int baseOffset) |
| + throws BadLocationException { |
| + // TODO(paulberry): consider extending to support optional arguments, as |
| + // FilledArgumentNamesMethodProposal does. |
| + for (int i = 0; i != argumentOffsets.length; i++) { |
| + LinkedPositionGroup group = new LinkedPositionGroup(); |
| + LinkedPosition pos = new LinkedPosition( |
| + document, |
| + baseOffset + argumentOffsets[i], |
| + argumentLengths[i], |
| + LinkedPositionGroup.NO_STOP); |
| + group.addPosition(pos); |
| + model.addGroup(group); |
| + } |
| + } |
| + |
| + /** |
| + * Compute {@link replacementString} and {@link selectionOffset} if they haven't been computed |
|
danrubel
2015/01/06 23:49:36
If you are listing specifically what it computes,
Paul Berry
2015/01/07 15:39:14
Oops, yes, I do. Fixed.
|
| + * already. |
| + */ |
| + private void computeCompletion() { |
| + if (replacementString != null) { |
| + // Already computed. |
| + return; |
| + } |
| + List<String> parameterNames = suggestion.getParameterNames(); |
| + if (parameterNames == null) { |
| + // Just complete a single identifier. |
| + replacementString = suggestion.getCompletion(); |
| + selectionOffset = replacementString.length(); |
| + selectionLength = 0; |
| + } else { |
| + // Complete with the identifier, parens, and arguments. |
| + StringBuffer buffer = new StringBuffer(suggestion.getCompletion()); |
| + buffer.append('('); |
| + int requiredParameterCount = suggestion.getRequiredParameterCount(); |
| + if (requiredParameterCount > 0) { |
| + argumentOffsets = new int[requiredParameterCount]; |
| + argumentLengths = new int[requiredParameterCount]; |
| + for (int i = 0; i < requiredParameterCount; i++) { |
| + if (i != 0) { |
| + buffer.append(", "); |
| + } |
| + argumentOffsets[i] = buffer.length(); |
| + buffer.append(parameterNames.get(i)); |
| + argumentLengths[i] = buffer.length() - argumentOffsets[i]; |
| + } |
| + selectionOffset = argumentOffsets[0]; |
| + selectionLength = argumentLengths[0]; |
| + } else { |
| + selectionOffset = buffer.length(); |
| + selectionLength = 0; |
| + } |
| + buffer.append(')'); |
| + replacementString = buffer.toString(); |
| + } |
| + } |
| + |
| private Image computeImage() { |
| ImageDescriptorRegistry fRegistry = DartToolsPlugin.getImageDescriptorRegistry(); |
| ImageDescriptor descriptor = null; |
| @@ -514,7 +591,8 @@ public class DartServerProposal implements ICompletionProposal, ICompletionPropo |
| } |
| private String getCompletion() { |
| - return suggestion.getCompletion(); |
| + computeCompletion(); |
| + return replacementString; |
| } |
| /** |