GetIndentation computes the expected indentation for a position in a source file. This is the Go port of SmartIndenter.getIndentation from TypeScript.
(position int, sourceFile *ast.SourceFile, options lsutil.FormatCodeSettings, assumeNewLineBeforeCloseBrace bool)
| 22 | // GetIndentation computes the expected indentation for a position in a source file. |
| 23 | // This is the Go port of SmartIndenter.getIndentation from TypeScript. |
| 24 | func GetIndentation(position int, sourceFile *ast.SourceFile, options lsutil.FormatCodeSettings, assumeNewLineBeforeCloseBrace bool) int { |
| 25 | if position > len(sourceFile.Text()) { |
| 26 | return options.BaseIndentSize // past EOF |
| 27 | } |
| 28 | |
| 29 | // no indentation when the indent style is set to none, |
| 30 | // so we can return fast |
| 31 | if options.IndentStyle == lsutil.IndentStyleNone { |
| 32 | return 0 |
| 33 | } |
| 34 | |
| 35 | precedingToken := astnav.FindPrecedingTokenEx(sourceFile, position, nil /*startNode*/, true /*excludeJSDoc*/) |
| 36 | |
| 37 | enclosingCommentRange := getRangeOfEnclosingComment(sourceFile, position, precedingToken) |
| 38 | if enclosingCommentRange != nil && enclosingCommentRange.Kind == ast.KindMultiLineCommentTrivia { |
| 39 | return getCommentIndent(sourceFile, position, options, enclosingCommentRange) |
| 40 | } |
| 41 | |
| 42 | if precedingToken == nil { |
| 43 | return options.BaseIndentSize |
| 44 | } |
| 45 | |
| 46 | // no indentation in string/regex/template literals |
| 47 | if isStringOrRegularExpressionOrTemplateLiteral(precedingToken.Kind) { |
| 48 | tokenStart := scanner.GetTokenPosOfNode(precedingToken, sourceFile, false) |
| 49 | if tokenStart <= position && position < precedingToken.End() { |
| 50 | return 0 |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | lineAtPosition := scanner.GetECMALineOfPosition(sourceFile, position) |
| 55 | |
| 56 | // indentation is first non-whitespace character in a previous line |
| 57 | // for block indentation, we should look for a line which contains something that's not |
| 58 | // whitespace. |
| 59 | currentToken := astnav.GetTokenAtPosition(sourceFile, position) |
| 60 | // For object literals, we want indentation to work just like with blocks. |
| 61 | // If the `{` starts in any position (even in the middle of a line), then |
| 62 | // the following indentation should treat `{` as the start of that line (including leading whitespace). |
| 63 | // ``` |
| 64 | // const a: { x: undefined, y: undefined } = {} // leading 4 whitespaces and { starts in the middle of line |
| 65 | // -> |
| 66 | // const a: { x: undefined, y: undefined } = { |
| 67 | // x: undefined, |
| 68 | // y: undefined, |
| 69 | // } |
| 70 | // --------------------- |
| 71 | // const a: {x : undefined, y: undefined } = |
| 72 | // {} |
| 73 | // -> |
| 74 | // const a: { x: undefined, y: undefined } = |
| 75 | // { // leading 5 whitespaces and { starts at 6 column |
| 76 | // x: undefined, |
| 77 | // y: undefined, |
| 78 | // } |
| 79 | // ``` |
| 80 | isObjectLiteral := currentToken.Kind == ast.KindOpenBraceToken && currentToken.Parent != nil && currentToken.Parent.Kind == ast.KindObjectLiteralExpression |
| 81 | if options.IndentStyle == lsutil.IndentStyleBlock || isObjectLiteral { |