@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 smartIndentAfterClosingBracket(IDocument d, DocumentCommand c) {
    if (c.offset == -1 || d.getLength() == 0) return;

    try {
      int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
      int line = d.getLineOfOffset(p);
      int start = d.getLineOffset(line);
      int whiteend = findEndOfWhiteSpace(d, start, c.offset);

      JavaHeuristicScanner scanner = new JavaHeuristicScanner(d);
      JavaIndenter indenter = new JavaIndenter(d, scanner, fProject);

      // shift only when line does not contain any text up to the closing bracket
      if (whiteend == c.offset) {
        // evaluate the line with the opening bracket that matches out closing bracket
        int reference = indenter.findReferencePosition(c.offset, false, true, false, false);
        int indLine = d.getLineOfOffset(reference);
        if (indLine != -1 && indLine != line) {
          // take the indent of the found line
          StringBuffer replaceText = new StringBuffer(getIndentOfLine(d, indLine));
          // add the rest of the current line including the just added close bracket
          replaceText.append(d.get(whiteend, c.offset - whiteend));
          replaceText.append(c.text);
          // modify document command
          c.length += c.offset - start;
          c.offset = start;
          c.text = replaceText.toString();
        }
      }
    } catch (BadLocationException e) {
      JavaPlugin.log(e);
    }
  }
  @Test
  public void indentShouldNotBeAdded_whenPreviousLineDoesNotStartFromIndent() {
    document.set("xyz");
    command.offset = 3;
    command.text = "\n";

    strategy.customizeDocumentCommand(document, command);

    assertThat(command.text).isEqualTo("\n");
  }
  @Test
  public void indentFromPreviousLineShouldBeAdded() {
    document.set("    abc");
    command.offset = 7;
    command.text = "\n";

    strategy.customizeDocumentCommand(document, command);

    assertThat(command.text).isEqualTo("\n    ");
  }
  @Test
  public void commandShouldNotBeChanged_whenItIsNotLineBreak() {
    document.set("x");
    command.offset = 1;
    command.text = "q";

    strategy.customizeDocumentCommand(document, command);

    assertThat(command.text).isEqualTo("q");
  }
 @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);
 }
 private void reduceIndentOfCurrentLine() throws BadLocationException {
   int spaces = getIndentSpaces();
   String text = document.get(command.offset - spaces, spaces);
   if (endsWithSpaces(text, spaces)) {
     command.offset = command.offset - spaces;
     command.length = spaces;
   } else if (document.get(command.offset - 1, 1).equals("\t")) {
     command.offset = command.offset - 1;
     command.length = 1;
   }
 }
 @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);
 }
 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) +
             "*/";
   }
 }
  public void customizeDocumentCommand() {

    // Note that Correct Indentation sends us a tab
    // character at the start of each line of selected
    // text. This is amazingly sucky because it's very
    // difficult to distinguish Correct Indentation from
    // an actual typed tab.
    // Note also that typed tabs are replaced with spaces
    // before this method is called if the spacesfortabs
    // setting is enabled.

    if (command.text != null) {
      // command.length>0 means we are replacing or deleting text
      if (command.length == 0) {
        if (command.text.isEmpty()) {
          // workaround for a really annoying bug where we
          // get sent "" instead of "\t" or "    " by IMP
          // reconstruct what we would have been sent
          // without the bug
          if (getIndentWithSpaces()) {
            int overhang = getPrefix().length() % getIndentSpaces();
            command.text = getDefaultIndent().substring(overhang);
          } else {
            command.text = "\t";
          }
          smartIndentOnKeypress();
        } else if (isLineEnding(command.text)) {
          // a typed newline (might have length 1 or 2,
          // depending on the platform)
          smartIndentAfterNewline();
        } else if (command.text.length() == 1
            ||
            // when spacesfortabs is enabled, we get
            // sent spaces instead of a tab - the right
            // number of spaces to take us to the next
            // tab stop
            getIndentWithSpaces() && isIndent(getPrefix())) {
          // anything that might represent a single
          // keypress or a Correct Indentation
          smartIndentOnKeypress();
        }
      }

      if (command.text != null && command.text.length() == 1 && command.length == 0) {
        closeOpening();
      }
    }
  }
  protected void copyIndentation(final IDocument d, final DocumentCommand c) {
    // CODE KOPIERT AUS SUPER-KLASSE DA DORT PRIVATE
    // == DefaultIndentLineAutoEditStrategy.autoIndentAfterNewLine(IDocument d, DocumentCommand c)

    if (c.offset == -1 || d.getLength() == 0) return;

    try {
      // find start of line
      int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
      IRegion info = d.getLineInformationOfOffset(p);
      int start = info.getOffset();

      // find white spaces
      int end = findEndOfWhiteSpace(d, start, c.offset);

      StringBuffer buf = new StringBuffer(c.text);
      if (end > start) {
        // append to input
        buf.append(d.get(start, end - start));
      }

      c.text = buf.toString();

    } catch (BadLocationException excp) {
      // stop work
    }
  }
 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);
   }
 }
 public void customizeDocumentCommand(IDocument d, DocumentCommand c) {
   if (c.length == 0
       && c.text != null
       && TextUtilities.endsWith(d.getLegalLineDelimiters(), c.text) != -1) {
     autoIndentAfterNewLine(d, c);
   } else if (c.text.equals("\t")) {
     c.text = INDENT_STRING;
   }
 }
  private void autoEditBeforeCloseBrace(IDocument document, DocumentCommand command) {
    if (isNewLineBefore(document, command.offset)) {
      try {
        int spaceLength =
            command.offset - findEndOfWhiteSpaceBefore(document, command.offset - 1, 0) - 1;

        command.text =
            IndenterUtil.createWhiteSpace(
                    computeIndentCount(document, command.offset) - 1,
                    0,
                    TextUtilities.getDefaultLineDelimiter(document))
                + CLOSING_BRACE_STRING;
        command.offset -= spaceLength;
        document.replace(command.offset, spaceLength, "");
      } catch (BadLocationException e) {
        KotlinLogger.logAndThrow(e);
      }
    }
  }
  private void indentNewLine() throws BadLocationException {
    int stringIndent = getStringOrCommentIndent(command.offset);
    int start = getStartOfCurrentLine();
    if (stringIndent >= 0) {
      // we're in a string or multiline comment
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < stringIndent; i++) {
        char ws = document.getChar(start + i) == '\t' ? '\t' : ' ';
        sb.append(ws);
      }
      command.text = command.text + sb.toString() + getRelativeIndent(command.offset);
    } else {
      char endOfLastLineChar = getPreviousNonHiddenCharacterInLine(command.offset);
      char startOfNewLineChar = getNextNonHiddenCharacterInNewline(command.offset);

      StringBuilder buf = new StringBuilder(command.text);
      IPreferenceStore store = getPreferences();
      boolean closeBrace = store == null || store.getBoolean(CLOSE_BRACES);
      int end = getEndOfCurrentLine();
      appendIndent(
          command.offset,
          end,
          start,
          command.offset,
          startOfNewLineChar,
          endOfLastLineChar,
          closeBrace,
          buf);
      if (buf.length() > 2) {
        char ch = buf.charAt(buf.length() - 1);
        if (ch == '}' || ch == ')') {
          String hanging =
              document.get(
                  command.offset, end - command.offset); // stuff after the { on the current line
          buf.insert(command.caretOffset - command.offset, hanging);
          command.length = hanging.length();
        }
      }
      command.text = buf.toString();
    }
    closeUnterminatedMultlineComment();
  }
  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);
    }
  }
  protected void indentAfterNewLine(final IDocument d, final DocumentCommand c)
      throws BadLocationException {
    final int offset = c.offset;
    String txt = null;
    editor.reconcileNow();
    final IErlElement element = editor.getElementAt(offset, false);
    final IErlMember member = (IErlMember) element;
    if (member != null) {
      final int start = member.getSourceRange().getOffset();
      if (offset >= start) {
        txt = d.get(start, offset - start);
      }
    }
    if (txt == null) {
      txt = "";
    }
    final int lineN = d.getLineOfOffset(offset);
    final int lineOffset = d.getLineOffset(lineN);
    final int lineLength = d.getLineLength(lineN);
    final String oldLine = d.get(offset, lineLength + lineOffset - offset);
    try {
      final IRpcSite b = BackendCore.getBackendManager().getIdeBackend().getRpcSite();
      final int tabw = getTabWidthFromPreferences();

      final Map<String, String> prefs = new TreeMap<String, String>();
      IndentationPreferencePage.addKeysAndPrefs(prefs);
      SmartTypingPreferencePage.addAutoNLKeysAndPrefs(prefs);
      final boolean useTabs = getUseTabsFromPreferences();
      final IndentResult res =
          ErlideIndent.indentLine(b, oldLine, txt, c.text, tabw, useTabs, prefs);

      if (res.isAddNewLine()) {
        c.text += "\n";
      }
      c.text += res.getText();
      c.length += res.getRemoveNext();
    } catch (final Exception e) {
      ErlLogger.warn(e);
    }
  }
 private void fixIndentOfStringOrCommentContinuation() throws BadLocationException {
   int endOfWs = firstEndOfWhitespace(command.offset, getEndOfCurrentLine());
   if (endOfWs < 0) return;
   CommonToken tokenContainingOffset = getTokenStrictlyContainingOffset(command.offset);
   CommonToken token = getStartOfStringToken(tokenContainingOffset);
   int pos = command.offset - getStartOfCurrentLine();
   int tokenIndent = token.getCharPositionInLine();
   if (pos > tokenIndent) return;
   StringBuilder indent = new StringBuilder();
   int startOfTokenLine = document.getLineOffset(token.getLine() - 1);
   String prefix = document.get(startOfTokenLine + pos, tokenIndent - pos);
   for (int i = 0; i < prefix.length(); i++) {
     char ch = prefix.charAt(i);
     indent.append(ch == '\t' ? '\t' : ' ');
   }
   indent.append(getExtraIndent(token));
   indent.append(getRelativeIndent(command.offset));
   if (indent.length() > 0) {
     command.length = endOfWs - command.offset;
     command.text = indent.toString();
   }
 }
  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;
      }
    }
  }
  /**
   * Set the indent of a bracket based on the command provided in the supplied document.
   *
   * @param document - the document being parsed
   * @param command - the command being performed
   */
  protected void smartInsertAfterBracket(final IDocument document, final DocumentCommand command) {
    if (command.offset == -1 || document.getLength() == 0) {
      return;
    }

    try {
      int p = (command.offset == document.getLength() ? command.offset - 1 : command.offset);
      int line = document.getLineOfOffset(p);
      int start = document.getLineOffset(line);
      int whiteend = findEndOfWhiteSpace(document, start, command.offset);

      // shift only when line does not contain any text up to
      // the closing
      // bracket
      if (whiteend == command.offset) {
        // evaluate the line with the opening bracket
        // that matches out
        // closing bracket
        int indLine = findMatchingOpenBracket(document, command.offset);
        if (indLine != -1 && indLine != line) {
          // take the indent of the found line
          StringBuffer replaceText = new StringBuffer(getIndentOfLine(document, indLine, command));
          // add the rest of the current line
          // including the just added
          // close bracket
          // replaceText.append(document.get(whiteend,
          // command.offset
          // - whiteend));
          replaceText.append(command.text);
          // modify document command
          command.length = command.offset - start;
          command.offset = start;
          command.text = replaceText.toString();
        }
      }
    } catch (BadLocationException e) {
      ErrorReporter.logExceptionStackTrace(e);
    }
  }
  private void smartIndentAfterOpeningBracket(IDocument d, DocumentCommand c) {
    if (c.offset < 1 || d.getLength() == 0) return;

    JavaHeuristicScanner scanner = new JavaHeuristicScanner(d);

    int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);

    try {
      // current line
      int line = d.getLineOfOffset(p);
      int lineOffset = d.getLineOffset(line);

      // make sure we don't have any leading comments etc.
      if (d.get(lineOffset, p - lineOffset).trim().length() != 0) return;

      // line of last Java code
      int pos = scanner.findNonWhitespaceBackward(p, JavaHeuristicScanner.UNBOUND);
      if (pos == -1) return;
      int lastLine = d.getLineOfOffset(pos);

      // only shift if the last java line is further up and is a braceless block candidate
      if (lastLine < line) {

        JavaIndenter indenter = new JavaIndenter(d, scanner, fProject);
        StringBuffer indent = indenter.computeIndentation(p, true);
        String toDelete = d.get(lineOffset, c.offset - lineOffset);
        if (indent != null && !indent.toString().equals(toDelete)) {
          c.text = indent.append(c.text).toString();
          c.length += c.offset - lineOffset;
          c.offset = lineOffset;
        }
      }

    } catch (BadLocationException e) {
      JavaPlugin.log(e);
    }
  }
  private void AtlStringIndentAfterNewLine(IDocument document, DocumentCommand command)
      throws BadLocationException {

    ITypedRegion partition =
        TextUtilities.getPartition(document, fPartitioning, command.offset, true);
    int offset = partition.getOffset();
    int length = partition.getLength();

    if (command.offset == offset + length && document.getChar(offset + length - 1) == '\'') return;

    String indentation = getLineIndentation(document, command.offset);
    String delimiter = TextUtilities.getDefaultLineDelimiter(document);

    IRegion line = document.getLineInformationOfOffset(offset);
    String string = document.get(line.getOffset(), offset - line.getOffset());
    if (string.trim().length() != 0) indentation += String.valueOf("\t\t");

    IPreferenceStore preferenceStore = AtlUIPlugin.getDefault().getPreferenceStore();
    if (isLineDelimiter(document, command.text))
      command.text = "\' +" + command.text + indentation + "\'";
    else if (command.text.length() > 1
        && preferenceStore.getBoolean(AtlPreferenceConstants.TYPING_ESCAPE_STRINGS))
      command.text = getModifiedText(command.text, indentation, delimiter);
  }
  /**
   * Indent the new line the same way as the current line.
   *
   * @param doc the document to indent in
   * @param command the document command to customize
   * @throws BadLocationException if the offsets are invalid
   */
  private void copyPreviousLineIndentation(IDocument doc, DocumentCommand command)
      throws BadLocationException {

    if (command.offset == -1 || doc.getLength() == 0) {
      return;
    }

    int lineStart = findLineStart(doc, command.offset);
    int textStart = findTextStart(doc, lineStart, command.offset);

    StringBuilder sb = new StringBuilder(command.text);
    if (textStart > lineStart) {
      sb.append(doc.get(lineStart, textStart - lineStart));
    }

    command.text = sb.toString();
  }
  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());
  }
  /**
   * Adds two spaces to the indentation of the previous line.
   *
   * @param d the document to work on
   * @param c the command to deal with
   */
  private void autoIndentAfterNewLine(IDocument d, DocumentCommand c) {

    if (c.offset == -1 || d.getLength() == 0) return;

    try {
      String lastPartitionType = null;
      if (d instanceof IDocumentExtension3) {
        IDocumentExtension3 id3 = (IDocumentExtension3) d;
        lastPartitionType =
            id3.getDocumentPartitioner(SassEditor.SASS_PARTITIONING).getContentType(c.offset - 1);
      }

      // find start of line
      int p = (c.offset == d.getLength() ? c.offset - 1 : c.offset);
      IRegion info = d.getLineInformationOfOffset(p);
      int start = info.getOffset();

      // find white spaces
      int end = findEndOfWhiteSpace(d, start, c.offset);

      // indent if we just finished an element
      StringBuffer buf = new StringBuffer(c.text);
      if (lastPartitionType != null
          && (lastPartitionType.equalsIgnoreCase(SassPartitionScanner.SASS_CLASS)
              || lastPartitionType.equalsIgnoreCase(SassPartitionScanner.SASS_ID))) {
        buf.append("  ");
      }

      if (end > start) {
        // append to input
        buf.append(d.get(start, end - start));
      }

      c.text = buf.toString();

    } catch (BadLocationException excp) {
      // stop work
    }
  }
  @Override
  public void customizeDocumentCommand(final IDocument d, final DocumentCommand c) {
    if (TextUtilities.endsWith(d.getLegalLineDelimiters(), c.text) != -1) {
      // Start autoindentation after a cabal section (e.g., global, executable, library)
      try {
        IRegion r = d.getLineInformation(d.getLineOfOffset(c.offset));
        String s = d.get(r.getOffset(), r.getLength()).toLowerCase();

        for (String section : CabalSyntax.sections.keySet()) {
          if (s.equals(section) || s.startsWith(section + " ")) { // $NON-NLS-1$
            char[] ch = new char[getTabWidth()];
            Arrays.fill(ch, ' ');
            c.text = c.text + new String(ch);
          }
        }
      } catch (BadLocationException ble) {
        // ignore
      }
    } else {
      // Superclass takes care of autoindentation
      super.customizeDocumentCommand(d, c);
    }
  }
 /**
  * Copies the indentation of the previous line.
  *
  * @param d the document to work on
  * @param c the command to deal with
  */
 protected void autoIndentAfterNewLine(IDocument d, DocumentCommand c) {
   c.text += getAutoIndentAfterNewLine(d, c);
 }
  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);
    }
  }
  private void smartPaste(IDocument document, DocumentCommand command) {
    int newOffset = command.offset;
    int newLength = command.length;
    String newText = command.text;

    try {
      JavaHeuristicScanner scanner = new JavaHeuristicScanner(document);
      JavaIndenter indenter = new JavaIndenter(document, scanner, fProject);
      int offset = newOffset;

      // reference position to get the indent from
      int refOffset = indenter.findReferencePosition(offset);
      if (refOffset == JavaHeuristicScanner.NOT_FOUND) return;
      int peerOffset = getPeerPosition(document, command);
      peerOffset = indenter.findReferencePosition(peerOffset);
      if (peerOffset != JavaHeuristicScanner.NOT_FOUND) refOffset = Math.min(refOffset, peerOffset);

      // eat any WS before the insertion to the beginning of the line
      int firstLine =
          1; // don't format the first line per default, as it has other content before it
      IRegion line = document.getLineInformationOfOffset(offset);
      String notSelected = document.get(line.getOffset(), offset - line.getOffset());
      if (notSelected.trim().length() == 0) {
        newLength += notSelected.length();
        newOffset = line.getOffset();
        firstLine = 0;
      }

      // prefix: the part we need for formatting but won't paste
      IRegion refLine = document.getLineInformationOfOffset(refOffset);
      String prefix = document.get(refLine.getOffset(), newOffset - refLine.getOffset());

      // handle the indentation computation inside a temporary document
      Document temp = new Document(prefix + newText);
      DocumentRewriteSession session =
          temp.startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL);
      scanner = new JavaHeuristicScanner(temp);
      indenter = new JavaIndenter(temp, scanner, fProject);
      installJavaStuff(temp);

      // indent the first and second line
      // compute the relative indentation difference from the second line
      // (as the first might be partially selected) and use the value to
      // indent all other lines.
      boolean isIndentDetected = false;
      StringBuffer addition = new StringBuffer();
      int insertLength = 0;
      int firstLineInsertLength = 0;
      int firstLineIndent = 0;
      int first = document.computeNumberOfLines(prefix) + firstLine; // don't format first line
      int lines = temp.getNumberOfLines();
      int tabLength = getVisualTabLengthPreference();
      boolean changed = false;
      for (int l = first;
          l < lines;
          l++) { // we don't change the number of lines while adding indents

        IRegion r = temp.getLineInformation(l);
        int lineOffset = r.getOffset();
        int lineLength = r.getLength();

        if (lineLength == 0) // don't modify empty lines
        continue;

        if (!isIndentDetected) {

          // indent the first pasted line
          String current = getCurrentIndent(temp, l);
          StringBuffer correct = indenter.computeIndentation(lineOffset);
          if (correct == null) return; // bail out

          insertLength = subtractIndent(correct, current, addition, tabLength);
          if (l == first) {
            firstLineInsertLength = insertLength;
            firstLineIndent = current.length();
          }
          if (l != first && temp.get(lineOffset, lineLength).trim().length() != 0) {
            isIndentDetected = true;
            if (firstLineIndent >= current.length()) insertLength = firstLineInsertLength;
            if (insertLength == 0) {
              // no adjustment needed, bail out
              if (firstLine == 0) {
                // but we still need to adjust the first line
                command.offset = newOffset;
                command.length = newLength;
                if (changed) break; // still need to get the leading indent of the first line
              }
              return;
            }
          } else {
            changed = insertLength != 0;
          }
        }

        // relatively indent all pasted lines
        if (insertLength > 0) addIndent(temp, l, addition, tabLength);
        else if (insertLength < 0) cutIndent(temp, l, -insertLength, tabLength);
      }

      removeJavaStuff(temp);
      temp.stopRewriteSession(session);
      newText = temp.get(prefix.length(), temp.getLength() - prefix.length());

      command.offset = newOffset;
      command.length = newLength;
      command.text = newText;

    } catch (BadLocationException e) {
      JavaPlugin.log(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;
          }
        }
      }
    }
  }