@@ -20,7 +20,11 @@ type internal FSharpIndentationService
2020 [<ImportingConstructor>]
2121 ( projectInfoManager: FSharpProjectOptionsManager) =
2222
23- static member GetDesiredIndentation ( documentId : DocumentId , sourceText : SourceText , filePath : string , lineNumber : int , tabSize : int , optionsOpt : FSharpProjectOptions option ): Option < int > =
23+ static member IsSmartIndentEnabled ( options : Microsoft.CodeAnalysis.Options.OptionSet ) =
24+ options.GetOption( FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName) = FormattingOptions.IndentStyle.Smart
25+
26+ static member GetDesiredIndentation ( documentId : DocumentId , sourceText : SourceText , filePath : string , lineNumber : int , tabSize : int , indentStyle : FormattingOptions.IndentStyle , projectOptions : FSharpProjectOptions option ): Option < int > =
27+
2428 // Match indentation with previous line
2529 let rec tryFindPreviousNonEmptyLine l =
2630 if l <= 0 then None
@@ -31,16 +35,18 @@ type internal FSharpIndentationService
3135 else
3236 tryFindPreviousNonEmptyLine ( l - 1 )
3337
34- let rec tryFindLastNoneWhitespaceOrCommentToken ( line : TextLine ) = maybe {
35- let! options = optionsOpt
36- let defines = CompilerEnvironment.GetCompilationDefinesForEditing( filePath, options .OtherOptions |> Seq.toList)
38+ let rec tryFindLastNonWhitespaceOrCommentToken ( line : TextLine ) = maybe {
39+ let! projectOptions = projectOptions
40+ let defines = CompilerEnvironment.GetCompilationDefinesForEditing( filePath, projectOptions .OtherOptions |> Seq.toList)
3741 let tokens = Tokenizer.tokenizeLine( documentId, sourceText, line.Start, filePath, defines)
3842
3943 return !
4044 tokens
4145 |> List.rev
4246 |> List.tryFind ( fun x ->
43- x.Tag <> FSharpTokenTag.WHITESPACE && x.Tag <> FSharpTokenTag.COMMENT && x.Tag <> FSharpTokenTag.LINE_ COMMENT)
47+ x.Tag <> FSharpTokenTag.WHITESPACE &&
48+ x.Tag <> FSharpTokenTag.COMMENT &&
49+ x.Tag <> FSharpTokenTag.LINE_ COMMENT)
4450 }
4551
4652 let (| Eq | _ |) y x =
@@ -49,42 +55,43 @@ type internal FSharpIndentationService
4955
5056 let (| NeedIndent | _ |) ( token : FSharpTokenInfo ) =
5157 match token.Tag with
52- | Eq FSharpTokenTag.EQUALS
53- | Eq FSharpTokenTag.LARROW
54- | Eq FSharpTokenTag.RARROW
55- | Eq FSharpTokenTag.LPAREN
56- | Eq FSharpTokenTag.LBRACK
57- | Eq FSharpTokenTag.LBRACK_ BAR
58- | Eq FSharpTokenTag.LBRACK_ LESS
59- | Eq FSharpTokenTag.LBRACE
60- | Eq FSharpTokenTag.BEGIN
61- | Eq FSharpTokenTag.DO
62- | Eq FSharpTokenTag.FUNCTION
63- | Eq FSharpTokenTag.THEN
64- | Eq FSharpTokenTag.ELSE
65- | Eq FSharpTokenTag.STRUCT
66- | Eq FSharpTokenTag.CLASS
67- | Eq FSharpTokenTag.TRY -> Some ()
58+ | Eq FSharpTokenTag.EQUALS // =
59+ | Eq FSharpTokenTag.LARROW // <-
60+ | Eq FSharpTokenTag.RARROW // ->
61+ | Eq FSharpTokenTag.LPAREN // (
62+ | Eq FSharpTokenTag.LBRACK // [
63+ | Eq FSharpTokenTag.LBRACK_ BAR // [|
64+ | Eq FSharpTokenTag.LBRACK_ LESS // [<
65+ | Eq FSharpTokenTag.LBRACE // {
66+ | Eq FSharpTokenTag.BEGIN // begin
67+ | Eq FSharpTokenTag.DO // do
68+ | Eq FSharpTokenTag.THEN // then
69+ | Eq FSharpTokenTag.ELSE // else
70+ | Eq FSharpTokenTag.STRUCT // struct
71+ | Eq FSharpTokenTag.CLASS // class
72+ | Eq FSharpTokenTag.TRY -> // try
73+ Some ()
6874 | _ -> None
6975
7076 maybe {
7177 let! previousLine = tryFindPreviousNonEmptyLine lineNumber
78+
79+ let lastIndent =
80+ previousLine.ToString()
81+ |> Seq.takeWhile ((=) ' ' )
82+ |> Seq.length
7283
73- let rec loop column spaces =
74- if previousLine.Start + column >= previousLine.End then
75- spaces
84+ // Only use smart indentation after tokens that need indentation
85+ // if the option is enabled
86+ let lastToken =
87+ if indentStyle = FormattingOptions.IndentStyle.Smart then
88+ tryFindLastNonWhitespaceOrCommentToken previousLine
7689 else
77- match previousLine.Text.[ previousLine.Start + column] with
78- | ' ' -> loop ( column + 1 ) ( spaces + 1 )
79- | '\t' -> loop ( column + 1 ) ((( spaces / tabSize) + 1 ) * tabSize)
80- | _ -> spaces
81-
82- let lastIndent = loop 0 0
90+ None
8391
84- let lastToken = tryFindLastNoneWhitespaceOrCommentToken previousLine
8592 return
8693 match lastToken with
87- | Some( NeedIndent) -> ( lastIndent/ tabSize + 1 ) * tabSize
94+ | Some NeedIndent -> ( lastIndent/ tabSize + 1 ) * tabSize
8895 | _ -> lastIndent
8996 }
9097
@@ -94,9 +101,10 @@ type internal FSharpIndentationService
94101 let! cancellationToken = Async.CancellationToken
95102 let! sourceText = document.GetTextAsync( cancellationToken) |> Async.AwaitTask
96103 let! options = document.GetOptionsAsync( cancellationToken) |> Async.AwaitTask
97- let tabSize = options.GetOption( FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName)
104+ let tabSize = options.GetOption< int>( FormattingOptions.TabSize, FSharpConstants.FSharpLanguageName)
105+ let indentStyle = options.GetOption( FormattingOptions.SmartIndent, FSharpConstants.FSharpLanguageName)
98106 let projectOptionsOpt = projectInfoManager.TryGetOptionsForEditingDocumentOrProject document
99- let indent = FSharpIndentationService.GetDesiredIndentation( document.Id, sourceText, document.FilePath, lineNumber, tabSize, projectOptionsOpt)
107+ let indent = FSharpIndentationService.GetDesiredIndentation( document.Id, sourceText, document.FilePath, lineNumber, tabSize, indentStyle , projectOptionsOpt)
100108 return
101109 match indent with
102110 | None -> Nullable()
0 commit comments