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