From b7b3506c59de1497f5ae65ec556b9ffffa51eb7e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 6 Nov 2014 15:31:42 -0800 Subject: [PATCH] change folder structure, move all new formatting related bits to 'format' folder --- src/services/{formatting => }/format.ts | 11 +- .../{formatting/new => format}/formatting.ts | 2 +- .../new => format}/formattingContext.ts | 0 .../new => format}/formattingRequestKind.ts | 0 .../formattingScanner.ts | 2 + .../indentation.ts} | 0 .../{formatting/new => format}/rule.ts | 0 .../{formatting/new => format}/ruleAction.ts | 0 .../new => format}/ruleDescriptor.ts | 0 .../{formatting/new => format}/ruleFlag.ts | 0 .../new => format}/ruleOperation.ts | 0 .../new => format}/ruleOperationContext.ts | 0 .../{formatting/new => format}/rules.ts | 0 .../{formatting/new => format}/rulesMap.ts | 0 .../new => format}/rulesProvider.ts | 0 .../{formatting/new => format}/tokenRange.ts | 0 .../{formatting/new => format}/tokenSpan.ts | 0 src/services/formatting/lineMapUtilities.ts | 41 -- src/services/formatting/new/smartIndenter.ts | 401 ------------------ src/services/services.ts | 4 +- .../{formatting => }/smartIndenter.ts | 2 +- src/services/utilities.ts | 37 ++ 22 files changed, 48 insertions(+), 452 deletions(-) rename src/services/{formatting => }/format.ts (97%) rename src/services/{formatting/new => format}/formatting.ts (90%) rename src/services/{formatting/new => format}/formattingContext.ts (100%) rename src/services/{formatting/new => format}/formattingRequestKind.ts (100%) rename src/services/{formatting => format}/formattingScanner.ts (96%) rename src/services/{formatting/stringUtilities.ts => format/indentation.ts} (100%) rename src/services/{formatting/new => format}/rule.ts (100%) rename src/services/{formatting/new => format}/ruleAction.ts (100%) rename src/services/{formatting/new => format}/ruleDescriptor.ts (100%) rename src/services/{formatting/new => format}/ruleFlag.ts (100%) rename src/services/{formatting/new => format}/ruleOperation.ts (100%) rename src/services/{formatting/new => format}/ruleOperationContext.ts (100%) rename src/services/{formatting/new => format}/rules.ts (100%) rename src/services/{formatting/new => format}/rulesMap.ts (100%) rename src/services/{formatting/new => format}/rulesProvider.ts (100%) rename src/services/{formatting/new => format}/tokenRange.ts (100%) rename src/services/{formatting/new => format}/tokenSpan.ts (100%) delete mode 100644 src/services/formatting/lineMapUtilities.ts delete mode 100644 src/services/formatting/new/smartIndenter.ts rename src/services/{formatting => }/smartIndenter.ts (97%) diff --git a/src/services/formatting/format.ts b/src/services/format.ts similarity index 97% rename from src/services/formatting/format.ts rename to src/services/format.ts index 0adc2cb00fb..6e53fa26541 100644 --- a/src/services/formatting/format.ts +++ b/src/services/format.ts @@ -1,8 +1,7 @@ -/// -/// -/// -/// -/// +/// +/// +/// +/// module ts.formatting { @@ -25,10 +24,10 @@ module ts.formatting { getEffectiveCommentIndentation(commentLine: number): number; getDelta(): number; getIndentation(): number; + setDelta(delta: number): number; getCommentIndentation(): number; increaseCommentIndentation(delta: number): void; recomputeIndentation(lineAddedByFormatting: boolean): void; - setDelta(delta: number): number; } export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] { diff --git a/src/services/formatting/new/formatting.ts b/src/services/format/formatting.ts similarity index 90% rename from src/services/formatting/new/formatting.ts rename to src/services/format/formatting.ts index c61f1bce8af..3d19b33d821 100644 --- a/src/services/formatting/new/formatting.ts +++ b/src/services/format/formatting.ts @@ -13,7 +13,7 @@ // limitations under the License. // -/// +/// /// /// /// diff --git a/src/services/formatting/new/formattingContext.ts b/src/services/format/formattingContext.ts similarity index 100% rename from src/services/formatting/new/formattingContext.ts rename to src/services/format/formattingContext.ts diff --git a/src/services/formatting/new/formattingRequestKind.ts b/src/services/format/formattingRequestKind.ts similarity index 100% rename from src/services/formatting/new/formattingRequestKind.ts rename to src/services/format/formattingRequestKind.ts diff --git a/src/services/formatting/formattingScanner.ts b/src/services/format/formattingScanner.ts similarity index 96% rename from src/services/formatting/formattingScanner.ts rename to src/services/format/formattingScanner.ts index c9dc2949d17..e7f6b019057 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/format/formattingScanner.ts @@ -1,3 +1,5 @@ +/// + module ts.formatting { var scanner = createScanner(ScriptTarget.ES5, /*skipTrivia*/ false); diff --git a/src/services/formatting/stringUtilities.ts b/src/services/format/indentation.ts similarity index 100% rename from src/services/formatting/stringUtilities.ts rename to src/services/format/indentation.ts diff --git a/src/services/formatting/new/rule.ts b/src/services/format/rule.ts similarity index 100% rename from src/services/formatting/new/rule.ts rename to src/services/format/rule.ts diff --git a/src/services/formatting/new/ruleAction.ts b/src/services/format/ruleAction.ts similarity index 100% rename from src/services/formatting/new/ruleAction.ts rename to src/services/format/ruleAction.ts diff --git a/src/services/formatting/new/ruleDescriptor.ts b/src/services/format/ruleDescriptor.ts similarity index 100% rename from src/services/formatting/new/ruleDescriptor.ts rename to src/services/format/ruleDescriptor.ts diff --git a/src/services/formatting/new/ruleFlag.ts b/src/services/format/ruleFlag.ts similarity index 100% rename from src/services/formatting/new/ruleFlag.ts rename to src/services/format/ruleFlag.ts diff --git a/src/services/formatting/new/ruleOperation.ts b/src/services/format/ruleOperation.ts similarity index 100% rename from src/services/formatting/new/ruleOperation.ts rename to src/services/format/ruleOperation.ts diff --git a/src/services/formatting/new/ruleOperationContext.ts b/src/services/format/ruleOperationContext.ts similarity index 100% rename from src/services/formatting/new/ruleOperationContext.ts rename to src/services/format/ruleOperationContext.ts diff --git a/src/services/formatting/new/rules.ts b/src/services/format/rules.ts similarity index 100% rename from src/services/formatting/new/rules.ts rename to src/services/format/rules.ts diff --git a/src/services/formatting/new/rulesMap.ts b/src/services/format/rulesMap.ts similarity index 100% rename from src/services/formatting/new/rulesMap.ts rename to src/services/format/rulesMap.ts diff --git a/src/services/formatting/new/rulesProvider.ts b/src/services/format/rulesProvider.ts similarity index 100% rename from src/services/formatting/new/rulesProvider.ts rename to src/services/format/rulesProvider.ts diff --git a/src/services/formatting/new/tokenRange.ts b/src/services/format/tokenRange.ts similarity index 100% rename from src/services/formatting/new/tokenRange.ts rename to src/services/format/tokenRange.ts diff --git a/src/services/formatting/new/tokenSpan.ts b/src/services/format/tokenSpan.ts similarity index 100% rename from src/services/formatting/new/tokenSpan.ts rename to src/services/format/tokenSpan.ts diff --git a/src/services/formatting/lineMapUtilities.ts b/src/services/formatting/lineMapUtilities.ts deleted file mode 100644 index cd429019dba..00000000000 --- a/src/services/formatting/lineMapUtilities.ts +++ /dev/null @@ -1,41 +0,0 @@ -/// - -module ts.formatting { - - export function getEndLinePosition(line: number, sourceFile: SourceFile): number { - Debug.assert(line >= 1); - var lineStarts = sourceFile.getLineStarts(); - - line = line - 1; - if (line === lineStarts.length - 1) { - // last line - return EOF - return sourceFile.text.length - 1; - } - else { - // current line start - var start = lineStarts[line]; - // take the start position of the next line -1 = it should be some line break - var pos = lineStarts[line + 1] - 1; - Debug.assert(isLineBreak(sourceFile.text.charCodeAt(pos))); - // walk backwards skipping line breaks, stop the the beginning of current line. - // i.e: - // - // $ <- end of line for this position should match the start position - while (start <= pos && isLineBreak(sourceFile.text.charCodeAt(pos))) { - pos--; - } - return pos; - } - } - - export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number { - Debug.assert(line >= 1); - return sourceFile.getLineStarts()[line - 1]; - } - - export function getStartLinePositionForPosition(position: number, sourceFile: SourceFile): number { - var lineStarts = sourceFile.getLineStarts(); - var line = sourceFile.getLineAndCharacterFromPosition(position).line; - return lineStarts[line - 1]; - } -} \ No newline at end of file diff --git a/src/services/formatting/new/smartIndenter.ts b/src/services/formatting/new/smartIndenter.ts deleted file mode 100644 index df57929dff3..00000000000 --- a/src/services/formatting/new/smartIndenter.ts +++ /dev/null @@ -1,401 +0,0 @@ -/// -/// - -module ts.formatting { - export module SmartIndenter { - export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number { - if (position > sourceFile.text.length) { - return 0; // past EOF - } - - var precedingToken = ServicesSyntaxUtilities.findPrecedingToken(position, sourceFile); - if (!precedingToken) { - return 0; - } - - // no indentation in string \regex literals - if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) && - precedingToken.getStart(sourceFile) <= position && - precedingToken.end > position) { - return 0; - } - - var lineAtPosition = sourceFile.getLineAndCharacterFromPosition(position).line; - - if (precedingToken.kind === SyntaxKind.CommaToken && precedingToken.parent.kind !== SyntaxKind.BinaryExpression) { - // previous token is comma that separates items in list - find the previous item and try to derive indentation from it - var actualIndentation = getActualIndentationForListItemBeforeComma(precedingToken, sourceFile, options); - if (actualIndentation !== -1) { - return actualIndentation; - } - } - - // try to find node that can contribute to indentation and includes 'position' starting from 'precedingToken' - // if such node is found - compute initial indentation for 'position' inside this node - var previous: Node; - var current = precedingToken; - var currentStart: LineAndCharacter; - var indentationDelta: number; - - while (current) { - if (positionBelongsToNode(current, position, sourceFile) && nodeContentIsIndented(current, previous)) { - currentStart = getStartLineAndCharacterForNode(current, sourceFile); - - if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) { - indentationDelta = 0; - } - else { - indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0; - } - - break; - } - - // check if current node is a list item - if yes, take indentation from it - var actualIndentation = getActualIndentationForListItem(current, sourceFile, options); - if (actualIndentation !== -1) { - return actualIndentation; - } - - previous = current; - current = current.parent; - } - - if (!current) { - // no parent was found - return 0 to be indented on the level of SourceFile - return 0; - } - - return getIndentationForNode(current, currentStart, indentationDelta, sourceFile, options); - } - - export function getIndentationForNode(current: Node, currentStart: LineAndCharacter, indentationDelta: number, sourceFile: SourceFile, options: EditorOptions): number { - var parent: Node = current.parent; - var parentStart: LineAndCharacter; - - // walk upwards and collect indentations for pairs of parent-child nodes - // indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause' - while (parent) { - // check if current node is a list item - if yes, take indentation from it - var actualIndentation = getActualIndentationForListItem(current, sourceFile, options); - if (actualIndentation !== -1) { - return actualIndentation + indentationDelta; - } - - parentStart = sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile)); - var parentAndChildShareLine = - parentStart.line === currentStart.line || - childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); - - // try to fetch actual indentation for current node from source text - var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); - if (actualIndentation !== -1) { - return actualIndentation + indentationDelta; - } - - // increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line - if (nodeContentIsIndented(parent, current) && !parentAndChildShareLine) { - indentationDelta += options.IndentSize; - } - - current = parent; - currentStart = parentStart; - parent = current.parent; - } - - return indentationDelta; - } - - /* - * Function returns -1 if indentation cannot be determined - */ - function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number { - // previous token is comma that separates items in list - find the previous item and try to derive indentation from it - var commaItemInfo = ServicesSyntaxUtilities.findListItemInfo(commaToken); - Debug.assert(commaItemInfo.listItemIndex > 0); - // The item we're interested in is right before the comma - return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options); - } - - /* - * Function returns -1 if actual indentation for node should not be used (i.e because node is nested expression) - */ - function getActualIndentationForNode(current: Node, - parent: Node, - currentLineAndChar: LineAndCharacter, - parentAndChildShareLine: boolean, - sourceFile: SourceFile, - options: EditorOptions): number { - - // actual indentation is used for statements\declarations if one of cases below is true: - // - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually - // - parent and child are not on the same line - var useActualIndentation = - (isDeclaration(current) || isStatement(current)) && - (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); - - if (!useActualIndentation) { - return -1; - } - - return findColumnForFirstNonWhitespaceCharacterInLine(currentLineAndChar, sourceFile, options); - } - - function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): boolean { - var nextToken = ServicesSyntaxUtilities.findNextToken(precedingToken, current); - if (!nextToken) { - return false; - } - - if (nextToken.kind === SyntaxKind.OpenBraceToken) { - // open braces are always indented at the parent level - return true; - } - else if (nextToken.kind === SyntaxKind.CloseBraceToken) { - // close braces are indented at the parent level if they are located on the same line with cursor - // this means that if new line will be added at $ position, this case will be indented - // class A { - // $ - // } - /// and this one - not - // class A { - // $} - - var nextTokenStartLine = getStartLineAndCharacterForNode(nextToken, sourceFile).line; - return lineAtPosition === nextTokenStartLine; - } - - return false; - } - - function getStartLineAndCharacterForNode(n: Node, sourceFile: SourceFile): LineAndCharacter { - return sourceFile.getLineAndCharacterFromPosition(n.getStart(sourceFile)); - } - - function positionBelongsToNode(candidate: Node, position: number, sourceFile: SourceFile): boolean { - return candidate.end > position || !isCompletedNode(candidate, sourceFile); - } - - function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFile): boolean { - if (parent.kind === SyntaxKind.IfStatement && (parent).elseStatement === child) { - var elseKeyword = forEach(parent.getChildren(), c => c.kind === SyntaxKind.ElseKeyword && c); - Debug.assert(elseKeyword); - - var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line; - return elseKeywordStartLine === childStartLine; - } - } - - function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number { - if (node.parent) { - switch (node.parent.kind) { - case SyntaxKind.TypeReference: - if ((node.parent).typeArguments) { - return getActualIndentationFromList((node.parent).typeArguments); - } - break; - case SyntaxKind.ObjectLiteral: - return getActualIndentationFromList((node.parent).properties); - case SyntaxKind.TypeLiteral: - return getActualIndentationFromList((node.parent).members); - case SyntaxKind.ArrayLiteral: - return getActualIndentationFromList((node.parent).elements); - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.Method: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - if ((node.parent).typeParameters && node.end < (node.parent).typeParameters.end) { - return getActualIndentationFromList((node.parent).typeParameters); - } - - return getActualIndentationFromList((node.parent).parameters); - case SyntaxKind.NewExpression: - case SyntaxKind.CallExpression: - if ((node.parent).typeArguments && node.end < (node.parent).typeArguments.end) { - return getActualIndentationFromList((node.parent).typeArguments); - } - - return getActualIndentationFromList((node.parent).arguments); - } - } - - return -1; - - function getActualIndentationFromList(list: Node[]): number { - var index = indexOf(list, node); - return index !== -1 ? deriveActualIndentationFromList(list, index, sourceFile, options) : -1; - } - } - - - function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorOptions): number { - Debug.assert(index >= 0 && index < list.length); - var node = list[index]; - - // walk toward the start of the list starting from current node and check if the line is the same for all items. - // if end line for item [i - 1] differs from the start line for item [i] - find column of the first non-whitespace character on the line of item [i] - var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile); - for (var i = index - 1; i >= 0; --i) { - if (list[i].kind === SyntaxKind.CommaToken) { - continue; - } - // skip list items that ends on the same line with the current list element - var prevEndLine = sourceFile.getLineAndCharacterFromPosition(list[i].end).line; - if (prevEndLine !== lineAndCharacter.line) { - return findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter, sourceFile, options); - } - - lineAndCharacter = getStartLineAndCharacterForNode(list[i], sourceFile); - } - return -1; - } - - function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number { - var lineStart = sourceFile.getPositionFromLineAndCharacter(lineAndCharacter.line, 1); - var column = 0; - for (var i = 0; i < lineAndCharacter.character; ++i) { - var charCode = sourceFile.text.charCodeAt(lineStart + i); - if (!isWhiteSpace(charCode)) { - return column; - } - - if (charCode === CharacterCodes.tab) { - column += options.TabSize; - } - else { - column++; - } - } - - return column; - } - - function nodeContentIsIndented(parent: Node, child: Node): boolean { - switch (parent.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - return true; - case SyntaxKind.ModuleDeclaration: - // ModuleBlock should take care of indentation - return false; - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.Method: - case SyntaxKind.FunctionExpression: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: - // FunctionBlock should take care of indentation - return false; - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.ForStatement: - return child && child.kind !== SyntaxKind.Block; - case SyntaxKind.IfStatement: - return child && child.kind !== SyntaxKind.Block; - case SyntaxKind.TryStatement: - // TryBlock\CatchBlock\FinallyBlock should take care of indentation - return false; - case SyntaxKind.ArrayLiteral: - case SyntaxKind.Block: - case SyntaxKind.FunctionBlock: - case SyntaxKind.TryBlock: - case SyntaxKind.CatchBlock: - case SyntaxKind.FinallyBlock: - case SyntaxKind.ModuleBlock: - case SyntaxKind.ObjectLiteral: - case SyntaxKind.TypeLiteral: - case SyntaxKind.SwitchStatement: - case SyntaxKind.DefaultClause: - case SyntaxKind.CaseClause: - case SyntaxKind.ParenExpression: - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.VariableStatement: - case SyntaxKind.VariableDeclaration: - return true; - default: - return false; - } - } - - /* - * Checks if node ends with 'expectedLastToken'. - * If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'. - */ - function nodeEndsWith(n: Node, expectedLastToken: SyntaxKind, sourceFile: SourceFile): boolean { - var children = n.getChildren(sourceFile); - if (children.length) { - var last = children[children.length - 1]; - if (last.kind === expectedLastToken) { - return true; - } - else if (last.kind === SyntaxKind.SemicolonToken && children.length !== 1) { - return children[children.length - 2].kind === expectedLastToken; - } - } - return false; - } - - /* - * This function is always called when position of the cursor is located after the node - */ - function isCompletedNode(n: Node, sourceFile: SourceFile): boolean { - switch (n.kind) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ObjectLiteral: - case SyntaxKind.Block: - case SyntaxKind.CatchBlock: - case SyntaxKind.FinallyBlock: - case SyntaxKind.FunctionBlock: - case SyntaxKind.ModuleBlock: - case SyntaxKind.SwitchStatement: - return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile); - case SyntaxKind.ParenExpression: - case SyntaxKind.CallSignature: - case SyntaxKind.CallExpression: - case SyntaxKind.ConstructSignature: - return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile); - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.Method: - case SyntaxKind.ArrowFunction: - return !(n).body || isCompletedNode((n).body, sourceFile); - case SyntaxKind.ModuleDeclaration: - return (n).body && isCompletedNode((n).body, sourceFile); - case SyntaxKind.IfStatement: - if ((n).elseStatement) { - return isCompletedNode((n).elseStatement, sourceFile); - } - return isCompletedNode((n).thenStatement, sourceFile); - case SyntaxKind.ExpressionStatement: - return isCompletedNode((n).expression, sourceFile); - case SyntaxKind.ArrayLiteral: - return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile); - case SyntaxKind.Missing: - return false; - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - // there is no such thing as terminator token for CaseClause\DefaultClause so for simplicitly always consider them non-completed - return false; - case SyntaxKind.WhileStatement: - return isCompletedNode((n).statement, sourceFile); - case SyntaxKind.DoStatement: - // rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')'; - var hasWhileKeyword = forEach(n.getChildren(), c => c.kind === SyntaxKind.WhileKeyword && c); - if(hasWhileKeyword) { - return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile); - } - return isCompletedNode((n).statement, sourceFile); - default: - return true; - } - } - } -} - diff --git a/src/services/services.ts b/src/services/services.ts index 113e878efb4..33bec5ae8d8 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -12,8 +12,8 @@ /// /// /// -/// -/// +/// +/// /// /// diff --git a/src/services/formatting/smartIndenter.ts b/src/services/smartIndenter.ts similarity index 97% rename from src/services/formatting/smartIndenter.ts rename to src/services/smartIndenter.ts index 010dcf174c8..98971b1f14a 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/smartIndenter.ts @@ -1,4 +1,4 @@ -/// +/// module ts.formatting { export module SmartIndenter { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 1fede7f3a1b..a4146c52e5e 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -5,6 +5,43 @@ module ts { list: Node; } + export function getEndLinePosition(line: number, sourceFile: SourceFile): number { + Debug.assert(line >= 1); + var lineStarts = sourceFile.getLineStarts(); + + line = line - 1; + if (line === lineStarts.length - 1) { + // last line - return EOF + return sourceFile.text.length - 1; + } + else { + // current line start + var start = lineStarts[line]; + // take the start position of the next line -1 = it should be some line break + var pos = lineStarts[line + 1] - 1; + Debug.assert(isLineBreak(sourceFile.text.charCodeAt(pos))); + // walk backwards skipping line breaks, stop the the beginning of current line. + // i.e: + // + // $ <- end of line for this position should match the start position + while (start <= pos && isLineBreak(sourceFile.text.charCodeAt(pos))) { + pos--; + } + return pos; + } + } + + export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number { + Debug.assert(line >= 1); + return sourceFile.getLineStarts()[line - 1]; + } + + export function getStartLinePositionForPosition(position: number, sourceFile: SourceFile): number { + var lineStarts = sourceFile.getLineStarts(); + var line = sourceFile.getLineAndCharacterFromPosition(position).line; + return lineStarts[line - 1]; + } + export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean { return startEndContainsRange(r1.pos, r1.end, r2); }