[html] add symbol highlighting

This commit is contained in:
Martin Aeschlimann 2016-09-13 10:03:41 +02:00
parent 06727ce174
commit 6c8a859079
4 changed files with 98 additions and 13 deletions

View file

@ -3,12 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { parse} from './parser/htmlParser';
import { doComplete } from './services/htmlCompletion';
import { format } from './services/htmlFormatter';
import { TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, FormattingOptions, MarkedString } from 'vscode-languageserver-types';
import {parse} from './parser/htmlParser';
import {doComplete} from './services/htmlCompletion';
import {format} from './services/htmlFormatter';
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, FormattingOptions, MarkedString };
export {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, TextEdit, DocumentHighlight, FormattingOptions, MarkedString };
export interface HTMLFormatConfiguration {
@ -35,10 +36,8 @@ export interface LanguageService {
configure(settings: LanguageSettings): void;
parseHTMLDocument(document: TextDocument): HTMLDocument;
doValidation(document: TextDocument, htmlDocument: HTMLDocument): Diagnostic[];
// doResolve(item: CompletionItem): CompletionItem;
doComplete(document: TextDocument, position: Position, doc: HTMLDocument): CompletionList;
// findDocumentSymbols(document: TextDocument, doc: HTMLDocument): SymbolInformation[];
findDocumentHighlights(document: TextDocument, position: Position, htmlDocument: HTMLDocument): DocumentHighlight[];
doComplete(document: TextDocument, position: Position, htmlDocument: HTMLDocument): CompletionList;
// doHover(document: TextDocument, position: Position, doc: HTMLDocument): Hover;
format(document: TextDocument, range: Range, options: HTMLFormatConfiguration): TextEdit[];
}
@ -46,10 +45,10 @@ export interface LanguageService {
export function getLanguageService() : LanguageService {
return {
doValidation: (document, htmlDocument) => { return []; },
configure: (settings) => {},
parseHTMLDocument: (document) => parse(document.getText()),
doComplete,
format
format,
findDocumentHighlights
};
}

View file

@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {HTMLDocument} from '../parser/htmlParser';
import {TokenType, createScanner} from '../parser/htmlScanner';
import {TextDocument, Range, Position, DocumentHighlightKind, DocumentHighlight} from 'vscode-languageserver-types';
export function findDocumentHighlights(document: TextDocument, position: Position, htmlDocument: HTMLDocument): DocumentHighlight[] {
let offset = document.offsetAt(position);
let node = htmlDocument.findNodeAt(offset);
if (!node.tag || typeof node.endTagStart !== 'number') {
return [];
}
let startTagRange = getTagNameRange(TokenType.StartTag, document, node.start);
let endTagRange = getTagNameRange(TokenType.EndTag, document, node.endTagStart);
if (startTagRange && endTagRange && (covers(startTagRange, position) || covers(endTagRange, position))) {
return [ { kind: DocumentHighlightKind.Read, range: startTagRange }, { kind: DocumentHighlightKind.Read, range: endTagRange }];
}
return [];
}
function isBeforeOrEqual(pos1: Position, pos2: Position) {
return pos1.line < pos2.line || (pos1.line === pos2.line && pos1.character <= pos2.character);
}
function covers(range: Range, position: Position) {
return isBeforeOrEqual(range.start, position) && isBeforeOrEqual(position, range.end);
}
function getTagNameRange(tokenType: TokenType, document: TextDocument, startOffset: number ) : Range {
let scanner = createScanner(document.getText(), startOffset);
let token = scanner.scan();
while (token !== TokenType.EOS && token !== TokenType.StartTag) {
token = scanner.scan();
}
if (token !== TokenType.EOS) {
return { start: document.positionAt(scanner.getTokenOffset()), end: document.positionAt(scanner.getTokenEnd()) };
}
return null;
}

View file

@ -60,8 +60,8 @@ 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 jsonDoc = ls.parseHTMLDocument(document);
return asPromise(ls.doComplete(document, position, jsonDoc)).then(list => {
let htmlDoc = ls.parseHTMLDocument(document);
return asPromise(ls.doComplete(document, position, htmlDoc)).then(list => {
try {
if (expected.count) {
assert.equal(list.items, expected.count);

View file

@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import * as htmlLanguageService from '../htmlLanguageService';
import {CompletionList, TextDocument, TextEdit, Position, CompletionItemKind} from 'vscode-languageserver-types';
export function assertHighlights(value: string, expectedMatches: number[], elementName: string): Thenable<void> {
let offset = value.indexOf('|');
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();
let htmlDoc = ls.parseHTMLDocument(document);
let highlights = ls.findDocumentHighlights(document, position, htmlDoc);
assert.equal(highlights.length, expectedMatches.length);
for (let i = 0; i < highlights.length; i++) {
let actualStartOffset = document.offsetAt(highlights[i].range.start);
assert.equal(actualStartOffset, expectedMatches[i]);
let actualEndOffset = document.offsetAt(highlights[i].range.end);
assert.equal(actualEndOffset, expectedMatches[i] + elementName.length);
assert.equal(document.getText().substring(actualStartOffset, actualEndOffset), elementName);
}
}
suite('HTML Highlighting', () => {
test('Highlighting', function (testDone): any {
testHighlighting
}