diff --git a/src/dlangide/tools/d/dsyntax.d b/src/dlangide/tools/d/dsyntax.d index 9e753ee..bf6acc9 100644 --- a/src/dlangide/tools/d/dsyntax.d +++ b/src/dlangide/tools/d/dsyntax.d @@ -644,12 +644,80 @@ class SimpleDSyntaxSupport : SyntaxSupport { return true; } + protected bool _opInProgress; + protected void applyNewLineSmartIndent(EditOperation op, Object source) { + int line = op.newRange.end.line; + if (line == 0) + return; // not for first line + int prevLine = line - 1; + dstring lineText = _content.line(line); + TextLineMeasure lineMeasurement = _content.measureLine(line); + TextLineMeasure prevLineMeasurement = _content.measureLine(prevLine); + while (prevLineMeasurement.empty && prevLine > 0) { + prevLine--; + prevLineMeasurement = _content.measureLine(prevLine); + } + if (lineMeasurement.firstNonSpaceX >= 0 && lineMeasurement.firstNonSpaceX < prevLineMeasurement.firstNonSpaceX) { + dstring prevLineText = _content.line(prevLine); + TokenPropString prevLineTokenProps = _content.lineTokenProps(prevLine); + dchar lastOpChar = 0; + for (int j = prevLineMeasurement.lastNonSpace; j >= 0; j--) { + auto cat = j < prevLineTokenProps.length ? tokenCategory(prevLineTokenProps[j]) : 0; + if (cat == TokenCategory.Op) { + lastOpChar = prevLineText[j]; + break; + } else if (cat != TokenCategory.Comment && cat != TokenCategory.WhiteSpace) { + break; + } + } + int spacex = prevLineMeasurement.firstNonSpaceX; + if (lastOpChar == '{') + spacex = _content.nextTab(spacex); + dstring txt = _content.fillSpace(spacex); + EditOperation op2 = new EditOperation(EditAction.Replace, TextRange(TextPosition(line, 0), TextPosition(line, lineMeasurement.firstNonSpace >= 0 ? lineMeasurement.firstNonSpace : 0)), [txt]); + _opInProgress = true; + _content.performOperation(op2, source); + _opInProgress = false; + } + } + + protected void applyClosingCurlySmartIndent(EditOperation op, Object source) { + int line = op.newRange.end.line; + TextPosition p2 = findPairedBracket(op.newRange.start); + if (p2 == op.newRange.start || p2.line > op.newRange.start.line) + return; + int prevLine = p2.line; + TextLineMeasure lineMeasurement = _content.measureLine(line); + TextLineMeasure prevLineMeasurement = _content.measureLine(prevLine); + if (lineMeasurement.firstNonSpace != op.newRange.start.pos) + return; // not in beginning of line + if (lineMeasurement.firstNonSpaceX >= 0 && lineMeasurement.firstNonSpaceX != prevLineMeasurement.firstNonSpaceX) { + dstring prevLineText = _content.line(prevLine); + TokenPropString prevLineTokenProps = _content.lineTokenProps(prevLine); + int spacex = prevLineMeasurement.firstNonSpaceX; + if (spacex != lineMeasurement.firstNonSpaceX) { + dstring txt = _content.fillSpace(spacex); + txt = txt ~ "}"; + EditOperation op2 = new EditOperation(EditAction.Replace, TextRange(TextPosition(line, 0), TextPosition(line, lineMeasurement.firstNonSpace >= 0 ? lineMeasurement.firstNonSpace + 1 : 0)), [txt]); + _opInProgress = true; + _content.performOperation(op2, source); + _opInProgress = false; + } + } + } + /// apply smart indent, if supported override void applySmartIndent(EditOperation op, Object source) { + if (_opInProgress) + return; if (op.isInsertNewLine) { // Enter key pressed - new line inserted or splitted + applyNewLineSmartIndent(op, source); } else if (op.singleChar == '}') { - // } entered - probably need + // } entered - probably need unindent + applyClosingCurlySmartIndent(op, source); + } else if (op.singleChar == '{') { + // { entered - probably need auto closing } } } diff --git a/src/dlangide/ui/dsourceedit.d b/src/dlangide/ui/dsourceedit.d index 609f7ac..9655fc1 100644 --- a/src/dlangide/ui/dsourceedit.d +++ b/src/dlangide/ui/dsourceedit.d @@ -55,6 +55,8 @@ class DSourceEdit : SourceEdit { return; tabSize = _settings.tabSize; useSpacesForTabs = _settings.useSpacesForTabs; + smartIndents = _settings.smartIndents; + smartIndentsAfterPaste = _settings.smartIndentsAfterPaste; } protected ProjectSourceFile _projectSourceFile; @property ProjectSourceFile projectSourceFile() { return _projectSourceFile; } diff --git a/src/dlangide/ui/settings.d b/src/dlangide/ui/settings.d index a75b9e8..0be6ba1 100644 --- a/src/dlangide/ui/settings.d +++ b/src/dlangide/ui/settings.d @@ -16,6 +16,8 @@ class IDESettings : SettingsFile { Setting ed = editorSettings(); ed.setBooleanDef("useSpacesForTabs", true); ed.setIntegerDef("tabSize", 4); + ed.setBooleanDef("smartIndents", true); + ed.setBooleanDef("smartIndentsAfterPaste", true); Setting ui = uiSettings(); ui.setStringDef("theme", "theme_default"); ui.setStringDef("language", "en"); @@ -90,4 +92,14 @@ class IDESettings : SettingsFile { editorSettings.setInteger("tabSize", limitInt(v, 1, 16)); return this; } + + /// true if smart indents are enabled + @property bool smartIndents() { return editorSettings.getBoolean("smartIndents", true); } + /// set smart indents enabled flag + @property IDESettings smartIndents(bool enabled) { editorSettings.setBoolean("smartIndents", enabled); return this; } + + /// true if smart indents are enabled + @property bool smartIndentsAfterPaste() { return editorSettings.getBoolean("smartIndentsAfterPaste", true); } + /// set smart indents enabled flag + @property IDESettings smartIndentsAfterPaste(bool enabled) { editorSettings.setBoolean("smartIndentsAfterPaste", enabled); return this; } }