diff --git a/app/src/processing/app/syntax/SketchTextAreaEditorKit.java b/app/src/processing/app/syntax/SketchTextAreaEditorKit.java index b1c03e960..41379ae0b 100644 --- a/app/src/processing/app/syntax/SketchTextAreaEditorKit.java +++ b/app/src/processing/app/syntax/SketchTextAreaEditorKit.java @@ -1,5 +1,6 @@ package processing.app.syntax; +import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit; import org.fife.ui.rtextarea.RTextArea; import org.fife.ui.rtextarea.RecordableTextAction; @@ -16,7 +17,8 @@ public class SketchTextAreaEditorKit extends RSyntaxTextAreaEditorKit { private static final Action[] defaultActions = { new DeleteNextWordAction(), new DeleteLineToCursorAction(), - new SelectWholeLineAction() + new SelectWholeLineAction(), + new ToggleCommentAction() }; @Override @@ -126,4 +128,103 @@ public class SketchTextAreaEditorKit extends RSyntaxTextAreaEditorKit { } + public static class ToggleCommentAction extends RecordableTextAction { + + public ToggleCommentAction() { + super(rstaToggleCommentAction); + } + + @Override + public void actionPerformedImpl(ActionEvent e, RTextArea textArea) { + + if (!textArea.isEditable() || !textArea.isEnabled()) { + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + return; + } + + RSyntaxDocument doc = (RSyntaxDocument) textArea.getDocument(); + Element map = doc.getDefaultRootElement(); + Caret c = textArea.getCaret(); + int dot = c.getDot(); + int mark = c.getMark(); + int line1 = map.getElementIndex(dot); + int line2 = map.getElementIndex(mark); + int start = Math.min(line1, line2); + int end = Math.max(line1, line2); + + org.fife.ui.rsyntaxtextarea.Token t = doc.getTokenListForLine(start); + int languageIndex = t != null ? t.getLanguageIndex() : 0; + String[] startEnd = doc.getLineCommentStartAndEnd(languageIndex); + + if (startEnd == null) { + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + return; + } + + // Don't toggle comment on last line if there is no + // text selected on it. + if (start != end) { + Element elem = map.getElement(end); + if (Math.max(dot, mark) == elem.getStartOffset()) { + end--; + } + } + + textArea.beginAtomicEdit(); + try { + boolean add = getDoAdd(doc, map, start, end, startEnd); + for (line1 = start; line1 <= end; line1++) { + Element elem = map.getElement(line1); + handleToggleComment(elem, doc, startEnd, add); + } + } catch (BadLocationException ble) { + ble.printStackTrace(); + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + } finally { + textArea.endAtomicEdit(); + } + + } + + private boolean getDoAdd(Document doc, Element map, int startLine, int endLine, String[] startEnd) throws BadLocationException { + boolean doAdd = false; + for (int i = startLine; i <= endLine; i++) { + Element elem = map.getElement(i); + int start = elem.getStartOffset(); + String t = doc.getText(start, elem.getEndOffset() - start - 1).trim(); + if (!t.startsWith(startEnd[0]) || + (startEnd[1] != null && !t.endsWith(startEnd[1]))) { + doAdd = true; + break; + } + } + return doAdd; + } + + private void handleToggleComment(Element elem, Document doc, String[] startEnd, boolean add) throws BadLocationException { + int start = elem.getStartOffset(); + int end = elem.getEndOffset() - 1; + if (add) { + doc.insertString(start, startEnd[0], null); + if (startEnd[1] != null) { + doc.insertString(end + startEnd[0].length(), startEnd[1], null); + } + } else { + String text = doc.getText(start, elem.getEndOffset() - start - 1); + start += text.indexOf(startEnd[0]); + doc.remove(start, startEnd[0].length()); + if (startEnd[1] != null) { + int temp = startEnd[1].length(); + doc.remove(end - startEnd[0].length() - temp, temp); + } + } + } + + @Override + public final String getMacroID() { + return rstaToggleCommentAction; + } + + } + }