From 34e612c9fcde7621ce067d7cc6168d3099e9b42b Mon Sep 17 00:00:00 2001 From: steveluc Date: Tue, 17 Mar 2015 22:58:12 -0700 Subject: [PATCH] Add handling of hard tabs in server buffers. Change message protocol to pass locations as line/offset pairs instead of line/column pairs, where offset is a 1-based character offset from the beginning of the line. Offset will be equal to column if the line contains no tabs. If the line contains tabs, offset will be less than or equal to column, depending on how many tabs are before the offset. Also added tab size and indent size to file open message. --- src/server/client.ts | 114 ++++++++++++++++---------------- src/server/editorServices.ts | 86 ++++++++++-------------- src/server/protocol.d.ts | 24 +++---- src/server/session.ts | 124 ++++++++++++++++++----------------- 4 files changed, 167 insertions(+), 181 deletions(-) diff --git a/src/server/client.ts b/src/server/client.ts index c8e7f2fdcb1..07c742db4f8 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -46,21 +46,21 @@ module ts.server { return lineMap; } - private lineColToPosition(fileName: string, lineCol: protocol.Location): number { - return ts.computePositionOfLineAndCharacter(this.getLineMap(fileName), lineCol.line - 1, lineCol.col - 1); + private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location): number { + return ts.computePositionOfLineAndCharacter(this.getLineMap(fileName), lineOffset.line - 1, lineOffset.offset - 1); } - private positionToOneBasedLineCol(fileName: string, position: number): protocol.Location { - var lineCol = ts.computeLineAndCharacterOfPosition(this.getLineMap(fileName), position); + private positionToOneBasedLineOffset(fileName: string, position: number): protocol.Location { + var lineOffset = ts.computeLineAndCharacterOfPosition(this.getLineMap(fileName), position); return { - line: lineCol.line + 1, - col: lineCol.character + 1 + line: lineOffset.line + 1, + offset: lineOffset.character + 1 }; } private convertCodeEditsToTextChange(fileName: string, codeEdit: protocol.CodeEdit): ts.TextChange { - var start = this.lineColToPosition(fileName, codeEdit.start); - var end = this.lineColToPosition(fileName, codeEdit.end); + var start = this.lineOffsetToPosition(fileName, codeEdit.start); + var end = this.lineOffsetToPosition(fileName, codeEdit.end); return { span: ts.createTextSpanFromBounds(start, end), @@ -134,15 +134,15 @@ module ts.server { // clear the line map after an edit this.lineMaps[fileName] = undefined; - var lineCol = this.positionToOneBasedLineCol(fileName, start); - var endLineCol = this.positionToOneBasedLineCol(fileName, end); + var lineOffset = this.positionToOneBasedLineOffset(fileName, start); + var endLineOffset = this.positionToOneBasedLineOffset(fileName, end); var args: protocol.ChangeRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, - endLine: endLineCol.line, - endCol: endLineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, + endLine: endLineOffset.line, + endOffset: endLineOffset.offset, insertString: newText }; @@ -150,18 +150,18 @@ module ts.server { } getQuickInfoAtPosition(fileName: string, position: number): QuickInfo { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col + line: lineOffset.line, + offset: lineOffset.offset }; var request = this.processRequest(CommandNames.Quickinfo, args); var response = this.processResponse(request); - var start = this.lineColToPosition(fileName, response.body.start); - var end = this.lineColToPosition(fileName, response.body.end); + var start = this.lineOffsetToPosition(fileName, response.body.start); + var end = this.lineOffsetToPosition(fileName, response.body.end); return { kind: response.body.kind, @@ -173,11 +173,11 @@ module ts.server { } getCompletionsAtPosition(fileName: string, position: number): CompletionInfo { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.CompletionsRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, prefix: undefined }; @@ -194,11 +194,11 @@ module ts.server { } getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.CompletionDetailsRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, entryNames: [entryName] }; @@ -219,8 +219,8 @@ module ts.server { return response.body.map(entry => { var fileName = entry.file; - var start = this.lineColToPosition(fileName, entry.start); - var end = this.lineColToPosition(fileName, entry.end); + var start = this.lineOffsetToPosition(fileName, entry.start); + var end = this.lineOffsetToPosition(fileName, entry.end); return { name: entry.name, @@ -237,14 +237,14 @@ module ts.server { } getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): ts.TextChange[] { - var startLineCol = this.positionToOneBasedLineCol(fileName, start); - var endLineCol = this.positionToOneBasedLineCol(fileName, end); + var startLineOffset = this.positionToOneBasedLineOffset(fileName, start); + var endLineOffset = this.positionToOneBasedLineOffset(fileName, end); var args: protocol.FormatRequestArgs = { file: fileName, - line: startLineCol.line, - col: startLineCol.col, - endLine: endLineCol.line, - endCol: endLineCol.col, + line: startLineOffset.line, + offset: startLineOffset.offset, + endLine: endLineOffset.line, + endOffset: endLineOffset.offset, }; // TODO: handle FormatCodeOptions @@ -259,11 +259,11 @@ module ts.server { } getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): ts.TextChange[] { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FormatOnKeyRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, key: key }; @@ -275,11 +275,11 @@ module ts.server { } getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, }; var request = this.processRequest(CommandNames.Definition, args); @@ -287,8 +287,8 @@ module ts.server { return response.body.map(entry => { var fileName = entry.file; - var start = this.lineColToPosition(fileName, entry.start); - var end = this.lineColToPosition(fileName, entry.end); + var start = this.lineOffsetToPosition(fileName, entry.start); + var end = this.lineOffsetToPosition(fileName, entry.end); return { containerKind: "", containerName: "", @@ -301,11 +301,11 @@ module ts.server { } getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, }; var request = this.processRequest(CommandNames.References, args); @@ -313,8 +313,8 @@ module ts.server { return response.body.refs.map(entry => { var fileName = entry.file; - var start = this.lineColToPosition(fileName, entry.start); - var end = this.lineColToPosition(fileName, entry.end); + var start = this.lineOffsetToPosition(fileName, entry.start); + var end = this.lineOffsetToPosition(fileName, entry.end); return { fileName: fileName, textSpan: ts.createTextSpanFromBounds(start, end), @@ -340,11 +340,11 @@ module ts.server { } getRenameInfo(fileName: string, position: number, findInStrings?: boolean, findInComments?: boolean): RenameInfo { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.RenameRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, findInStrings, findInComments }; @@ -355,8 +355,8 @@ module ts.server { response.body.locs.map((entry: protocol.SpanGroup) => { var fileName = entry.file; entry.locs.map((loc: protocol.TextSpan) => { - var start = this.lineColToPosition(fileName, loc.start); - var end = this.lineColToPosition(fileName, loc.end); + var start = this.lineOffsetToPosition(fileName, loc.start); + var end = this.lineOffsetToPosition(fileName, loc.end); locations.push({ textSpan: ts.createTextSpanFromBounds(start, end), fileName: fileName @@ -400,7 +400,7 @@ module ts.server { text: item.text, kind: item.kind, kindModifiers: item.kindModifiers || "", - spans: item.spans.map(span=> createTextSpanFromBounds(this.lineColToPosition(fileName, span.start), this.lineColToPosition(fileName, span.end))), + spans: item.spans.map(span=> createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))), childItems: this.decodeNavigationBarItems(item.childItems, fileName), indent: 0, bolded: false, @@ -444,19 +444,19 @@ module ts.server { } getBraceMatchingAtPosition(fileName: string, position: number): TextSpan[] { - var lineCol = this.positionToOneBasedLineCol(fileName, position); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); var args: protocol.FileLocationRequestArgs = { file: fileName, - line: lineCol.line, - col: lineCol.col, + line: lineOffset.line, + offset: lineOffset.offset, }; var request = this.processRequest(CommandNames.Brace, args); var response = this.processResponse(request); return response.body.map(entry => { - var start = this.lineColToPosition(fileName, entry.start); - var end = this.lineColToPosition(fileName, entry.end); + var start = this.lineOffsetToPosition(fileName, entry.start); + var end = this.lineOffsetToPosition(fileName, entry.end); return { start: start, length: end - start, diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 4861c2cdfd3..1f9df9b46f0 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -27,9 +27,13 @@ module ts.server { this.svc = ScriptVersionCache.fromString(content); } - setFormatOptions(tabSize: number, indentSize: number) { - this.formatCodeOptions.TabSize = tabSize; - this.formatCodeOptions.IndentSize = indentSize; + setFormatOptions(tabSize?: number, indentSize?: number) { + if (tabSize) { + this.formatCodeOptions.TabSize = tabSize; + } + if (indentSize) { + this.formatCodeOptions.IndentSize = indentSize; + } } close() { @@ -160,15 +164,12 @@ module ts.server { reloadScript(filename: string, tmpfilename: string, cb: () => any) { var script = this.getScriptInfo(filename); if (script) { - script.svc.reloadFromFile(tmpfilename, script.formatCodeOptions.TabSize, cb); + script.svc.reloadFromFile(tmpfilename, cb); } } editScript(filename: string, start: number, end: number, newText: string) { var script = this.getScriptInfo(filename); - if (newText && (newText.length > 0)) { - newText = expandTabs(newText, script.formatCodeOptions.TabSize); - } if (script) { script.editContent(start, end, newText); return; @@ -207,33 +208,33 @@ module ts.server { } else { var nextLineInfo = index.lineNumberToInfo(line + 2); - len = nextLineInfo.col - lineInfo.col; + len = nextLineInfo.offset - lineInfo.offset; } - return ts.createTextSpan(lineInfo.col, len); + return ts.createTextSpan(lineInfo.offset, len); } /** * @param line 1 based index - * @param col 1 based index + * @param offset 1 based index */ - lineColToPosition(filename: string, line: number, col: number): number { + lineOffsetToPosition(filename: string, line: number, offset: number): number { var script: ScriptInfo = this.filenameToScript[filename]; var index = script.snap().index; var lineInfo = index.lineNumberToInfo(line); - // TODO: assert this column is actually on the line - return (lineInfo.col + col - 1); + // TODO: assert this offset is actually on the line + return (lineInfo.offset + offset - 1); } /** * @param line 1-based index - * @param col 1-based index + * @param offset 1-based index */ - positionToLineCol(filename: string, position: number): ILineInfo { + positionToLineOffset(filename: string, position: number): ILineInfo { var script: ScriptInfo = this.filenameToScript[filename]; var index = script.snap().index; - var lineCol = index.charOffsetToLineNumberAndPos(position); - return { line: lineCol.line, col: lineCol.col + 1 }; + var lineOffset = index.charOffsetToLineNumberAndPos(position); + return { line: lineOffset.line, offset: lineOffset.offset + 1 }; } } @@ -372,12 +373,6 @@ module ts.server { hostInfo: string; } - export function expandTabs(text: string, tabSize: number) { - var spaces = generateSpaces(tabSize); - return text.replace(/\t/g, spaces); - } - - export class ProjectService { filenameToScriptInfo: ts.Map = {}; // open, non-configured files in two lists @@ -421,7 +416,7 @@ module ts.server { } else { if (info && (!info.isOpen)) { - info.svc.reloadFromFile(info.fileName, info.formatCodeOptions.TabSize); + info.svc.reloadFromFile(info.fileName); } } } @@ -646,7 +641,7 @@ module ts.server { /** * @param filename is absolute pathname */ - openFile(fileName: string, openedByClient: boolean, tabSize?: number) { + openFile(fileName: string, openedByClient: boolean) { fileName = ts.normalizePath(fileName); var info = ts.lookUp(this.filenameToScriptInfo, fileName); if (!info) { @@ -661,25 +656,11 @@ module ts.server { } if (content !== undefined) { var indentSize: number; - if (!tabSize) { - tabSize = this.hostConfiguration.formatCodeOptions.TabSize; - indentSize = this.hostConfiguration.formatCodeOptions.IndentSize; - } - else { - indentSize = tabSize; - } - if (openedByClient) { - this.log("Expanding tabs for file " + fileName + " with tab size " + tabSize.toString()); - content = expandTabs(content, tabSize); - } info = new ScriptInfo(this.host, fileName, content, openedByClient); this.filenameToScriptInfo[fileName] = info; if (!info.isOpen) { info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); }); } - else { - info.setFormatOptions(tabSize, indentSize); - } } } if (info) { @@ -695,9 +676,9 @@ module ts.server { * @param filename is absolute pathname */ - openClientFile(filename: string, tabSize?: number) { + openClientFile(filename: string) { // TODO: tsconfig check - var info = this.openFile(filename, true, tabSize); + var info = this.openFile(filename, true); this.addOpenFile(info); this.printProjects(); return info; @@ -878,7 +859,7 @@ module ts.server { export interface ILineInfo { line: number; - col: number; + offset: number; text?: string; leaf?: LineLeaf; } @@ -1159,9 +1140,8 @@ module ts.server { return this.currentVersion; } - reloadFromFile(filename: string, tabSize: number, cb?: () => any) { + reloadFromFile(filename: string, cb?: () => any) { var content = ts.sys.readFile(filename); - content = expandTabs(content, tabSize); this.reload(content); if (cb) cb(); @@ -1272,7 +1252,7 @@ module ts.server { getLineMapper() { return ((line: number) => { - return this.index.lineNumberToInfo(line).col; + return this.index.lineNumberToInfo(line).offset; }); } @@ -1309,7 +1289,7 @@ module ts.server { else { return { line: lineNumber, - col: this.root.charCount() + offset: this.root.charCount() } } } @@ -1395,7 +1375,7 @@ module ts.server { // check whether last characters deleted are line break var e = pos + deleteLength; var lineInfo = this.charOffsetToLineNumberAndPos(e); - if ((lineInfo && (lineInfo.col == 0))) { + if ((lineInfo && (lineInfo.offset == 0))) { // move range end just past line that will merge with previous line deleteLength += lineInfo.text.length; // store text by appending to end of insertedText @@ -1571,14 +1551,14 @@ module ts.server { if (!childInfo.child) { return { line: lineNumber, - col: charOffset, + offset: charOffset, } } else if (childInfo.childIndex < this.children.length) { if (childInfo.child.isLeaf()) { return { line: childInfo.lineNumber, - col: childInfo.charOffset, + offset: childInfo.charOffset, text: ((childInfo.child)).text, leaf: ((childInfo.child)) }; @@ -1590,7 +1570,7 @@ module ts.server { } else { var lineInfo = this.lineNumberToInfo(this.lineCount(), 0); - return { line: this.lineCount(), col: lineInfo.leaf.charCount() }; + return { line: this.lineCount(), offset: lineInfo.leaf.charCount() }; } } @@ -1599,13 +1579,13 @@ module ts.server { if (!childInfo.child) { return { line: lineNumber, - col: charOffset + offset: charOffset } - } + } else if (childInfo.child.isLeaf()) { return { line: lineNumber, - col: childInfo.charOffset, + offset: childInfo.charOffset, text: ((childInfo.child)).text, leaf: ((childInfo.child)) } diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index a7a0642de2e..d63aa53ba12 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -96,7 +96,7 @@ declare module ts.server.protocol { /** * Instances of this interface specify a location in a source file: - * (file, line, col), where line and column are 1-based. + * (file, line, character offset), where line and character offset are 1-based. */ export interface FileLocationRequestArgs extends FileRequestArgs { /** @@ -105,9 +105,9 @@ declare module ts.server.protocol { line: number; /** - * The column for the request (1-based). + * The character offset (on the line) for the request (1-based). */ - col: number; + offset: number; } /** @@ -126,11 +126,11 @@ declare module ts.server.protocol { } /** - * Location in source code expressed as (one-based) line and column. + * Location in source code expressed as (one-based) line and character offset. */ export interface Location { line: number; - col: number; + offset: number; } /** @@ -202,9 +202,9 @@ declare module ts.server.protocol { symbolName: string; /** - * The start column of the symbol (on the line provided by the references request). + * The start character offset of the symbol (on the line provided by the references request). */ - symbolStartCol: number; + symbolStartOffset: number; /** * The full display name of the symbol. @@ -339,6 +339,8 @@ declare module ts.server.protocol { export interface OpenRequestArgs extends FileRequestArgs { /** Initial tab size of file. */ tabSize?: number; + /** Number of spaces to indent during formatting */ + indentSize?: number; } /** @@ -424,9 +426,9 @@ declare module ts.server.protocol { endLine: number; /** - * Last column of range for which to format text in file. + * Character offset on last line of range for which to format text in file. */ - endCol: number; + endOffset: number; } /** @@ -805,7 +807,7 @@ declare module ts.server.protocol { */ export interface ChangeRequestArgs extends FormatRequestArgs { /** - * Optional string to insert at location (file, line, col). + * Optional string to insert at location (file, line, offset). */ insertString?: string; } @@ -829,7 +831,7 @@ declare module ts.server.protocol { /** * Brace matching request; value of command field is "brace". * Return response giving the file locations of matching braces - * found in file at location line, col. + * found in file at location line, offset. */ export interface BraceRequest extends FileLocationRequest { } diff --git a/src/server/session.ts b/src/server/session.ts index d6243e4b7a7..79eefb879da 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -44,7 +44,7 @@ module ts.server { else if (a.file == b.file) { var n = compareNumber(a.start.line, b.start.line); if (n == 0) { - return compareNumber(a.start.col, b.start.col); + return compareNumber(a.start.offset, b.start.offset); } else return n; } @@ -55,8 +55,8 @@ module ts.server { function formatDiag(fileName: string, project: Project, diag: ts.Diagnostic) { return { - start: project.compilerService.host.positionToLineCol(fileName, diag.start), - end: project.compilerService.host.positionToLineCol(fileName, diag.start + diag.length), + start: project.compilerService.host.positionToLineOffset(fileName, diag.start), + end: project.compilerService.host.positionToLineOffset(fileName, diag.start + diag.length), text: ts.flattenDiagnosticMessageText(diag.messageText, "\n") }; } @@ -260,7 +260,7 @@ module ts.server { } } - getDefinition(line: number, col: number, fileName: string): protocol.FileSpan[] { + getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -268,7 +268,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var definitions = compilerService.languageService.getDefinitionAtPosition(file, position); if (!definitions) { @@ -277,12 +277,12 @@ module ts.server { return definitions.map(def => ({ file: def.fileName, - start: compilerService.host.positionToLineCol(def.fileName, def.textSpan.start), - end: compilerService.host.positionToLineCol(def.fileName, ts.textSpanEnd(def.textSpan)) + start: compilerService.host.positionToLineOffset(def.fileName, def.textSpan.start), + end: compilerService.host.positionToLineOffset(def.fileName, ts.textSpanEnd(def.textSpan)) })); } - getRenameLocations(line: number, col: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { + getRenameLocations(line: number, offset: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -290,7 +290,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var renameInfo = compilerService.languageService.getRenameInfo(file, position); if (!renameInfo) { return undefined; @@ -310,8 +310,8 @@ module ts.server { var bakedRenameLocs = renameLocations.map(location => ({ file: location.fileName, - start: compilerService.host.positionToLineCol(location.fileName, location.textSpan.start), - end: compilerService.host.positionToLineCol(location.fileName, ts.textSpanEnd(location.textSpan)), + start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), + end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), })).sort((a, b) => { if (a.file < b.file) { return -1; @@ -328,7 +328,7 @@ module ts.server { return -1; } else { - return b.start.col - a.start.col; + return b.start.offset - a.start.offset; } } }).reduce((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => { @@ -350,7 +350,7 @@ module ts.server { return { info: renameInfo, locs: bakedRenameLocs }; } - getReferences(line: number, col: number, fileName: string): protocol.ReferencesResponseBody { + getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { // TODO: get all projects for this file; report refs for all projects deleting duplicates // can avoid duplicates by eliminating same ref file from subsequent projects var file = ts.normalizePath(fileName); @@ -360,7 +360,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var references = compilerService.languageService.getReferencesAtPosition(file, position); if (!references) { @@ -374,10 +374,10 @@ module ts.server { var displayString = ts.displayPartsToString(nameInfo.displayParts); var nameSpan = nameInfo.textSpan; - var nameColStart = compilerService.host.positionToLineCol(file, nameSpan.start).col; + var nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset; var nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); var bakedRefs: protocol.ReferencesResponseItem[] = references.map((ref) => { - var start = compilerService.host.positionToLineCol(ref.fileName, ref.textSpan.start); + var start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); var refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); var snap = compilerService.host.getScriptSnapshot(ref.fileName); var lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); @@ -385,24 +385,27 @@ module ts.server { file: ref.fileName, start: start, lineText: lineText, - end: compilerService.host.positionToLineCol(ref.fileName, ts.textSpanEnd(ref.textSpan)), + end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)), isWriteAccess: ref.isWriteAccess }; }).sort(compareFileStart); return { refs: bakedRefs, symbolName: nameText, - symbolStartCol: nameColStart, + symbolStartOffset: nameColStart, symbolDisplayString: displayString }; } - openClientFile(fileName: string, tabSize?: number) { + openClientFile(fileName: string, tabSize?: number, indentSize?: number) { var file = ts.normalizePath(fileName); - this.projectService.openClientFile(file, tabSize); + var info = this.projectService.openClientFile(file); + if (info) { + info.setFormatOptions(tabSize, indentSize); + } } - getQuickInfo(line: number, col: number, fileName: string): protocol.QuickInfoResponseBody { + getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -410,7 +413,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var quickInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); if (!quickInfo) { return undefined; @@ -421,14 +424,14 @@ module ts.server { return { kind: quickInfo.kind, kindModifiers: quickInfo.kindModifiers, - start: compilerService.host.positionToLineCol(file, quickInfo.textSpan.start), - end: compilerService.host.positionToLineCol(file, ts.textSpanEnd(quickInfo.textSpan)), + start: compilerService.host.positionToLineOffset(file, quickInfo.textSpan.start), + end: compilerService.host.positionToLineOffset(file, ts.textSpanEnd(quickInfo.textSpan)), displayString: displayString, documentation: docString, }; } - getFormattingEditsForRange(line: number, col: number, endLine: number, endCol: number, fileName: string): protocol.CodeEdit[] { + getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (!project) { @@ -436,8 +439,8 @@ module ts.server { } var compilerService = project.compilerService; - var startPosition = compilerService.host.lineColToPosition(file, line, col); - var endPosition = compilerService.host.lineColToPosition(file, endLine, endCol); + var startPosition = compilerService.host.lineOffsetToPosition(file, line, offset); + var endPosition = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); // TODO: avoid duplicate code (with formatonkey) var edits = compilerService.languageService.getFormattingEditsForRange(file, startPosition, endPosition, @@ -448,14 +451,14 @@ module ts.server { return edits.map((edit) => { return { - start: compilerService.host.positionToLineCol(file, edit.span.start), - end: compilerService.host.positionToLineCol(file, ts.textSpanEnd(edit.span)), + start: compilerService.host.positionToLineOffset(file, edit.span.start), + end: compilerService.host.positionToLineOffset(file, ts.textSpanEnd(edit.span)), newText: edit.newText ? edit.newText : "" }; }); } - getFormattingEditsAfterKeystroke(line: number, col: number, key: string, fileName: string): protocol.CodeEdit[] { + getFormattingEditsAfterKeystroke(line: number, offset: number, key: string, fileName: string): protocol.CodeEdit[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -464,7 +467,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var formatOptions = this.projectService.getFormatCodeOptions(file); var edits = compilerService.languageService.getFormattingEditsAfterKeystroke(file, position, key, formatOptions); @@ -519,16 +522,16 @@ module ts.server { return edits.map((edit) => { return { - start: compilerService.host.positionToLineCol(file, + start: compilerService.host.positionToLineOffset(file, edit.span.start), - end: compilerService.host.positionToLineCol(file, + end: compilerService.host.positionToLineOffset(file, ts.textSpanEnd(edit.span)), newText: edit.newText ? edit.newText : "" }; }); } - getCompletions(line: number, col: number, prefix: string, fileName: string): protocol.CompletionEntry[] { + getCompletions(line: number, offset: number, prefix: string, fileName: string): protocol.CompletionEntry[] { if (!prefix) { prefix = ""; } @@ -539,7 +542,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var completions = compilerService.languageService.getCompletionsAtPosition(file, position); if (!completions) { @@ -554,7 +557,7 @@ module ts.server { }, []); } - getCompletionEntryDetails(line: number, col: number, + getCompletionEntryDetails(line: number, offset: number, entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -563,7 +566,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); return entryNames.reduce((accum: protocol.CompletionEntryDetails[], entryName: string) => { var details = compilerService.languageService.getCompletionEntryDetails(file, position, entryName); @@ -589,13 +592,13 @@ module ts.server { } } - change(line: number, col: number, endLine: number, endCol: number, insertString: string, fileName: string) { + change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); if (project) { var compilerService = project.compilerService; - var start = compilerService.host.lineColToPosition(file, line, col); - var end = compilerService.host.lineColToPosition(file, endLine, endCol); + var start = compilerService.host.lineOffsetToPosition(file, line, offset); + var end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); if (start >= 0) { compilerService.host.editScript(file, start, end, insertString); this.changeSeq++; @@ -644,8 +647,8 @@ module ts.server { kind: item.kind, kindModifiers: item.kindModifiers, spans: item.spans.map(span => ({ - start: compilerService.host.positionToLineCol(fileName, span.start), - end: compilerService.host.positionToLineCol(fileName, ts.textSpanEnd(span)) + start: compilerService.host.positionToLineOffset(fileName, span.start), + end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span)) })), childItems: this.decorateNavigationBarItem(project, fileName, item.childItems) })); @@ -681,8 +684,8 @@ module ts.server { } return navItems.map((navItem) => { - var start = compilerService.host.positionToLineCol(navItem.fileName, navItem.textSpan.start); - var end = compilerService.host.positionToLineCol(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); + var start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); + var end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); var bakedItem: protocol.NavtoItem = { name: navItem.name, kind: navItem.kind, @@ -706,7 +709,7 @@ module ts.server { }); } - getBraceMatching(line: number, col: number, fileName: string): protocol.TextSpan[] { + getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] { var file = ts.normalizePath(fileName); var project = this.projectService.getProjectForFile(file); @@ -715,7 +718,7 @@ module ts.server { } var compilerService = project.compilerService; - var position = compilerService.host.lineColToPosition(file, line, col); + var position = compilerService.host.lineOffsetToPosition(file, line, offset); var spans = compilerService.languageService.getBraceMatchingAtPosition(file, position); if (!spans) { @@ -723,8 +726,8 @@ module ts.server { } return spans.map(span => ({ - start: compilerService.host.positionToLineCol(file, span.start), - end: compilerService.host.positionToLineCol(file, span.start + span.length) + start: compilerService.host.positionToLineOffset(file, span.start), + end: compilerService.host.positionToLineOffset(file, span.start + span.length) })); } @@ -741,49 +744,50 @@ module ts.server { switch (request.command) { case CommandNames.Definition: { var defArgs = request.arguments; - response = this.getDefinition(defArgs.line, defArgs.col, defArgs.file); + response = this.getDefinition(defArgs.line, defArgs.offset, defArgs.file); break; } case CommandNames.References: { var refArgs = request.arguments; - response = this.getReferences(refArgs.line, refArgs.col, refArgs.file); + response = this.getReferences(refArgs.line, refArgs.offset, refArgs.file); break; } case CommandNames.Rename: { var renameArgs = request.arguments; - response = this.getRenameLocations(renameArgs.line, renameArgs.col, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings); + response = this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings); break; } case CommandNames.Open: { var openArgs = request.arguments; - this.openClientFile(openArgs.file,openArgs.tabSize); + this.openClientFile(openArgs.file,openArgs.tabSize, openArgs.indentSize); responseRequired = false; break; } case CommandNames.Quickinfo: { var quickinfoArgs = request.arguments; - response = this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.col, quickinfoArgs.file); + response = this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file); break; } case CommandNames.Format: { var formatArgs = request.arguments; - response = this.getFormattingEditsForRange(formatArgs.line, formatArgs.col, formatArgs.endLine, formatArgs.endCol, formatArgs.file); + response = this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file); break; } case CommandNames.Formatonkey: { var formatOnKeyArgs = request.arguments; - response = this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.col, formatOnKeyArgs.key, formatOnKeyArgs.file); + response = this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file); break; } case CommandNames.Completions: { var completionsArgs = request.arguments; - response = this.getCompletions(request.arguments.line, request.arguments.col, completionsArgs.prefix, request.arguments.file); + response = this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file); break; } case CommandNames.CompletionDetails: { var completionDetailsArgs = request.arguments; - response = this.getCompletionEntryDetails(request.arguments.line, request.arguments.col, completionDetailsArgs.entryNames, - request.arguments.file); + response = + this.getCompletionEntryDetails(completionDetailsArgs.line,completionDetailsArgs.offset, + completionDetailsArgs.entryNames,completionDetailsArgs.file); break; } case CommandNames.Geterr: { @@ -794,7 +798,7 @@ module ts.server { } case CommandNames.Change: { var changeArgs = request.arguments; - this.change(changeArgs.line, changeArgs.col, changeArgs.endLine, changeArgs.endCol, + this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset, changeArgs.insertString, changeArgs.file); responseRequired = false; break; @@ -831,7 +835,7 @@ module ts.server { } case CommandNames.Brace: { var braceArguments = request.arguments; - response = this.getBraceMatching(braceArguments.line, braceArguments.col, braceArguments.file); + response = this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file); break; } case CommandNames.NavBar: {