diff --git a/autotests/input/indent/cppstyle/autobrackets1/expected b/autotests/input/indent/cppstyle/autobrackets1/expected new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets1/expected @@ -0,0 +1,9 @@ +class X +{ + void foo() + { + + } +}; + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/autobrackets1/input.js b/autotests/input/indent/cppstyle/autobrackets1/input.js new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets1/input.js @@ -0,0 +1,6 @@ +v.setAutoBrackets(true); +v.setCursorPosition(2, 14); +v.enter(); +v.type("{"); +v.enter(); +v.setAutoBrackets(false); diff --git a/autotests/input/indent/cppstyle/autobrackets1/origin b/autotests/input/indent/cppstyle/autobrackets1/origin new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets1/origin @@ -0,0 +1,6 @@ +class X +{ + void foo() +}; + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/autobrackets2/expected b/autotests/input/indent/cppstyle/autobrackets2/expected new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets2/expected @@ -0,0 +1,12 @@ +class X +{ + void foo() + { + if (true) + { + + } + } +}; + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/autobrackets2/input.js b/autotests/input/indent/cppstyle/autobrackets2/input.js new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets2/input.js @@ -0,0 +1,9 @@ +v.setAutoBrackets(true); +v.setCursorPosition(4, 17); +v.enter(); +v.type("{"); +v.enter(); +v.setCursorPosition(7, 9); +v.enter(); +v.type("}"); +v.setAutoBrackets(false); diff --git a/autotests/input/indent/cppstyle/autobrackets2/origin b/autotests/input/indent/cppstyle/autobrackets2/origin new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets2/origin @@ -0,0 +1,8 @@ +class X +{ + void foo() + { + if (true) +}; + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/autobrackets3/expected b/autotests/input/indent/cppstyle/autobrackets3/expected new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets3/expected @@ -0,0 +1,11 @@ +class X +{ + void foo() + { + if (true) + { + } + } +}; + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/autobrackets3/input.js b/autotests/input/indent/cppstyle/autobrackets3/input.js new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets3/input.js @@ -0,0 +1,8 @@ +v.setAutoBrackets(true); +v.setCursorPosition(6, 12); +v.type("}"); +v.enter(); +v.type("}"); +v.enter(); +v.type("}"); +v.setAutoBrackets(false); diff --git a/autotests/input/indent/cppstyle/autobrackets3/origin b/autotests/input/indent/cppstyle/autobrackets3/origin new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cppstyle/autobrackets3/origin @@ -0,0 +1,9 @@ +class X +{ + void foo() + { + if (true) + { + + +// kate: auto-brackets on; diff --git a/autotests/input/indent/cppstyle/comma4/expected b/autotests/input/indent/cppstyle/comma4/expected --- a/autotests/input/indent/cppstyle/comma4/expected +++ b/autotests/input/indent/cppstyle/comma4/expected @@ -1,3 +1,3 @@ some, ok -some, okok +some, ok, ok some, ok diff --git a/autotests/input/indent/cstyle/openpar11/expected b/autotests/input/indent/cstyle/openpar11/expected new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar11/expected @@ -0,0 +1,9 @@ +class X +{ + void foo() + { + if (true) + {} +}; + +// kate: auto-brackets on; indent-mode cstyle; diff --git a/autotests/input/indent/cstyle/openpar11/input.js b/autotests/input/indent/cstyle/openpar11/input.js new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar11/input.js @@ -0,0 +1,5 @@ +v.setAutoBrackets(true); +v.setCursorPosition(4,13); +v.enter(); +v.type("{"); +v.setAutoBrackets(false); diff --git a/autotests/input/indent/cstyle/openpar11/origin b/autotests/input/indent/cstyle/openpar11/origin new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar11/origin @@ -0,0 +1,8 @@ +class X +{ + void foo() + { + if (true) +}; + +// kate: auto-brackets on; indent-mode cstyle; diff --git a/autotests/input/indent/cstyle/openpar12/expected b/autotests/input/indent/cstyle/openpar12/expected new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar12/expected @@ -0,0 +1,9 @@ +class X +{ + void foo() + { + + } +}; + +// kate: auto-brackets on; indent-mode cstyle; diff --git a/autotests/input/indent/cstyle/openpar12/input.js b/autotests/input/indent/cstyle/openpar12/input.js new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar12/input.js @@ -0,0 +1,6 @@ +v.setAutoBrackets(true); +v.setCursorPosition(2,12); +v.enter(); +v.type("{"); +v.enter(); +v.setAutoBrackets(false); diff --git a/autotests/input/indent/cstyle/openpar12/origin b/autotests/input/indent/cstyle/openpar12/origin new file mode 100644 --- /dev/null +++ b/autotests/input/indent/cstyle/openpar12/origin @@ -0,0 +1,6 @@ +class X +{ + void foo() +}; + +// kate: auto-brackets on; indent-mode cstyle; diff --git a/autotests/src/testutils.h b/autotests/src/testutils.h --- a/autotests/src/testutils.h +++ b/autotests/src/testutils.h @@ -117,6 +117,12 @@ Q_INVOKABLE void shiftToMatchingBracket(int cnt = 1); Q_INVOKABLE bool type(const QString &str); + + /** + * Toggle auto brackets. If you make use of it, make sure to + * disable them again at the end of your test, otherwise any following tests may fail. + */ + Q_INVOKABLE void setAutoBrackets(bool enable = true); // Aliases Q_INVOKABLE void enter(int cnt = 1); // KeyReturn diff --git a/autotests/src/testutils.cpp b/autotests/src/testutils.cpp --- a/autotests/src/testutils.cpp +++ b/autotests/src/testutils.cpp @@ -27,6 +27,7 @@ #include "testutils.h" #include "kateview.h" +#include "kateconfig.h" #include "katedocument.h" #include "katescripthelpers.h" @@ -89,7 +90,7 @@ m_engine->globalObject().setProperty(QStringLiteral("read"), m_engine->newFunction(Kate::Script::read)); m_engine->globalObject().setProperty(QStringLiteral("require"), m_engine->newFunction(Kate::Script::require)); m_engine->globalObject().setProperty(QStringLiteral("require_guard"), m_engine->newObject()); - + // export debug function m_engine->globalObject().setProperty(QStringLiteral("debug"), m_engine->newFunction(Kate::Script::debug)); @@ -200,6 +201,12 @@ return view()->doc()->typeChars(view(), str); } +void KateViewObject::setAutoBrackets(bool enable) +{ + view()->config()->setAutoBrackets(enable); +} + + #define ALIAS(alias, func) \ void KateViewObject::alias(int cnt) { \ func(cnt); \ diff --git a/src/script/data/indentation/cppstyle.js b/src/script/data/indentation/cppstyle.js --- a/src/script/data/indentation/cppstyle.js +++ b/src/script/data/indentation/cppstyle.js @@ -1640,15 +1640,30 @@ var result = -2; var line = cursor.line; var column = cursor.column; - + var braceCursor = Cursor.invalid(); if (ch != '>') { // TODO Make sure a given `ch` in the gBraceMap braceCursor = document.anchor(line, column - 1, gBraceMap[ch]); + + // make sure we are actually on the character we are expecting + // if that's not the case, a brace was probably inserted behind the cursor by auto brackets + realCharacter = document.charAt(line, column - 1); + if (realCharacter != ch) { + braceCursor = document.anchor(line, column, gBraceMap[ch]); + } // TODO Otherwise, it seems we have a template parameters list... } + // unindent when starting new block and previous line has lower indentation level + // prevents over-indentation when inserting condition or loop headers with their opening brace in the next line + var firstPos = document.firstColumn(line); + var prevFirstPos = document.firstColumn(line - 1); + if (firstPos == column - 1 && ch == '}' && firstPos > prevFirstPos) { + result = prevFirstPos; + } + // Check if a given closing brace is a first char on a line // (i.e. it is 'dangling' brace)... if (justEnteredCharIsFirstOnLine(line, column, ch) && braceCursor.isValid()) @@ -1658,8 +1673,9 @@ result = document.firstColumn(braceCursor.line) + (ch != '}' ? 2 : 0); dbg("tryCloseBracket: setting result="+result); } - - // Check if ';' required after closing '}' + + // Check if ';' required after closing '}', but make sure it was inserted by the user + // and not automatically by auto brackets (behind the cursor) if (ch == '}' && braceCursor.isValid()) { var is_check_needed = false; @@ -1677,7 +1693,7 @@ } else (!is_check_needed && 0 < braceCursor.line) // Is there any line before? { - dbg("tryCloseBracket: cheking prev line"); + dbg("tryCloseBracket: checking prev line"); // Ok, lets check it! anchoredString = document.line(braceCursor.line - 1); @@ -1699,8 +1715,14 @@ ; if (!is_ok) { - document.insertText(line, column, ';'); - view.setCursorPosition(line, column + 1); + var pos = column; + var newCursorPos = pos + 1; + if (document.charAt(line, column - 1) != '}' && document.charAt(line, column) == '}') { + ++pos; + --newCursorPos; + } + document.insertText(line, pos, ';'); + view.setCursorPosition(line, newCursorPos); } } } @@ -2347,9 +2369,8 @@ document.editBegin(); // Check if char under cursor is the same as just entered, // and if so, remove it... to make it behave like "overwrite" mode - if (ch != ' ' && document.charAt(cursor) == ch) - document.removeText(line, cursor.column, line, cursor.column + 1); - + //if (ch != ' ' && document.charAt(cursor) == ch) + // document.removeText(line, cursor.column, line, cursor.column + 1); switch (ch) { case '\n': diff --git a/src/script/data/indentation/cstyle.js b/src/script/data/indentation/cstyle.js --- a/src/script/data/indentation/cstyle.js +++ b/src/script/data/indentation/cstyle.js @@ -751,9 +751,10 @@ if (!cursor) return -2; - var column = cursor.column; - var firstPos = document.firstColumn(line); - var lastPos = document.lastColumn(line); + var column = cursor.column; + var firstPos = document.firstColumn(line); + var prevFirstPos = document.firstColumn(line - 1); + var lastPos = document.lastColumn(line); dbg("firstPos: " + firstPos); dbg("column..: " + column); @@ -771,11 +772,16 @@ filler = -2; return filler; - } else if (firstPos == column - 1 && c == '}') { + } else if (firstPos == column - 1 && c == '}' && document.charAt(line, column - 1) == '}') { + // unindent after closing brace, but not when brace is auto inserted (i.e., behind cursor) var indentation = findLeftBrace(line, firstPos); if (indentation == -1) indentation = -2; return indentation; + } else if (firstPos == column - 1 && c == '}' && firstPos > prevFirstPos) { + // align indentation to previous line when creating new block with auto brackets enabled + // prevents over-indentation for if blocks and loops + return prevFirstPos; } else if (cfgSnapSlash && c == '/' && lastPos == column - 1) { // try to snap the string "* /" to "*/" var currentString = document.line(line);