UNPKG

vscode-css-languageservice

Version:
324 lines (323 loc) 14.1 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; import { DocumentHighlightKind, Location, Range, SymbolKind, TextEdit } from '../cssLanguageTypes'; import * as nls from 'vscode-nls'; import * as nodes from '../parser/cssNodes'; import { Symbols } from '../parser/cssSymbolScope'; import { getColorValue, hslFromColor } from '../languageFacts/facts'; import { startsWith } from '../utils/strings'; var localize = nls.loadMessageBundle(); var CSSNavigation = /** @class */ (function () { function CSSNavigation() { } CSSNavigation.prototype.findDefinition = function (document, position, stylesheet) { var symbols = new Symbols(stylesheet); var offset = document.offsetAt(position); var node = nodes.getNodeAtOffset(stylesheet, offset); if (!node) { return null; } var symbol = symbols.findSymbolFromNode(node); if (!symbol) { return null; } return { uri: document.uri, range: getRange(symbol.node, document) }; }; CSSNavigation.prototype.findReferences = function (document, position, stylesheet) { var highlights = this.findDocumentHighlights(document, position, stylesheet); return highlights.map(function (h) { return { uri: document.uri, range: h.range }; }); }; CSSNavigation.prototype.findDocumentHighlights = function (document, position, stylesheet) { var result = []; var offset = document.offsetAt(position); var node = nodes.getNodeAtOffset(stylesheet, offset); if (!node || node.type === nodes.NodeType.Stylesheet || node.type === nodes.NodeType.Declarations) { return result; } if (node.type === nodes.NodeType.Identifier && node.parent && node.parent.type === nodes.NodeType.ClassSelector) { node = node.parent; } var symbols = new Symbols(stylesheet); var symbol = symbols.findSymbolFromNode(node); var name = node.getText(); stylesheet.accept(function (candidate) { if (symbol) { if (symbols.matchesSymbol(candidate, symbol)) { result.push({ kind: getHighlightKind(candidate), range: getRange(candidate, document) }); return false; } } else if (node && node.type === candidate.type && candidate.matches(name)) { // Same node type and data result.push({ kind: getHighlightKind(candidate), range: getRange(candidate, document) }); } return true; }); return result; }; CSSNavigation.prototype.isRawStringDocumentLinkNode = function (node) { return node.type === nodes.NodeType.Import; }; CSSNavigation.prototype.findDocumentLinks = function (document, stylesheet, documentContext) { var _this = this; var result = []; stylesheet.accept(function (candidate) { if (candidate.type === nodes.NodeType.URILiteral) { var link = uriLiteralNodeToDocumentLink(document, candidate, documentContext); if (link) { result.push(link); } return false; } /** * In @import, it is possible to include links that do not use `url()` * For example, `@import 'foo.css';` */ if (candidate.parent && _this.isRawStringDocumentLinkNode(candidate.parent)) { var rawText = candidate.getText(); if (startsWith(rawText, "'") || startsWith(rawText, "\"")) { var link = uriStringNodeToDocumentLink(document, candidate, documentContext); if (link) { result.push(link); } } return false; } return true; }); return result; }; CSSNavigation.prototype.findDocumentLinks2 = function (document, stylesheet, documentContext) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, this.findDocumentLinks(document, stylesheet, documentContext)]; }); }); }; CSSNavigation.prototype.findDocumentSymbols = function (document, stylesheet) { var result = []; stylesheet.accept(function (node) { var entry = { name: null, kind: SymbolKind.Class, location: null }; var locationNode = node; if (node instanceof nodes.Selector) { entry.name = node.getText(); locationNode = node.findAParent(nodes.NodeType.Ruleset, nodes.NodeType.ExtendsReference); if (locationNode) { entry.location = Location.create(document.uri, getRange(locationNode, document)); result.push(entry); } return false; } else if (node instanceof nodes.VariableDeclaration) { entry.name = node.getName(); entry.kind = SymbolKind.Variable; } else if (node instanceof nodes.MixinDeclaration) { entry.name = node.getName(); entry.kind = SymbolKind.Method; } else if (node instanceof nodes.FunctionDeclaration) { entry.name = node.getName(); entry.kind = SymbolKind.Function; } else if (node instanceof nodes.Keyframe) { entry.name = localize('literal.keyframes', "@keyframes {0}", node.getName()); } else if (node instanceof nodes.FontFace) { entry.name = localize('literal.fontface', "@font-face"); } else if (node instanceof nodes.Media) { var mediaList = node.getChild(0); if (mediaList instanceof nodes.Medialist) { entry.name = '@media ' + mediaList.getText(); entry.kind = SymbolKind.Module; } } if (entry.name) { entry.location = Location.create(document.uri, getRange(locationNode, document)); result.push(entry); } return true; }); return result; }; CSSNavigation.prototype.findDocumentColors = function (document, stylesheet) { var result = []; stylesheet.accept(function (node) { var colorInfo = getColorInformation(node, document); if (colorInfo) { result.push(colorInfo); } return true; }); return result; }; CSSNavigation.prototype.getColorPresentations = function (document, stylesheet, color, range) { var result = []; var red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255); var label; if (color.alpha === 1) { label = "rgb(" + red256 + ", " + green256 + ", " + blue256 + ")"; } else { label = "rgba(" + red256 + ", " + green256 + ", " + blue256 + ", " + color.alpha + ")"; } result.push({ label: label, textEdit: TextEdit.replace(range, label) }); if (color.alpha === 1) { label = "#" + toTwoDigitHex(red256) + toTwoDigitHex(green256) + toTwoDigitHex(blue256); } else { label = "#" + toTwoDigitHex(red256) + toTwoDigitHex(green256) + toTwoDigitHex(blue256) + toTwoDigitHex(Math.round(color.alpha * 255)); } result.push({ label: label, textEdit: TextEdit.replace(range, label) }); var hsl = hslFromColor(color); if (hsl.a === 1) { label = "hsl(" + hsl.h + ", " + Math.round(hsl.s * 100) + "%, " + Math.round(hsl.l * 100) + "%)"; } else { label = "hsla(" + hsl.h + ", " + Math.round(hsl.s * 100) + "%, " + Math.round(hsl.l * 100) + "%, " + hsl.a + ")"; } result.push({ label: label, textEdit: TextEdit.replace(range, label) }); return result; }; CSSNavigation.prototype.doRename = function (document, position, newName, stylesheet) { var _a; var highlights = this.findDocumentHighlights(document, position, stylesheet); var edits = highlights.map(function (h) { return TextEdit.replace(h.range, newName); }); return { changes: (_a = {}, _a[document.uri] = edits, _a) }; }; return CSSNavigation; }()); export { CSSNavigation }; function getColorInformation(node, document) { var color = getColorValue(node); if (color) { var range = getRange(node, document); return { color: color, range: range }; } return null; } function uriLiteralNodeToDocumentLink(document, uriLiteralNode, documentContext) { if (uriLiteralNode.getChildren().length === 0) { return null; } var uriStringNode = uriLiteralNode.getChild(0); return uriStringNodeToDocumentLink(document, uriStringNode, documentContext); } function uriStringNodeToDocumentLink(document, uriStringNode, documentContext) { if (!uriStringNode) { return null; } var rawUri = uriStringNode.getText(); var range = getRange(uriStringNode, document); // Make sure the range is not empty if (range.start.line === range.end.line && range.start.character === range.end.character) { return null; } if (startsWith(rawUri, "'") || startsWith(rawUri, "\"")) { rawUri = rawUri.slice(1, -1); } var target; if (startsWith(rawUri, 'http://') || startsWith(rawUri, 'https://')) { target = rawUri; } else if (/^\w+:\/\//g.test(rawUri)) { target = rawUri; } else { target = documentContext.resolveReference(rawUri, document.uri); } return { range: range, target: target }; } function getRange(node, document) { return Range.create(document.positionAt(node.offset), document.positionAt(node.end)); } function getHighlightKind(node) { if (node.type === nodes.NodeType.Selector) { return DocumentHighlightKind.Write; } if (node instanceof nodes.Identifier) { if (node.parent && node.parent instanceof nodes.Property) { if (node.isCustomProperty) { return DocumentHighlightKind.Write; } } } if (node.parent) { switch (node.parent.type) { case nodes.NodeType.FunctionDeclaration: case nodes.NodeType.MixinDeclaration: case nodes.NodeType.Keyframe: case nodes.NodeType.VariableDeclaration: case nodes.NodeType.FunctionParameter: return DocumentHighlightKind.Write; } } return DocumentHighlightKind.Read; } function toTwoDigitHex(n) { var r = n.toString(16); return r.length !== 2 ? '0' + r : r; }