• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import { TextRangeWithKind } from "../_namespaces/ts.formatting";
2import { Debug, findChildOfKind, FormatCodeSettings, Node, SourceFileLike, SyntaxKind } from "../_namespaces/ts";
3
4/** @internal */
5export const enum FormattingRequestKind {
6    FormatDocument,
7    FormatSelection,
8    FormatOnEnter,
9    FormatOnSemicolon,
10    FormatOnOpeningCurlyBrace,
11    FormatOnClosingCurlyBrace
12}
13
14/** @internal */
15export class FormattingContext {
16    public currentTokenSpan!: TextRangeWithKind;
17    public nextTokenSpan!: TextRangeWithKind;
18    public contextNode!: Node;
19    public currentTokenParent!: Node;
20    public nextTokenParent!: Node;
21
22    private contextNodeAllOnSameLine: boolean | undefined;
23    private nextNodeAllOnSameLine: boolean | undefined;
24    private tokensAreOnSameLine: boolean | undefined;
25    private contextNodeBlockIsOnOneLine: boolean | undefined;
26    private nextNodeBlockIsOnOneLine: boolean | undefined;
27
28    constructor(public readonly sourceFile: SourceFileLike, public formattingRequestKind: FormattingRequestKind, public options: FormatCodeSettings) {
29    }
30
31    public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) {
32        this.currentTokenSpan = Debug.checkDefined(currentRange);
33        this.currentTokenParent = Debug.checkDefined(currentTokenParent);
34        this.nextTokenSpan = Debug.checkDefined(nextRange);
35        this.nextTokenParent = Debug.checkDefined(nextTokenParent);
36        this.contextNode = Debug.checkDefined(commonParent);
37
38        // drop cached results
39        this.contextNodeAllOnSameLine = undefined;
40        this.nextNodeAllOnSameLine = undefined;
41        this.tokensAreOnSameLine = undefined;
42        this.contextNodeBlockIsOnOneLine = undefined;
43        this.nextNodeBlockIsOnOneLine = undefined;
44    }
45
46    public ContextNodeAllOnSameLine(): boolean {
47        if (this.contextNodeAllOnSameLine === undefined) {
48            this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
49        }
50
51        return this.contextNodeAllOnSameLine;
52    }
53
54    public NextNodeAllOnSameLine(): boolean {
55        if (this.nextNodeAllOnSameLine === undefined) {
56            this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
57        }
58
59        return this.nextNodeAllOnSameLine;
60    }
61
62    public TokensAreOnSameLine(): boolean {
63        if (this.tokensAreOnSameLine === undefined) {
64            const startLine = this.sourceFile.getLineAndCharacterOfPosition(this.currentTokenSpan.pos).line;
65            const endLine = this.sourceFile.getLineAndCharacterOfPosition(this.nextTokenSpan.pos).line;
66            this.tokensAreOnSameLine = (startLine === endLine);
67        }
68
69        return this.tokensAreOnSameLine;
70    }
71
72    public ContextNodeBlockIsOnOneLine() {
73        if (this.contextNodeBlockIsOnOneLine === undefined) {
74            this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
75        }
76
77        return this.contextNodeBlockIsOnOneLine;
78    }
79
80    public NextNodeBlockIsOnOneLine() {
81        if (this.nextNodeBlockIsOnOneLine === undefined) {
82            this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
83        }
84
85        return this.nextNodeBlockIsOnOneLine;
86    }
87
88    private NodeIsOnOneLine(node: Node): boolean {
89        const startLine = this.sourceFile.getLineAndCharacterOfPosition(node.getStart(this.sourceFile)).line;
90        const endLine = this.sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line;
91        return startLine === endLine;
92    }
93
94    private BlockIsOnOneLine(node: Node): boolean {
95        const openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
96        const closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
97        if (openBrace && closeBrace) {
98            const startLine = this.sourceFile.getLineAndCharacterOfPosition(openBrace.getEnd()).line;
99            const endLine = this.sourceFile.getLineAndCharacterOfPosition(closeBrace.getStart(this.sourceFile)).line;
100            return startLine === endLine;
101        }
102        return false;
103    }
104}
105