提交 2b247ccb 编写于 作者: M Martin Aeschlimann

[css] move to extension

上级 966cb81e
......@@ -71,6 +71,7 @@ var copyrightFilter = [
'!**/*.bat',
'!**/*.cmd',
'!resources/win32/bin/code.js',
'!**/*.xml',
'!**/*.sh',
'!**/*.txt',
'!**/*.xpm',
......
......@@ -13,7 +13,8 @@ const extensions = [
'configuration-editing',
'typescript',
'php',
'javascript'
'javascript',
'css'
];
extensions.forEach(extension => {
......
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceRoot}"
],
"stopOnEntry": false,
"sourceMaps": true,
"outDir": "${workspaceRoot}/client/out",
"preLaunchTask": "npm"
},
{
"name": "Launch Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/client/out/test" ],
"stopOnEntry": false,
"sourceMaps": true,
"outDir": "${workspaceRoot}/client/out/test",
"preLaunchTask": "npm"
}
]
}
\ No newline at end of file
// Available variables which can be used inside of strings.
// ${workspaceRoot}: the root folder of the team
// ${file}: the current opened file
// ${fileBasename}: the current opened file's basename
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
// A task runner that calls a custom npm script that compiles the extension.
{
"version": "0.1.0",
// we want to run npm
"command": "npm",
// the command is a shell script
"isShellCommand": true,
// show the output window only if unrecognized errors occur.
"showOutput": "silent",
// we run the custom script "compile" as defined in package.json
"args": ["run", "compile"],
// The tsc compiler is started in watching mode
"isWatching": true,
// use the standard tsc in watch mode problem matcher to find compile problems in the output.
"problemMatcher": "$tsc-watch"
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* 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 {window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range} from 'vscode';
let decorationType: DecorationRenderOptions = {
before: {
contentText: ' ',
border: 'solid 0.1em #000',
margin: '0.1em 0.2em 0 0.2em',
width: '0.8em',
height: '0.8em'
},
dark: {
before: {
border: 'solid 0.1em #eee'
}
}
};
export function activateColorDecorations(decoratorProvider: (uri: string) => Thenable<Range[]>, supportedLanguages: { [id: string]: boolean }): Disposable {
let disposables: Disposable[] = [];
let colorsDecorationType = window.createTextEditorDecorationType(decorationType);
disposables.push(colorsDecorationType);
let activeEditor = window.activeTextEditor;
if (activeEditor) {
triggerUpdateDecorations();
}
window.onDidChangeActiveTextEditor(editor => {
activeEditor = editor;
if (editor && supportedLanguages[activeEditor.document.languageId]) {
triggerUpdateDecorations();
}
}, null, disposables);
workspace.onDidChangeTextDocument(event => {
if (activeEditor && event.document === activeEditor.document && supportedLanguages[activeEditor.document.languageId]) {
triggerUpdateDecorations();
}
}, null, disposables);
let timeout = null;
function triggerUpdateDecorations() {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(updateDecorations, 500);
}
function updateDecorations() {
if (!activeEditor) {
return;
}
let document = activeEditor.document;
if (!supportedLanguages[document.languageId]) {
return;
}
let uri = activeEditor.document.uri.toString();
decoratorProvider(uri).then(ranges => {
let decorations = ranges.map(range => {
let color = document.getText(range);
return <DecorationOptions>{
range: range,
renderOptions: {
before: {
backgroundColor: color
}
}
};
});
activeEditor.setDecorations(colorsDecorationType, decorations);
});
}
return Disposable.from(...disposables);
}
/*---------------------------------------------------------------------------------------------
* 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 path from 'path';
import {languages, window, commands, ExtensionContext} from 'vscode';
import {LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, Range, TextEdit, Protocol2Code} from 'vscode-languageclient';
import {activateColorDecorations} from './colorDecorators';
namespace ColorSymbolRequest {
export const type: RequestType<string, Range[], any> = { get method() { return 'css/colorSymbols'; } };
}
// this method is called when vs code is activated
export function activate(context: ExtensionContext) {
// The server is implemented in node
let serverModule = context.asAbsolutePath(path.join('server', 'out', 'cssServerMain.js'));
// The debug options for the server
let debugOptions = { execArgv: ['--nolazy', '--debug=6004'] };
// If the extension is launch in debug mode the debug server options are use
// Otherwise the run options are used
let serverOptions: ServerOptions = {
run: { module: serverModule, transport: TransportKind.ipc },
debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions }
};
// Options to control the language client
let clientOptions: LanguageClientOptions = {
documentSelector: ['css', 'less', 'scss'],
synchronize: {
configurationSection: ['css', 'scss', 'less']
},
initializationOptions: {
}
};
// Create the language client and start the client.
let client = new LanguageClient('css', serverOptions, clientOptions);
let disposable = client.start();
// Push the disposable to the context's subscriptions so that the
// client can be deactivated on extension deactivation
context.subscriptions.push(disposable);
let colorRequestor = (uri: string) => {
return client.sendRequest(ColorSymbolRequest.type, uri).then(ranges => ranges.map(Protocol2Code.asRange));
};
disposable = activateColorDecorations(colorRequestor, { css: true, scss: true, less: true });
context.subscriptions.push(disposable);
languages.setLanguageConfiguration('css', {
wordPattern: /(#?-?\d*\.\d\w*%?)|((::|[@#.!:])?[\w-?]+%?)|::|[@#.!:]/g,
comments: {
blockComment: ['/*', '*/']
},
brackets: [['{', '}'], ['[', ']'], ['(', ')']],
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '"', close: '"', notIn: ['string'] },
{ open: '\'', close: '\'', notIn: ['string'] }
]
});
languages.setLanguageConfiguration('less', {
wordPattern: /(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g,
comments: {
blockComment: ['/*', '*/'],
lineComment: '//'
},
brackets: [['{', '}'], ['[', ']'], ['(', ')'], ['<', '>']],
autoClosingPairs: [
{ open: '"', close: '"', notIn: ['string', 'comment'] },
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
{ open: '{', close: '}', notIn: ['string', 'comment'] },
{ open: '[', close: ']', notIn: ['string', 'comment'] },
{ open: '(', close: ')', notIn: ['string', 'comment'] },
{ open: '<', close: '>', notIn: ['string', 'comment'] },
]
});
languages.setLanguageConfiguration('scss', {
wordPattern: /(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g,
comments: {
blockComment: ['/*', '*/'],
lineComment: '//'
},
brackets: [['{', '}'], ['[', ']'], ['(', ')'], ['<', '>']],
autoClosingPairs: [
{ open: '"', close: '"', notIn: ['string', 'comment'] },
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
{ open: '{', close: '}', notIn: ['string', 'comment'] },
{ open: '[', close: ']', notIn: ['string', 'comment'] },
{ open: '(', close: ')', notIn: ['string', 'comment'] },
{ open: '<', close: '>', notIn: ['string', 'comment'] },
]
});
commands.registerCommand('_css.applyCodeAction', applyCodeAction);
}
function applyCodeAction(uri: string, documentVersion: number, edits: TextEdit[]) {
let textEditor = window.activeTextEditor;
if (textEditor && textEditor.document.uri.toString() === uri) {
if (textEditor.document.version !== documentVersion) {
window.showInformationMessage(`CSS fix is outdated and can't be applied to the document.`);
}
textEditor.edit(mutator => {
for (let edit of edits) {
mutator.replace(Protocol2Code.asRange(edit.range), edit.newText);
}
}).then(success => {
if (!success) {
window.showErrorMessage('Failed to apply CSS fix to the document. Please consider opening an issue with steps to reproduce.');
}
});
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../../src/vs/vscode.d.ts'/>
/// <reference path='../../../../../src/typings/mocha.d.ts'/>
/// <reference path='../../../../../extensions/node.d.ts'/>
/// <reference path='../../../../../extensions/lib.core.d.ts'/>
/// <reference path='../../../../../extensions/declares.d.ts'/>
/// <reference path='../../../node_modules/vscode-languageclient/lib/main.d.ts'/>
\ No newline at end of file
{
"compilerOptions": {
"noLib": true,
"target": "es5",
"module": "commonjs",
"outDir": "./out"
},
"exclude": [
"node_modules"
]
}
\ No newline at end of file
......@@ -2,7 +2,20 @@
"name": "css",
"version": "0.1.0",
"publisher": "vscode",
"engines": { "vscode": "*" },
"engines": {
"vscode": "0.10.x"
},
"activationEvents": [
"onLanguage:css",
"onLanguage:less",
"onLanguage:sass",
"onCommand:_css.applyCodeAction"
],
"main": "./client/out/cssMain",
"scripts": {
"compile": "gulp compile-extension:css-client && gulp compile-extension:css-server",
"postinstall": "cd server && npm install"
},
"contributes": {
"languages": [{
"id": "css",
......@@ -18,6 +31,531 @@
"snippets": [{
"language": "css",
"path": "./snippets/css.json"
}]
}],
"configuration": {
"allOf": [{
"id": "css",
"order": 20,
"title": "CSS configuration",
"allOf": [
{
"title": "Controls CSS validation and problem severities.",
"properties": {
"css.validate": {
"type": "boolean",
"default": true,
"description": "Enables or disables all validations"
},
"css.lint.compatibleVendorPrefixes": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties"
},
"css.lint.vendorPrefix": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "warning",
"description": "When using a vendor-specific prefix also include the standard property"
},
"css.lint.duplicateProperties": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Do not use duplicate style definitions"
},
"css.lint.emptyRules": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "warning",
"description": "Do not use empty rulesets"
},
"css.lint.importStatement": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Import statements do not load in parallel"
},
"css.lint.boxModel": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Do not use width or height when using padding or border"
},
"css.lint.universalSelector": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "The universal selector (*) is known to be slow"
},
"css.lint.zeroUnits": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "No unit for zero needed"
},
"css.lint.fontFaceProperties": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "warning",
"description": "@font-face rule must define 'src' and 'font-family' properties"
},
"css.lint.hexColorLength": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "error",
"description": "Hex colors must consist of three or six hex numbers"
},
"css.lint.argumentsInColorFunction": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "error",
"description": "Invalid number of parameters"
},
"css.lint.unknownProperties": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "warning",
"description": "Unknown property."
},
"css.lint.ieHack": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "IE hacks are only necessary when supporting IE7 and older"
},
"css.lint.unknownVendorSpecificProperties": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Unknown vendor specific property."
},
"css.lint.propertyIgnoredDueToDisplay": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "warning",
"description": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect"
},
"css.lint.important": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored."
},
"css.lint.float": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes."
},
"css.lint.idSelector": {
"type": "string",
"enum": [ "ignore", "warning", "error"],
"default": "ignore",
"description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML."
}
}
}
]
},
{
"id": "scss",
"order": 24,
"title": "SCSS (Sass) configuration",
"allOf": [
{
"title": "Controls SCSS validation and problem severities.",
"properties": {
"scss.validate": {
"type": "boolean",
"default": true,
"description": "Enables or disables all validations"
},
"scss.lint.compatibleVendorPrefixes": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties"
},
"scss.lint.vendorPrefix": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "When using a vendor-specific prefix also include the standard property"
},
"scss.lint.duplicateProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Do not use duplicate style definitions"
},
"scss.lint.emptyRules": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Do not use empty rulesets"
},
"scss.lint.importStatement": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Import statements do not load in parallel"
},
"scss.lint.boxModel": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Do not use width or height when using padding or border"
},
"scss.lint.universalSelector": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "The universal selector (*) is known to be slow"
},
"scss.lint.zeroUnits": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "No unit for zero needed"
},
"scss.lint.fontFaceProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "@font-face rule must define 'src' and 'font-family' properties"
},
"scss.lint.hexColorLength": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "error",
"description": "Hex colors must consist of three or six hex numbers"
},
"scss.lint.argumentsInColorFunction": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "error",
"description": "Invalid number of parameters"
},
"scss.lint.unknownProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Unknown property."
},
"scss.lint.ieHack": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "IE hacks are only necessary when supporting IE7 and older"
},
"scss.lint.unknownVendorSpecificProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Unknown vendor specific property."
},
"scss.lint.propertyIgnoredDueToDisplay": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect"
},
"scss.lint.important": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored."
},
"scss.lint.float": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes."
},
"scss.lint.idSelector": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML."
}
}
}
]
},
{
"id": "less",
"order": 22,
"type": "object",
"title": "LESS configuration",
"allOf": [
{
"title": "Controls LESS validation and problem severities.",
"properties": {
"less.validate": {
"type": "boolean",
"default": true,
"description": "Enables or disables all validations"
},
"less.lint.compatibleVendorPrefixes": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "When using a vendor-specific prefix make sure to also include all other vendor-specific properties"
},
"less.lint.vendorPrefix": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "When using a vendor-specific prefix also include the standard property"
},
"less.lint.duplicateProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Do not use duplicate style definitions"
},
"less.lint.emptyRules": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Do not use empty rulesets"
},
"less.lint.importStatement": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Import statements do not load in parallel"
},
"less.lint.boxModel": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Do not use width or height when using padding or border"
},
"less.lint.universalSelector": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "The universal selector (*) is known to be slow"
},
"less.lint.zeroUnits": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "No unit for zero needed"
},
"less.lint.fontFaceProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "@font-face rule must define 'src' and 'font-family' properties"
},
"less.lint.hexColorLength": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "error",
"description": "Hex colors must consist of three or six hex numbers"
},
"less.lint.argumentsInColorFunction": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "error",
"description": "Invalid number of parameters"
},
"less.lint.unknownProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Unknown property."
},
"less.lint.ieHack": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "IE hacks are only necessary when supporting IE7 and older"
},
"less.lint.unknownVendorSpecificProperties": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Unknown vendor specific property."
},
"less.lint.propertyIgnoredDueToDisplay": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "warning",
"description": "Property is ignored due to the display. E.g. with 'display: inline', the width, height, margin-top, margin-bottom, and float properties have no effect"
},
"less.lint.important": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Avoid using !important. It is an indication that the specificity of the entire CSS has gotten out of control and needs to be refactored."
},
"less.lint.float": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Avoid using 'float'. Floats lead to fragile CSS that is easy to break if one aspect of the layout changes."
},
"less.lint.idSelector": {
"type": "string",
"enum": [
"ignore",
"warning",
"error"
],
"default": "ignore",
"description": "Selectors should not contain IDs because these rules are too tightly coupled with the HTML."
}
}
}
]
}]
}
},
"dependencies": {
"vscode-languageclient": "^2.2.1"
}
}
\ No newline at end of file
{
"version": "0.1.0",
// List of configurations. Add new configurations or edit existing ones.
"configurations": [
{
"name": "Attach",
"type": "node",
"request": "attach",
"port": 6004,
"sourceMaps": true,
"outDir": "${workspaceRoot}/out"
},
{
"name": "Unit Tests",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/../../../node_modules/mocha/bin/_mocha",
"stopOnEntry": false,
"args": [
"--timeout",
"999999",
"--colors"
],
"cwd": "${workspaceRoot}",
"runtimeExecutable": null,
"runtimeArgs": [],
"env": {},
"sourceMaps": true,
"outDir": "${workspaceRoot}/out"
}
]
}
\ No newline at end of file
{
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "silent",
"args": ["run", "watch"],
"isWatching": true,
"problemMatcher": "$tsc-watch"
}
\ No newline at end of file
{
"name": "vscode-css-server",
"description": "CSS/LESS/SCSS language server",
"version": "0.0.1",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
"node": "*"
},
"dependencies": {
"vscode-languageserver": "^2.2.0",
"vscode-nls": "^1.0.4"
},
"scripts": {
"compile": "gulp compile-extension:css-server",
"watch": "gulp watch-extension:css-server"
}
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* 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 {
IPCMessageReader, IPCMessageWriter, createConnection, IConnection, Range,
TextDocuments, TextDocument, InitializeParams, InitializeResult, RequestType
} from 'vscode-languageserver';
import {Parser} from './parser/cssParser';
import {CSSCompletion} from './services/cssCompletion';
import {CSSHover} from './services/cssHover';
import {CSSNavigation} from './services/cssNavigation';
import {CSSCodeActions} from './services/cssCodeActions';
import {CSSValidation, Settings} from './services/cssValidation';
import {Stylesheet} from './parser/cssNodes';
import * as nls from 'vscode-nls';
nls.config(process.env['VSCODE_NLS_CONFIG']);
namespace ColorSymbolRequest {
export const type: RequestType<string, Range[], any> = { get method() { return 'css/colorSymbols'; } };
}
// Create a connection for the server. The connection uses for
// stdin / stdout for message passing
let connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process));
// Create a simple text document manager. The text document manager
// supports full document sync only
let documents: TextDocuments = new TextDocuments();
// Make the text document manager listen on the connection
// for open, change and close text document events
documents.listen(connection);
// 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 => {
return {
capabilities: {
// Tell the client that the server works in FULL text document sync mode
textDocumentSync: documents.syncKind,
completionProvider: { resolveProvider: false },
hoverProvider: true,
documentSymbolProvider: true,
referencesProvider: true,
definitionProvider: true,
documentHighlightProvider: true,
codeActionProvider: true
}
};
});
let cssCompletion = new CSSCompletion();
let cssHover = new CSSHover();
let cssValidation = new CSSValidation();
let cssNavigation = new CSSNavigation();
let cssCodeActions = new CSSCodeActions();
// The content of a text document has changed. This event is emitted
// when the text document first opened or when its content has changed.
documents.onDidChangeContent((change) => {
validateTextDocument(change.document);
});
// The settings have changed. Is send on server activation as well.
connection.onDidChangeConfiguration((change) => {
updateConfiguration(<Settings>change.settings);
});
function updateConfiguration(settings: Settings) {
cssValidation.configure(settings.css);
// Revalidate any open text documents
documents.all().forEach(validateTextDocument);
}
function validateTextDocument(textDocument: TextDocument): void {
if (textDocument.getText().length === 0) {
// ignore empty documents
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
return;
}
let stylesheet = getStylesheet(textDocument);
cssValidation.doValidation(textDocument, stylesheet).then(diagnostics => {
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
});
}
let parser = new Parser();
function getStylesheet(document: TextDocument): Stylesheet {
return parser.parseStylesheet(document);
}
connection.onCompletion(textDocumentPosition => {
let document = documents.get(textDocumentPosition.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssCompletion.doComplete(document, textDocumentPosition.position, stylesheet);
});
connection.onHover(textDocumentPosition => {
let document = documents.get(textDocumentPosition.textDocument.uri);
let styleSheet = getStylesheet(document);
return cssHover.doHover(document, textDocumentPosition.position, styleSheet);
});
connection.onDocumentSymbol(documentSymbolParams => {
let document = documents.get(documentSymbolParams.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssNavigation.findDocumentSymbols(document, stylesheet);
});
connection.onDefinition(documentSymbolParams => {
let document = documents.get(documentSymbolParams.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssNavigation.findDefinition(document, documentSymbolParams.position, stylesheet);
});
connection.onDocumentHighlight(documentSymbolParams => {
let document = documents.get(documentSymbolParams.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssNavigation.findDocumentHighlights(document, documentSymbolParams.position, stylesheet);
});
connection.onReferences(referenceParams => {
let document = documents.get(referenceParams.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssNavigation.findReferences(document, referenceParams.position, stylesheet);
});
connection.onCodeAction(codeActionParams => {
let document = documents.get(codeActionParams.textDocument.uri);
let stylesheet = getStylesheet(document);
return cssCodeActions.doCodeActions(document, codeActionParams.range, codeActionParams.context, stylesheet);
});
connection.onRequest(ColorSymbolRequest.type, uri => {
let document = documents.get(uri);
let stylesheet = getStylesheet(document);
return cssNavigation.findColorSymbols(document, stylesheet);
});
// Listen on the connection
connection.listen();
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export declare var data: any;
export declare var descriptions: any;
\ No newline at end of file
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* global __dirname */
var fs = require('fs');
var path = require('path');
var xml2js = require('xml2js');
var os = require('os');
var util = require('util');
// keep in sync with data from language facts
var colors = {
aliceblue: '#f0f8ff',
antiquewhite: '#faebd7',
aqua: '#00ffff',
aquamarine: '#7fffd4',
azure: '#f0ffff',
beige: '#f5f5dc',
bisque: '#ffe4c4',
black: '#000000',
blanchedalmond: '#ffebcd',
blue: '#0000ff',
blueviolet: '#8a2be2',
brown: '#a52a2a',
burlywood: '#deb887',
cadetblue: '#5f9ea0',
chartreuse: '#7fff00',
chocolate: '#d2691e',
coral: '#ff7f50',
cornflowerblue: '#6495ed',
cornsilk: '#fff8dc',
crimson: '#dc143c',
cyan: '#00ffff',
darkblue: '#00008b',
darkcyan: '#008b8b',
darkgoldenrod: '#b8860b',
darkgray: '#a9a9a9',
darkgrey: '#a9a9a9',
darkgreen: '#006400',
darkkhaki: '#bdb76b',
darkmagenta: '#8b008b',
darkolivegreen: '#556b2f',
darkorange: '#ff8c00',
darkorchid: '#9932cc',
darkred: '#8b0000',
darksalmon: '#e9967a',
darkseagreen: '#8fbc8f',
darkslateblue: '#483d8b',
darkslategray: '#2f4f4f',
darkslategrey: '#2f4f4f',
darkturquoise: '#00ced1',
darkviolet: '#9400d3',
deeppink: '#ff1493',
deepskyblue: '#00bfff',
dimgray: '#696969',
dimgrey: '#696969',
dodgerblue: '#1e90ff',
firebrick: '#b22222',
floralwhite: '#fffaf0',
forestgreen: '#228b22',
fuchsia: '#ff00ff',
gainsboro: '#dcdcdc',
ghostwhite: '#f8f8ff',
gold: '#ffd700',
goldenrod: '#daa520',
gray: '#808080',
grey: '#808080',
green: '#008000',
greenyellow: '#adff2f',
honeydew: '#f0fff0',
hotpink: '#ff69b4',
indianred: '#cd5c5c',
indigo: '#4b0082',
ivory: '#fffff0',
khaki: '#f0e68c',
lavender: '#e6e6fa',
lavenderblush: '#fff0f5',
lawngreen: '#7cfc00',
lemonchiffon: '#fffacd',
lightblue: '#add8e6',
lightcoral: '#f08080',
lightcyan: '#e0ffff',
lightgoldenrodyellow: '#fafad2',
lightgray: '#d3d3d3',
lightgrey: '#d3d3d3',
lightgreen: '#90ee90',
lightpink: '#ffb6c1',
lightsalmon: '#ffa07a',
lightseagreen: '#20b2aa',
lightskyblue: '#87cefa',
lightslategray: '#778899',
lightslategrey: '#778899',
lightsteelblue: '#b0c4de',
lightyellow: '#ffffe0',
lime: '#00ff00',
limegreen: '#32cd32',
linen: '#faf0e6',
magenta: '#ff00ff',
maroon: '#800000',
mediumaquamarine: '#66cdaa',
mediumblue: '#0000cd',
mediumorchid: '#ba55d3',
mediumpurple: '#9370d8',
mediumseagreen: '#3cb371',
mediumslateblue: '#7b68ee',
mediumspringgreen: '#00fa9a',
mediumturquoise: '#48d1cc',
mediumvioletred: '#c71585',
midnightblue: '#191970',
mintcream: '#f5fffa',
mistyrose: '#ffe4e1',
moccasin: '#ffe4b5',
navajowhite: '#ffdead',
navy: '#000080',
oldlace: '#fdf5e6',
olive: '#808000',
olivedrab: '#6b8e23',
orange: '#ffa500',
orangered: '#ff4500',
orchid: '#da70d6',
palegoldenrod: '#eee8aa',
palegreen: '#98fb98',
paleturquoise: '#afeeee',
palevioletred: '#d87093',
papayawhip: '#ffefd5',
peachpuff: '#ffdab9',
peru: '#cd853f',
pink: '#ffc0cb',
plum: '#dda0dd',
powderblue: '#b0e0e6',
purple: '#800080',
red: '#ff0000',
rebeccapurple: '#663399',
rosybrown: '#bc8f8f',
royalblue: '#4169e1',
saddlebrown: '#8b4513',
salmon: '#fa8072',
sandybrown: '#f4a460',
seagreen: '#2e8b57',
seashell: '#fff5ee',
sienna: '#a0522d',
silver: '#c0c0c0',
skyblue: '#87ceeb',
slateblue: '#6a5acd',
slategray: '#708090',
slategrey: '#708090',
snow: '#fffafa',
springgreen: '#00ff7f',
steelblue: '#4682b4',
tan: '#d2b48c',
teal: '#008080',
thistle: '#d8bfd8',
tomato: '#ff6347',
turquoise: '#40e0d0',
violet: '#ee82ee',
wheat: '#f5deb3',
white: '#ffffff',
whitesmoke: '#f5f5f5',
yellow: '#ffff00',
yellowgreen: '#9acd32'
};
var otherColors = {
"ActiveBorder": "Active window border.",
"ActiveCaption": "Active window caption.",
"AppWorkspace": "Background color of multiple document interface.",
"Background": "Desktop background.",
"ButtonFace": "The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",
"ButtonHighlight": "The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
"ButtonShadow": "The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",
"ButtonText": "Text on push buttons.",
"CaptionText": "Text in caption, size box, and scrollbar arrow box.",
"currentColor": "The value of the 'color' property. The computed value of the 'currentColor' keyword is the computed value of the 'color' property. If the 'currentColor' keyword is set on the 'color' property itself, it is treated as 'color:inherit' at parse time.",
"GrayText": "Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",
"Highlight": "Item(s) selected in a control.",
"HighlightText": "Text of item(s) selected in a control.",
"InactiveBorder": "Inactive window border.",
"InactiveCaption": "Inactive window caption.",
"InactiveCaptionText": "Color of text in an inactive caption.",
"InfoBackground": "Background color for tooltip controls.",
"InfoText": "Text color for tooltip controls.",
"Menu": "Menu background.",
"MenuText": "Text in menus.",
"Scrollbar": "Scroll bar gray area.",
"ThreeDDarkShadow": "The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
"ThreeDFace": "The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
"ThreeDHighlight": "The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
"ThreeDLightShadow": "The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
"ThreeDShadow": "The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",
"transparent": "Fully transparent. This keyword can be considered a shorthand for rgba(0,0,0,0) which is its computed value.",
"Window": "Window background.",
"WindowFrame": "Window frame.",
"WindowText": "Text in windows.",
"none": "",
//ignore these
"-webkit-activelink": "",
"-webkit-focus-ring-color": '',
"-webkit-link": '',
"-webkit-text": ''
};
function clone(obj) {
var copy = {};
for (var i in obj) {
copy[i] = obj[i];
}
return copy;
}
function getProperties(obj) {
var res = [];
for (var i in obj) {
res.push(i);
}
return res;
}
function getValues(valArr, restriction, ruleName) {
if (!Array.isArray(valArr)) {
if (valArr.$) {
valArr = [ valArr ];
} else {
return [];
}
}
var vals = valArr.map(function (v) {
return {
name: v.$.name,
desc: v.desc,
browsers: v.$.browsers !== 'all' ? v.$.browsers : void 0
};
}).filter(function (v) {
if (v.browsers === 'none') {
return false;
}
return true;
});
if (restriction.indexOf('color') !== -1) {
var colorsCopy = clone(colors);
var otherColorsCopy = clone(otherColors);
var moreColors = {};
vals = vals.filter(function (v) {
if (typeof colorsCopy[v.name] === 'string') {
delete colorsCopy[v.name];
return false;
}
if (typeof otherColorsCopy[v.name] === 'string') {
delete otherColorsCopy[v.name];
return false;
}
moreColors[v.name] = v.desc;
return true;
});
var notCovered = [];
for (var i in colorsCopy) {
notCovered.push(i);
}
for (var i in otherColorsCopy) {
notCovered.push(i);
}
if (notCovered.length > 0) {
console.log('***' + ruleName + ' uncovered: ' + notCovered.length); // + ' - ' + JSON.stringify(notCovered));
}
if (restriction === 'color') {
var properties = getProperties(moreColors);
console.log('---' + ruleName + ' others : ' + properties.length); // + ' - ' + JSON.stringify(properties));
}
}
return vals;
}
function internalizeDescriptions(entries) {
var descriptions = {};
var conflicts = {};
entries.forEach(function (e) {
if (e.values) {
e.values.forEach(function (d) {
if (!d.desc) {
conflicts[d.name] = true;
return;
}
var existing = descriptions[d.name];
if (existing) {
if (existing !== d.desc) {
conflicts[d.name] = true;
}
}
descriptions[d.name] = d.desc;
});
}
});
entries.forEach(function (e) {
if (e.values) {
e.values.forEach(function (d) {
if (!conflicts[d.name]) {
delete d.desc;
} else {
delete descriptions[d.name];
}
});
}
});
return descriptions;
}
function toSource(object, keyName) {
if (!object.css[keyName]) {
return [];
}
var result = [];
var entryArr = object.css[keyName].entry;
entryArr.forEach(function (e) {
if (e.$.browsers === 'none') {
return;
}
var data = {
name: e.$.name,
desc: e.desc,
browsers: e.$.browsers !== 'all' ? e.$.browsers : void 0
};
if (e.$.restriction) {
data.restriction= e.$.restriction;
}
if (e.values) {
data.values= getValues(e.values.value, data.restriction || '', data.name);
}
result.push(data);
});
return result;
}
var parser = new xml2js.Parser({explicitArray : false});
var schemaFileName= 'css-schema.xml';
fs.readFile(path.resolve(__dirname, schemaFileName), function(err, data) {
parser.parseString(data, function (err, result) {
//console.log(util.inspect(result, {depth: null})); //Work
var atdirectives = toSource(result, 'atDirectives');
var pseudoclasses = toSource(result, 'pseudoClasses');
var pseudoelements = toSource(result, 'pseudoElements');
var properties = toSource(result, 'properties');
var descriptions = internalizeDescriptions([].concat(atdirectives, pseudoclasses, pseudoelements, properties));
var resultObject = {
css: {
atdirectives: atdirectives,
pseudoclasses: pseudoclasses,
pseudoelements: pseudoelements,
properties: properties
}
};
var output = [
'/*---------------------------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * Licensed under the MIT License. See License.txt in the project root for license information.',
' *--------------------------------------------------------------------------------------------*/',
'// file generated from ' + schemaFileName + ' using css-exclude_generate_browserjs.js',
'',
'(function (factory) {',
'\tif (typeof module === "object" && typeof module.exports === "object") {',
'\t\tvar v = factory(require, exports); if (v !== undefined) module.exports = v;',
'\t} else if (typeof define === "function" && define.amd) {',
'\t\tdefine(["require", "exports"], factory);',
'\t}',
'})(function (require, exports) {',
'\texports.data = ' + JSON.stringify(resultObject, null, '\t') + ';',
'\texports.descriptions = ' + JSON.stringify(descriptions, null, '\t') + ';',
'});'
];
var outputPath = path.resolve(__dirname, '../browsers.js');
console.log('Writing to: ' + outputPath);
var content = output.join(os.EOL);
fs.writeFileSync(outputPath, content);
console.log('Done');
});
});
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* 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 nodes from './cssNodes';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class CSSIssueType implements nodes.IRule {
id: string;
message: string;
public constructor(id: string, message: string) {
this.id = id;
this.message = message;
}
}
export let ParseError = {
NumberExpected: new CSSIssueType('css-numberexpected', localize('expected.number', "number expected")),
ConditionExpected: new CSSIssueType('css-conditionexpected', localize('expected.condt', "condition expected")),
RuleOrSelectorExpected: new CSSIssueType('css-ruleorselectorexpected', localize('expected.ruleorselector', "at-rule or selector expected")),
DotExpected: new CSSIssueType('css-dotexpected', localize('expected.dot', "dot expected")),
ColonExpected: new CSSIssueType('css-colonexpected', localize('expected.colon', "colon expected")),
SemiColonExpected: new CSSIssueType('css-semicolonexpected', localize('expected.semicolon', "semi-colon expected")),
TermExpected: new CSSIssueType('css-termexpected', localize('expected.term', "term expected")),
ExpressionExpected: new CSSIssueType('css-expressionexpected', localize('expected.expression', "expression expected")),
OperatorExpected: new CSSIssueType('css-operatorexpected', localize('expected.operator', "operator expected")),
IdentifierExpected: new CSSIssueType('css-identifierexpected', localize('expected.ident', "identifier expected")),
PercentageExpected: new CSSIssueType('css-percentageexpected', localize('expected.percentage', "percentage expected")),
URIOrStringExpected: new CSSIssueType('css-uriorstringexpected', localize('expected.uriorstring', "uri or string expected")),
URIExpected: new CSSIssueType('css-uriexpected', localize('expected.uri', "URI expected")),
VariableNameExpected: new CSSIssueType('css-varnameexpected', localize('expected.varname', "variable name expected")),
VariableValueExpected: new CSSIssueType('css-varvalueexpected', localize('expected.varvalue', "variable value expected")),
PropertyValueExpected: new CSSIssueType('css-propertyvalueexpected', localize('expected.propvalue', "property value expected")),
LeftCurlyExpected: new CSSIssueType('css-lcurlyexpected', localize('expected.lcurly', "{ expected")),
RightCurlyExpected: new CSSIssueType('css-rcurlyexpected', localize('expected.rcurly', "} expected")),
LeftSquareBracketExpected: new CSSIssueType('css-rbracketexpected', localize('expected.lsquare', "[ expected")),
RightSquareBracketExpected: new CSSIssueType('css-lbracketexpected', localize('expected.rsquare', "] expected")),
LeftParenthesisExpected: new CSSIssueType('css-lparentexpected', localize('expected.lparen', "( expected")),
RightParenthesisExpected: new CSSIssueType('css-rparentexpected', localize('expected.rparent', ") expected")),
CommaExpected: new CSSIssueType('css-commaexpected', localize('expected.comma', "comma expected")),
PageDirectiveOrDeclarationExpected: new CSSIssueType('css-pagedirordeclexpected', localize('expected.pagedirordecl', "page directive or declaraton expected")),
UnknownAtRule: new CSSIssueType('css-unknownatrule', localize('unknown.atrule', "at-rule unknown")),
UnknownKeyword: new CSSIssueType('css-unknownkeyword', localize('unknown.keyword', "unknown keyword")),
SelectorExpected: new CSSIssueType('css-selectorexpected', localize('expected.selector', "selector expected")),
StringLiteralExpected: new CSSIssueType('css-stringliteralexpected', localize('expected.stringliteral', "string literal expected")),
};
此差异已折叠。
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export enum TokenType {
Ident,
AtKeyword,
String,
BadString,
BadUri,
Hash,
Num,
Percentage,
Dimension,
URI,
UnicodeRange,
CDO,
CDC,
Colon,
SemiColon,
CurlyL,
CurlyR,
ParenthesisL,
ParenthesisR,
BracketL,
BracketR,
Whitespace,
Includes,
Dashmatch,
SubstringOperator,
PrefixOperator,
SuffixOperator,
Delim,
EMS,
EXS,
Length,
Angle,
Time,
Freq,
Exclamation,
Resolution,
Comma,
Charset,
EscapedJavaScript,
BadEscapedJavaScript,
Comment,
SingleLineComment,
EOF,
CustomToken
}
export interface IToken {
type: TokenType;
text: string;
offset: number;
len: number;
}
export class MultiLineStream {
private source: string;
private len: number;
private position: number;
constructor(source: string) {
this.source = source;
this.len = source.length;
this.position = 0;
}
public substring(from: number, to: number = this.position): string {
return this.source.substring(from, to);
}
public eos(): boolean {
return this.len <= this.position;
}
public pos(): number {
return this.position;
}
public goBackTo(pos: number): void {
this.position = pos;
}
public goBack(n: number): void {
this.position -= n;
}
public advance(n: number): void {
this.position += n;
}
public nextChar(): number {
return this.source.charCodeAt(this.position++) || 0;
}
public peekChar(n: number = 0): number {
return this.source.charCodeAt(this.position + n) || 0;
}
public lookbackChar(n: number = 0): number {
return this.source.charCodeAt(this.position - n) || 0;
}
public advanceIfChar(ch: number): boolean {
if (ch === this.source.charCodeAt(this.position)) {
this.position++;
return true;
}
return false;
}
public advanceIfChars(ch: number[]): boolean {
let i: number;
if (this.position + ch.length > this.source.length) {
return false;
}
for (i = 0; i < ch.length; i++) {
if (this.source.charCodeAt(this.position + i) !== ch[i]) {
return false;
}
}
this.advance(i);
return true;
}
public advanceWhileChar(condition: (ch: number) => boolean): number {
let posNow = this.position;
while (this.position < this.len && condition(this.source.charCodeAt(this.position))) {
this.position++;
}
return this.position - posNow;
}
}
const _a = 'a'.charCodeAt(0);
const _e = 'e'.charCodeAt(0);
const _f = 'f'.charCodeAt(0);
const _i = 'i'.charCodeAt(0);
const _l = 'l'.charCodeAt(0);
const _p = 'p'.charCodeAt(0);
const _r = 'r'.charCodeAt(0);
const _u = 'u'.charCodeAt(0);
const _x = 'x'.charCodeAt(0);
const _z = 'z'.charCodeAt(0);
const _A = 'A'.charCodeAt(0);
const _E = 'E'.charCodeAt(0);
const _F = 'F'.charCodeAt(0);
const _I = 'I'.charCodeAt(0);
const _L = 'L'.charCodeAt(0);
const _P = 'P'.charCodeAt(0);
const _R = 'R'.charCodeAt(0);
const _U = 'U'.charCodeAt(0);
const _X = 'X'.charCodeAt(0);
const _Z = 'Z'.charCodeAt(0);
const _0 = '0'.charCodeAt(0);
const _9 = '9'.charCodeAt(0);
const _TLD = '~'.charCodeAt(0);
const _HAT = '^'.charCodeAt(0);
const _EQS = '='.charCodeAt(0);
const _PIP = '|'.charCodeAt(0);
const _MIN = '-'.charCodeAt(0);
const _USC = '_'.charCodeAt(0);
const _PRC = '%'.charCodeAt(0);
const _MUL = '*'.charCodeAt(0);
const _LPA = '('.charCodeAt(0);
const _RPA = ')'.charCodeAt(0);
const _LAN = '<'.charCodeAt(0);
const _RAN = '>'.charCodeAt(0);
const _ATS = '@'.charCodeAt(0);
const _HSH = '#'.charCodeAt(0);
const _DLR = '$'.charCodeAt(0);
const _BSL = '\\'.charCodeAt(0);
const _FSL = '/'.charCodeAt(0);
const _NWL = '\n'.charCodeAt(0);
const _CAR = '\r'.charCodeAt(0);
const _LFD = '\f'.charCodeAt(0);
const _DQO = '"'.charCodeAt(0);
const _SQO = '\''.charCodeAt(0);
const _WSP = ' '.charCodeAt(0);
const _TAB = '\t'.charCodeAt(0);
const _SEM = ';'.charCodeAt(0);
const _COL = ':'.charCodeAt(0);
const _CUL = '{'.charCodeAt(0);
const _CUR = '}'.charCodeAt(0);
const _BRL = '['.charCodeAt(0);
const _BRR = ']'.charCodeAt(0);
const _CMA = ','.charCodeAt(0);
const _DOT = '.'.charCodeAt(0);
const _BNG = '!'.charCodeAt(0);
const _url = [_u, _U, _r, _R, _l, _L, _LPA, _LPA];
const _url_prefix = [_u, _U, _r, _R, _l, _L, _MIN, _MIN, _p, _P, _r, _R, _e, _E, _f, _F, _i, _I, _x, _X, _LPA, _LPA];
const staticTokenTable: { [code: number]: TokenType; } = {};
staticTokenTable[_SEM] = TokenType.SemiColon;
staticTokenTable[_COL] = TokenType.Colon;
staticTokenTable[_CUL] = TokenType.CurlyL;
staticTokenTable[_CUR] = TokenType.CurlyR;
staticTokenTable[_BRR] = TokenType.BracketR;
staticTokenTable[_BRL] = TokenType.BracketL;
staticTokenTable[_LPA] = TokenType.ParenthesisL;
staticTokenTable[_RPA] = TokenType.ParenthesisR;
staticTokenTable[_CMA] = TokenType.Comma;
const staticUnitTable: { [code: number]: TokenType; } = {};
staticUnitTable['em'] = TokenType.EMS;
staticUnitTable['ex'] = TokenType.EXS;
staticUnitTable['px'] = TokenType.Length;
staticUnitTable['cm'] = TokenType.Length;
staticUnitTable['mm'] = TokenType.Length;
staticUnitTable['in'] = TokenType.Length;
staticUnitTable['pt'] = TokenType.Length;
staticUnitTable['pc'] = TokenType.Length;
staticUnitTable['deg'] = TokenType.Angle;
staticUnitTable['rad'] = TokenType.Angle;
staticUnitTable['grad'] = TokenType.Angle;
staticUnitTable['ms'] = TokenType.Time;
staticUnitTable['s'] = TokenType.Time;
staticUnitTable['hz'] = TokenType.Freq;
staticUnitTable['khz'] = TokenType.Freq;
staticUnitTable['%'] = TokenType.Percentage;
staticUnitTable['dpi'] = TokenType.Resolution;
staticUnitTable['dpcm'] = TokenType.Resolution;
export class Scanner {
public stream: MultiLineStream;
public ignoreComment = true;
public ignoreWhitespace = true;
public setSource(input: string): void {
this.stream = new MultiLineStream(input);
}
public finishToken(offset: number, type: TokenType, text?: string): IToken {
return {
offset: offset,
len: this.stream.pos() - offset,
type: type,
text: text || this.stream.substring(offset)
};
}
public substring(offset: number, len: number): string {
return this.stream.substring(offset, offset + len);
}
public pos(): number {
return this.stream.pos();
}
public goBackTo(pos: number): void {
this.stream.goBackTo(pos);
}
public scan(): IToken {
// processes all whitespaces and comments
let triviaToken = this.trivia();
if (triviaToken !== null) {
return triviaToken;
}
let offset = this.stream.pos();
// End of file/input
if (this.stream.eos()) {
return this.finishToken(offset, TokenType.EOF);
}
// CDO <!--
if (this.stream.advanceIfChars([_LAN, _BNG, _MIN, _MIN])) {
return this.finishToken(offset, TokenType.CDO);
}
// CDC -->
if (this.stream.advanceIfChars([_MIN, _MIN, _RAN])) {
return this.finishToken(offset, TokenType.CDC);
}
// URL
let tokenType = this._url();
if (tokenType !== null) {
return this.finishToken(offset, tokenType);
}
let content: string[] = [];
if (this.ident(content)) {
return this.finishToken(offset, TokenType.Ident, content.join(''));
}
// at-keyword
if (this.stream.advanceIfChar(_ATS)) {
content = ['@'];
if (this._name(content)) {
let keywordText = content.join('');
if (keywordText === '@charset') {
return this.finishToken(offset, TokenType.Charset, keywordText);
}
return this.finishToken(offset, TokenType.AtKeyword, keywordText);
} else {
return this.finishToken(offset, TokenType.Delim);
}
}
// hash
if (this.stream.advanceIfChar(_HSH)) {
content = ['#'];
if (this._name(content)) {
return this.finishToken(offset, TokenType.Hash, content.join(''));
} else {
return this.finishToken(offset, TokenType.Delim);
}
}
// Important
if (this.stream.advanceIfChar(_BNG)) {
return this.finishToken(offset, TokenType.Exclamation);
}
// Numbers
if (this._number()) {
let pos = this.stream.pos();
content = [this.stream.substring(offset, pos)];
if (this.stream.advanceIfChar(_PRC)) {
// Percentage 43%
return this.finishToken(offset, TokenType.Percentage);
} else if (this.ident(content)) {
let dim = this.stream.substring(pos).toLowerCase();
tokenType = <TokenType>staticUnitTable[dim];
if (typeof tokenType !== 'undefined') {
// Known dimension 43px
return this.finishToken(offset, tokenType, content.join(''));
} else {
// Unknown dimension 43ft
return this.finishToken(offset, TokenType.Dimension, content.join(''));
}
}
return this.finishToken(offset, TokenType.Num);
}
// String, BadString
content = [];
tokenType = this._string(content);
if (tokenType !== null) {
return this.finishToken(offset, tokenType, content.join(''));
}
// single character tokens
tokenType = <TokenType>staticTokenTable[this.stream.peekChar()];
if (typeof tokenType !== 'undefined') {
this.stream.advance(1);
return this.finishToken(offset, tokenType);
}
// includes ~=
if (this.stream.peekChar(0) === _TLD && this.stream.peekChar(1) === _EQS) {
this.stream.advance(2);
return this.finishToken(offset, TokenType.Includes);
}
// DashMatch |=
if (this.stream.peekChar(0) === _PIP && this.stream.peekChar(1) === _EQS) {
this.stream.advance(2);
return this.finishToken(offset, TokenType.Dashmatch);
}
// Substring operator *=
if (this.stream.peekChar(0) === _MUL && this.stream.peekChar(1) === _EQS) {
this.stream.advance(2);
return this.finishToken(offset, TokenType.SubstringOperator);
}
// Substring operator ^=
if (this.stream.peekChar(0) === _HAT && this.stream.peekChar(1) === _EQS) {
this.stream.advance(2);
return this.finishToken(offset, TokenType.PrefixOperator);
}
// Substring operator $=
if (this.stream.peekChar(0) === _DLR && this.stream.peekChar(1) === _EQS) {
this.stream.advance(2);
return this.finishToken(offset, TokenType.SuffixOperator);
}
// Delim
this.stream.nextChar();
return this.finishToken(offset, TokenType.Delim);
}
private _matchWordAnyCase(characters: number[]): boolean {
let index = 0;
this.stream.advanceWhileChar((ch: number) => {
let result = characters[index] === ch || characters[index + 1] === ch;
if (result) {
index += 2;
}
return result;
});
if (index === characters.length) {
return true;
} else {
this.stream.goBack(index / 2);
return false;
}
}
protected trivia(): IToken {
while (true) {
let offset = this.stream.pos();
if (this._whitespace()) {
if (!this.ignoreWhitespace) {
return this.finishToken(offset, TokenType.Whitespace);
}
} else if (this.comment()) {
if (!this.ignoreComment) {
return this.finishToken(offset, TokenType.Comment);
}
} else {
return null;
}
}
}
protected comment(): boolean {
if (this.stream.advanceIfChars([_FSL, _MUL])) {
let success = false, hot = false;
this.stream.advanceWhileChar((ch) => {
if (hot && ch === _FSL) {
success = true;
return false;
}
hot = ch === _MUL;
return true;
});
if (success) {
this.stream.advance(1);
}
return true;
}
return false;
}
private _number(): boolean {
let npeek = 0, ch: number;
if (this.stream.peekChar() === _DOT) {
npeek = 1;
}
ch = this.stream.peekChar(npeek);
if (ch >= _0 && ch <= _9) {
this.stream.advance(npeek + 1);
this.stream.advanceWhileChar((ch) => {
return ch >= _0 && ch <= _9 || npeek === 0 && ch === _DOT;
});
return true;
}
return false;
}
private _newline(result: string[]): boolean {
let ch = this.stream.peekChar();
switch (ch) {
case _CAR:
case _LFD:
case _NWL:
this.stream.advance(1);
result.push(String.fromCharCode(ch));
if (ch === _CAR && this.stream.advanceIfChar(_NWL)) {
result.push('\n');
}
return true;
}
return false;
}
private _escape(result: string[], includeNewLines?: boolean): boolean {
let ch = this.stream.peekChar();
if (ch === _BSL) {
this.stream.advance(1);
ch = this.stream.peekChar();
let hexNumCount = 0;
while (hexNumCount < 6 && (ch >= _0 && ch <= _9 || ch >= _a && ch <= _f || ch >= _A && ch <= _F)) {
this.stream.advance(1);
ch = this.stream.peekChar();
hexNumCount++;
}
if (hexNumCount > 0) {
try {
let hexVal = parseInt(this.stream.substring(this.stream.pos() - hexNumCount), 16);
if (hexVal) {
result.push(String.fromCharCode(hexVal));
}
} catch (e) {
// ignore
}
// optional whitespace or new line, not part of result text
if (ch === _WSP || ch === _TAB) {
this.stream.advance(1);
} else {
this._newline([]);
}
return true;
}
if (ch !== _CAR && ch !== _LFD && ch !== _NWL) {
this.stream.advance(1);
result.push(String.fromCharCode(ch));
return true;
} else if (includeNewLines) {
return this._newline(result);
}
}
return false;
}
private _stringChar(closeQuote: number, result: string[]) {
// not closeQuote, not backslash, not newline
let ch = this.stream.peekChar();
if (ch !== 0 && ch !== closeQuote && ch !== _BSL && ch !== _CAR && ch !== _LFD && ch !== _NWL) {
this.stream.advance(1);
result.push(String.fromCharCode(ch));
return true;
}
return false;
};
private _string(result: string[]): TokenType {
if (this.stream.peekChar() === _SQO || this.stream.peekChar() === _DQO) {
let closeQuote = this.stream.nextChar();
result.push(String.fromCharCode(closeQuote));
while (this._stringChar(closeQuote, result) || this._escape(result, true)) {
// loop
}
if (this.stream.peekChar() === closeQuote) {
this.stream.nextChar();
result.push(String.fromCharCode(closeQuote));
return TokenType.String;
} else {
return TokenType.BadString;
}
}
return null;
}
private _url(): TokenType {
if (this._matchWordAnyCase(_url) || this._matchWordAnyCase(_url_prefix)) {
this._whitespace();
let tokenType = TokenType.URI, stringType = this._string([]);
if (stringType === TokenType.BadString) {
tokenType = TokenType.BadUri;
} else if (stringType === null) {
this.stream.advanceWhileChar((ch) => {
return ch !== _RPA;
});
tokenType = TokenType.URI;
}
this._whitespace();
if (this.stream.advanceIfChar(_RPA)) {
return tokenType;
} else {
return TokenType.BadUri;
}
}
return null;
}
private _whitespace(): boolean {
let n = this.stream.advanceWhileChar((ch) => {
return ch === _WSP || ch === _TAB || ch === _NWL || ch === _LFD || ch === _CAR;
});
return n > 0;
}
private _name(result: string[]): boolean {
let matched = false;
while (this._identChar(result) || this._escape(result)) {
matched = true;
}
return matched;
}
protected ident(result: string[]): boolean {
let pos = this.stream.pos();
let hasMinus = this._minus(result);
if (hasMinus && this._minus(result) /* -- */) {
let hasContent = false;
while (this._identChar(result) || this._escape(result)) {
hasContent = true;
}
if (hasContent) {
return true;
}
} else if (this._identFirstChar(result) || this._escape(result)) {
while (this._identChar(result) || this._escape(result)) {
// loop
}
return true;
}
this.stream.goBackTo(pos);
return false;
}
private _identFirstChar(result: string[]): boolean {
let ch = this.stream.peekChar();
if (ch === _USC || // _
ch >= _a && ch <= _z || // a-z
ch >= _A && ch <= _Z || // A-Z
ch >= 0x80 && ch <= 0xFFFF) { // nonascii
this.stream.advance(1);
result.push(String.fromCharCode(ch));
return true;
}
return false;
}
private _minus(result: string[]): boolean {
let ch = this.stream.peekChar();
if (ch === _MIN) {
this.stream.advance(1);
result.push(String.fromCharCode(ch));
return true;
}
return false;
}
private _identChar(result: string[]): boolean {
let ch = this.stream.peekChar();
if (ch === _USC || // _
ch === _MIN || // -
ch >= _a && ch <= _z || // a-z
ch >= _A && ch <= _Z || // A-Z
ch >= _0 && ch <= _9 || // 0/9
ch >= 0x80 && ch <= 0xFFFF) { // nonascii
this.stream.advance(1);
result.push(String.fromCharCode(ch));
return true;
}
return false;
}
}
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* 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 nodes from '../parser/cssNodes';
import * as languageFacts from './languageFacts';
import {difference} from '../utils/strings';
import {Rules} from '../services/lintRules';
import {TextDocument, Range, CodeActionContext, Diagnostic, Command, TextEdit} from 'vscode-languageserver';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
export class CSSCodeActions {
constructor() {
}
public doCodeActions(document: TextDocument, range: Range, context: CodeActionContext, stylesheet: nodes.Stylesheet): Thenable<Command[]> {
let result: Command[] = [];
if (context.diagnostics) {
for (let diagnostic of context.diagnostics) {
this.appendFixesForMarker(document, stylesheet, diagnostic, result);
}
}
return Promise.resolve(result);
}
private getFixesForUnknownProperty(document: TextDocument, property: nodes.Property, marker: Diagnostic, result: Command[]): void {
interface RankedProperty {
property: string;
score: number;
}
let propertyName = property.getName();
let candidates: RankedProperty[] = [];
for (let p in languageFacts.getProperties()) {
let score = difference(propertyName, p);
if (score >= propertyName.length / 2 /*score_lim*/) {
candidates.push({ property: p, score });
}
}
// Sort in descending order.
candidates.sort((a, b) => {
return b.score - a.score;
});
let maxActions = 3;
for (let candidate of candidates) {
let propertyName = candidate.property;
let title = localize('css.codeaction.rename', "Rename to '{0}'", propertyName);
let edit = TextEdit.replace(marker.range, propertyName);
result.push(Command.create(title, '_css.applyCodeAction', document.uri, document.version, [edit]));
if (--maxActions <= 0) {
return;
}
}
}
private appendFixesForMarker(document: TextDocument, stylesheet: nodes.Stylesheet, marker: Diagnostic, result: Command[]): void {
if (marker.code !== Rules.UnknownProperty.id) {
return;
}
let offset = document.offsetAt(marker.range.start);
let end = document.offsetAt(marker.range.end);
let nodepath = nodes.getNodePath(stylesheet, offset);
for (let i = nodepath.length - 1; i >= 0; i--) {
let node = nodepath[i];
if (node instanceof nodes.Declaration) {
let property = (<nodes.Declaration>node).getProperty();
if (property && property.offset === offset && property.end === end) {
this.getFixesForUnknownProperty(document, property, marker, result);
return;
}
}
}
}
}
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* 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 nodes from '../parser/cssNodes';
import * as languageFacts from './languageFacts';
import {TextDocument, Range, Position, Hover} from 'vscode-languageserver';
import {selectorToMarkedString, simpleSelectorToMarkedString} from './selectorPrinting';
export class CSSHover {
constructor() {
}
public doHover(document: TextDocument, position: Position, stylesheet: nodes.Stylesheet): Thenable<Hover> {
function getRange(node: nodes.Node) {
return Range.create(document.positionAt(node.offset), document.positionAt(node.end));
}
let offset = document.offsetAt(position);
let nodepath = nodes.getNodePath(stylesheet, offset);
for (let i = 0; i < nodepath.length; i++) {
let node = nodepath[i];
if (node instanceof nodes.Selector) {
return Promise.resolve({
contents: selectorToMarkedString(<nodes.Selector>node),
range: getRange(node)
});
}
if (node instanceof nodes.SimpleSelector) {
return Promise.resolve({
contents: simpleSelectorToMarkedString(<nodes.SimpleSelector>node),
range: getRange(node)
});
}
if (node instanceof nodes.Declaration) {
let propertyName = node.getFullPropertyName();
let entry = languageFacts.getProperties()[propertyName];
if (entry) {
return Promise.resolve({
contents: entry.description,
range: getRange(node)
});
}
}
}
return null;
}
}
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* 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 nodes from '../parser/cssNodes';
import {TextDocument, Range, Diagnostic, DiagnosticSeverity} from 'vscode-languageserver';
import {ILintConfigurationSettings, sanitize} from './lintRules';
import {LintVisitor} from './lint';
export interface LanguageSettings {
validate?: boolean;
lint?: ILintConfigurationSettings;
}
// The settings interface describe the server relevant settings part
export interface Settings {
css: LanguageSettings;
less: LanguageSettings;
scss: LanguageSettings;
}
export class CSSValidation {
private lintSettings: ILintConfigurationSettings;
private validationEnabled: boolean;
constructor() {
}
public configure(raw: LanguageSettings) {
if (raw) {
this.validationEnabled = raw.validate;
if (raw.lint) {
this.lintSettings = sanitize(raw.lint);
} else {
this.lintSettings = {};
}
}
}
public doValidation(document: TextDocument, stylesheet: nodes.Stylesheet): Thenable<Diagnostic[]> {
if (!this.validationEnabled) {
return Promise.resolve([]);
}
let entries: nodes.IMarker[] = [];
entries.push.apply(entries, nodes.ParseErrorCollector.entries(stylesheet));
entries.push.apply(entries, LintVisitor.entries(stylesheet, this.lintSettings));
function toDiagnostic(marker: nodes.IMarker): Diagnostic {
let range = Range.create(document.positionAt(marker.getOffset()), document.positionAt(marker.getOffset() + marker.getLength()));
return <Diagnostic>{
code: marker.getRule().id,
message: marker.getMessage(),
severity: marker.getLevel() === nodes.Level.Warning ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error,
range: range
};
}
return Promise.resolve(entries.filter(entry => entry.getLevel() !== nodes.Level.Ignore).map(toDiagnostic));
}
}
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/// <reference path='../../../../../src/typings/mocha.d.ts'/>
/// <reference path='../../../../../extensions/node.d.ts'/>
/// <reference path='../../../../../extensions/lib.core.d.ts'/>
/// <reference path='../../../../../extensions/declares.d.ts'/>
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册