From d53cfdcb5b70e7f165c580745a12102f6590fc51 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Mon, 3 Aug 2015 20:45:39 -0700 Subject: [PATCH 1/6] Expose document highlighting to server. --- src/harness/fourslash.ts | 47 ++++++++++++++++++- src/server/client.ts | 24 +++++++++- src/server/protocol.d.ts | 22 +++++++++ src/server/session.ts | 43 ++++++++++++++++- tests/cases/fourslash/fourslash.ts | 8 ++++ .../fourslash/server/documentHighlights01.ts | 18 +++++++ 6 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/server/documentHighlights01.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 5d73e04c8cb..a82346d888e 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2132,7 +2132,7 @@ module FourSlash { let occurance = occurances[i]; if (occurance && occurance.fileName === fileName && occurance.textSpan.start === start && ts.textSpanEnd(occurance.textSpan) === end) { if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) { - this.raiseError('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); + this.raiseError('verifyOccurancesAtPositionListContains failed - item isWriteAccess value does not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } return; } @@ -2152,6 +2152,51 @@ module FourSlash { } } + private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: string[]) { + let filesToSearch = fileNamesToSearch.map(name => this.basePath + "/" + name); + return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); + } + + public verifyDocumentHighlightsAtPositionListContains(fileName: string, start: number, end: number, fileNamesToSearch: string[], kind?: string) { + this.taoInvalidReason = 'verifyDocumentHighlightsAtPositionListContains NYI'; + + let documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); + + if (!documentHighlights || documentHighlights.length === 0) { + this.raiseError('verifyDocumentHighlightsAtPositionListContains failed - found 0 highlights, expected at least one.'); + } + + for (let i = 0; i < documentHighlights.length; i++) if (documentHighlights[i].fileName === fileName) { + let { highlightSpans } = documentHighlights[i]; + + for (let highlight of highlightSpans) { + if (highlight && highlight.textSpan.start === start && ts.textSpanEnd(highlight.textSpan) === end) { + if (typeof kind !== "undefined" && highlight.kind !== kind) { + this.raiseError('verifyDocumentHighlightsAtPositionListContains failed - item "kind" value does not match, actual: ' + highlight.kind + ', expected: ' + kind + '.'); + } + return; + } + } + } + + let missingItem = { fileName: fileName, start: start, end: end, kind: kind }; + this.raiseError('verifyOccurancesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(documentHighlights) + ')'); + } + + public verifyDocumentHighlightsAtPositionListCount(expectedCount: number, fileNamesToSearch: string[]) { + this.taoInvalidReason = 'verifyDocumentHighlightsAtPositionListCount NYI'; + + let documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); + let actualCount = documentHighlights + ? documentHighlights.reduce((currentCount, currentDocumentHighlights) => { + return currentCount + currentDocumentHighlights.highlightSpans.length}, 0) + : 0; + + if (expectedCount !== actualCount) { + this.raiseError('verifyDocumentHighlightsAtPositionListCount failed - actual: ' + actualCount + ', expected:' + expectedCount); + } + } + // Get the text of the entire line the caret is currently at private getCurrentLineContent() { let text = this.getFileContent(this.activeFile.fileName); diff --git a/src/server/client.ts b/src/server/client.ts index 3ad7230cf33..f02961f02ad 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -528,7 +528,29 @@ namespace ts.server { } getDocumentHighlights(fileName: string, position: number): DocumentHighlights[] { - throw new Error("Not Implemented Yet."); + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); + var args: protocol.FileLocationRequestArgs = { + file: fileName, + line: lineOffset.line, + offset: lineOffset.offset, + }; + + var request = this.processRequest(CommandNames.DocumentHighlights, args); + var response = this.processResponse(request); + + return response.body.map(entry => { // convert ts.server.protocol.DocumentHighlightsItem to ts.DocumentHighlights + return { + fileName: entry.file, + highlightSpans: entry.highlightSpans.map(span => { // convert ts.server.protocol.HighlightSpan to ts.HighlighSpan + var start = this.lineOffsetToPosition(entry.file, span.start); + var end = this.lineOffsetToPosition(entry.file, span.end); + return { + textSpan: ts.createTextSpanFromBounds(start, end), + kind: span.kind + }; + }) + }; + }); } getOutliningSpans(fileName: string): OutliningSpan[] { diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index 017a8c1d81a..0822f537365 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -238,6 +238,28 @@ declare namespace ts.server.protocol { body?: OccurrencesResponseItem[]; } + /** + * Get document highlights request; value of command field is + * "documentHighlights". Return response giving spans that are relevant + * in the file at a given line and column. + */ + export interface DocumentHighlightsRequest extends FileLocationRequest { + } + + export interface HighLightSpan extends TextSpan { + kind: string + } + + export interface DocumentHighlightsItem { + file: string, + highlightSpans: HighLightSpan[]; + } + + export interface DocumentHighlightsResponse extends Response { + body?: DocumentHighlightsItem[]; + } + + /** * Find references request; value of command field is * "references". Return response giving the file locations that diff --git a/src/server/session.ts b/src/server/session.ts index 9a5cee32264..c91cf385c0f 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -89,6 +89,7 @@ namespace ts.server { export const NavBar = "navbar"; export const Navto = "navto"; export const Occurrences = "occurrences"; + export const DocumentHighlights = "documentHighlights"; export const Open = "open"; export const Quickinfo = "quickinfo"; export const References = "references"; @@ -313,7 +314,7 @@ namespace ts.server { })); } - private getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[]{ + private getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[] { fileName = ts.normalizePath(fileName); let project = this.projectService.getProjectForFile(fileName); @@ -343,6 +344,42 @@ namespace ts.server { }); } + private getDocumentHighlights(line: number, offset: number, fileName: string): protocol.DocumentHighlightsItem[] { + fileName = ts.normalizePath(fileName); + let project = this.projectService.getProjectForFile(fileName); + + if (!project) { + throw Errors.NoProject; + } + + let { compilerService } = project; + let position = compilerService.host.lineOffsetToPosition(fileName, line, offset); + let filesToSearch = [fileName]; // only search for highlights inside the current file + + let documentHighlights = compilerService.languageService.getDocumentHighlights(fileName, position, filesToSearch); + + if (!documentHighlights) { + return undefined; + } + + return documentHighlights.map(documentHighlight => { // convert ts.DocumentHighlights to ts.server.protocol.DocumentHighlightsItem + var file = documentHighlight.fileName; + return { + file: file, + highlightSpans: documentHighlight.highlightSpans.map(highlightSpan => { // convert to ts.HighlightSpan to ts.server.protocol.HighlightSpan + let { textSpan, kind } = highlightSpan; + let start = compilerService.host.positionToLineOffset(file, textSpan.start); + let end = compilerService.host.positionToLineOffset(file, ts.textSpanEnd(textSpan)); + return { + start: start, + end: end, + kind: kind + } + }) + } + }); + } + private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo { fileName = ts.normalizePath(fileName) let project = this.projectService.getProjectForFile(fileName) @@ -937,6 +974,10 @@ namespace ts.server { var { line, offset, file: fileName } = request.arguments; return {response: this.getOccurrences(line, offset, fileName), responseRequired: true}; }, + [CommandNames.DocumentHighlights]: (request: protocol.Request) => { + var { line, offset, file: fileName } = request.arguments; + return {response: this.getDocumentHighlights(line, offset, fileName), responseRequired: true}; + }, [CommandNames.ProjectInfo]: (request: protocol.Request) => { var { file, needFileNameList } = request.arguments; return {response: this.getProjectInfo(file, needFileNameList), responseRequired: true}; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index cbba2e916ce..e809834e568 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -421,6 +421,14 @@ module FourSlashInterface { FourSlash.currentTestState.verifyOccurrencesAtPositionListCount(expectedCount); } + public documentHighlightsAtPositionContains(range: Range, fileNamesToSearch: string[], kind?: string) { + FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListContains(range.fileName, range.start, range.end, fileNamesToSearch, kind); + } + + public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[], kind?: string) { + FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); + } + public completionEntryDetailIs(entryName: string, text: string, documentation?: string, kind?: string) { FourSlash.currentTestState.verifyCompletionEntryDetails(entryName, text, documentation, kind); } diff --git a/tests/cases/fourslash/server/documentHighlights01.ts b/tests/cases/fourslash/server/documentHighlights01.ts new file mode 100644 index 00000000000..d4be88f9357 --- /dev/null +++ b/tests/cases/fourslash/server/documentHighlights01.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: a.ts +////function [|f|](x: typeof [|f|]) { +//// [|f|]([|f|]); +////} + +let ranges = test.ranges(); + +for (let r of ranges) { + goTo.position(r.start); + verify.documentHighlightsAtPositionCount(ranges.length, ["a.ts"]); + + for (let range of ranges) { + verify.documentHighlightsAtPositionContains(range, ["a.ts"]); + } +} + From 67d986af4344d15b2459f813e7f4a48d6fa2ac3e Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Tue, 4 Aug 2015 14:20:49 -0700 Subject: [PATCH 2/6] Fix `occurance` typo. --- src/harness/fourslash.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index a82346d888e..2cd06e93d41 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2122,31 +2122,31 @@ module FourSlash { public verifyOccurrencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) { this.taoInvalidReason = 'verifyOccurrencesAtPositionListContains NYI'; - let occurances = this.getOccurancesAtCurrentPosition(); + let occurrences = this.getOccurancesAtCurrentPosition(); - if (!occurances || occurances.length === 0) { + if (!occurrences || occurrences.length === 0) { this.raiseError('verifyOccurancesAtPositionListContains failed - found 0 references, expected at least one.'); } - for (let i = 0; i < occurances.length; i++) { - let occurance = occurances[i]; - if (occurance && occurance.fileName === fileName && occurance.textSpan.start === start && ts.textSpanEnd(occurance.textSpan) === end) { - if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) { - this.raiseError('verifyOccurancesAtPositionListContains failed - item isWriteAccess value does not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); + for (let i = 0; i < occurrences.length; i++) { + let occurrence = occurrences[i]; + if (occurrence && occurrence.fileName === fileName && occurrence.textSpan.start === start && ts.textSpanEnd(occurrence.textSpan) === end) { + if (typeof isWriteAccess !== "undefined" && occurrence.isWriteAccess !== isWriteAccess) { + this.raiseError('verifyOccurrencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ' + occurrence.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } return; } } let missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess }; - this.raiseError('verifyOccurancesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(occurances) + ')'); + this.raiseError('verifyOccurrencesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(occurrences) + ')'); } public verifyOccurrencesAtPositionListCount(expectedCount: number) { this.taoInvalidReason = 'verifyOccurrencesAtPositionListCount NYI'; - let occurances = this.getOccurancesAtCurrentPosition(); - let actualCount = occurances ? occurances.length : 0; + let occurrences = this.getOccurancesAtCurrentPosition(); + let actualCount = occurrences ? occurrences.length : 0; if (expectedCount !== actualCount) { this.raiseError('verifyOccurrencesAtPositionListCount failed - actual: ' + actualCount + ', expected:' + expectedCount); } From 8550c7de4e6ea0afe139ed1574c6e4f3bfdbb070 Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Tue, 4 Aug 2015 15:46:38 -0700 Subject: [PATCH 3/6] Address feedback. --- src/harness/fourslash.ts | 22 ++++++++-------- src/server/client.ts | 41 ++++++++++++++++-------------- src/server/protocol.d.ts | 4 +-- src/server/session.ts | 31 +++++++++++----------- tests/cases/fourslash/fourslash.ts | 2 +- 5 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 2cd06e93d41..f7564ef52f0 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2166,15 +2166,17 @@ module FourSlash { this.raiseError('verifyDocumentHighlightsAtPositionListContains failed - found 0 highlights, expected at least one.'); } - for (let i = 0; i < documentHighlights.length; i++) if (documentHighlights[i].fileName === fileName) { - let { highlightSpans } = documentHighlights[i]; + for (let documentHighlight of documentHighlights) { + if (documentHighlight.fileName === fileName) { + let { highlightSpans } = documentHighlight; - for (let highlight of highlightSpans) { - if (highlight && highlight.textSpan.start === start && ts.textSpanEnd(highlight.textSpan) === end) { - if (typeof kind !== "undefined" && highlight.kind !== kind) { - this.raiseError('verifyDocumentHighlightsAtPositionListContains failed - item "kind" value does not match, actual: ' + highlight.kind + ', expected: ' + kind + '.'); + for (let highlight of highlightSpans) { + if (highlight && highlight.textSpan.start === start && ts.textSpanEnd(highlight.textSpan) === end) { + if (typeof kind !== "undefined" && highlight.kind !== kind) { + this.raiseError('verifyDocumentHighlightsAtPositionListContains failed - item "kind" value does not match, actual: ' + highlight.kind + ', expected: ' + kind + '.'); + } + return; } - return; } } } @@ -2187,9 +2189,9 @@ module FourSlash { this.taoInvalidReason = 'verifyDocumentHighlightsAtPositionListCount NYI'; let documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); - let actualCount = documentHighlights - ? documentHighlights.reduce((currentCount, currentDocumentHighlights) => { - return currentCount + currentDocumentHighlights.highlightSpans.length}, 0) + let actualCount = documentHighlights + ? documentHighlights.reduce((currentCount, { fileName, highlightSpans }) => { + return currentCount + highlightSpans.length}, 0) : 0; if (expectedCount !== actualCount) { diff --git a/src/server/client.ts b/src/server/client.ts index f02961f02ad..d11a3c75466 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -528,29 +528,32 @@ namespace ts.server { } getDocumentHighlights(fileName: string, position: number): DocumentHighlights[] { - var lineOffset = this.positionToOneBasedLineOffset(fileName, position); - var args: protocol.FileLocationRequestArgs = { - file: fileName, - line: lineOffset.line, - offset: lineOffset.offset, - }; + let { line, offset } = this.positionToOneBasedLineOffset(fileName, position); + let args: protocol.FileLocationRequestArgs = { file: fileName, line, offset }; - var request = this.processRequest(CommandNames.DocumentHighlights, args); - var response = this.processResponse(request); + let request = this.processRequest(CommandNames.DocumentHighlights, args); + let response = this.processResponse(request); + + let _self = this; + return response.body.map(convertToDocumentHighlights); + + function convertToDocumentHighlights(item: ts.server.protocol.DocumentHighlightsItem): ts.DocumentHighlights { + let { file, highlightSpans } = item; - return response.body.map(entry => { // convert ts.server.protocol.DocumentHighlightsItem to ts.DocumentHighlights return { - fileName: entry.file, - highlightSpans: entry.highlightSpans.map(span => { // convert ts.server.protocol.HighlightSpan to ts.HighlighSpan - var start = this.lineOffsetToPosition(entry.file, span.start); - var end = this.lineOffsetToPosition(entry.file, span.end); - return { - textSpan: ts.createTextSpanFromBounds(start, end), - kind: span.kind - }; - }) + fileName: file, + highlightSpans: highlightSpans.map(convertHighlightSpan2) }; - }); + + function convertHighlightSpan2(span: ts.server.protocol.HighlightSpan): ts.HighlightSpan { + let start = _self.lineOffsetToPosition(file, span.start); + let end = _self.lineOffsetToPosition(file, span.end); + return { + textSpan: ts.createTextSpanFromBounds(start, end), + kind: span.kind + }; + } + } } getOutliningSpans(fileName: string): OutliningSpan[] { diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index 0822f537365..bdabf89a982 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -246,13 +246,13 @@ declare namespace ts.server.protocol { export interface DocumentHighlightsRequest extends FileLocationRequest { } - export interface HighLightSpan extends TextSpan { + export interface HighlightSpan extends TextSpan { kind: string } export interface DocumentHighlightsItem { file: string, - highlightSpans: HighLightSpan[]; + highlightSpans: HighlightSpan[]; } export interface DocumentHighlightsResponse extends Response { diff --git a/src/server/session.ts b/src/server/session.ts index c91cf385c0f..8a9c15b2449 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -354,7 +354,7 @@ namespace ts.server { let { compilerService } = project; let position = compilerService.host.lineOffsetToPosition(fileName, line, offset); - let filesToSearch = [fileName]; // only search for highlights inside the current file + let filesToSearch = [ fileName ]; // only search for highlights inside the current file let documentHighlights = compilerService.languageService.getDocumentHighlights(fileName, position, filesToSearch); @@ -362,22 +362,23 @@ namespace ts.server { return undefined; } - return documentHighlights.map(documentHighlight => { // convert ts.DocumentHighlights to ts.server.protocol.DocumentHighlightsItem - var file = documentHighlight.fileName; + return documentHighlights.map(convertToDocumentHighlightsItem); + + function convertToDocumentHighlightsItem(documentHighlights: ts.DocumentHighlights): ts.server.protocol.DocumentHighlightsItem { + let { fileName, highlightSpans } = documentHighlights; + return { - file: file, - highlightSpans: documentHighlight.highlightSpans.map(highlightSpan => { // convert to ts.HighlightSpan to ts.server.protocol.HighlightSpan - let { textSpan, kind } = highlightSpan; - let start = compilerService.host.positionToLineOffset(file, textSpan.start); - let end = compilerService.host.positionToLineOffset(file, ts.textSpanEnd(textSpan)); - return { - start: start, - end: end, - kind: kind - } - }) + file: fileName, + highlightSpans: highlightSpans.map(convertHighlightSpan1) + }; + + function convertHighlightSpan1(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan { + let { textSpan, kind } = highlightSpan; + let start = compilerService.host.positionToLineOffset(fileName, textSpan.start); + let end = compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(textSpan)); + return { start, end, kind }; } - }); + } } private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo { diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index e809834e568..44ce4525754 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -425,7 +425,7 @@ module FourSlashInterface { FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListContains(range.fileName, range.start, range.end, fileNamesToSearch, kind); } - public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[], kind?: string) { + public documentHighlightsAtPositionCount(expectedCount: number, fileNamesToSearch: string[]) { FourSlash.currentTestState.verifyDocumentHighlightsAtPositionListCount(expectedCount, fileNamesToSearch); } From 71e6f3a94760660d206104213edb1a44ef214e3a Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Wed, 5 Aug 2015 17:09:01 -0700 Subject: [PATCH 4/6] Address PR feedback. --- src/harness/fourslash.ts | 8 +++---- src/server/client.ts | 10 ++++---- src/server/session.ts | 4 ++-- .../fourslash/server/documentHighlights02.ts | 23 +++++++++++++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 tests/cases/fourslash/server/documentHighlights02.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index f7564ef52f0..49ecc7d9a47 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2128,8 +2128,7 @@ module FourSlash { this.raiseError('verifyOccurancesAtPositionListContains failed - found 0 references, expected at least one.'); } - for (let i = 0; i < occurrences.length; i++) { - let occurrence = occurrences[i]; + for (let occurrence of occurrences) { if (occurrence && occurrence.fileName === fileName && occurrence.textSpan.start === start && ts.textSpanEnd(occurrence.textSpan) === end) { if (typeof isWriteAccess !== "undefined" && occurrence.isWriteAccess !== isWriteAccess) { this.raiseError('verifyOccurrencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ' + occurrence.isWriteAccess + ', expected: ' + isWriteAccess + '.'); @@ -2189,9 +2188,8 @@ module FourSlash { this.taoInvalidReason = 'verifyDocumentHighlightsAtPositionListCount NYI'; let documentHighlights = this.getDocumentHighlightsAtCurrentPosition(fileNamesToSearch); - let actualCount = documentHighlights - ? documentHighlights.reduce((currentCount, { fileName, highlightSpans }) => { - return currentCount + highlightSpans.length}, 0) + let actualCount = documentHighlights + ? documentHighlights.reduce((currentCount, { highlightSpans }) => currentCount + highlightSpans.length, 0) : 0; if (expectedCount !== actualCount) { diff --git a/src/server/client.ts b/src/server/client.ts index d11a3c75466..2ec0dd4de62 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -534,7 +534,7 @@ namespace ts.server { let request = this.processRequest(CommandNames.DocumentHighlights, args); let response = this.processResponse(request); - let _self = this; + let self = this; return response.body.map(convertToDocumentHighlights); function convertToDocumentHighlights(item: ts.server.protocol.DocumentHighlightsItem): ts.DocumentHighlights { @@ -542,12 +542,12 @@ namespace ts.server { return { fileName: file, - highlightSpans: highlightSpans.map(convertHighlightSpan2) + highlightSpans: highlightSpans.map(convertHighlightSpan) }; - function convertHighlightSpan2(span: ts.server.protocol.HighlightSpan): ts.HighlightSpan { - let start = _self.lineOffsetToPosition(file, span.start); - let end = _self.lineOffsetToPosition(file, span.end); + function convertHighlightSpan(span: ts.server.protocol.HighlightSpan): ts.HighlightSpan { + let start = self.lineOffsetToPosition(file, span.start); + let end = self.lineOffsetToPosition(file, span.end); return { textSpan: ts.createTextSpanFromBounds(start, end), kind: span.kind diff --git a/src/server/session.ts b/src/server/session.ts index 8a9c15b2449..963c443f09b 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -369,10 +369,10 @@ namespace ts.server { return { file: fileName, - highlightSpans: highlightSpans.map(convertHighlightSpan1) + highlightSpans: highlightSpans.map(convertHighlightSpan) }; - function convertHighlightSpan1(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan { + function convertHighlightSpan(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan { let { textSpan, kind } = highlightSpan; let start = compilerService.host.positionToLineOffset(fileName, textSpan.start); let end = compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(textSpan)); diff --git a/tests/cases/fourslash/server/documentHighlights02.ts b/tests/cases/fourslash/server/documentHighlights02.ts new file mode 100644 index 00000000000..8cf7038395a --- /dev/null +++ b/tests/cases/fourslash/server/documentHighlights02.ts @@ -0,0 +1,23 @@ +/// + +// @Filename: a.ts +////function foo() { +//// return 1; +////} + +// @Filename: b.ts +/////// +////[|foo|](); + + +let ranges = test.ranges(); + +for (let r of ranges) { + goTo.position(r.start); + verify.documentHighlightsAtPositionCount(2, ["b.ts"]); + + /*for (let range of ranges) { + verify.documentHighlightsAtPositionContains(range, ["a.ts"]); + }*/ +} + From bf7d923e09f58a029cb1556837cf4925334c3c6a Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Thu, 6 Aug 2015 14:01:36 -0700 Subject: [PATCH 5/6] Add filesToSearch to documentHighlights request. --- src/server/client.ts | 4 +-- src/server/protocol.d.ts | 20 ++++++++++++- src/server/session.ts | 7 ++--- .../fourslash/server/documentHighlights02.ts | 28 +++++++++++++------ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/server/client.ts b/src/server/client.ts index 2ec0dd4de62..cc89349b442 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -527,9 +527,9 @@ namespace ts.server { }); } - getDocumentHighlights(fileName: string, position: number): DocumentHighlights[] { + getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[] { let { line, offset } = this.positionToOneBasedLineOffset(fileName, position); - let args: protocol.FileLocationRequestArgs = { file: fileName, line, offset }; + let args: protocol.DocumentHighlightsRequestArgs = { file: fileName, line, offset, filesToSearch }; let request = this.processRequest(CommandNames.DocumentHighlights, args); let response = this.processResponse(request); diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index bdabf89a982..837bce4f99d 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -156,6 +156,17 @@ declare namespace ts.server.protocol { arguments: FileLocationRequestArgs; } + /** + * Arguments in document highlight request; include: filesToSearch, file, + * line, offset. + */ + export interface DocumentHighlightsRequestArgs extends FileLocationRequestArgs { + /** + * List of files to search for document highlights. + */ + filesToSearch: string[]; + } + /** * Go to definition request; value of command field is * "definition". Return response giving the file locations that @@ -244,6 +255,7 @@ declare namespace ts.server.protocol { * in the file at a given line and column. */ export interface DocumentHighlightsRequest extends FileLocationRequest { + arguments: DocumentHighlightsRequestArgs } export interface HighlightSpan extends TextSpan { @@ -251,7 +263,14 @@ declare namespace ts.server.protocol { } export interface DocumentHighlightsItem { + /** + * File containing highlight spans. + */ file: string, + + /** + * Spans to highlight in file. + */ highlightSpans: HighlightSpan[]; } @@ -259,7 +278,6 @@ declare namespace ts.server.protocol { body?: DocumentHighlightsItem[]; } - /** * Find references request; value of command field is * "references". Return response giving the file locations that diff --git a/src/server/session.ts b/src/server/session.ts index 963c443f09b..54e4423d382 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -344,7 +344,7 @@ namespace ts.server { }); } - private getDocumentHighlights(line: number, offset: number, fileName: string): protocol.DocumentHighlightsItem[] { + private getDocumentHighlights(line: number, offset: number, fileName: string, filesToSearch: string[]): protocol.DocumentHighlightsItem[] { fileName = ts.normalizePath(fileName); let project = this.projectService.getProjectForFile(fileName); @@ -354,7 +354,6 @@ namespace ts.server { let { compilerService } = project; let position = compilerService.host.lineOffsetToPosition(fileName, line, offset); - let filesToSearch = [ fileName ]; // only search for highlights inside the current file let documentHighlights = compilerService.languageService.getDocumentHighlights(fileName, position, filesToSearch); @@ -976,8 +975,8 @@ namespace ts.server { return {response: this.getOccurrences(line, offset, fileName), responseRequired: true}; }, [CommandNames.DocumentHighlights]: (request: protocol.Request) => { - var { line, offset, file: fileName } = request.arguments; - return {response: this.getDocumentHighlights(line, offset, fileName), responseRequired: true}; + var { line, offset, file: fileName, filesToSearch } = request.arguments; + return {response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true}; }, [CommandNames.ProjectInfo]: (request: protocol.Request) => { var { file, needFileNameList } = request.arguments; diff --git a/tests/cases/fourslash/server/documentHighlights02.ts b/tests/cases/fourslash/server/documentHighlights02.ts index 8cf7038395a..357f82e9c2d 100644 --- a/tests/cases/fourslash/server/documentHighlights02.ts +++ b/tests/cases/fourslash/server/documentHighlights02.ts @@ -1,23 +1,35 @@ /// // @Filename: a.ts -////function foo() { +////function [|foo|] () { //// return 1; ////} +////[|foo|](); // @Filename: b.ts /////// -////[|foo|](); +////foo(); +// open two files +goTo.file("a.ts"); +goTo.file("b.ts"); let ranges = test.ranges(); -for (let r of ranges) { +for (let i = 0; i < ranges.length; ++i) { + let r = ranges[i]; + + if (i < 2) { + goTo.file("a.ts"); + } + else { + goTo.file("b.ts"); + } + goTo.position(r.start); - verify.documentHighlightsAtPositionCount(2, ["b.ts"]); + verify.documentHighlightsAtPositionCount(3, ["a.ts", "b.ts"]); - /*for (let range of ranges) { - verify.documentHighlightsAtPositionContains(range, ["a.ts"]); - }*/ + for (let range of ranges) { + verify.documentHighlightsAtPositionContains(range, ["a.ts", "b.ts"]); + } } - From 91452bf3ae7efc7b63ab7a005b2eec519f55fa9c Mon Sep 17 00:00:00 2001 From: Tien Nguyen Date: Thu, 6 Aug 2015 14:15:00 -0700 Subject: [PATCH 6/6] Use combinesPath. --- src/harness/fourslash.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 49ecc7d9a47..f9470ab2d58 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2152,7 +2152,7 @@ module FourSlash { } private getDocumentHighlightsAtCurrentPosition(fileNamesToSearch: string[]) { - let filesToSearch = fileNamesToSearch.map(name => this.basePath + "/" + name); + let filesToSearch = fileNamesToSearch.map(name => ts.combinePaths(this.basePath, name)); return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch); }