Automatic add closing curly brace

Questions on using RSyntaxTextArea should go here.

Moderator: robert

Automatic add closing curly brace

Postby Archivist » Thu Mar 26, 2009 5:35 pm

How I can add automatic closing curly brace functionality?
Archivist
 

Re: Automatic add closing curly brace

Postby Archivist » Thu Mar 26, 2009 5:36 pm

Meaning that it happens after typing '{' and pressing enter.
Archivist
 

Re: Automatic add closing curly brace

Postby robert » Thu Mar 26, 2009 6:33 pm

I added a Feature Request for this on SourceForge. This is definitely doable, and indeed I have already considered doing it. The question was simply how to implement it. I think most of the code is actually already there and simply commented out.

I was trying to make it "smart" and just "do the right thing" like Eclipse (which knows if a closing brace already exists, and doesn't insert a new one if it does), but maybe I should just go ahead and put in a simple implementation, always inserting a closing brace on Enter. It could always be made smarter later.
User avatar
robert
 
Posts: 774
Joined: Sat May 10, 2008 5:16 pm

Re: Automatic add closing curly brace

Postby Archivist » Fri Mar 27, 2009 6:04 am

I did this feature by adding custom KeyAdapter, but currently its impelementation works with bugs.
Archivist
 

Re: Automatic add closing curly brace

Postby Archivist » Fri Mar 27, 2009 9:22 am

I made one more try, and seems that it is working ok. The code is not very nice, but maybe it can help:

public static class InsertCloseCurlyBraceAction extends RecordableTextAction {

private static final long serialVersionUID = 1L;

private Segment seg;

public InsertCloseCurlyBraceAction() {
super(rstaInsertCloseCurlyBraceAction);
seg = new Segment();
}

public void actionPerformedImpl(ActionEvent e, RTextArea textArea) {

RSyntaxTextArea rsta = (RSyntaxTextArea) textArea;
RSyntaxDocument doc = (RSyntaxDocument) rsta.getDocument();
boolean alignCurlyBraces = rsta.isAutoIndentEnabled() && doc.getCurlyBracesDenoteCodeBlocks();

if (alignCurlyBraces) {
textArea.beginAtomicEdit();
}

try {

int caretPosition = textArea.getCaretPosition();
int lineOfOffset = textArea.getLineOfOffset(caretPosition);
if (!(lineOfOffset - 2 >= 0)) return;
int prevLineEnd = textArea.getLineEndOffset(lineOfOffset - 2);
// int diff = curLineEnd - prevLineEnd;
int diff = caretPosition - prevLineEnd;
String selectedLineText = textArea.getText(prevLineEnd, diff);

if (!textArea.isEditable() || !textArea.isEnabled()) {
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
return;
}

RSyntaxTextArea sta = (RSyntaxTextArea) textArea;
boolean isNeedAdd = possibleNeedAddClosingBrace(selectedLineText);
// If we're in insert-mode and auto-indenting...
if (sta.getTextMode() == RTextArea.INSERT_MODE && sta.isAutoIndentEnabled() && sta.getSelectionStart() == sta.getSelectionEnd()) {
(new InsertBreakAction()).insertNewlineWithAutoIndent(sta);
}

// Otherwise, we're in overwrite-mode or not auto-indenting.
else {
textArea.replaceSelection("\n");
}
caretPosition = textArea.getCaretPosition();
lineOfOffset = textArea.getLineOfOffset(caretPosition);
if (isNeedAdd&&isNotEqualAmount(textArea.getText())) {
insertNewlineWithAutoIndent(sta);
textArea.insert("}", textArea.getCaretPosition());
textArea.setCaretPosition(caretPosition);
}

} catch (Exception exception) {
// do nothing
exception.printStackTrace();
} finally {
if (alignCurlyBraces) {
textArea.endAtomicEdit();
}
}
}

private void insertNewlineWithAutoIndent(RSyntaxTextArea sta) {

try {

int caretPosition = sta.getCaretPosition();
Document doc = sta.getDocument();
Element map = doc.getDefaultRootElement();
int lineNum = map.getElementIndex(caretPosition);
Element line = map.getElement(lineNum);
int start = line.getStartOffset();
int end = line.getEndOffset() - 1; // Why always "-1"?
int len = end - start;
String s = doc.getText(start, len);

// endWS is the end of the leading whitespace of the
// current line.
String leadingWS = RSyntaxUtilities.getLeadingWhitespace(s);
if (leadingWS.length() >= sta.getTabSize()) {
leadingWS = leadingWS.substring(0, leadingWS.length() - sta.getTabSize());
}
StringBuffer sb = new StringBuffer("\n");
sb.append(leadingWS);

// If there is only whitespace between the caret and
// the EOL, pressing Enter auto-indents the new line to
// the same place as the previous line.
int nonWhitespacePos = atEndOfLine(caretPosition - start, s, len);
if (nonWhitespacePos == -1) {
// If the line was nothing but whitespace...
if (leadingWS.length() == len && sta.isClearWhitespaceLinesEnabled()) {
sta.replaceRange(null, start, end);
}
sta.replaceSelection(sb.toString());
}

// If there is non-whitespace between the caret and the
// EOL, pressing Enter takes that text to the next line
// and auto-indents it to the same place as the last
// line.
else {
sb.append(s.substring(nonWhitespacePos));
sta.replaceRange(sb.toString(), caretPosition, end);
sta.setCaretPosition(caretPosition + leadingWS.length() + 1);
}

// Must do it after everything else, as the "smart indent"
// calculation depends on the previous line's state
// AFTER the Enter press (stuff may have been moved down).
if (sta.getShouldIndentNextLine(lineNum)) {
sta.replaceSelection("\t");
}

// if (sta.getCloseCurlyBraces()) {
// int dot = sta.getCaretPosition();
// String str = "\n" + leadingWS + "}";
// sta.replaceRange(str, dot, dot);
// sta.setCaretPosition(dot);
// }

} catch (BadLocationException ble) { // Never happens
sta.replaceSelection("\n");
ble.printStackTrace();
}

}

/**
* @return The first location in the string past <code>pos</code> that
* is NOT a whitespace char, or <code>-1</code> if only
* whitespace chars follow <code>pos</code> (or it is the end
* position in the string).
*/
private static final int atEndOfLine(int pos, String s, int sLen) {
for (int i = pos; i < sLen; i++) {
if (!RSyntaxUtilities.isWhitespace(s.charAt(i))) return i;
}
return -1;
}

public final String getMacroID() {
return rstaCloseCurlyBraceAction;
}

private boolean possibleNeedAddClosingBrace(String selectedLine) {
char a[] = selectedLine.toCharArray();
if (a.length > 0) {
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] == 9 || a[i] == 32 || a[i] == 10 || a[i] == 13) continue;
if (a[i] == 123) return true;
else return false;
}

return false;
} else return false;
}

private boolean isNotEqualAmount(String selectedLine) {
char a[] = selectedLine.toCharArray();
int closeCurly = 0;
int openCurly = 0;
if (a.length > 0) {
for (int i = a.length - 1; i >= 0; i--) {
if (a[i] == 123) {
openCurly++;
} else if (a[i] == 125) {
closeCurly++;
}
}
}
if (openCurly > closeCurly) {
return true;
} else {
return false;
}
}
}
Archivist
 
Posts: 1
Joined: Fri Mar 27, 2009 9:18 am

Re: Automatic add closing curly brace

Postby robert » Sat Mar 28, 2009 4:18 pm

This is just an FYI that I am looking into adding this. I skimmed over your implementation and it's similar to what I would do, although there is at least one place where performance would need to be improved, as it would be slow for very large files.
User avatar
robert
 
Posts: 774
Joined: Sat May 10, 2008 5:16 pm


Return to Help

Who is online

Users browsing this forum: No registered users and 2 guests