diff --git a/src/dlangide/ui/commands.d b/src/dlangide/ui/commands.d index 6c16df7..0c74d51 100644 --- a/src/dlangide/ui/commands.d +++ b/src/dlangide/ui/commands.d @@ -69,8 +69,8 @@ const Action ACTION_EDIT_UNDO = (new Action(EditorActions.Undo, "MENU_EDIT_UNDO" const Action ACTION_EDIT_REDO = (new Action(EditorActions.Redo, "MENU_EDIT_REDO"c, "edit-redo"c, KeyCode.KEY_Z, KeyFlag.Control|KeyFlag.Shift)).disableByDefault(); const Action ACTION_EDIT_INDENT = (new Action(EditorActions.Indent, "MENU_EDIT_INDENT"c, "edit-indent"c, KeyCode.TAB, 0)).disableByDefault(); const Action ACTION_EDIT_UNINDENT = (new Action(EditorActions.Unindent, "MENU_EDIT_UNINDENT"c, "edit-unindent", KeyCode.TAB, KeyFlag.Shift)).disableByDefault(); -const Action ACTION_EDIT_TOGGLE_LINE_COMMENT = (new Action(EditorActions.Redo, "MENU_EDIT_TOGGLE_LINE_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control)).disableByDefault(); -const Action ACTION_EDIT_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.Redo, "MENU_EDIT_TOGGLE_BLOCK_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control|KeyFlag.Shift)).disableByDefault(); +const Action ACTION_EDIT_TOGGLE_LINE_COMMENT = (new Action(EditorActions.ToggleLineComment, "MENU_EDIT_TOGGLE_LINE_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control)).disableByDefault(); +const Action ACTION_EDIT_TOGGLE_BLOCK_COMMENT = (new Action(EditorActions.ToggleBlockComment, "MENU_EDIT_TOGGLE_BLOCK_COMMENT"c, null, KeyCode.KEY_DIVIDE, KeyFlag.Control|KeyFlag.Shift)).disableByDefault(); const Action ACTION_EDIT_PREFERENCES = (new Action(EditorActions.Redo, "MENU_EDIT_PREFERENCES"c, null)); const Action ACTION_HELP_ABOUT = new Action(IDEActions.HelpAbout, "MENU_HELP_ABOUT"c); const Action ACTION_WINDOW_CLOSE_ALL_DOCUMENTS = new Action(IDEActions.WindowCloseAllDocuments, "MENU_WINDOW_CLOSE_ALL_DOCUMENTS"c); diff --git a/src/dlangide/ui/dsourceedit.d b/src/dlangide/ui/dsourceedit.d index 6ecd7b8..f8964df 100644 --- a/src/dlangide/ui/dsourceedit.d +++ b/src/dlangide/ui/dsourceedit.d @@ -89,6 +89,7 @@ class DSourceEdit : SourceEdit { class SimpleDSyntaxHighlighter : SyntaxHighlighter { + EditableContent _content; SourceFile _file; ArraySourceLines _lines; Tokenizer _tokenizer; @@ -101,6 +102,141 @@ class SimpleDSyntaxHighlighter : SyntaxHighlighter { TokenPropString[] _props; + /// returns editable content + @property EditableContent content() { return _content; } + /// set editable content + @property SyntaxHighlighter content(EditableContent content) { + _content = content; + return this; + } + + /// return true if toggle line comment is supported for file type + override @property bool supportsToggleLineComment() { + return true; + } + + + + /// return true if can toggle line comments for specified text range + override bool canToggleLineComment(TextRange range) { + return true; + } + + protected bool isLineComment(dstring s) { + for (int i = 0; i < s.length - 2; i++) { + if (s[i] == '/' && s[i + 1] == '/') + return true; + else if (s[i] != ' ' && s[i] != '\t') + return false; + } + return false; + } + + protected dstring commentLine(dstring s, int commentX) { + dchar[] res; + int x = 0; + bool commented = false; + for (int i = 0; i < s.length; i++) { + dchar ch = s[i]; + if (ch == '\t') { + int newX = (x + _content.tabSize) / _content.tabSize * _content.tabSize; + if (!commented && newX >= commentX) { + commented = true; + if (newX != commentX) { + // replace tab with space + for (; x <= commentX; x++) + res ~= ' '; + } else { + res ~= ch; + x = newX; + } + res ~= "//"; + x += 2; + } else { + res ~= ch; + x = newX; + } + } else { + if (!commented && x == commentX) { + commented = true; + res ~= "//"; + res ~= ch; + x += 3; + } else { + res ~= ch; + x++; + } + } + } + if (!commented) { + for (; x < commentX; x++) + res ~= ' '; + res ~= "//"; + } + return cast(dstring)res; + } + + /// toggle line comments for specified text range + override void toggleLineComment(TextRange range, Object source) { + TextRange r = content.fullLinesRange(range); + int lineCount = r.end.line - r.start.line; + bool noEolAtEndOfRange = false; + if (lineCount == 0 || r.end.pos > 0) { + noEolAtEndOfRange = true; + lineCount++; + } + int minLeftX = -1; + bool hasComments = false; + bool hasNoComments = false; + bool hasNonEmpty = false; + dstring[] srctext; + dstring[] dsttext; + for (int i = 0; i < lineCount; i++) { + int lineIndex = r.start.line + i; + dstring s = content.line(lineIndex); + srctext ~= s; + TextLineMeasure m = content.measureLine(lineIndex); + if (!m.empty) { + if (minLeftX < 0 || minLeftX > m.firstNonSpaceX) + minLeftX = m.firstNonSpaceX; + hasNonEmpty = true; + if (isLineComment(s)) + hasComments = true; + else + hasNoComments = true; + } + } + if (minLeftX < 0) + minLeftX = 0; + if (hasNoComments || !hasComments) { + // comment + for (int i = 0; i < lineCount; i++) { + dsttext ~= commentLine(srctext[i], minLeftX); + } + if (!noEolAtEndOfRange) + dsttext ~= ""d; + EditOperation op = new EditOperation(EditAction.Replace, r, dsttext); + _content.performOperation(op, source); + } else { + // uncomment + } + } + + /// return true if toggle block comment is supported for file type + override @property bool supportsToggleBlockComment() { + // TODO + return false; + } + /// return true if can toggle block comments for specified text range + override bool canToggleBlockComment(TextRange range) { + // TODO + return false; + } + /// toggle block comments for specified text range + override void toggleBlockComment(TextRange range, Object source) { + // TODO + } + /// categorize characters in content by token types void updateHighlight(dstring[] lines, TokenPropString[] props, int changeStartLine, int changeEndLine) { //Log.d("updateHighlight");