| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014, the Dart project authors. | 2 * Copyright (c) 2014, the Dart project authors. |
| 3 * | 3 * |
| 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except | 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u
se this file except |
| 5 * in compliance with the License. You may obtain a copy of the License at | 5 * in compliance with the License. You may obtain a copy of the License at |
| 6 * | 6 * |
| 7 * http://www.eclipse.org/legal/epl-v10.html | 7 * http://www.eclipse.org/legal/epl-v10.html |
| 8 * | 8 * |
| 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License | 9 * Unless required by applicable law or agreed to in writing, software distribut
ed under the License |
| 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express | 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K
IND, either express |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 doc.replace(offset, 0, Character.toString(trigger)); | 246 doc.replace(offset, 0, Character.toString(trigger)); |
| 247 return; | 247 return; |
| 248 } | 248 } |
| 249 /* | 249 /* |
| 250 * Simplistic argument list completion... strip parens and continue | 250 * Simplistic argument list completion... strip parens and continue |
| 251 */ | 251 */ |
| 252 // TODO (danrubel) improve argument list completion | 252 // TODO (danrubel) improve argument list completion |
| 253 if (completion.startsWith("(")) { | 253 if (completion.startsWith("(")) { |
| 254 completion = completion.substring(1, completion.length() - 1); | 254 completion = completion.substring(1, completion.length() - 1); |
| 255 } | 255 } |
| 256 boolean hasArgumentList = completion.endsWith(")"); |
| 257 boolean hasArguments = !completion.endsWith("()"); |
| 256 /* | 258 /* |
| 257 * Insert the suggestion | 259 * Insert the suggestion |
| 258 */ | 260 */ |
| 259 doc.replace(replacementOffset, replacementLength, completion); | 261 doc.replace(replacementOffset, replacementLength, completion); |
| 260 /* | 262 /* |
| 261 * If the suggestion has parameters, initiate entering parameters | 263 * Check if linked mode for arguments is needed |
| 262 */ | 264 */ |
| 263 if (argumentLengths != null) { | 265 boolean isTriggerEnter = trigger == '\0' || trigger == '\n'; |
| 264 // Set up linked position groups for the arguments. | 266 if (hasArgumentList && (isTriggerEnter || trigger == '(')) { |
| 267 // If Enter or '(' (when blind typing), then use linked mode. |
| 268 } else { |
| 269 // Insert the trigger and stop completion. |
| 270 selectionOffset = completion.length(); |
| 271 selectionLength = 0; |
| 272 if (!isTriggerEnter) { |
| 273 doc.replace( |
| 274 replacementOffset + selectionOffset, |
| 275 selectionLength, |
| 276 Character.toString(trigger)); |
| 277 ++selectionOffset; |
| 278 } |
| 279 return; |
| 280 } |
| 281 /* |
| 282 * Done if zero arguments and Enter is the trigger |
| 283 */ |
| 284 if (!hasArguments && isTriggerEnter) { |
| 285 return; |
| 286 } |
| 287 /* |
| 288 * If the suggestion has an argument list, initiate entering arguments |
| 289 */ |
| 290 if (hasArgumentList) { |
| 291 // Prepare linked mode model |
| 265 LinkedModeModel model = new LinkedModeModel(); | 292 LinkedModeModel model = new LinkedModeModel(); |
| 266 buildLinkedModeModel(model, doc, replacementOffset); | 293 if (hasArguments) { |
| 294 buildLinkedModeModel_hasArgumentList(model, doc, replacementOffset); |
| 295 } else { |
| 296 // If there are no arguments, we still want to use linked mode to igno
re ')'. |
| 297 buildLinkedModeModel_emptyArguments(model, doc, replacementOffset, com
pletion); |
| 298 } |
| 267 model.forceInstall(); | 299 model.forceInstall(); |
| 268 | 300 // Start linked mode UI |
| 269 LinkedModeUI ui = new EditorLinkedModeUI(model, viewer); | 301 LinkedModeUI ui = new EditorLinkedModeUI(model, viewer); |
| 270 ui.setExitPolicy(new ExitPolicy(')', doc, viewer)); | 302 if (hasArguments) { |
| 303 ui.setExitPolicy(new ExitPolicy(')', doc, viewer)); |
| 304 } else { |
| 305 ui.setExitPolicy(new AnyExitPolicy()); |
| 306 } |
| 271 ui.setExitPosition(viewer, replacementOffset + completion.length(), 0, I
nteger.MAX_VALUE); | 307 ui.setExitPosition(viewer, replacementOffset + completion.length(), 0, I
nteger.MAX_VALUE); |
| 272 ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT); | 308 ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT); |
| 273 ui.enter(); | 309 ui.enter(); |
| 274 return; | |
| 275 } | |
| 276 /* | |
| 277 * If completion already includes '()' then don't insert extra '(' or ')' | |
| 278 */ | |
| 279 if (completion.endsWith(")") && (trigger == '(' || trigger == ')')) { | |
| 280 return; | |
| 281 } | |
| 282 /* | |
| 283 * Insert the trigger character typed if it is not enter or null | |
| 284 */ | |
| 285 if (trigger != '\0' && trigger != '\n') { | |
| 286 doc.replace( | |
| 287 replacementOffset + selectionOffset, | |
| 288 selectionLength, | |
| 289 Character.toString(trigger)); | |
| 290 ++selectionOffset; | |
| 291 selectionLength = 0; | |
| 292 return; | |
| 293 } | 310 } |
| 294 } catch (BadLocationException e) { | 311 } catch (BadLocationException e) { |
| 295 DartCore.logInformation("Failed to replace offset:" + replacementOffset +
" length:" | 312 DartCore.logInformation("Failed to replace offset:" + replacementOffset +
" length:" |
| 296 + replacementLength + " with:" + completion, e); | 313 + replacementLength + " with:" + completion, e); |
| 297 instrumentation.metric("Problem", "BadLocationException"); | 314 instrumentation.metric("Problem", "BadLocationException"); |
| 298 } finally { | 315 } finally { |
| 299 instrumentation.log(); | 316 instrumentation.log(); |
| 300 } | 317 } |
| 301 } | 318 } |
| 302 | 319 |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 try { | 490 try { |
| 474 textEntered = document.get(replacementOffset, offset - replacementOffset); | 491 textEntered = document.get(replacementOffset, offset - replacementOffset); |
| 475 } catch (BadLocationException x) { | 492 } catch (BadLocationException x) { |
| 476 return false; | 493 return false; |
| 477 } | 494 } |
| 478 String completion = TextProcessor.deprocess(getDisplayString()); | 495 String completion = TextProcessor.deprocess(getDisplayString()); |
| 479 if (completion.length() == 0 || completion.length() < textEntered.length())
{ | 496 if (completion.length() == 0 || completion.length() < textEntered.length())
{ |
| 480 return false; | 497 return false; |
| 481 } | 498 } |
| 482 // If the user has entered an upper case char as the first char | 499 // If the user has entered an upper case char as the first char |
| 483 // then filter all lower case first character suggestions. | 500 // then filter using only camelCaseMatching |
| 484 if (Character.isUpperCase(textEntered.charAt(0)) && Character.isLowerCase(co
mpletion.charAt(0))) { | 501 if (!Character.isUpperCase(textEntered.charAt(0))) { |
| 485 return false; | 502 String partialCompletion = completion.substring(0, textEntered.length()); |
| 486 } | 503 if (partialCompletion.equalsIgnoreCase(textEntered)) { |
| 487 String partialCompletion = completion.substring(0, textEntered.length()); | 504 return true; |
| 488 if (partialCompletion.equalsIgnoreCase(textEntered)) { | 505 } |
| 489 return true; | |
| 490 } | 506 } |
| 491 char[] pattern = textEntered.toCharArray(); | 507 char[] pattern = textEntered.toCharArray(); |
| 492 char[] name = completion.toCharArray(); | 508 char[] name = completion.toCharArray(); |
| 493 return CharOperation.camelCaseMatch(pattern, 0, pattern.length, name, 0, nam
e.length, false); | 509 return CharOperation.camelCaseMatch(pattern, 0, pattern.length, name, 0, nam
e.length, false); |
| 494 } | 510 } |
| 495 | 511 |
| 496 protected void buildLinkedModeModel(LinkedModeModel model, IDocument document,
int baseOffset) | 512 protected void buildLinkedModeModel_emptyArguments(LinkedModeModel model, IDoc
ument document, |
| 497 throws BadLocationException { | 513 int baseOffset, String completion) throws BadLocationException { |
| 514 LinkedPositionGroup group = new LinkedPositionGroup(); |
| 515 LinkedPosition pos = new LinkedPosition( |
| 516 document, |
| 517 baseOffset + completion.length(), |
| 518 0, |
| 519 LinkedPositionGroup.NO_STOP); |
| 520 group.addPosition(pos); |
| 521 model.addGroup(group); |
| 522 } |
| 523 |
| 524 protected void buildLinkedModeModel_hasArgumentList(LinkedModeModel model, IDo
cument document, |
| 525 int baseOffset) throws BadLocationException { |
| 498 // TODO(paulberry): consider extending to support optional arguments, as | 526 // TODO(paulberry): consider extending to support optional arguments, as |
| 499 // FilledArgumentNamesMethodProposal does. | 527 // FilledArgumentNamesMethodProposal does. |
| 500 for (int i = 0; i != argumentOffsets.length; i++) { | 528 for (int i = 0; i != argumentOffsets.length; i++) { |
| 501 LinkedPositionGroup group = new LinkedPositionGroup(); | 529 LinkedPositionGroup group = new LinkedPositionGroup(); |
| 502 LinkedPosition pos = new LinkedPosition( | 530 LinkedPosition pos = new LinkedPosition( |
| 503 document, | 531 document, |
| 504 baseOffset + argumentOffsets[i], | 532 baseOffset + argumentOffsets[i], |
| 505 argumentLengths[i], | 533 argumentLengths[i], |
| 506 LinkedPositionGroup.NO_STOP); | 534 LinkedPositionGroup.NO_STOP); |
| 507 group.addPosition(pos); | 535 group.addPosition(pos); |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 if (element != null) { | 697 if (element != null) { |
| 670 return element.getParameters(); | 698 return element.getParameters(); |
| 671 } | 699 } |
| 672 } | 700 } |
| 673 } | 701 } |
| 674 return null; | 702 return null; |
| 675 } | 703 } |
| 676 } | 704 } |
| 677 | 705 |
| 678 /** | 706 /** |
| 707 * {@link IExitPolicy} that exists on any character. |
| 708 */ |
| 709 class AnyExitPolicy implements IExitPolicy { |
| 710 @Override |
| 711 public ExitFlags doExit(LinkedModeModel environment, VerifyEvent event, int of
fset, int length) { |
| 712 if (event.character == 0) { |
| 713 return null; |
| 714 } |
| 715 boolean doit = event.character != ')'; |
| 716 return new ExitFlags(ILinkedModeListener.UPDATE_CARET, doit); |
| 717 } |
| 718 } |
| 719 |
| 720 /** |
| 679 * Allow the linked mode editor to continue running even when the exit character
is typed as part of | 721 * Allow the linked mode editor to continue running even when the exit character
is typed as part of |
| 680 * a function argument. Using shift operators in a context that expects balanced
angle brackets is | 722 * a function argument. Using shift operators in a context that expects balanced
angle brackets is |
| 681 * not legal syntax and will confuse the linked mode editor. | 723 * not legal syntax and will confuse the linked mode editor. |
| 682 */ | 724 */ |
| 683 class ExitPolicy implements IExitPolicy { | 725 class ExitPolicy implements IExitPolicy { |
| 684 | 726 |
| 685 private int parenCount = 0; | 727 private int parenCount = 0; |
| 686 private int braceCount = 0; | 728 private int braceCount = 0; |
| 687 private int bracketCount = 0; | 729 private int bracketCount = 0; |
| 688 private int angleBracketCount = 0; | 730 private int angleBracketCount = 0; |
| 689 private char lastChar = (char) 0; | 731 private char lastChar = (char) 0; |
| 690 | 732 |
| 691 final char exitChar; | 733 private final char exitChar; |
| 692 private final IDocument document; | 734 private final IDocument document; |
| 693 private final ITextViewer viewer; | 735 private final ITextViewer viewer; |
| 694 | 736 |
| 695 public ExitPolicy(char exitChar, IDocument document, ITextViewer viewer) { | 737 public ExitPolicy(char exitChar, IDocument document, ITextViewer viewer) { |
| 696 this.exitChar = exitChar; | 738 this.exitChar = exitChar; |
| 697 this.document = document; | 739 this.document = document; |
| 698 this.viewer = viewer; | 740 this.viewer = viewer; |
| 699 } | 741 } |
| 700 | 742 |
| 701 @Override | 743 @Override |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 823 return braceCount == -1; | 865 return braceCount == -1; |
| 824 case ']': | 866 case ']': |
| 825 return bracketCount == -1; | 867 return bracketCount == -1; |
| 826 case '>': | 868 case '>': |
| 827 return angleBracketCount == -1; | 869 return angleBracketCount == -1; |
| 828 default: | 870 default: |
| 829 return true; // never unbalanced | 871 return true; // never unbalanced |
| 830 } | 872 } |
| 831 } | 873 } |
| 832 } | 874 } |
| OLD | NEW |