diff --git a/extensions/html/package.json b/extensions/html/package.json
index bce7398ef258c8446d9bc424767e17dc80ab286a..0c1ad9ea506e1cd6e10bbe2ebb012e38022b1573 100644
--- a/extensions/html/package.json
+++ b/extensions/html/package.json
@@ -104,7 +104,7 @@
}
},
"dependencies": {
- "vscode-languageclient": "^2.4.2-next.22",
+ "vscode-languageclient": "^2.6.0-next.1",
"vscode-nls": "^1.0.7"
}
}
diff --git a/extensions/html/server/package.json b/extensions/html/server/package.json
index f885a65adc3c3f66c3b6eb59759828688ae23c78..755a6eaadd8d406b0142d9107a30ed73771c83ce 100644
--- a/extensions/html/server/package.json
+++ b/extensions/html/server/package.json
@@ -8,7 +8,7 @@
"node": "*"
},
"dependencies": {
- "vscode-languageserver": "^2.4.0-next.12",
+ "vscode-languageserver": "^2.6.0-next.3",
"vscode-nls": "^1.0.4",
"vscode-uri": "^0.0.7"
},
diff --git a/extensions/html/server/src/htmlServerMain.ts b/extensions/html/server/src/htmlServerMain.ts
index c9389ca38b1258595879f6b8da505ba6ee5783e1..a26b216278259030557072c99134308d9daf58a2 100644
--- a/extensions/html/server/src/htmlServerMain.ts
+++ b/extensions/html/server/src/htmlServerMain.ts
@@ -27,10 +27,12 @@ let documents: TextDocuments = new TextDocuments();
// for open, change and close text document events
documents.listen(connection);
+let workspacePath: string;
// After the server has started the client sends an initilize request. The server receives
// in the passed params the rootPath of the workspace plus the client capabilites
connection.onInitialize((params: InitializeParams): InitializeResult => {
+ workspacePath = params.rootPath;
return {
capabilities: {
// Tell the client that the server works in FULL text document sync mode
@@ -38,7 +40,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => {
completionProvider: { resolveProvider: false, triggerCharacters: ['.', ':', '<', '"', '=', '/'] },
documentHighlightProvider: true,
documentRangeFormattingProvider: true,
- documentFormattingProvider: true
+ documentFormattingProvider: true,
+ documentLinkProvider: true
}
};
});
@@ -108,5 +111,11 @@ connection.onDocumentRangeFormatting(formatParams => {
return languageService.format(document, formatParams.range, getFormattingOptions(formatParams));
});
+connection.onDocumentLinks(documentLinkParam => {
+ let document = documents.get(documentLinkParam.textDocument.uri);
+ return languageService.findDocumentLinks(document, workspacePath);
+});
+
+
// Listen on the connection
connection.listen();
\ No newline at end of file
diff --git a/extensions/html/server/src/service/htmlLanguageService.ts b/extensions/html/server/src/service/htmlLanguageService.ts
index 2a9c464bd27851a0ee38af8dd94afd0fab121077..b5244d1348d251d6fbd74f3d59babeeee8a07940 100644
--- a/extensions/html/server/src/service/htmlLanguageService.ts
+++ b/extensions/html/server/src/service/htmlLanguageService.ts
@@ -6,27 +6,11 @@
import {parse} from './parser/htmlParser';
import {doComplete} from './services/htmlCompletion';
import {format} from './services/htmlFormatter';
-import {provideLinks} from './services/htmlLinks';
+import {findDocumentLinks} from './services/htmlLinks';
import {findDocumentHighlights} from './services/htmlHighlighting';
-import {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString } from 'vscode-languageserver-types';
-
-export {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString };
-
-
-export class DocumentLink {
-
- /**
- * The range this link applies to.
- */
- range: Range;
-
- /**
- * The uri this link points to.
- */
- target: string;
-
-}
+import {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString, DocumentLink } from 'vscode-languageserver-types';
+export {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString, DocumentLink };
export interface HTMLFormatConfiguration {
tabSize: number;
@@ -52,7 +36,7 @@ export interface LanguageService {
findDocumentHighlights(document: TextDocument, position: Position, htmlDocument: HTMLDocument): DocumentHighlight[];
doComplete(document: TextDocument, position: Position, htmlDocument: HTMLDocument, options?: CompletionConfiguration): CompletionList;
format(document: TextDocument, range: Range, options: HTMLFormatConfiguration): TextEdit[];
- provideLinks(document: TextDocument, workspacePath:string): DocumentLink[];
+ findDocumentLinks(document: TextDocument, workspacePath:string): DocumentLink[];
}
export function getLanguageService() : LanguageService {
@@ -61,6 +45,6 @@ export function getLanguageService() : LanguageService {
doComplete,
format,
findDocumentHighlights,
- provideLinks
+ findDocumentLinks
};
}
\ No newline at end of file
diff --git a/extensions/html/server/src/service/services/htmlLinks.ts b/extensions/html/server/src/service/services/htmlLinks.ts
index 18e8c921af553355c19604acdfaffe9c13d66935..650a2296e816f8d93cefe80de0820fd900cb0313 100644
--- a/extensions/html/server/src/service/services/htmlLinks.ts
+++ b/extensions/html/server/src/service/services/htmlLinks.ts
@@ -12,15 +12,13 @@ import Uri from 'vscode-uri';
import {DocumentLink} from '../htmlLanguageService';
-function _stripQuotes(url: string): string {
+function stripQuotes(url: string): string {
return url
.replace(/^'([^']+)'$/,(substr, match1) => match1)
.replace(/^"([^"]+)"$/,(substr, match1) => match1);
}
-export function _getWorkspaceUrl(modelAbsoluteUri: Uri, rootAbsoluteUrl: Uri, tokenContent: string): string {
- tokenContent = _stripQuotes(tokenContent);
-
+function getWorkspaceUrl(modelAbsoluteUri: Uri, rootAbsoluteUrl: Uri, tokenContent: string): string {
if (/^\s*javascript\:/i.test(tokenContent) || /^\s*\#/i.test(tokenContent)) {
return null;
}
@@ -64,9 +62,14 @@ export function _getWorkspaceUrl(modelAbsoluteUri: Uri, rootAbsoluteUrl: Uri, to
return potentialResult;
}
-function createLink(document: TextDocument, rootAbsoluteUrl: Uri, tokenContent: string, startOffset: number, endOffset: number): DocumentLink {
+function createLink(document: TextDocument, rootAbsoluteUrl: Uri, attributeValue: string, startOffset: number, endOffset: number): DocumentLink {
let documentUri = Uri.parse(document.uri);
- let workspaceUrl = _getWorkspaceUrl(documentUri, rootAbsoluteUrl, tokenContent);
+ let tokenContent = stripQuotes(attributeValue);
+ if (tokenContent.length < attributeValue.length) {
+ startOffset++;
+ endOffset--;
+ }
+ let workspaceUrl = getWorkspaceUrl(documentUri, rootAbsoluteUrl, tokenContent);
if (!workspaceUrl) {
return null;
}
@@ -76,7 +79,7 @@ function createLink(document: TextDocument, rootAbsoluteUrl: Uri, tokenContent:
};
}
-export function provideLinks(document: TextDocument, workspacePath:string): DocumentLink[] {
+export function findDocumentLinks(document: TextDocument, workspacePath:string): DocumentLink[] {
let newLinks: DocumentLink[] = [];
let rootAbsoluteUrl: Uri = null;
@@ -94,13 +97,13 @@ export function provideLinks(document: TextDocument, workspacePath:string): Docu
while (token !== TokenType.EOS) {
switch (token) {
case TokenType.AttributeName:
- let tokenContent = scanner.getTokenText();
- afterHrefOrSrc = tokenContent === 'src' || tokenContent === 'href';
+ let attributeName = scanner.getTokenText();
+ afterHrefOrSrc = attributeName === 'src' || attributeName === 'href';
break;
case TokenType.AttributeValue:
if (afterHrefOrSrc) {
- let tokenContent = scanner.getTokenText();
- let link = createLink(document, rootAbsoluteUrl, tokenContent, scanner.getTokenOffset(), scanner.getTokenEnd());
+ let attributeValue = scanner.getTokenText();
+ let link = createLink(document, rootAbsoluteUrl, attributeValue, scanner.getTokenOffset(), scanner.getTokenEnd());
if (link) {
newLinks.push(link);
}
@@ -108,6 +111,7 @@ export function provideLinks(document: TextDocument, workspacePath:string): Docu
}
break;
}
+ token = scanner.scan();
}
return newLinks;
}
\ No newline at end of file
diff --git a/extensions/html/server/src/service/test/completion.test.ts b/extensions/html/server/src/service/test/completion.test.ts
index 73fb2e7804d219a138b39d5004a331d56a46fed1..52db1dddc5fba6ec932196fd3878d477813d72bb 100644
--- a/extensions/html/server/src/service/test/completion.test.ts
+++ b/extensions/html/server/src/service/test/completion.test.ts
@@ -67,21 +67,16 @@ let testCompletionFor = function (value: string, expected: { count?: number, ite
let document = TextDocument.create('test://test/test.html', 'html', 0, value);
let position = document.positionAt(offset);
let htmlDoc = ls.parseHTMLDocument(document);
- return asPromise(ls.doComplete(document, position, htmlDoc, settings)).then(list => {
- try {
- if (expected.count) {
- assert.equal(list.items, expected.count);
- }
- if (expected.items) {
- for (let item of expected.items) {
- assertCompletion(list, item, document, offset);
- }
- }
- } catch (e) {
- return Promise.reject(e);
+ let list = ls.doComplete(document, position, htmlDoc, settings);
+ if (expected.count) {
+ assert.equal(list.items, expected.count);
+ }
+ if (expected.items) {
+ for (let item of expected.items) {
+ assertCompletion(list, item, document, offset);
}
-
- });
+ }
+ return Promise.resolve();
};
function run(tests: Thenable[], testDone) {
Promise.all(tests).then(() => {
@@ -275,12 +270,11 @@ suite('HTML Completion', () => {
], testDone);
});
- suite('Handlevar Completion', (testDone) => {
+ test('Handlebar Completion', function (testDone) {
run([
-
- testCompletionFor('' , {
+ testCompletionFor('' , {
items: [
- { label: 'div', resultText: '' },
+ { label: 'div', resultText: '' },
]
})
], testDone);
diff --git a/extensions/html/server/src/service/test/highlighting.test.ts b/extensions/html/server/src/service/test/highlighting.test.ts
index 0ba7d1b398f220fddec77176cfd3959f55efe94d..a8ca00452ac7816ce6e723ecd94e962f5119e838 100644
--- a/extensions/html/server/src/service/test/highlighting.test.ts
+++ b/extensions/html/server/src/service/test/highlighting.test.ts
@@ -13,7 +13,6 @@ export function assertHighlights(value: string, expectedMatches: number[], eleme
value = value.substr(0, offset) + value.substr(offset + 1);
let document = TextDocument.create('test://test/test.html', 'html', 0, value);
- let htmlDocument = htmlLanguageService.getLanguageService().parseHTMLDocument(document);
let position = document.positionAt(offset);
let ls = htmlLanguageService.getLanguageService();
diff --git a/extensions/html/server/src/service/test/links.test.ts b/extensions/html/server/src/service/test/links.test.ts
index 66cabef6ce022082001a28f9f008d3ac5553d604..6d7040a816df14828ffc1c72d3fc450aba0da04e 100644
--- a/extensions/html/server/src/service/test/links.test.ts
+++ b/extensions/html/server/src/service/test/links.test.ts
@@ -9,13 +9,23 @@ import * as assert from 'assert';
import * as htmlLinks from '../services/htmlLinks';
import {CompletionList, TextDocument, TextEdit, Position, CompletionItemKind} from 'vscode-languageserver-types';
import Uri from 'vscode-uri';
+import * as htmlLanguageService from '../htmlLanguageService';
suite('HTML Link Detection', () => {
function testLinkCreation(modelUrl:string, rootUrl:string, tokenContent:string, expected:string): void {
- var _modelUrl = Uri.parse(modelUrl);
- var actual = htmlLinks._getWorkspaceUrl(_modelUrl, Uri.parse(rootUrl), tokenContent);
- assert.equal(actual, expected);
+ let document = TextDocument.create(modelUrl, 'html', 0, ``);
+ let ls = htmlLanguageService.getLanguageService();
+ let links = ls.findDocumentLinks(document, rootUrl);
+ assert.equal(links[0] && links[0].target, expected);
+ }
+
+ function testLinkDetection(value:string, expectedLinkLocations:number[]): void {
+ let document = TextDocument.create('test://test/test.html', 'html', 0, value);
+
+ let ls = htmlLanguageService.getLanguageService();
+ let links = ls.findDocumentLinks(document, 'test://test');
+ assert.deepEqual(links.map(l => l.range.start.character), expectedLinkLocations);
}
test('Link creation', () => {
@@ -68,4 +78,10 @@ suite('HTML Link Detection', () => {
// Bug #18314: Ctrl + Click does not open existing file if folder's name starts with 'c' character
testLinkCreation('file:///c:/Alex/working_dir/18314-link-detection/test.html', 'file:///c:/Alex/working_dir/18314-link-detection/', '/class/class.js', 'file:///c:/Alex/working_dir/18314-link-detection/class/class.js');
});
+
+ test('Link detection', () => {
+ testLinkDetection('
', [ 9 ]);
+ testLinkDetection('', [ 8 ]);
+ });
+
});
\ No newline at end of file