diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 01.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 01.fs.gold index 012fad6b8f..99a818db80 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 01.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module let _ = diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 02.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 02.fs.gold index 7fa6a1e252..c23150b364 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Begin 02.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module let _ = diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 01.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 01.fs.gold index 82913c2582..4bc429bb7d 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 01.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module type T() = diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 02.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 02.fs.gold index 82913c2582..4bc429bb7d 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 02.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module type T() = diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 03.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 03.fs.gold index ed2b697163..d354f0a9f1 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 03.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 03.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module type T() = diff --git a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 04.fs.gold b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 04.fs.gold index cf9a9024ab..5d8b4a84de 100644 --- a/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 04.fs.gold +++ b/ReSharper.FSharp/test/data/features/service/typingAssist/Enter - Parens - Type 04.fs.gold @@ -1,4 +1,4 @@ -// ${CHAR:Enter} +// ${CHAR:Enter} module Module type T() = diff --git a/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpEnterHandlerDelegate.kt b/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpEnterHandlerDelegate.kt index a72f69722c..9c8109a354 100644 --- a/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpEnterHandlerDelegate.kt +++ b/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpEnterHandlerDelegate.kt @@ -92,6 +92,13 @@ class FSharpEnterHandlerDelegate : EnterHandlerDelegateAdapter() { FSharpTokenType.END ) + private val bracketsAllowingDeindent: TokenSet = TokenSet.create( + FSharpTokenType.LBRACE, + FSharpTokenType.LBRACK, + FSharpTokenType.LBRACK_BAR, + FSharpTokenType.LPAREN + ) + private val emptyBracketsToAddSpace = setOf( Pair(FSharpTokenType.LBRACE, FSharpTokenType.RBRACE), Pair(FSharpTokenType.LBRACK, FSharpTokenType.RBRACK), @@ -108,7 +115,13 @@ class FSharpEnterHandlerDelegate : EnterHandlerDelegateAdapter() { FSharpTokenType.LBRACK_BAR, FSharpTokenType.LBRACK_LESS, FSharpTokenType.LQUOTE_TYPED, - FSharpTokenType.LQUOTE_UNTYPED + FSharpTokenType.LQUOTE_UNTYPED, + + FSharpTokenType.CLASS, + FSharpTokenType.INTERFACE, + FSharpTokenType.STRUCT, + + FSharpTokenType.BEGIN ) private val rightBracketsToAddSpace = emptyBracketsToAddSpace.map { it.second }.toSet() @@ -621,6 +634,8 @@ class FSharpEnterHandlerDelegate : EnterHandlerDelegateAdapter() { val document = editor.document val line = document.getLineNumber(tokenStart) + if (handleEnterInsideSingleLineBrackets(editor, iterator, line)) return true + if (leftBracketsToAddIndent.contains(tokenType) && !isSingleLineBrackets(editor, tokenStart) && !isLastTokenOnLine(editor, tokenStart) && @@ -705,6 +720,71 @@ class FSharpEnterHandlerDelegate : EnterHandlerDelegateAdapter() { return true } + fun handleEnterInsideSingleLineBrackets(editor: Editor, iterator: HighlighterIterator, line: Int): Boolean { + val document = editor.document + val iterator = editor.highlighter.createIterator(iterator.start) + + val tokenType = iterator.tokenType + val leftBracketStartOffset = iterator.start + val leftBracketEndOffset = iterator.end + val leftBracketLine = document.getLineNumber(leftBracketStartOffset) + + if (!findRightBracket(iterator)) return false + if (document.getLineNumber(iterator.start) != leftBracketLine) return false + + val rightBracketStartOffset = iterator.start + + iterator.retreat() + while (iterator.tokenTypeSafe == FSharpTokenType.WHITESPACE) + iterator.retreat() + + val lastElementEndOffset = iterator.end + + val deindentIter = editor.highlighter.createIterator(leftBracketStartOffset - 1) + while (!deindentIter.atEnd() && isIgnored(iterator.tokenType)) + deindentIter.retreat() + + val shouldDeindent = + bracketsAllowingDeindent.contains(tokenType) && deindentIter.tokenType != FSharpTokenType.NEW_LINE + + val baseIndentLength = + if (!shouldDeindent) + getOffsetInLine(document, line, leftBracketStartOffset) + else { + val line = getContinuedIndentLine(editor, leftBracketStartOffset, true) + getLineWhitespaceIndent(editor, line) + } + + val indent = getIndentSettings(editor).indentSize + val baseIndentString = "\n" + " ".repeat(baseIndentLength) + val indentString = baseIndentString + " ".repeat(indent) + + if (lastElementEndOffset == leftBracketEndOffset) { + val newText = if (tokenType == FSharpTokenType.LPAREN) { + indentString + } else { + indentString + baseIndentString + } + document.replaceString(lastElementEndOffset, rightBracketStartOffset, newText) + } else { + val firstElementIter = editor.highlighter.createIterator(leftBracketEndOffset) + + while (!firstElementIter.atEnd() && isIgnored(firstElementIter.tokenTypeSafe)) + firstElementIter.advance() + + val firstElementStartOffset = firstElementIter.start + + if (tokenType != FSharpTokenType.LPAREN) { + document.replaceString(lastElementEndOffset, rightBracketStartOffset, baseIndentString) + } + document.replaceString(leftBracketEndOffset, firstElementStartOffset, indentString) + } + + editor.caretModel.moveToOffset(leftBracketEndOffset + indentString.length) + editor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE) + return true + } + private fun handleEnter( editor: Editor, caretOffset: Int, diff --git a/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpTypingAssistUtils.kt b/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpTypingAssistUtils.kt index 339e69f6a4..5a41dd4455 100644 --- a/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpTypingAssistUtils.kt +++ b/rider-fsharp/src/main/java/com/jetbrains/rider/plugins/fsharp/editorActions/FSharpTypingAssistUtils.kt @@ -42,6 +42,12 @@ class FSharpBracketMatcher : BracketMatcher( Pair(FSharpTokenType.LBRACE_BAR, FSharpTokenType.BAR_RBRACE), Pair(FSharpTokenType.LBRACK_LESS, FSharpTokenType.GREATER_RBRACK), Pair(FSharpTokenType.LQUOTE_TYPED, FSharpTokenType.RQUOTE_TYPED), - Pair(FSharpTokenType.LQUOTE_UNTYPED, FSharpTokenType.RQUOTE_UNTYPED) + Pair(FSharpTokenType.LQUOTE_UNTYPED, FSharpTokenType.RQUOTE_UNTYPED), + + Pair(FSharpTokenType.CLASS, FSharpTokenType.END), + Pair(FSharpTokenType.INTERFACE, FSharpTokenType.END), + Pair(FSharpTokenType.STRUCT, FSharpTokenType.END), + + Pair(FSharpTokenType.BEGIN, FSharpTokenType.END) ) ) diff --git a/rider-fsharp/src/test/kotlin/com/jetbrains/rider/plugins/fsharp/test/cases/typingAssist/FSharpPatchEngineTypingAssists.kt b/rider-fsharp/src/test/kotlin/com/jetbrains/rider/plugins/fsharp/test/cases/typingAssist/FSharpPatchEngineTypingAssists.kt index 00a8b122e5..ca50bce687 100644 --- a/rider-fsharp/src/test/kotlin/com/jetbrains/rider/plugins/fsharp/test/cases/typingAssist/FSharpPatchEngineTypingAssists.kt +++ b/rider-fsharp/src/test/kotlin/com/jetbrains/rider/plugins/fsharp/test/cases/typingAssist/FSharpPatchEngineTypingAssists.kt @@ -185,12 +185,19 @@ class FSharpEnterTypingAssistSyncTest : FSharpBackendSyncTypingAssistTestBase(Id "Enter 28 - No indent after else and new line", "Enter 29 - No indent before source", "Enter 30 - No indent before source 2", + "Enter 31 - Inside empty ctor", "Enter 32 - Nested binding", "Enter 33 - After then on line with multiple parens in row", "Enter 34 - After line with multiple parens in row", "Enter 35 - Nested binding and indent", "Enter 36 - Indent after =, trim before source", + "Enter 38 - Empty list", + "Enter 39 - Empty list with spaces", + "Enter 40 - Empty list continuing line", + "Enter 41 - Empty array continuing line", "Enter 42 - Before first list element and new line", + "Enter 43 - Before first list element", + "Enter 44 - Before first list element and spaces", "Enter 45 - Before first list element in multiline list", "Enter 46 - Before first list element in multiline list", "Enter 47 - Before first list element in multiline list", @@ -261,7 +268,13 @@ class FSharpEnterTypingAssistSyncTest : FSharpBackendSyncTypingAssistTestBase(Id "Enter - String 12", "Enter - String 13", "Enter - String 14", - "Enter - String 15" + "Enter - String 15", + "Enter - Parens - Begin 01", + "Enter - Parens - Begin 02", + "Enter - Parens - Type 01", + "Enter - Parens - Type 02", + "Enter - Parens - Type 03", + "Enter - Parens - Type 04" ) @DataProvider(name = SUPPORTED_BACKEND_CASES)