VISTALL / jsyntaxpane

Automatically exported from code.google.com/p/jsyntaxpane
0 stars 0 forks source link

JavaIndent in not working at its optimum #42

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
e.g. you type in as follows:

if (k == 1) {
} else if (k == 2) {
} else {
}

The result looks like this afterwards:

if (k == 1) {
    } else if (k == 2) {
        else {
        }

It would be better to separate indentation and
de-indentation actions; the first could be triggered
by pressing Return, the other by entering a closing
brace (}).

Besides, comments aren't recognised at indent time, like:

if (true) { // do it always

My suggestion to implement this is here:

import java.awt.event.ActionEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;

import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.TokenType;
import jsyntaxpane.actions.SyntaxActions;

public class JIndentAction extends TextAction {

  /**
   * Crerates new JIndentAction.
   */
  public JIndentAction() {
    super("JINDENT");
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void actionPerformed(ActionEvent e) {
    JTextComponent target = getTextComponent(e);
    if (target != null) {
      SyntaxDocument sDoc = SyntaxActions.getSyntaxDocument(target);
      int pos = target.getCaretPosition();
      int start = sDoc.getParagraphElement(pos).getStartOffset();
      String line = SyntaxActions.getLine(target);
      String lineToPos = line.substring(0, pos - start);
      String prefix = SyntaxActions.getIndent(line);
      int tabSize = JavaScriptKit.getTabSize(target);
      if (lineToPos.trim().endsWith("{")) {
        prefix += StringTools.fillString(" ", tabSize);
      } else {
        String noComment = getLineTextWithoutComment(start, pos, sDoc); //
skip EOL comments
        if (noComment.trim().endsWith("{")) {
          prefix += StringTools.fillString(" ", tabSize);
        }
      }
      target.replaceSelection("\n" + prefix);
    }
  }

  /**
   * Gets the line without the comments. For example for the string
   * <code>{ // it's a comment</code> this method will return "{ ".
   * @param aStart start of the line.
   * @param anEnd end of the line.
   * @param aDocument document which holds the line.
   * @return string for the line without comments (if exists).
   */
  protected String getLineTextWithoutComment(int aStart, int anEnd,
SyntaxDocument aDocument) {
    Set<Token> tokens = new HashSet<Token>();
    StringBuilder result = new StringBuilder();
    for (int i = aStart; i < anEnd; i++) {
      Token t = aDocument.getTokenAt(i);
      if (null != t && ! tokens.contains(t)) {
        tokens.add(t);
        if (TokenType.COMMENT != t.type && TokenType.COMMENT2 != t.type) {
          result.append(t.getText(aDocument));
        }
      }
    }
    return result.toString();
  }

}

import java.awt.event.ActionEvent;

import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.TextAction;

import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import jsyntaxpane.actions.SyntaxActions;

public class JDeindentAction extends TextAction {

  /**
   * Crerates new DeindentAction.
   * @param name
   */
  public JDeindentAction() {
    super("JDEINDENT");
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void actionPerformed(ActionEvent e) {
    JTextComponent target = getTextComponent(e);
    if (target != null) {
      SyntaxDocument sDoc = SyntaxActions.getSyntaxDocument(target);
      int pos = target.getCaretPosition();
      int start = sDoc.getParagraphElement(pos).getStartOffset();
      String line = SyntaxActions.getLine(target);
      int tabSize = JavaScriptKit.getTabSize(target);
      if (StringTools.notNull(line).trim().isEmpty()) {
        try {
          sDoc.insertString(pos, "}", null);
          Token t = sDoc.getPairFor(sDoc.getTokenAt(pos));
          if (null != t) {
            String pairLine = SyntaxActions.getLineAt(target, t.start);
            String indent = getIndent(pairLine, tabSize);
            sDoc.replace(start, line.length() + 1, indent + "}", null);
          }
        } catch (BadLocationException ble) {
          target.replaceSelection("}");
        }
      } else {
        target.replaceSelection("}");
      }
    }
  }

  /**
   * Gets the indent string for the given line.
   * @param aLine string whos indent must be returned.
   * @param aTabSize number of spaces per tab.
   * @return indent string for the line.
   */
  public static String getIndent(String aLine, int aTabSize) {
    StringBuilder b = new StringBuilder();
    if (! StringTools.isEmpty(aLine)) {
      int i = 0;
      while (i < aLine.length() && (aLine.charAt(i) == ' ' ||
aLine.charAt(i) == '\t')) {
        if (aLine.charAt(i) == ' ') {
          b.append(aLine.charAt(i));
        } else {
          b.append(StringTools.fillString(" ", aTabSize));
        }
        i++;
      }

    }
    return b.toString();
  }

}

Here some used util methods:

class StringTools

  public static String fillString(String source, int repeat) {
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < repeat; i++) {
      buffer.append(source);
    }
    return buffer.toString();
  }
  public static String notNull(String aString) {
    String result = aString;
    if (null == result) {
      result = ""; //$NON-NLS-1$
    }

    return result;
  }
  public static boolean isEmpty(String s) {
    return (null == s) || (0 == s.length());
  }

class JavaScriptKit

  public static int getTabSize(JTextComponent aComponent) {
    Integer tabs = (Integer)
aComponent.getDocument().getProperty(PlainDocument.tabSizeAttribute);
    return null == tabs || tabs.intValue() == 0? 4 : tabs.intValue();
  }

Original issue reported on code.google.com by ser...@mail.ru on 20 Nov 2008 at 8:43

GoogleCodeExporter commented 9 years ago
Thanks for the code.  I'll incorporate this in a next release.

Original comment by ayman.al...@gmail.com on 20 Nov 2008 at 12:23

GoogleCodeExporter commented 9 years ago
Thanks for the code.  Added with modifications to release 0.9.4 and used in 
Java.

Original comment by ayman.al...@gmail.com on 1 Dec 2008 at 12:13