vscode-html-languageservice
Advanced tools
Comparing version 3.0.3 to 3.0.4-next.0
@@ -9,2 +9,22 @@ { | ||
"required": ["version"], | ||
"definitions": { | ||
"markupDescription": { | ||
"type": "object", | ||
"required": ["kind", "value"], | ||
"properties": { | ||
"kind": { | ||
"type": "string", | ||
"description": "Whether `description.value` should be rendered as plaintext or markdown", | ||
"enum": [ | ||
"plaintext", | ||
"markdown" | ||
] | ||
}, | ||
"value": { | ||
"type": "string", | ||
"description": "Description shown in completion and hover" | ||
} | ||
} | ||
} | ||
}, | ||
"properties": { | ||
@@ -37,4 +57,9 @@ "version": { | ||
"description": { | ||
"type": "string", | ||
"description": "Description of tag shown in completion and hover" | ||
"description": "Description of tag shown in completion and hover", | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ "$ref": "#/definitions/markupDescription" } | ||
] | ||
}, | ||
@@ -62,4 +87,9 @@ "attributes": { | ||
"description": { | ||
"type": "string", | ||
"description": "Description of attribute shown in completion and hover" | ||
"description": "Description of attribute shown in completion and hover", | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ "$ref": "#/definitions/markupDescription" } | ||
] | ||
}, | ||
@@ -90,4 +120,9 @@ "valueSet": { | ||
"description": { | ||
"type": "string", | ||
"description": "Description of attribute value shown in completion and hover" | ||
"description": "Description of attribute value shown in completion and hover", | ||
"anyOf": [ | ||
{ | ||
"type": "string" | ||
}, | ||
{ "$ref": "#/definitions/markupDescription" } | ||
] | ||
} | ||
@@ -94,0 +129,0 @@ } |
import { TextDocument, Position, CompletionList, Hover, Range, SymbolInformation, TextEdit, DocumentHighlight, DocumentLink, FoldingRange, SelectionRange } from 'vscode-languageserver-types'; | ||
import { Scanner, HTMLDocument, CompletionConfiguration, ICompletionParticipant, HTMLFormatConfiguration, DocumentContext, IHTMLDataProvider, HTMLDataV1 } from './htmlLanguageTypes'; | ||
import { Scanner, HTMLDocument, CompletionConfiguration, ICompletionParticipant, HTMLFormatConfiguration, DocumentContext, IHTMLDataProvider, HTMLDataV1, LanguageServiceOptions } from './htmlLanguageTypes'; | ||
export * from './htmlLanguageTypes'; | ||
@@ -21,6 +21,3 @@ export * from 'vscode-languageserver-types'; | ||
} | ||
export interface LanguageServiceOptions { | ||
customDataProviders?: IHTMLDataProvider[]; | ||
} | ||
export declare function getLanguageService(options?: LanguageServiceOptions): LanguageService; | ||
export declare function newHTMLDataProvider(id: string, customData: HTMLDataV1): IHTMLDataProvider; |
@@ -8,3 +8,3 @@ /*--------------------------------------------------------------------------------------------- | ||
import { HTMLCompletion } from './services/htmlCompletion'; | ||
import { doHover } from './services/htmlHover'; | ||
import { HTMLHover } from './services/htmlHover'; | ||
import { format } from './services/htmlFormatter'; | ||
@@ -21,3 +21,4 @@ import { findDocumentLinks } from './services/htmlLinks'; | ||
export function getLanguageService(options) { | ||
var htmlCompletion = new HTMLCompletion(); | ||
var htmlHover = new HTMLHover(options && options.clientCapabilities); | ||
var htmlCompletion = new HTMLCompletion(options && options.clientCapabilities); | ||
if (options && options.customDataProviders) { | ||
@@ -31,3 +32,3 @@ handleCustomDataProviders(options.customDataProviders); | ||
setCompletionParticipants: htmlCompletion.setCompletionParticipants.bind(htmlCompletion), | ||
doHover: doHover, | ||
doHover: htmlHover.doHover.bind(htmlHover), | ||
format: format, | ||
@@ -34,0 +35,0 @@ findDocumentHighlights: findDocumentHighlights, |
@@ -1,2 +0,2 @@ | ||
import { TextDocument, Position, Range } from 'vscode-languageserver-types'; | ||
import { TextDocument, Position, Range, MarkupContent, MarkupKind } from 'vscode-languageserver-types'; | ||
export interface HTMLFormatConfiguration { | ||
@@ -107,3 +107,3 @@ tabSize?: number; | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
attributes: IAttributeData[]; | ||
@@ -113,3 +113,3 @@ } | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
valueSet?: string; | ||
@@ -120,3 +120,3 @@ values?: IValueData[]; | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
} | ||
@@ -140,1 +140,51 @@ export interface IValueSet { | ||
} | ||
/** | ||
* Describes what LSP capabilities the client supports | ||
*/ | ||
export interface ClientCapabilities { | ||
/** | ||
* The text document client capabilities | ||
*/ | ||
textDocument?: { | ||
/** | ||
* Capabilities specific to completions. | ||
*/ | ||
completion?: { | ||
/** | ||
* The client supports the following `CompletionItem` specific | ||
* capabilities. | ||
*/ | ||
completionItem?: { | ||
/** | ||
* Client supports the follow content formats for the documentation | ||
* property. The order describes the preferred format of the client. | ||
*/ | ||
documentationFormat?: MarkupKind[]; | ||
}; | ||
}; | ||
/** | ||
* Capabilities specific to hovers. | ||
*/ | ||
hover?: { | ||
/** | ||
* Client supports the follow content formats for the content | ||
* property. The order describes the preferred format of the client. | ||
*/ | ||
contentFormat?: MarkupKind[]; | ||
}; | ||
}; | ||
} | ||
export declare namespace ClientCapabilities { | ||
const LATEST: ClientCapabilities; | ||
} | ||
export interface LanguageServiceOptions { | ||
/** | ||
* Provide data that could enhance the service's understanding of | ||
* HTML tag / attribute / attribute-value | ||
*/ | ||
customDataProviders?: IHTMLDataProvider[]; | ||
/** | ||
* Describes the LSP capabilities the client supports. | ||
*/ | ||
clientCapabilities?: ClientCapabilities; | ||
} |
@@ -5,2 +5,3 @@ /*--------------------------------------------------------------------------------------------- | ||
*--------------------------------------------------------------------------------------------*/ | ||
import { MarkupKind } from 'vscode-languageserver-types'; | ||
export var TokenType; | ||
@@ -45,1 +46,16 @@ (function (TokenType) { | ||
})(ScannerState || (ScannerState = {})); | ||
export var ClientCapabilities; | ||
(function (ClientCapabilities) { | ||
ClientCapabilities.LATEST = { | ||
textDocument: { | ||
completion: { | ||
completionItem: { | ||
documentationFormat: [MarkupKind.Markdown, MarkupKind.PlainText] | ||
} | ||
}, | ||
hover: { | ||
contentFormat: [MarkupKind.Markdown, MarkupKind.PlainText] | ||
} | ||
} | ||
}; | ||
})(ClientCapabilities || (ClientCapabilities = {})); |
@@ -5,3 +5,3 @@ /*--------------------------------------------------------------------------------------------- | ||
*--------------------------------------------------------------------------------------------*/ | ||
import { Position, CompletionItemKind, Range, TextEdit, InsertTextFormat } from 'vscode-languageserver-types'; | ||
import { Position, CompletionItemKind, Range, TextEdit, InsertTextFormat, MarkupKind } from 'vscode-languageserver-types'; | ||
import { createScanner } from '../parser/htmlScanner'; | ||
@@ -14,5 +14,7 @@ import { ScannerState, TokenType } from '../htmlLanguageTypes'; | ||
import { isVoidElement } from '../languageFacts/fact'; | ||
import { isDefined } from '../utils/object'; | ||
var localize = nls.loadMessageBundle(); | ||
var HTMLCompletion = /** @class */ (function () { | ||
function HTMLCompletion() { | ||
function HTMLCompletion(clientCapabilities) { | ||
this.clientCapabilities = clientCapabilities; | ||
this.completionParticipants = []; | ||
@@ -24,2 +26,6 @@ } | ||
HTMLCompletion.prototype.doComplete = function (document, position, htmlDocument, settings) { | ||
var result = this._doComplete(document, position, htmlDocument, settings); | ||
return this.convertCompletionList(result); | ||
}; | ||
HTMLCompletion.prototype._doComplete = function (document, position, htmlDocument, settings) { | ||
var result = { | ||
@@ -248,2 +254,3 @@ isIncomplete: false, | ||
kind: CompletionItemKind.Unit, | ||
documentation: value.description, | ||
textEdit: TextEdit.replace(range, insertText), | ||
@@ -445,2 +452,26 @@ insertTextFormat: InsertTextFormat.PlainText | ||
}; | ||
HTMLCompletion.prototype.convertCompletionList = function (list) { | ||
if (!this.doesSupportMarkdown()) { | ||
list.items.forEach(function (item) { | ||
if (item.documentation && typeof item.documentation !== 'string') { | ||
item.documentation = { | ||
kind: 'plaintext', | ||
value: item.documentation.value | ||
}; | ||
} | ||
}); | ||
} | ||
return list; | ||
}; | ||
HTMLCompletion.prototype.doesSupportMarkdown = function () { | ||
if (!this.clientCapabilities) { | ||
this.supportsMarkdown = true; | ||
return this.supportsMarkdown; | ||
} | ||
if (!isDefined(this.supportsMarkdown)) { | ||
var hover = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.hover; | ||
this.supportsMarkdown = hover && hover.contentFormat && Array.isArray(hover.contentFormat) && hover.contentFormat.indexOf(MarkupKind.Markdown) !== -1; | ||
} | ||
return this.supportsMarkdown; | ||
}; | ||
return HTMLCompletion; | ||
@@ -447,0 +478,0 @@ }()); |
@@ -6,58 +6,203 @@ /*--------------------------------------------------------------------------------------------- | ||
import { createScanner } from '../parser/htmlScanner'; | ||
import { MarkedString } from 'vscode-languageserver-types'; | ||
import { MarkedString, MarkupKind } from 'vscode-languageserver-types'; | ||
import { TokenType } from '../htmlLanguageTypes'; | ||
import { getAllDataProviders } from '../languageFacts/builtinDataProviders'; | ||
export function doHover(document, position, htmlDocument) { | ||
var offset = document.offsetAt(position); | ||
var node = htmlDocument.findNodeAt(offset); | ||
if (!node || !node.tag) { | ||
return null; | ||
import { isDefined } from '../utils/object'; | ||
import { isArray } from 'util'; | ||
var HTMLHover = /** @class */ (function () { | ||
function HTMLHover(clientCapabilities) { | ||
this.clientCapabilities = clientCapabilities; | ||
} | ||
var dataProviders = getAllDataProviders().filter(function (p) { return p.isApplicable(document.languageId); }); | ||
function getTagHover(currTag, range, open) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_1 = function (provider) { | ||
var hover = null; | ||
provider.provideTags().forEach(function (tag) { | ||
if (tag.name.toLowerCase() === currTag.toLowerCase()) { | ||
var tagLabel = open ? '<' + currTag + '>' : '</' + currTag + '>'; | ||
var tagDescription = tag.description || ''; | ||
hover = { contents: [{ language: 'html', value: tagLabel }, MarkedString.fromPlainText(tagDescription)], range: range }; | ||
HTMLHover.prototype.doHover = function (document, position, htmlDocument) { | ||
var convertContents = this.convertContents.bind(this); | ||
var offset = document.offsetAt(position); | ||
var node = htmlDocument.findNodeAt(offset); | ||
if (!node || !node.tag) { | ||
return null; | ||
} | ||
var dataProviders = getAllDataProviders().filter(function (p) { return p.isApplicable(document.languageId); }); | ||
function getTagHover(currTag, range, open) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_1 = function (provider) { | ||
var hover = null; | ||
provider.provideTags().forEach(function (tag) { | ||
if (tag.name.toLowerCase() === currTag.toLowerCase()) { | ||
var tagLabel = open ? '<' + currTag + '>' : '</' + currTag + '>'; | ||
var tagDescription = tag.description || ''; | ||
if (typeof tagDescription === 'string') { | ||
hover = { contents: [{ language: 'html', value: tagLabel }, MarkedString.fromPlainText(tagDescription)], range: range }; | ||
} | ||
else { | ||
hover = { contents: tagDescription, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}); | ||
if (hover) { | ||
return { value: hover }; | ||
}; | ||
for (var _i = 0, dataProviders_1 = dataProviders; _i < dataProviders_1.length; _i++) { | ||
var provider = dataProviders_1[_i]; | ||
var state_1 = _loop_1(provider); | ||
if (typeof state_1 === "object") | ||
return state_1.value; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_1 = dataProviders; _i < dataProviders_1.length; _i++) { | ||
var provider = dataProviders_1[_i]; | ||
var state_1 = _loop_1(provider); | ||
if (typeof state_1 === "object") | ||
return state_1.value; | ||
return null; | ||
} | ||
return null; | ||
} | ||
function getTagNameRange(tokenType, startOffset) { | ||
var scanner = createScanner(document.getText(), startOffset); | ||
var token = scanner.scan(); | ||
while (token !== TokenType.EOS && (scanner.getTokenEnd() < offset || scanner.getTokenEnd() === offset && token !== tokenType)) { | ||
token = scanner.scan(); | ||
function getAttrHover(currTag, currAttr, range) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_2 = function (provider) { | ||
var hover = null; | ||
provider.provideAttributes(currTag).forEach(function (attr) { | ||
if (currAttr === attr.name && attr.description) { | ||
if (typeof attr.description === 'string') { | ||
hover = { contents: [MarkedString.fromPlainText(attr.description)], range: range }; | ||
} | ||
else { | ||
hover = { contents: attr.description, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_2 = dataProviders; _i < dataProviders_2.length; _i++) { | ||
var provider = dataProviders_2[_i]; | ||
var state_2 = _loop_2(provider); | ||
if (typeof state_2 === "object") | ||
return state_2.value; | ||
} | ||
return null; | ||
} | ||
if (token === tokenType && offset <= scanner.getTokenEnd()) { | ||
return { start: document.positionAt(scanner.getTokenOffset()), end: document.positionAt(scanner.getTokenEnd()) }; | ||
function getAttrValueHover(currTag, currAttr, currAttrValue, range) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_3 = function (provider) { | ||
var hover = null; | ||
provider.provideValues(currTag, currAttr).forEach(function (attrValue) { | ||
if (currAttrValue === attrValue.name && attrValue.description) { | ||
if (typeof attrValue.description === 'string') { | ||
hover = { contents: [MarkedString.fromPlainText(attrValue.description)], range: range }; | ||
} | ||
else { | ||
hover = { contents: attrValue.description, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_3 = dataProviders; _i < dataProviders_3.length; _i++) { | ||
var provider = dataProviders_3[_i]; | ||
var state_3 = _loop_3(provider); | ||
if (typeof state_3 === "object") | ||
return state_3.value; | ||
} | ||
return null; | ||
} | ||
function getTagNameRange(tokenType, startOffset) { | ||
var scanner = createScanner(document.getText(), startOffset); | ||
var token = scanner.scan(); | ||
while (token !== TokenType.EOS && (scanner.getTokenEnd() < offset || scanner.getTokenEnd() === offset && token !== tokenType)) { | ||
token = scanner.scan(); | ||
} | ||
if (token === tokenType && offset <= scanner.getTokenEnd()) { | ||
return { start: document.positionAt(scanner.getTokenOffset()), end: document.positionAt(scanner.getTokenEnd()) }; | ||
} | ||
return null; | ||
} | ||
if (node.endTagStart && offset >= node.endTagStart) { | ||
var tagRange_1 = getTagNameRange(TokenType.EndTag, node.endTagStart); | ||
if (tagRange_1) { | ||
return getTagHover(node.tag, tagRange_1, false); | ||
} | ||
return null; | ||
} | ||
var tagRange = getTagNameRange(TokenType.StartTag, node.start); | ||
if (tagRange) { | ||
return getTagHover(node.tag, tagRange, true); | ||
} | ||
var attrRange = getTagNameRange(TokenType.AttributeName, node.start); | ||
if (attrRange) { | ||
var tag = node.tag; | ||
var attr = document.getText(attrRange); | ||
return getAttrHover(tag, attr, attrRange); | ||
} | ||
function scanAttrAndAttrValue(nodeStart, attrValueStart) { | ||
var scanner = createScanner(document.getText(), nodeStart); | ||
var token = scanner.scan(); | ||
var prevAttr = undefined; | ||
while (token !== TokenType.EOS && (scanner.getTokenEnd() <= attrValueStart)) { | ||
token = scanner.scan(); | ||
if (token === TokenType.AttributeName) { | ||
prevAttr = scanner.getTokenText(); | ||
} | ||
} | ||
return prevAttr; | ||
} | ||
var attrValueRange = getTagNameRange(TokenType.AttributeValue, node.start); | ||
if (attrValueRange) { | ||
var tag = node.tag; | ||
var attrValue = trimQuotes(document.getText(attrValueRange)); | ||
var matchAttr = scanAttrAndAttrValue(node.start, document.offsetAt(attrValueRange.start)); | ||
if (matchAttr) { | ||
return getAttrValueHover(tag, matchAttr, attrValue, attrValueRange); | ||
} | ||
} | ||
return null; | ||
} | ||
if (node.endTagStart && offset >= node.endTagStart) { | ||
var tagRange_1 = getTagNameRange(TokenType.EndTag, node.endTagStart); | ||
if (tagRange_1) { | ||
return getTagHover(node.tag, tagRange_1, false); | ||
}; | ||
HTMLHover.prototype.convertContents = function (contents) { | ||
if (!this.doesSupportMarkdown()) { | ||
if (typeof contents === 'string') { | ||
return contents; | ||
} | ||
// MarkupContent | ||
else if ('kind' in contents) { | ||
return { | ||
kind: 'plaintext', | ||
value: contents.value | ||
}; | ||
} | ||
// MarkedString[] | ||
else if (isArray(contents)) { | ||
contents.map(function (c) { | ||
return typeof c === 'string' ? c : c.value; | ||
}); | ||
} | ||
// MarkedString | ||
else { | ||
return contents.value; | ||
} | ||
} | ||
return null; | ||
return contents; | ||
}; | ||
HTMLHover.prototype.doesSupportMarkdown = function () { | ||
if (!this.clientCapabilities) { | ||
this.supportsMarkdown = true; | ||
return this.supportsMarkdown; | ||
} | ||
if (!isDefined(this.supportsMarkdown)) { | ||
var hover = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.hover; | ||
this.supportsMarkdown = hover && hover.contentFormat && Array.isArray(hover.contentFormat) && hover.contentFormat.indexOf(MarkupKind.Markdown) !== -1; | ||
} | ||
return this.supportsMarkdown; | ||
}; | ||
return HTMLHover; | ||
}()); | ||
export { HTMLHover }; | ||
function trimQuotes(s) { | ||
if (s.length <= 1) { | ||
return s.replace(/['"]/, ''); | ||
} | ||
var tagRange = getTagNameRange(TokenType.StartTag, node.start); | ||
if (tagRange) { | ||
return getTagHover(node.tag, tagRange, true); | ||
if (s[0] === "'" || s[0] === "\"") { | ||
s = s.slice(1); | ||
} | ||
return null; | ||
if (s[s.length - 1] === "'" || s[s.length - 1] === "\"") { | ||
s = s.slice(0, -1); | ||
} | ||
return s; | ||
} |
import { TextDocument, Position, CompletionList, Hover, Range, SymbolInformation, TextEdit, DocumentHighlight, DocumentLink, FoldingRange, SelectionRange } from 'vscode-languageserver-types'; | ||
import { Scanner, HTMLDocument, CompletionConfiguration, ICompletionParticipant, HTMLFormatConfiguration, DocumentContext, IHTMLDataProvider, HTMLDataV1 } from './htmlLanguageTypes'; | ||
import { Scanner, HTMLDocument, CompletionConfiguration, ICompletionParticipant, HTMLFormatConfiguration, DocumentContext, IHTMLDataProvider, HTMLDataV1, LanguageServiceOptions } from './htmlLanguageTypes'; | ||
export * from './htmlLanguageTypes'; | ||
@@ -21,6 +21,3 @@ export * from 'vscode-languageserver-types'; | ||
} | ||
export interface LanguageServiceOptions { | ||
customDataProviders?: IHTMLDataProvider[]; | ||
} | ||
export declare function getLanguageService(options?: LanguageServiceOptions): LanguageService; | ||
export declare function newHTMLDataProvider(id: string, customData: HTMLDataV1): IHTMLDataProvider; |
@@ -34,3 +34,4 @@ /*--------------------------------------------------------------------------------------------- | ||
function getLanguageService(options) { | ||
var htmlCompletion = new htmlCompletion_1.HTMLCompletion(); | ||
var htmlHover = new htmlHover_1.HTMLHover(options && options.clientCapabilities); | ||
var htmlCompletion = new htmlCompletion_1.HTMLCompletion(options && options.clientCapabilities); | ||
if (options && options.customDataProviders) { | ||
@@ -44,3 +45,3 @@ builtinDataProviders_1.handleCustomDataProviders(options.customDataProviders); | ||
setCompletionParticipants: htmlCompletion.setCompletionParticipants.bind(htmlCompletion), | ||
doHover: htmlHover_1.doHover, | ||
doHover: htmlHover.doHover.bind(htmlHover), | ||
format: htmlFormatter_1.format, | ||
@@ -47,0 +48,0 @@ findDocumentHighlights: htmlHighlighting_1.findDocumentHighlights, |
@@ -1,2 +0,2 @@ | ||
import { TextDocument, Position, Range } from 'vscode-languageserver-types'; | ||
import { TextDocument, Position, Range, MarkupContent, MarkupKind } from 'vscode-languageserver-types'; | ||
export interface HTMLFormatConfiguration { | ||
@@ -107,3 +107,3 @@ tabSize?: number; | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
attributes: IAttributeData[]; | ||
@@ -113,3 +113,3 @@ } | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
valueSet?: string; | ||
@@ -120,3 +120,3 @@ values?: IValueData[]; | ||
name: string; | ||
description?: string; | ||
description?: string | MarkupContent; | ||
} | ||
@@ -140,1 +140,51 @@ export interface IValueSet { | ||
} | ||
/** | ||
* Describes what LSP capabilities the client supports | ||
*/ | ||
export interface ClientCapabilities { | ||
/** | ||
* The text document client capabilities | ||
*/ | ||
textDocument?: { | ||
/** | ||
* Capabilities specific to completions. | ||
*/ | ||
completion?: { | ||
/** | ||
* The client supports the following `CompletionItem` specific | ||
* capabilities. | ||
*/ | ||
completionItem?: { | ||
/** | ||
* Client supports the follow content formats for the documentation | ||
* property. The order describes the preferred format of the client. | ||
*/ | ||
documentationFormat?: MarkupKind[]; | ||
}; | ||
}; | ||
/** | ||
* Capabilities specific to hovers. | ||
*/ | ||
hover?: { | ||
/** | ||
* Client supports the follow content formats for the content | ||
* property. The order describes the preferred format of the client. | ||
*/ | ||
contentFormat?: MarkupKind[]; | ||
}; | ||
}; | ||
} | ||
export declare namespace ClientCapabilities { | ||
const LATEST: ClientCapabilities; | ||
} | ||
export interface LanguageServiceOptions { | ||
/** | ||
* Provide data that could enhance the service's understanding of | ||
* HTML tag / attribute / attribute-value | ||
*/ | ||
customDataProviders?: IHTMLDataProvider[]; | ||
/** | ||
* Describes the LSP capabilities the client supports. | ||
*/ | ||
clientCapabilities?: ClientCapabilities; | ||
} |
@@ -11,3 +11,3 @@ /*--------------------------------------------------------------------------------------------- | ||
else if (typeof define === "function" && define.amd) { | ||
define(["require", "exports"], factory); | ||
define(["require", "exports", "vscode-languageserver-types"], factory); | ||
} | ||
@@ -17,2 +17,3 @@ })(function (require, exports) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var vscode_languageserver_types_1 = require("vscode-languageserver-types"); | ||
var TokenType; | ||
@@ -57,2 +58,17 @@ (function (TokenType) { | ||
})(ScannerState = exports.ScannerState || (exports.ScannerState = {})); | ||
var ClientCapabilities; | ||
(function (ClientCapabilities) { | ||
ClientCapabilities.LATEST = { | ||
textDocument: { | ||
completion: { | ||
completionItem: { | ||
documentationFormat: [vscode_languageserver_types_1.MarkupKind.Markdown, vscode_languageserver_types_1.MarkupKind.PlainText] | ||
} | ||
}, | ||
hover: { | ||
contentFormat: [vscode_languageserver_types_1.MarkupKind.Markdown, vscode_languageserver_types_1.MarkupKind.PlainText] | ||
} | ||
} | ||
}; | ||
})(ClientCapabilities = exports.ClientCapabilities || (exports.ClientCapabilities = {})); | ||
}); |
@@ -11,3 +11,3 @@ /*--------------------------------------------------------------------------------------------- | ||
else if (typeof define === "function" && define.amd) { | ||
define(["require", "exports", "vscode-languageserver-types", "../parser/htmlScanner", "../htmlLanguageTypes", "../parser/htmlEntities", "vscode-nls", "../utils/strings", "../languageFacts/builtinDataProviders", "../languageFacts/fact"], factory); | ||
define(["require", "exports", "vscode-languageserver-types", "../parser/htmlScanner", "../htmlLanguageTypes", "../parser/htmlEntities", "vscode-nls", "../utils/strings", "../languageFacts/builtinDataProviders", "../languageFacts/fact", "../utils/object"], factory); | ||
} | ||
@@ -25,5 +25,7 @@ })(function (require, exports) { | ||
var fact_1 = require("../languageFacts/fact"); | ||
var object_1 = require("../utils/object"); | ||
var localize = nls.loadMessageBundle(); | ||
var HTMLCompletion = /** @class */ (function () { | ||
function HTMLCompletion() { | ||
function HTMLCompletion(clientCapabilities) { | ||
this.clientCapabilities = clientCapabilities; | ||
this.completionParticipants = []; | ||
@@ -35,2 +37,6 @@ } | ||
HTMLCompletion.prototype.doComplete = function (document, position, htmlDocument, settings) { | ||
var result = this._doComplete(document, position, htmlDocument, settings); | ||
return this.convertCompletionList(result); | ||
}; | ||
HTMLCompletion.prototype._doComplete = function (document, position, htmlDocument, settings) { | ||
var result = { | ||
@@ -259,2 +265,3 @@ isIncomplete: false, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Unit, | ||
documentation: value.description, | ||
textEdit: vscode_languageserver_types_1.TextEdit.replace(range, insertText), | ||
@@ -456,2 +463,26 @@ insertTextFormat: vscode_languageserver_types_1.InsertTextFormat.PlainText | ||
}; | ||
HTMLCompletion.prototype.convertCompletionList = function (list) { | ||
if (!this.doesSupportMarkdown()) { | ||
list.items.forEach(function (item) { | ||
if (item.documentation && typeof item.documentation !== 'string') { | ||
item.documentation = { | ||
kind: 'plaintext', | ||
value: item.documentation.value | ||
}; | ||
} | ||
}); | ||
} | ||
return list; | ||
}; | ||
HTMLCompletion.prototype.doesSupportMarkdown = function () { | ||
if (!this.clientCapabilities) { | ||
this.supportsMarkdown = true; | ||
return this.supportsMarkdown; | ||
} | ||
if (!object_1.isDefined(this.supportsMarkdown)) { | ||
var hover = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.hover; | ||
this.supportsMarkdown = hover && hover.contentFormat && Array.isArray(hover.contentFormat) && hover.contentFormat.indexOf(vscode_languageserver_types_1.MarkupKind.Markdown) !== -1; | ||
} | ||
return this.supportsMarkdown; | ||
}; | ||
return HTMLCompletion; | ||
@@ -458,0 +489,0 @@ }()); |
@@ -11,3 +11,3 @@ /*--------------------------------------------------------------------------------------------- | ||
else if (typeof define === "function" && define.amd) { | ||
define(["require", "exports", "../parser/htmlScanner", "vscode-languageserver-types", "../htmlLanguageTypes", "../languageFacts/builtinDataProviders"], factory); | ||
define(["require", "exports", "../parser/htmlScanner", "vscode-languageserver-types", "../htmlLanguageTypes", "../languageFacts/builtinDataProviders", "../utils/object", "util"], factory); | ||
} | ||
@@ -21,57 +21,201 @@ })(function (require, exports) { | ||
var builtinDataProviders_1 = require("../languageFacts/builtinDataProviders"); | ||
function doHover(document, position, htmlDocument) { | ||
var offset = document.offsetAt(position); | ||
var node = htmlDocument.findNodeAt(offset); | ||
if (!node || !node.tag) { | ||
return null; | ||
var object_1 = require("../utils/object"); | ||
var util_1 = require("util"); | ||
var HTMLHover = /** @class */ (function () { | ||
function HTMLHover(clientCapabilities) { | ||
this.clientCapabilities = clientCapabilities; | ||
} | ||
var dataProviders = builtinDataProviders_1.getAllDataProviders().filter(function (p) { return p.isApplicable(document.languageId); }); | ||
function getTagHover(currTag, range, open) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_1 = function (provider) { | ||
var hover = null; | ||
provider.provideTags().forEach(function (tag) { | ||
if (tag.name.toLowerCase() === currTag.toLowerCase()) { | ||
var tagLabel = open ? '<' + currTag + '>' : '</' + currTag + '>'; | ||
var tagDescription = tag.description || ''; | ||
hover = { contents: [{ language: 'html', value: tagLabel }, vscode_languageserver_types_1.MarkedString.fromPlainText(tagDescription)], range: range }; | ||
HTMLHover.prototype.doHover = function (document, position, htmlDocument) { | ||
var convertContents = this.convertContents.bind(this); | ||
var offset = document.offsetAt(position); | ||
var node = htmlDocument.findNodeAt(offset); | ||
if (!node || !node.tag) { | ||
return null; | ||
} | ||
var dataProviders = builtinDataProviders_1.getAllDataProviders().filter(function (p) { return p.isApplicable(document.languageId); }); | ||
function getTagHover(currTag, range, open) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_1 = function (provider) { | ||
var hover = null; | ||
provider.provideTags().forEach(function (tag) { | ||
if (tag.name.toLowerCase() === currTag.toLowerCase()) { | ||
var tagLabel = open ? '<' + currTag + '>' : '</' + currTag + '>'; | ||
var tagDescription = tag.description || ''; | ||
if (typeof tagDescription === 'string') { | ||
hover = { contents: [{ language: 'html', value: tagLabel }, vscode_languageserver_types_1.MarkedString.fromPlainText(tagDescription)], range: range }; | ||
} | ||
else { | ||
hover = { contents: tagDescription, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}); | ||
if (hover) { | ||
return { value: hover }; | ||
}; | ||
for (var _i = 0, dataProviders_1 = dataProviders; _i < dataProviders_1.length; _i++) { | ||
var provider = dataProviders_1[_i]; | ||
var state_1 = _loop_1(provider); | ||
if (typeof state_1 === "object") | ||
return state_1.value; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_1 = dataProviders; _i < dataProviders_1.length; _i++) { | ||
var provider = dataProviders_1[_i]; | ||
var state_1 = _loop_1(provider); | ||
if (typeof state_1 === "object") | ||
return state_1.value; | ||
return null; | ||
} | ||
return null; | ||
} | ||
function getTagNameRange(tokenType, startOffset) { | ||
var scanner = htmlScanner_1.createScanner(document.getText(), startOffset); | ||
var token = scanner.scan(); | ||
while (token !== htmlLanguageTypes_1.TokenType.EOS && (scanner.getTokenEnd() < offset || scanner.getTokenEnd() === offset && token !== tokenType)) { | ||
token = scanner.scan(); | ||
function getAttrHover(currTag, currAttr, range) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_2 = function (provider) { | ||
var hover = null; | ||
provider.provideAttributes(currTag).forEach(function (attr) { | ||
if (currAttr === attr.name && attr.description) { | ||
if (typeof attr.description === 'string') { | ||
hover = { contents: [vscode_languageserver_types_1.MarkedString.fromPlainText(attr.description)], range: range }; | ||
} | ||
else { | ||
hover = { contents: attr.description, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_2 = dataProviders; _i < dataProviders_2.length; _i++) { | ||
var provider = dataProviders_2[_i]; | ||
var state_2 = _loop_2(provider); | ||
if (typeof state_2 === "object") | ||
return state_2.value; | ||
} | ||
return null; | ||
} | ||
if (token === tokenType && offset <= scanner.getTokenEnd()) { | ||
return { start: document.positionAt(scanner.getTokenOffset()), end: document.positionAt(scanner.getTokenEnd()) }; | ||
function getAttrValueHover(currTag, currAttr, currAttrValue, range) { | ||
currTag = currTag.toLowerCase(); | ||
var _loop_3 = function (provider) { | ||
var hover = null; | ||
provider.provideValues(currTag, currAttr).forEach(function (attrValue) { | ||
if (currAttrValue === attrValue.name && attrValue.description) { | ||
if (typeof attrValue.description === 'string') { | ||
hover = { contents: [vscode_languageserver_types_1.MarkedString.fromPlainText(attrValue.description)], range: range }; | ||
} | ||
else { | ||
hover = { contents: attrValue.description, range: range }; | ||
} | ||
} | ||
}); | ||
if (hover) { | ||
hover.contents = convertContents(hover.contents); | ||
return { value: hover }; | ||
} | ||
}; | ||
for (var _i = 0, dataProviders_3 = dataProviders; _i < dataProviders_3.length; _i++) { | ||
var provider = dataProviders_3[_i]; | ||
var state_3 = _loop_3(provider); | ||
if (typeof state_3 === "object") | ||
return state_3.value; | ||
} | ||
return null; | ||
} | ||
function getTagNameRange(tokenType, startOffset) { | ||
var scanner = htmlScanner_1.createScanner(document.getText(), startOffset); | ||
var token = scanner.scan(); | ||
while (token !== htmlLanguageTypes_1.TokenType.EOS && (scanner.getTokenEnd() < offset || scanner.getTokenEnd() === offset && token !== tokenType)) { | ||
token = scanner.scan(); | ||
} | ||
if (token === tokenType && offset <= scanner.getTokenEnd()) { | ||
return { start: document.positionAt(scanner.getTokenOffset()), end: document.positionAt(scanner.getTokenEnd()) }; | ||
} | ||
return null; | ||
} | ||
if (node.endTagStart && offset >= node.endTagStart) { | ||
var tagRange_1 = getTagNameRange(htmlLanguageTypes_1.TokenType.EndTag, node.endTagStart); | ||
if (tagRange_1) { | ||
return getTagHover(node.tag, tagRange_1, false); | ||
} | ||
return null; | ||
} | ||
var tagRange = getTagNameRange(htmlLanguageTypes_1.TokenType.StartTag, node.start); | ||
if (tagRange) { | ||
return getTagHover(node.tag, tagRange, true); | ||
} | ||
var attrRange = getTagNameRange(htmlLanguageTypes_1.TokenType.AttributeName, node.start); | ||
if (attrRange) { | ||
var tag = node.tag; | ||
var attr = document.getText(attrRange); | ||
return getAttrHover(tag, attr, attrRange); | ||
} | ||
function scanAttrAndAttrValue(nodeStart, attrValueStart) { | ||
var scanner = htmlScanner_1.createScanner(document.getText(), nodeStart); | ||
var token = scanner.scan(); | ||
var prevAttr = undefined; | ||
while (token !== htmlLanguageTypes_1.TokenType.EOS && (scanner.getTokenEnd() <= attrValueStart)) { | ||
token = scanner.scan(); | ||
if (token === htmlLanguageTypes_1.TokenType.AttributeName) { | ||
prevAttr = scanner.getTokenText(); | ||
} | ||
} | ||
return prevAttr; | ||
} | ||
var attrValueRange = getTagNameRange(htmlLanguageTypes_1.TokenType.AttributeValue, node.start); | ||
if (attrValueRange) { | ||
var tag = node.tag; | ||
var attrValue = trimQuotes(document.getText(attrValueRange)); | ||
var matchAttr = scanAttrAndAttrValue(node.start, document.offsetAt(attrValueRange.start)); | ||
if (matchAttr) { | ||
return getAttrValueHover(tag, matchAttr, attrValue, attrValueRange); | ||
} | ||
} | ||
return null; | ||
} | ||
if (node.endTagStart && offset >= node.endTagStart) { | ||
var tagRange_1 = getTagNameRange(htmlLanguageTypes_1.TokenType.EndTag, node.endTagStart); | ||
if (tagRange_1) { | ||
return getTagHover(node.tag, tagRange_1, false); | ||
}; | ||
HTMLHover.prototype.convertContents = function (contents) { | ||
if (!this.doesSupportMarkdown()) { | ||
if (typeof contents === 'string') { | ||
return contents; | ||
} | ||
// MarkupContent | ||
else if ('kind' in contents) { | ||
return { | ||
kind: 'plaintext', | ||
value: contents.value | ||
}; | ||
} | ||
// MarkedString[] | ||
else if (util_1.isArray(contents)) { | ||
contents.map(function (c) { | ||
return typeof c === 'string' ? c : c.value; | ||
}); | ||
} | ||
// MarkedString | ||
else { | ||
return contents.value; | ||
} | ||
} | ||
return null; | ||
return contents; | ||
}; | ||
HTMLHover.prototype.doesSupportMarkdown = function () { | ||
if (!this.clientCapabilities) { | ||
this.supportsMarkdown = true; | ||
return this.supportsMarkdown; | ||
} | ||
if (!object_1.isDefined(this.supportsMarkdown)) { | ||
var hover = this.clientCapabilities.textDocument && this.clientCapabilities.textDocument.hover; | ||
this.supportsMarkdown = hover && hover.contentFormat && Array.isArray(hover.contentFormat) && hover.contentFormat.indexOf(vscode_languageserver_types_1.MarkupKind.Markdown) !== -1; | ||
} | ||
return this.supportsMarkdown; | ||
}; | ||
return HTMLHover; | ||
}()); | ||
exports.HTMLHover = HTMLHover; | ||
function trimQuotes(s) { | ||
if (s.length <= 1) { | ||
return s.replace(/['"]/, ''); | ||
} | ||
var tagRange = getTagNameRange(htmlLanguageTypes_1.TokenType.StartTag, node.start); | ||
if (tagRange) { | ||
return getTagHover(node.tag, tagRange, true); | ||
if (s[0] === "'" || s[0] === "\"") { | ||
s = s.slice(1); | ||
} | ||
return null; | ||
if (s[s.length - 1] === "'" || s[s.length - 1] === "\"") { | ||
s = s.slice(0, -1); | ||
} | ||
return s; | ||
} | ||
exports.doHover = doHover; | ||
}); |
{ | ||
"name": "vscode-html-languageservice", | ||
"version": "3.0.3", | ||
"version": "3.0.4-next.0", | ||
"description": "Language service for HTML", | ||
@@ -5,0 +5,0 @@ "main": "./lib/umd/htmlLanguageService.js", |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1463301
84
30676
2