-
Notifications
You must be signed in to change notification settings - Fork 780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Increase indent level after line end with certain keywords #3196
Conversation
@xuanduc987, |
Some test failurs in part1:
|
Adjusting the tests should be adequate test coverage |
c53aee5
to
243f0ee
Compare
🤦♂️ |
Shouldn't we be using the tokenizer here instead of regexes to match keywords? |
) | ||
\s*$" | ||
if Regex.IsMatch(previousLine.ToString(), regex, RegexOptions.IgnorePatternWhitespace) then | ||
Some ((lastIndent/tabSize + 1) * tabSize) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this just Some (lastIndent + tabSize)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically, yes, technically no, if the indent is not a multiple of tabSize.
> let lastIndent = 3;;
val lastIndent : int = 3
> let tabSize = 4;;
val tabSize : int = 4
> (lastIndent/tabSize + 1) * tabSize;;
val it : int = 4
> lastIndent + tabSize;;
val it : int = 7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's consistent with L42 above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice.
| begin | do | class | function | then | else | struct | try | ||
) | ||
\s*$" | ||
if Regex.IsMatch(previousLine.ToString(), regex, RegexOptions.IgnorePatternWhitespace) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
@brettfo just pointed out that lines ending with comments may give an issue, here.
both for single line comments // and comment blocks (*
What do you propose we in those circumstances?
Kevin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KevinRansom
A better approach should be like @saul said, using tokenizer but I honestly don't know how.
I think comments end with the above keywords are not as common as normal code though.
@xuanduc987 use Hopefully that's enough to get you started :) |
@saul |
@xuanduc987 there's no reason why you can't change us from ISynchronousIndentationService to IIndentationService. They have the same API (apart from the latter returning a Task) |
@saul Thanks for the pointer, I had push some commits to use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good :) I have a couple of questions though:
Does this also indent after the following code?
let foo () = <enter>
Or:
{ new MyInterface with <enter>
Also please can write some unit tests for the cases that you've added? This looks fantastic so far
match lastToken with | ||
| NeedIndent -> (lastIndent/tabSize + 1) * tabSize | ||
| _ -> lastIndent | ||
} | ||
|
||
interface ISynchronousIndentationService with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use IIndentationService instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know the different but seems like C# and VB also use ISynchronousIndentationService
loop xs | ||
else Some x | ||
|
||
return! loop (List.rev tokens) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get rid of the loop
function and this can just become tokens |> List.rev |> List.tryFind (fun x -> x.Tag <> FSharpTokenTag.WHITESPACE)
|
||
maybe { | ||
// No indentation on the first line of a document | ||
if lineNumber = 0 then return! None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only need the else branch of this if statement - tryFindPreviousNonEmptyLine already checks if lineNumber is 0.
| _ -> spaces | ||
Some (loop 0 0) | ||
|
||
let rec tryFindLastNoneEmptyToken (line: TextLine) = maybe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename this from tryFindLastNoneEmptyToken
to tryFindLastNonWhitespaceToken
@KevinRansom if @xuanduc987 is happy with this I think this is good to merge 👍 |
@dotnet-bot test Windows_NT Release_ci_part3 Build please |
@saul @KevinRansom All green 💯 |
try | ||
failwith \"fail\" | ||
with | ||
| :? System.Exception -> \"error\" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We aren't testing whether this line gets indented.
Also these test cases would be far easier to read if instead of specifying which lines we expect indentation in a separate array, we specified them inline in the template.
For example, these few lines would become:
try
failwith \"fail\" // $Indent: 4$
with
| :? System.Exception -> \"error\" // $Indent: 4$
You could then parse the template like:
let indentComment = System.Text.RegularExpressions.Regex(@"\/\/\s*\$\s*Indent:\s*(\d+)\s*\$")
template.Split [|'\n'|]
|> Seq.map (fun s -> s.Trim())
|> Seq.indexed
|> Seq.choose (fun (line, text) ->
let m = indentComment.Match text
if m.Success then Some (line, System.Convert.ToInt32 m.Groups.[1].Value)
else None
)
This will return you a list of lineNumber * indentSize
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
As for the line after with
, it would not be auto indented, because match x with <enter>
should not.
Fantastic 😃 |
* Increase indent level after line end with certain keywords * Fix test case * Use Tokenizer * Refactoring and fix test * Saul review * Add more test * Fix tests * Rename tryFindLastNoneEmptyToken -> tryFindLastNoneWhitespaceToken * Trailing comment is ok * Move auto indent to a separate test * Use same indentation as the previous comment line
No unit test because I don't know how to assert these indent level :(