@Override public void customizeDocumentCommand(IDocument d, DocumentCommand c) { try { if ("-".equals(c.text) && c.offset >= 3 && d.get(c.offset - 3, 3).equals("<!-")) { c.text = "- -->"; c.shiftsCaret = false; c.caretOffset = c.offset + 2; c.doit = false; return; } if ("[".equals(c.text) && c.offset >= 2 && d.get(c.offset - 2, 2).equals("<!")) { c.text = "[CDATA[]]>"; c.shiftsCaret = false; c.caretOffset = c.offset + 7; c.doit = false; return; } if ("l".equals(c.text) && c.offset >= 4 && d.get(c.offset - 4, 4).equals("<?xm")) { c.text = "l version = \"1.0\" encoding = \"" + charset + "\"?>"; return; } } catch (BadLocationException e) { HTMLPlugin.logException(e); } super.customizeDocumentCommand(d, c); }
@Override public void customizeDocumentCommand(IDocument d, DocumentCommand c) { try { // if("%".equals(c.text) && c.offset > 0){ // if(d.getChar(c.offset - 1) == '<'){ // c.text = "% %>"; // c.shiftsCaret = false; // c.caretOffset = c.offset + 1; // c.doit = false; // return; // } // } if ("{".equals(c.text) && c.offset > 0) { if (d.getChar(c.offset - 1) == '$') { c.text = "{}"; c.shiftsCaret = false; c.caretOffset = c.offset + 1; c.doit = false; return; } } if ("-".equals(c.text) && c.offset >= 3 && d.get(c.offset - 3, 3).equals("<%-")) { c.text = "- --%>"; c.shiftsCaret = false; c.caretOffset = c.offset + 2; c.doit = false; return; } } catch (BadLocationException e) { HTMLPlugin.logException(e); } super.customizeDocumentCommand(d, c); }
@Test public void testBacketHandling() { IDocument document = new Document(); document.set(input.replace(CURSOR, "")); DocumentCommand command = new DocumentCommandStub(); command.text = textToInsert; // insert text at cursor position command.offset = input.indexOf(CURSOR); // position cursor at correct position in input text command.caretOffset = input.indexOf(CURSOR); command.shiftsCaret = true; stategy.customizeDocumentCommand(document, command); System.out.println("text = '" + command.text + "'"); String expectedDocumentAfter = expected.replace(CURSOR, ""); System.out.println("Cursor before " + command.caretOffset); executeCommand(document, command); System.out.println("Cursor after " + command.caretOffset); String documentAfter = document.get(); System.out.println("Document after: '" + documentAfter + "'"); assertEquals(expectedDocumentAfter, documentAfter); int expectedCursorOffset = expected.indexOf(CURSOR); assertEquals("Cursor at unexpected position", expectedCursorOffset, command.caretOffset); }
private void appendIndent( boolean isContinuation, boolean isOpening, boolean isClosing, boolean isListContinuation, int start, int end, boolean closeBraces, StringBuilder buf) throws BadLocationException { int line = document.getLineOfOffset(start); String indent = getIndent(start, end); String delim = getLineDelimiter(document, line); buf.append(indent); if (isOpening || isListContinuation) { if (isClosing) { if (closeBraces && isOpening) { // increment the indent level incrementIndent(buf, indent); // move the closing brace to next line command.shiftsCaret = false; command.caretOffset = command.offset + buf.length(); buf.append(delim).append(indent); } // else if (closeBraces && //hack just to distinguish a newline from a // correct indentation! // isListContinuation) { // //just increment the indent level // incrementIndent(buf, indent); // } } else { // increment the indent level incrementIndent(buf, indent); if (closeBraces && count("{") > count("}")) { // close the opening brace command.shiftsCaret = false; command.caretOffset = command.offset + buf.length(); buf.append(delim).append(indent).append('}'); } } } else if (isContinuation) { incrementIndent(buf, indent); incrementIndent(buf, indent); } else if (isClosing) { decrementIndent(buf, indent); } }
private void fixIndentOfCurrentLine() throws BadLocationException { int start = getStartOfCurrentLine(); int end = getEndOfCurrentLine(); int endOfWs = firstEndOfWhitespace(start, end); // we want this to happen in three cases: // 1. the user types a tab in the whitespace // at the start of the line // 2. the user types { or ( at the start of // the line // 3. Correct Indentation is calling us // test for Correct Indentation action boolean correctingIndentation = command.offset == start && !command.shiftsCaret; boolean opening = command.text.equals("{") || command.text.equals("("); if (command.offset < endOfWs || // we want strictly < since we don't want to prevent the caret advancing when a space is // typed command.offset == endOfWs && endOfWs == end && opening || // this can cause the caret to jump *backwards* when a { or ( is typed! correctingIndentation) { int endOfPrev = getEndOfPreviousLine(); int startOfPrev = getStartOfPreviousLine(); char startOfCurrentLineChar = opening ? command.text.charAt(0) : // the typed character is now the first character in the line getNextNonHiddenCharacterInLine(start); char endOfLastLineChar = getPreviousNonHiddenCharacterInLine(endOfPrev); StringBuilder buf = new StringBuilder(); appendIndent( start, end, startOfPrev, endOfPrev, startOfCurrentLineChar, endOfLastLineChar, false, buf); int len = endOfWs - start; String text = buf.toString(); if (text.length() != len || !document.get(start, len).equals(text)) { if (opening) { text += command.text; } command.text = text; command.offset = start; command.length = len; } else if (!opening) { command.caretOffset = start + len; command.shiftsCaret = false; command.text = null; } } }
private void closeUnterminatedMultlineComment() { if (isInUnterminatedMultilineComment(command.offset, document)) { command.shiftsCaret = false; String text = command.text; command.caretOffset = command.offset + text.length(); command.text = text + text + // uncomment to get a bigger indent // (text.indexOf(' ')>=0 ? // text.replaceFirst(" ", "") : text) + "*/"; } }
private void handleSmartTrigger(IDocument document, char trigger, int referenceOffset) throws BadLocationException { DocumentCommand cmd = new DocumentCommand() {}; cmd.offset = referenceOffset; cmd.length = 0; cmd.text = Character.toString(trigger); cmd.doit = true; cmd.shiftsCaret = true; cmd.caretOffset = getReplacementOffset() + getCursorPosition(); SmartSemicolonAutoEditStrategy strategy = new SmartSemicolonAutoEditStrategy(DartPartitions.DART_PARTITIONING); strategy.customizeDocumentCommand(document, cmd); replace(document, cmd.offset, cmd.length, cmd.text); setCursorPosition(cmd.caretOffset - getReplacementOffset() + cmd.text.length()); }
private void autoEditAfterNewLine(IDocument document, DocumentCommand command) { if (command.offset == -1 || document.getLength() == 0) { return; } try { int p = command.offset == document.getLength() ? command.offset - 1 : command.offset; IRegion info = document.getLineInformationOfOffset(p); int start = info.getOffset(); StringBuffer buf = new StringBuffer(command.text); int end = findEndOfWhiteSpaceAfter(document, start, command.offset); String lineSpaces = (end > start) ? document.get(start, end - start) : ""; buf.append(lineSpaces); if (isAfterOpenBrace(document, command.offset - 1, start)) { buf.append( IndenterUtil.createWhiteSpace(1, 0, TextUtilities.getDefaultLineDelimiter(document))); if (isBeforeCloseBrace(document, command.offset, info.getOffset() + info.getLength())) { command.shiftsCaret = false; command.caretOffset = command.offset + buf.length(); buf.append(command.text); buf.append(lineSpaces); } command.text = buf.toString(); } else { int indent = computeIndentCount(document, command.offset); if (isBeforeCloseBrace(document, command.offset, info.getOffset() + info.getLength())) { indent--; } command.text += IndenterUtil.createWhiteSpace( indent, 0, TextUtilities.getDefaultLineDelimiter(document)); } } catch (BadLocationException e) { KotlinLogger.logAndThrow(e); } }
private void closeOpening() { if (isCommented(command.offset)) { return; } boolean quoted = isQuoted(command.offset); String current = command.text; try { // don't close fences after a backslash escape // TODO: improve this, check the surrounding // token type! if (command.offset > 0 && document.getChar(command.offset - 1) == '\\') { return; } // don't close fences before an identifier, // literal or opening paren if (!quoted && // there are special rules for < below !current.equals("<")) { int curr = command.offset; while (curr < document.getLength()) { char ch = document.getChar(curr++); if (isLetter(ch) || isDigit(ch) || ch == '(') { return; } if (ch == '"' && !"\"".equals(current) && !"`".equals(current)) { return; } if (ch == '\'' && !"\'".equals(current)) { return; } if (ch != ' ') { break; } } } } catch (BadLocationException e) { } String opening = null; String closing = null; boolean found = false; IPreferenceStore store = getPreferences(); for (String[] type : FENCES) { if (type[0].equals(current) || type[1].equals(current)) { if (store == null || store.getBoolean(type[2])) { opening = type[0]; closing = type[1]; found = true; break; } } } if (found) { if (current.equals(closing)) { // typed character is a closing fence try { // skip one ahead if next char is already a closing fence if (skipClosingFence(closing) && closeOpeningFence(opening, closing)) { command.text = null; command.shiftsCaret = false; command.caretOffset = command.offset + 1; return; } } catch (BadLocationException e) { } } boolean isInterpolation = isGraveAccentCharacterInStringLiteral(command.offset, opening); boolean isDocLink = isOpeningBracketInAnnotationStringLiteral(command.offset, opening); if (current.equals(opening) && (isInterpolation || isDocLink || !quoted)) { // typed character is an opening fence if (isInterpolation || isDocLink || closeOpeningFence(opening, closing)) { // add a closing fence command.shiftsCaret = false; command.caretOffset = command.offset + 1; if (isInterpolation) { try { if (command.offset > 1 && document.get(command.offset - 1, 1).equals("`") && !document.get(command.offset - 2, 1).equals("`")) { command.text += "``"; } } catch (BadLocationException e) { } } else if (isDocLink) { try { if (command.offset > 1 && document.get(command.offset - 1, 1).equals("[") && !document.get(command.offset - 2, 1).equals("]")) { command.text += "]]"; } } catch (BadLocationException e) { } } else if (opening.equals("\"")) { try { if (command.offset <= 1 || !document.get(command.offset - 1, 1).equals("\"")) { command.text += closing; } else if (command.offset > 1 && document.get(command.offset - 2, 2).equals("\"\"") && !(command.offset > 2 && document.get(command.offset - 3, 1).equals("\""))) { command.text += "\"\"\""; } } catch (BadLocationException e) { } } else { command.text += closing; } } } } }
private void smartIndentAfterNewLine(IDocument d, DocumentCommand c) { JavaHeuristicScanner scanner = new JavaHeuristicScanner(d); JavaIndenter indenter = new JavaIndenter(d, scanner, fProject); StringBuffer indent = indenter.computeIndentation(c.offset); if (indent == null) indent = new StringBuffer(); int docLength = d.getLength(); if (c.offset == -1 || docLength == 0) return; try { int p = (c.offset == docLength ? c.offset - 1 : c.offset); int line = d.getLineOfOffset(p); StringBuffer buf = new StringBuffer(c.text + indent); IRegion reg = d.getLineInformation(line); int lineEnd = reg.getOffset() + reg.getLength(); int contentStart = findEndOfWhiteSpace(d, c.offset, lineEnd); c.length = Math.max(contentStart - c.offset, 0); int start = reg.getOffset(); ITypedRegion region = TextUtilities.getPartition(d, fPartitioning, start, true); if (IJavaPartitions.JAVA_DOC.equals(region.getType())) start = d.getLineInformationOfOffset(region.getOffset()).getOffset(); // insert closing brace on new line after an unclosed opening brace if (getBracketCount(d, start, c.offset, true) > 0 && closeBrace() && !isClosed(d, c.offset, c.length)) { c.caretOffset = c.offset + buf.length(); c.shiftsCaret = false; // copy old content of line behind insertion point to new line // unless we think we are inserting an anonymous type definition if (c.offset == 0 || computeAnonymousPosition(d, c.offset - 1, fPartitioning, lineEnd) == -1) { if (lineEnd - contentStart > 0) { c.length = lineEnd - c.offset; buf.append(d.get(contentStart, lineEnd - contentStart).toCharArray()); } } buf.append(TextUtilities.getDefaultLineDelimiter(d)); StringBuffer reference = null; int nonWS = findEndOfWhiteSpace(d, start, lineEnd); if (nonWS < c.offset && d.getChar(nonWS) == '{') reference = new StringBuffer(d.get(start, nonWS - start)); else reference = indenter.getReferenceIndentation(c.offset); if (reference != null) buf.append(reference); buf.append('}'); } // insert extra line upon new line between two braces else if (c.offset > start && contentStart < lineEnd && d.getChar(contentStart) == '}') { int firstCharPos = scanner.findNonWhitespaceBackward(c.offset - 1, start); if (firstCharPos != JavaHeuristicScanner.NOT_FOUND && d.getChar(firstCharPos) == '{') { c.caretOffset = c.offset + buf.length(); c.shiftsCaret = false; StringBuffer reference = null; int nonWS = findEndOfWhiteSpace(d, start, lineEnd); if (nonWS < c.offset && d.getChar(nonWS) == '{') reference = new StringBuffer(d.get(start, nonWS - start)); else reference = indenter.getReferenceIndentation(c.offset); buf.append(TextUtilities.getDefaultLineDelimiter(d)); if (reference != null) buf.append(reference); } } c.text = buf.toString(); } catch (BadLocationException e) { JavaPlugin.log(e); } }
public void customizeDocumentCommand(IDocument document, DocumentCommand c) { if (!isSmartInsertMode()) { return; } if (!(document instanceof IStructuredDocument)) { // This shouldn't happen unless this strategy is used on an invalid document return; } IStructuredDocument doc = (IStructuredDocument) document; // Handle newlines/indentation if (c.length == 0 && c.text != null && TextUtilities.endsWith(doc.getLegalLineDelimiters(), c.text) != -1) { IModelManager modelManager = StructuredModelManager.getModelManager(); IStructuredModel model = modelManager.getModelForRead(doc); if (model != null) { try { final int offset = c.offset; int lineStart = findLineStart(doc, offset); int textStart = findTextStart(doc, lineStart, offset); IStructuredDocumentRegion region = doc.getRegionAtCharacterOffset(textStart); if (region != null && region.getType().equals(XML_TAG_NAME)) { Pair<Integer, Integer> balance = getBalance(doc, textStart, offset); int tagBalance = balance.getFirst(); int bracketBalance = balance.getSecond(); String lineIndent = ""; // $NON-NLS-1$ if (textStart > lineStart) { lineIndent = doc.get(lineStart, textStart - lineStart); } // We only care if tag or bracket balance is greater than 0; // we never *dedent* on negative balances boolean addIndent = false; if (bracketBalance < 0) { // Handle // <foo // ></foo>^ // and // <foo // />^ ITextRegion left = getRegionAt(doc, offset, true /*biasLeft*/); if (left != null && (left.getType().equals(XML_TAG_CLOSE) || left.getType().equals(XML_EMPTY_TAG_CLOSE))) { // Find the corresponding open tag... // The org.eclipse.wst.xml.ui.gotoMatchingTag frequently // doesn't work, it just says "No matching brace found" // (or I would use that here). int targetBalance = 0; ITextRegion right = getRegionAt(doc, offset, false /*biasLeft*/); if (right != null && right.getType().equals(XML_END_TAG_OPEN)) { targetBalance = -1; } int openTag = AndroidXmlCharacterMatcher.findTagBackwards(doc, offset, targetBalance); if (openTag != -1) { // Look up the indentation of the given line lineIndent = AndroidXmlEditor.getIndentAtOffset(doc, openTag); } } } else if (tagBalance > 0 || bracketBalance > 0) { // Add indentation addIndent = true; } StringBuilder sb = new StringBuilder(c.text); sb.append(lineIndent); String oneIndentUnit = XmlFormatPreferences.create().getOneIndentUnit(); if (addIndent) { sb.append(oneIndentUnit); } // Handle // <foo>^</foo> // turning into // <foo> // ^ // </foo> ITextRegion left = getRegionAt(doc, offset, true /*biasLeft*/); ITextRegion right = getRegionAt(doc, offset, false /*biasLeft*/); if (left != null && right != null && left.getType().equals(XML_TAG_CLOSE) && right.getType().equals(XML_END_TAG_OPEN)) { // Move end tag if (tagBalance > 0 && bracketBalance < 0) { sb.append(oneIndentUnit); } c.caretOffset = offset + sb.length(); c.shiftsCaret = false; sb.append(TextUtilities.getDefaultLineDelimiter(doc)); sb.append(lineIndent); } c.text = sb.toString(); } else if (region != null && region.getType().equals(XML_CONTENT)) { // Indenting in text content. If you're in the middle of editing // text, just copy the current line indentation. // However, if you're editing in leading whitespace (e.g. you press // newline on a blank line following say an element) then figure // out the indentation as if the newline had been pressed at the // end of the element, and insert that amount of indentation. // In this case we need to also make sure to subtract any existing // whitespace on the current line such that if we have // // <foo> // ^ <bar/> // </foo> // // you end up with // // <foo> // // ^<bar/> // </foo> // String text = region.getText(); int regionStart = region.getStartOffset(); int delta = offset - regionStart; boolean inWhitespacePrefix = true; for (int i = 0, n = Math.min(delta, text.length()); i < n; i++) { char ch = text.charAt(i); if (!Character.isWhitespace(ch)) { inWhitespacePrefix = false; break; } } if (inWhitespacePrefix) { IStructuredDocumentRegion previous = region.getPrevious(); if (previous != null && previous.getType() == XML_TAG_NAME) { ITextRegionList subRegions = previous.getRegions(); ITextRegion last = subRegions.get(subRegions.size() - 1); if (last.getType() == XML_TAG_CLOSE || last.getType() == XML_EMPTY_TAG_CLOSE) { int begin = AndroidXmlCharacterMatcher.findTagBackwards( doc, previous.getStartOffset() + last.getStart(), 0); int prevLineStart = findLineStart(doc, begin); int prevTextStart = findTextStart(doc, prevLineStart, begin); String lineIndent = ""; // $NON-NLS-1$ if (prevTextStart > prevLineStart) { lineIndent = doc.get(prevLineStart, prevTextStart - prevLineStart); } StringBuilder sb = new StringBuilder(c.text); sb.append(lineIndent); String oneIndentUnit = XmlFormatPreferences.create().getOneIndentUnit(); // See if there is whitespace on the insert line that // we should also remove for (int i = delta, n = text.length(); i < n; i++) { char ch = text.charAt(i); if (ch == ' ') { c.length++; } else { break; } } boolean onClosingTagLine = false; if (text.indexOf('\n', delta) == -1) { IStructuredDocumentRegion next = region.getNext(); if (next != null && next.getType() == XML_TAG_NAME) { String nextType = next.getRegions().get(0).getType(); if (nextType == XML_END_TAG_OPEN) { onClosingTagLine = true; } } } boolean addIndent = (last.getType() == XML_TAG_CLOSE) && !onClosingTagLine; if (addIndent) { sb.append(oneIndentUnit); } c.text = sb.toString(); return; } } } copyPreviousLineIndentation(doc, c); } else { copyPreviousLineIndentation(doc, c); } } catch (BadLocationException e) { AdtPlugin.log(e, null); } finally { model.releaseFromRead(); } } } }