diff --git a/README.md b/README.md index b988b69a..be487e54 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ CSS language plugin for the Monaco Editor. It provides the following features wh * Validation: Syntax errors and linting * Find definition, references & highlights for symbols in the same file * Document Symbols +* Color Decorators Linting an be configured through the API. See [here](https://github.com/Microsoft/monaco-css/blob/master/src/monaco.d.ts) for the API that the CSS plugin offers to configure the CSS/LESS/SCSS language support. @@ -27,7 +28,7 @@ This npm module is bundled and distributed in the [monaco-editor](https://www.np * `git clone https://github.com/Microsoft/monaco-css` * `cd monaco-css` * `npm install .` -* `npm run watch` +* `npm run prepublish` * open `$/monaco-css/test/index.html` in your favorite browser. ## License diff --git a/src/cssMode.ts b/src/cssMode.ts index 140ffb18..e8bce90b 100644 --- a/src/cssMode.ts +++ b/src/cssMode.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {WorkerManager} from './workerManager'; -import {CSSWorker} from './cssWorker'; -import {LanguageServiceDefaultsImpl} from './monaco.contribution'; +import { WorkerManager } from './workerManager'; +import { CSSWorker } from './cssWorker'; +import { LanguageServiceDefaultsImpl } from './monaco.contribution'; import * as languageFeatures from './languageFeatures'; import Promise = monaco.Promise; @@ -29,7 +29,8 @@ export function setupMode(defaults: LanguageServiceDefaultsImpl): void { monaco.languages.registerReferenceProvider(languageId, new languageFeatures.ReferenceAdapter(worker)); monaco.languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)); monaco.languages.registerRenameProvider(languageId, new languageFeatures.RenameAdapter(worker)); - new languageFeatures.DiagnostcsAdapter(languageId, worker)); + monaco.languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)); + new languageFeatures.DiagnostcsAdapter(languageId, worker); } diff --git a/src/cssWorker.ts b/src/cssWorker.ts index 3eaa2df8..d0f54e69 100644 --- a/src/cssWorker.ts +++ b/src/cssWorker.ts @@ -14,12 +14,12 @@ export class CSSWorker { // --- model sync ----------------------- - private _ctx:IWorkerContext; + private _ctx: IWorkerContext; private _languageService: cssService.LanguageService; private _languageSettings: cssService.LanguageSettings; private _languageId: string; - constructor(ctx:IWorkerContext, createData: ICreateData) { + constructor(ctx: IWorkerContext, createData: ICreateData) { this._ctx = ctx; this._languageSettings = createData.languageSettings; this._languageId = createData.languageId; @@ -41,7 +41,7 @@ export class CSSWorker { // --- language service host --------------- - doValidation(uri: string): Promise { + doValidation(uri: string): Promise { let document = this._getTextDocument(uri); if (document) { let stylesheet = this._languageService.parseStylesheet(document); @@ -50,55 +50,61 @@ export class CSSWorker { } return Promise.as([]); } - doComplete(uri: string, position: ls.Position): Promise { + doComplete(uri: string, position: ls.Position): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let completions = this._languageService.doComplete(document, position, stylesheet); return Promise.as(completions); } - doHover(uri: string, position: ls.Position): Promise { + doHover(uri: string, position: ls.Position): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let hover = this._languageService.doHover(document, position, stylesheet); return Promise.as(hover); } - findDefinition(uri: string, position: ls.Position): Promise { + findDefinition(uri: string, position: ls.Position): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let definition = this._languageService.findDefinition(document, position, stylesheet); return Promise.as(definition); } - findReferences(uri: string, position: ls.Position): Promise { + findReferences(uri: string, position: ls.Position): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let references = this._languageService.findReferences(document, position, stylesheet); return Promise.as(references); } - findDocumentHighlights(uri: string, position: ls.Position): Promise { + findDocumentHighlights(uri: string, position: ls.Position): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let highlights = this._languageService.findDocumentHighlights(document, position, stylesheet); return Promise.as(highlights); } - findDocumentSymbols(uri: string): Promise { + findDocumentSymbols(uri: string): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let symbols = this._languageService.findDocumentSymbols(document, stylesheet); return Promise.as(symbols); } - doCodeActions(uri: string, range: ls.Range, context: ls.CodeActionContext): Promise { + doCodeActions(uri: string, range: ls.Range, context: ls.CodeActionContext): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let actions = this._languageService.doCodeActions(document, range, context, stylesheet); return Promise.as(actions); } - findColorSymbols(uri: string): Promise { + findDocumentColors(uri: string): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); - let colorSymbols = this._languageService.findColorSymbols(document, stylesheet); + let colorSymbols = this._languageService.findDocumentColors(document, stylesheet); return Promise.as(colorSymbols); } - doRename(uri: string, position: ls.Position, newName: string): Promise { + getColorPresentations(uri: string, color: cssService.Color, range: ls.Range): Promise { + let document = this._getTextDocument(uri); + let stylesheet = this._languageService.parseStylesheet(document); + let colorPresentations = this._languageService.getColorPresentations(document, stylesheet, color, range); + return Promise.as(colorPresentations); + } + doRename(uri: string, position: ls.Position, newName: string): Promise { let document = this._getTextDocument(uri); let stylesheet = this._languageService.parseStylesheet(document); let renames = this._languageService.doRename(document, position, newName, stylesheet); @@ -120,6 +126,6 @@ export interface ICreateData { languageSettings: cssService.LanguageSettings; } -export function create(ctx:IWorkerContext, createData: ICreateData): CSSWorker { +export function create(ctx: IWorkerContext, createData: ICreateData): CSSWorker { return new CSSWorker(ctx, createData); } diff --git a/src/languageFeatures.ts b/src/languageFeatures.ts index cab6acfe..8d363a70 100644 --- a/src/languageFeatures.ts +++ b/src/languageFeatures.ts @@ -11,6 +11,7 @@ import * as ls from 'vscode-languageserver-types'; import Uri = monaco.Uri; import Position = monaco.Position; +import IRange = monaco.IRange; import Range = monaco.Range; import Thenable = monaco.Thenable; import Promise = monaco.Promise; @@ -130,18 +131,18 @@ function fromPosition(position: Position): ls.Position { return { character: position.column - 1, line: position.lineNumber - 1 }; } -function fromRange(range: Range): ls.Range { +function fromRange(range: IRange): ls.Range { if (!range) { return void 0; } - return { start: fromPosition(range.getStartPosition()), end: fromPosition(range.getEndPosition()) }; + return { start: { line: range.startLineNumber - 1, character: range.startColumn - 1 }, end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } }; } function toRange(range: ls.Range): Range { if (!range) { return void 0; } - return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1); + return new monaco.Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1); } function toCompletionItemKind(kind: number): monaco.languages.CompletionItemKind { @@ -200,7 +201,7 @@ export class CompletionAdapter implements monaco.languages.CompletionItemProvide return; } let items: monaco.languages.CompletionItem[] = info.items.map(entry => { - let item : monaco.languages.CompletionItem = { + let item: monaco.languages.CompletionItem = { label: entry.label, insertText: entry.insertText, sortText: entry.sortText, @@ -213,8 +214,11 @@ export class CompletionAdapter implements monaco.languages.CompletionItemProvide item.range = toRange(entry.textEdit.range); item.insertText = entry.textEdit.newText; } + if (entry.additionalTextEdits) { + item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit) + } if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) { - item.insertText = { value: item.insertText }; + item.insertText = { value: item.insertText }; } return item; }); @@ -462,6 +466,48 @@ export class DocumentSymbolAdapter implements monaco.languages.DocumentSymbolPro } } +export class DocumentColorAdapter implements monaco.languages.DocumentColorProvider { + + constructor(private _worker: WorkerAccessor) { + } + + public provideDocumentColors(model: monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable { + const resource = model.uri; + + return wireCancellationToken(token, this._worker(resource).then(worker => worker.findDocumentColors(resource.toString())).then(infos => { + if (!infos) { + return; + } + return infos.map(item => ({ + color: item.color, + range: toRange(item.range) + })); + })); + } + + public provideColorPresentations(model: monaco.editor.IReadOnlyModel, info: monaco.languages.IColorInformation, token: CancellationToken): Thenable { + const resource = model.uri; + + return wireCancellationToken(token, this._worker(resource).then(worker => worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range))).then(presentations => { + if (!presentations) { + return; + } + return presentations.map(presentation => { + let item: monaco.languages.IColorPresentation = { + label: presentation.label, + }; + if (presentation.textEdit) { + item.textEdit = toTextEdit(presentation.textEdit) + } + if (presentation.additionalTextEdits) { + item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit) + } + return item; + }); + })); + } +} + /** * Hook a cancellation token to a WinJS Promise */