1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Bug 435235 - Automatically close opening brace of list initializer

This commit is contained in:
Sergey Prigogin 2014-05-19 18:52:07 -07:00
parent c91dfd42d0
commit 5b6571f5d9
2 changed files with 84 additions and 15 deletions

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* Copyright (c) 2000, 2014 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text;
@ -77,7 +78,7 @@ public class BracketInserterTest extends TestCase {
// Document offsets.
private static final int INCLUDE_OFFSET= 9;
private static final int BODY_OFFSET= 212;
private static final int BODY_OFFSET= 213;
private static final int ARGS_OFFSET= 184;
private static final int BRACKETS_OFFSET= 262;
@ -123,7 +124,7 @@ public class BracketInserterTest extends TestCase {
IFile file= ResourcesPlugin.getWorkspace().getRoot().getFile(path);
assertTrue(file != null && file.exists());
try {
return (CEditor)EditorTestHelper.openInEditor(file, true);
return (CEditor) EditorTestHelper.openInEditor(file, true);
} catch (PartInitException e) {
fail();
return null;
@ -175,19 +176,19 @@ public class BracketInserterTest extends TestCase {
setCaret(BODY_OFFSET);
type("((((");
// delete two levels
// Delete two levels.
linkedType(SWT.BS, true, ILinkedModeListener.EXTERNAL_MODIFICATION);
linkedType(SWT.BS, true, ILinkedModeListener.EXTERNAL_MODIFICATION);
assertEquals("(())", fDocument.get(BODY_OFFSET, 4));
assertEquals(BODY_OFFSET + 2, getCaret());
// delete the second-last level
// Delete the second-last level
linkedType(SWT.BS, true, ILinkedModeListener.EXTERNAL_MODIFICATION);
assertEquals("()", fDocument.get(BODY_OFFSET, 2));
assertEquals(BODY_OFFSET + 1, getCaret());
// delete last level
// Delete last level
linkedType(SWT.BS, false, ILinkedModeListener.EXTERNAL_MODIFICATION);
assertEquals(TU_CONTENTS, fDocument.get());
assertEquals(BODY_OFFSET, getCaret());
@ -304,18 +305,18 @@ public class BracketInserterTest extends TestCase {
setCaret(BODY_OFFSET);
type("#define MACRO ");
int offset = getCaret();
// enter opening quote (should be closed again)
// Enter opening quote (should be closed again).
type('"');
assertEquals("\"\"", fDocument.get(offset, 2));
assertSingleLinkedPosition(offset + 1);
// enter closing quote (should not add a quote, but proceed cursor)
// Enter closing quote (should not add a quote, but proceed cursor).
type('"');
assertEquals("\"\"", fDocument.get(offset, 2));
assertEquals(offset + 2, getCaret());
// delete closing quote and enter quote again
// Delete closing quote and enter quote again.
type(SWT.BS);
assertEquals("\"", fDocument.get(offset, 1));
int length = fDocument.getLength();
@ -358,6 +359,23 @@ public class BracketInserterTest extends TestCase {
assertSingleLinkedPosition(BODY_OFFSET + 5);
}
public void testCurlyBraceInsideParentheses() throws Exception {
setCaret(BODY_OFFSET);
type("f({");
assertEquals("f({})", fDocument.get(BODY_OFFSET, 5));
assertSingleLinkedPosition(BODY_OFFSET + 3, true);
}
public void testCurlyBraceOutsideParentheses() throws Exception {
setCaret(BODY_OFFSET);
type("struct A {");
assertFalse("}".equals(fDocument.get(BODY_OFFSET + 10, 1)));
assertEquals(BODY_OFFSET + 10, getCaret());
assertFalse(LinkedModeModel.hasInstalledModel(fDocument));
}
public void testAngleBracketsInInclude() throws Exception {
setCaret(INCLUDE_OFFSET);
type('<');
@ -396,9 +414,13 @@ public class BracketInserterTest extends TestCase {
/* utilities */
private void assertSingleLinkedPosition(int offset) {
assertSingleLinkedPosition(offset, false);
}
private void assertSingleLinkedPosition(int offset, boolean nested) {
assertEquals(offset, getCaret());
LinkedPosition position= assertModel(false).findPosition(new LinkedPosition(fDocument, offset, 0));
LinkedPosition position= assertModel(nested).findPosition(new LinkedPosition(fDocument, offset, 0));
assertNotNull(position);
assertEquals(offset, position.getOffset());
assertEquals(0, position.getLength());

View file

@ -535,6 +535,7 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
private boolean fCloseBrackets = true;
private boolean fCloseStrings = true;
private boolean fCloseAngularBrackets = true;
private boolean fCloseBraces = true;
private final String CATEGORY = toString();
private IPositionUpdater fUpdater = new ExclusivePositionUpdater(CATEGORY);
private Deque<BracketLevel> fBracketLevelStack = new ArrayDeque<>();
@ -551,6 +552,10 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
fCloseAngularBrackets = enabled;
}
public void setCloseBracesEnabled(boolean enabled) {
fCloseBraces = enabled;
}
private boolean isAngularIntroducer(String identifier) {
return identifier.length() > 0 && (Character.isUpperCase(identifier.charAt(0))
|| angularIntroducers.contains(identifier)
@ -560,13 +565,14 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
@Override
public void verifyKey(VerifyEvent event) {
// Early pruning to slow down normal typing as little as possible.
// Early pruning to minimize overhead for normal typing.
if (!event.doit || getInsertMode() != SMART_INSERT)
return;
switch (event.character) {
case '(':
case '<':
case '[':
case '{':
case '\'':
case '\"':
break;
@ -624,6 +630,16 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
return;
break;
case '{':
// An opening brace inside parentheses probably starts an initializer list -
// close it.
if (!fCloseBraces
|| nextToken == Symbols.TokenIDENT
|| next != null && next.length() > 1
|| !isInsideParentheses(scanner, offset - 1))
return;
break;
case '\'':
case '"':
if (!fCloseStrings
@ -687,6 +703,24 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
}
}
private boolean isInsideParentheses(CHeuristicScanner scanner, int offset) {
int depth = 0;
// Limit the scanning distance to 100 tokens.
for (int i = 0; i < 100; i++) {
int token = scanner.previousToken(offset, 0);
if (token == Symbols.TokenLPAREN) {
if (--depth < 0)
return true;
} else if (token == Symbols.TokenRPAREN) {
++depth;
} else if (token == Symbols.TokenEOF) {
return false;
}
offset = scanner.getPosition();
}
return false;
}
private boolean isInsideStringInPreprocessorDirective(ITypedRegion partition, IDocument document, int offset) throws BadLocationException {
if (ICPartitions.C_PREPROCESSOR.equals(partition.getType()) && offset < document.getLength()) {
// Use temporary document to test whether offset is inside non-default partition.
@ -706,7 +740,6 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
@Override
public void left(LinkedModeModel environment, int flags) {
final BracketLevel level = fBracketLevelStack.pop();
if (flags != ILinkedModeListener.EXTERNAL_MODIFICATION)
@ -1197,6 +1230,8 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
private static final String CLOSE_BRACKETS = PreferenceConstants.EDITOR_CLOSE_BRACKETS;
/** Preference key for automatically closing angular brackets */
private static final String CLOSE_ANGULAR_BRACKETS = PreferenceConstants.EDITOR_CLOSE_ANGULAR_BRACKETS;
/** Preference key for automatically closing curly braces */
private static final String CLOSE_BRACES = PreferenceConstants.EDITOR_CLOSE_BRACES;
/** Preference key for compiler task tags */
private static final String TODO_TASK_TAGS = CCorePreferenceConstants.TODO_TASK_TAGS;
@ -1532,6 +1567,11 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
return;
}
if (CLOSE_BRACES.equals(property)) {
fBracketInserter.setCloseBracesEnabled(newBooleanValue);
return;
}
if (CLOSE_STRINGS.equals(property)) {
fBracketInserter.setCloseStringsEnabled(newBooleanValue);
return;
@ -2403,11 +2443,13 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
IPreferenceStore preferenceStore = getPreferenceStore();
boolean closeBrackets = preferenceStore.getBoolean(CLOSE_BRACKETS);
boolean closeAngularBrackets = preferenceStore.getBoolean(CLOSE_ANGULAR_BRACKETS);
boolean closeBraces = preferenceStore.getBoolean(CLOSE_BRACES);
boolean closeStrings = preferenceStore.getBoolean(CLOSE_STRINGS);
fBracketInserter.setCloseBracketsEnabled(closeBrackets);
fBracketInserter.setCloseStringsEnabled(closeStrings);
fBracketInserter.setCloseAngularBracketsEnabled(closeAngularBrackets);
fBracketInserter.setCloseAngularBracketsEnabled(closeBraces);
fBracketInserter.setCloseStringsEnabled(closeStrings);
ISourceViewer sourceViewer = getSourceViewer();
if (sourceViewer instanceof ITextViewerExtension)
@ -2867,8 +2909,7 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
return false;
try {
return isBracket(document.getChar(offset - 1)) &&
isBracket(document.getChar(offset));
return isBracket(document.getChar(offset - 1)) && isBracket(document.getChar(offset));
} catch (BadLocationException e) {
return false;
}
@ -2904,6 +2945,12 @@ public class CEditor extends TextEditor implements ICEditor, ISelectionChangedLi
case ']':
return '[';
case '{':
return '}';
case '}':
return '{';
case '"':
return character;