mirror of
https://github.com/microsoft/monaco-editor.git
synced 2025-12-22 15:05:39 +01:00
Tokenization of html, razor and handlebars is in monaco-languages
This commit is contained in:
parent
f26f3636d9
commit
8cc4c3d35c
5 changed files with 12 additions and 203 deletions
|
|
@ -25,7 +25,7 @@
|
||||||
"gulp-tsb": "^1.10.4",
|
"gulp-tsb": "^1.10.4",
|
||||||
"gulp-uglify": "^1.5.3",
|
"gulp-uglify": "^1.5.3",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0",
|
||||||
"monaco-editor-core": "0.6.0",
|
"monaco-editor-core": "0.7.1",
|
||||||
"object-assign": "^4.1.0",
|
"object-assign": "^4.1.0",
|
||||||
"rimraf": "^2.5.2",
|
"rimraf": "^2.5.2",
|
||||||
"typescript": "1.8.10",
|
"typescript": "1.8.10",
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import {WorkerManager} from './workerManager';
|
||||||
import {HTMLWorker} from './htmlWorker';
|
import {HTMLWorker} from './htmlWorker';
|
||||||
import {LanguageServiceDefaultsImpl} from './monaco.contribution';
|
import {LanguageServiceDefaultsImpl} from './monaco.contribution';
|
||||||
import * as languageFeatures from './languageFeatures';
|
import * as languageFeatures from './languageFeatures';
|
||||||
import {createTokenizationSupport} from './tokenization';
|
|
||||||
|
|
||||||
import Promise = monaco.Promise;
|
import Promise = monaco.Promise;
|
||||||
import Uri = monaco.Uri;
|
import Uri = monaco.Uri;
|
||||||
|
|
@ -27,53 +26,15 @@ export function setupMode(defaults: LanguageServiceDefaultsImpl): void {
|
||||||
|
|
||||||
let languageId = defaults.languageId;
|
let languageId = defaults.languageId;
|
||||||
|
|
||||||
|
// all modes
|
||||||
disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
|
disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
|
||||||
disposables.push(monaco.languages.registerDocumentHighlightProvider(languageId, new languageFeatures.DocumentHighlightAdapter(worker)));
|
disposables.push(monaco.languages.registerDocumentHighlightProvider(languageId, new languageFeatures.DocumentHighlightAdapter(worker)));
|
||||||
|
disposables.push(monaco.languages.registerLinkProvider(languageId, new languageFeatures.DocumentLinkAdapter(worker)));
|
||||||
|
|
||||||
|
// only html
|
||||||
|
if (languageId === 'html') {
|
||||||
disposables.push(monaco.languages.registerDocumentFormattingEditProvider(languageId, new languageFeatures.DocumentFormattingEditProvider(worker)));
|
disposables.push(monaco.languages.registerDocumentFormattingEditProvider(languageId, new languageFeatures.DocumentFormattingEditProvider(worker)));
|
||||||
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(languageId, new languageFeatures.DocumentRangeFormattingEditProvider(worker)));
|
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(languageId, new languageFeatures.DocumentRangeFormattingEditProvider(worker)));
|
||||||
disposables.push(new languageFeatures.DiagnostcsAdapter(languageId, worker));
|
disposables.push(new languageFeatures.DiagnostcsAdapter(languageId, worker));
|
||||||
disposables.push(monaco.languages.registerLinkProvider(languageId, new languageFeatures.DocumentLinkAdapter(worker)));
|
|
||||||
disposables.push(monaco.languages.setTokensProvider(languageId, createTokenizationSupport(true)));
|
|
||||||
disposables.push(monaco.languages.setLanguageConfiguration(languageId, richEditConfiguration));
|
|
||||||
}
|
|
||||||
|
|
||||||
const EMPTY_ELEMENTS:string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'];
|
|
||||||
|
|
||||||
const richEditConfiguration: monaco.languages.LanguageConfiguration = {
|
|
||||||
wordPattern: /(-?\d*\.\d\w*)|([^\[\{\]\}\:\"\,\s]+)/g,
|
|
||||||
|
|
||||||
comments: {
|
|
||||||
blockComment: ['<!--', '-->']
|
|
||||||
},
|
|
||||||
|
|
||||||
brackets: [
|
|
||||||
['<!--', '-->'],
|
|
||||||
['<', '>'],
|
|
||||||
],
|
|
||||||
|
|
||||||
autoClosingPairs: [
|
|
||||||
{ open: '{', close: '}' },
|
|
||||||
{ open: '[', close: ']' },
|
|
||||||
{ open: '(', close: ')' },
|
|
||||||
{ open: '"', close: '"' },
|
|
||||||
{ open: '\'', close: '\'' }
|
|
||||||
],
|
|
||||||
|
|
||||||
surroundingPairs: [
|
|
||||||
{ open: '"', close: '"' },
|
|
||||||
{ open: '\'', close: '\'' }
|
|
||||||
],
|
|
||||||
|
|
||||||
onEnterRules: [
|
|
||||||
{
|
|
||||||
beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'),
|
|
||||||
afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i,
|
|
||||||
action: { indentAction: monaco.languages.IndentAction.IndentOutdent }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'),
|
|
||||||
action: { indentAction: monaco.languages.IndentAction.Indent }
|
|
||||||
}
|
}
|
||||||
],
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,24 +95,6 @@ function withMode(callback: (module: typeof mode) => void): void {
|
||||||
require<typeof mode>(['vs/language/html/htmlMode'], callback);
|
require<typeof mode>(['vs/language/html/htmlMode'], callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
monaco.languages.register({
|
|
||||||
id: htmlLanguageId,
|
|
||||||
extensions: ['.html', '.htm', '.shtml', '.xhtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm'],
|
|
||||||
aliases: ['HTML', 'htm', 'html', 'xhtml'],
|
|
||||||
mimetypes: ['text/html', 'text/x-jshtm', 'text/template', 'text/ng-template']
|
|
||||||
});
|
|
||||||
monaco.languages.register({
|
|
||||||
id: handlebarsLanguageId,
|
|
||||||
extensions: ['.handlebars', '.hbs'],
|
|
||||||
aliases: ['Handlebars', 'handlebars'],
|
|
||||||
mimetypes: ['text/x-handlebars-template']
|
|
||||||
});
|
|
||||||
monaco.languages.register({
|
|
||||||
id: razorLanguageId,
|
|
||||||
extensions: ['.cshtml'],
|
|
||||||
aliases: ['Razor', 'razor'],
|
|
||||||
mimetypes: ['text/x-cshtml']
|
|
||||||
});
|
|
||||||
monaco.languages.onLanguage(htmlLanguageId, () => {
|
monaco.languages.onLanguage(htmlLanguageId, () => {
|
||||||
withMode(mode => mode.setupMode(htmlDefaults));
|
withMode(mode => mode.setupMode(htmlDefaults));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* 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 {Scanner, ScannerState, TokenType, createScanner} from 'vscode-html-languageservice/lib/parser/htmlScanner';
|
|
||||||
|
|
||||||
|
|
||||||
export function createTokenizationSupport(supportComments: boolean): monaco.languages.TokensProvider {
|
|
||||||
return {
|
|
||||||
getInitialState: () => new HTMLState(null, ScannerState.WithinContent),
|
|
||||||
tokenize: (line, state, offsetDelta?, stopAtOffset?) => tokenize(line, <HTMLState>state, offsetDelta, stopAtOffset)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const DELIM_END = 'punctuation.definition.meta.tag.end.html';
|
|
||||||
const DELIM_START = 'punctuation.definition.meta.tag.begin.html';
|
|
||||||
const DELIM_ASSIGN = 'meta.tag.assign.html';
|
|
||||||
const ATTRIB_NAME = 'entity.other.attribute-name.html';
|
|
||||||
const ATTRIB_VALUE = 'string.html';
|
|
||||||
const COMMENT = 'comment.html.content';
|
|
||||||
const DELIM_COMMENT = 'comment.html';
|
|
||||||
const DOCTYPE = 'entity.other.attribute-name.html';
|
|
||||||
const DELIM_DOCTYPE = 'entity.name.tag.html';
|
|
||||||
|
|
||||||
function getTag(name: string) {
|
|
||||||
return TAG_PREFIX + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TAG_PREFIX = 'entity.name.tag.tag-';
|
|
||||||
|
|
||||||
class HTMLState implements monaco.languages.IState {
|
|
||||||
|
|
||||||
private _state: monaco.languages.IState;
|
|
||||||
|
|
||||||
public scannerState: ScannerState;
|
|
||||||
|
|
||||||
constructor(state: monaco.languages.IState, scannerState: ScannerState) {
|
|
||||||
this._state = state;
|
|
||||||
this.scannerState = scannerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clone(): HTMLState {
|
|
||||||
return new HTMLState(this._state, this.scannerState);
|
|
||||||
}
|
|
||||||
|
|
||||||
public equals(other: monaco.languages.IState): boolean {
|
|
||||||
if (other === this) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!other || !(other instanceof HTMLState)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return this.scannerState === (<HTMLState>other).scannerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getStateData(): monaco.languages.IState {
|
|
||||||
return this._state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setStateData(state: monaco.languages.IState): void {
|
|
||||||
this._state = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function tokenize(line: string, state: HTMLState, offsetDelta: number = 0, stopAtOffset = line.length): monaco.languages.ILineTokens {
|
|
||||||
|
|
||||||
let scanner = createScanner(line, 0, state && state.scannerState);
|
|
||||||
let tokenType = scanner.scan();
|
|
||||||
let ret = {
|
|
||||||
tokens: <monaco.languages.IToken[]>[],
|
|
||||||
endState: state.clone()
|
|
||||||
};
|
|
||||||
let position = -1;
|
|
||||||
while (tokenType !== TokenType.EOS && scanner.getTokenOffset() < stopAtOffset) {
|
|
||||||
let scope;
|
|
||||||
switch (tokenType) {
|
|
||||||
case TokenType.AttributeName:
|
|
||||||
scope = ATTRIB_NAME;
|
|
||||||
break;
|
|
||||||
case TokenType.AttributeValue:
|
|
||||||
scope = ATTRIB_VALUE;
|
|
||||||
break;
|
|
||||||
case TokenType.StartTag:
|
|
||||||
case TokenType.EndTag:
|
|
||||||
scope = getTag(scanner.getTokenText());
|
|
||||||
break;
|
|
||||||
case TokenType.DelimiterAssign:
|
|
||||||
scope = DELIM_ASSIGN;
|
|
||||||
break;
|
|
||||||
case TokenType.StartTagOpen:
|
|
||||||
case TokenType.StartTagClose:
|
|
||||||
case TokenType.StartTagSelfClose:
|
|
||||||
scope = DELIM_START;
|
|
||||||
break;
|
|
||||||
case TokenType.EndTagOpen:
|
|
||||||
case TokenType.EndTagClose:
|
|
||||||
scope = DELIM_END;
|
|
||||||
break;
|
|
||||||
case TokenType.Doctype:
|
|
||||||
scope = DOCTYPE;
|
|
||||||
break;
|
|
||||||
case TokenType.StartDoctypeTag:
|
|
||||||
case TokenType.EndDoctypeTag:
|
|
||||||
scope = DELIM_DOCTYPE;
|
|
||||||
break;
|
|
||||||
case TokenType.Comment:
|
|
||||||
scope = COMMENT;
|
|
||||||
break;
|
|
||||||
case TokenType.StartCommentTag:
|
|
||||||
case TokenType.EndCommentTag:
|
|
||||||
scope = DELIM_COMMENT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scope = '';
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
if (position < scanner.getTokenOffset()) {
|
|
||||||
ret.tokens.push({
|
|
||||||
startIndex: scanner.getTokenOffset() + offsetDelta,
|
|
||||||
scopes: scope
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
throw new Error('Scanner did not advance, next 3 characters are: ' + line.substr(scanner.getTokenOffset(), 3));
|
|
||||||
}
|
|
||||||
position = scanner.getTokenOffset();
|
|
||||||
|
|
||||||
tokenType = scanner.scan();
|
|
||||||
}
|
|
||||||
ret.endState = new HTMLState(state.getStateData(), scanner.getScannerState());
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -68,7 +68,9 @@ export class WorkerManager {
|
||||||
createData: {
|
createData: {
|
||||||
languageSettings: this._defaults.options,
|
languageSettings: this._defaults.options,
|
||||||
languageId: this._defaults.languageId
|
languageId: this._defaults.languageId
|
||||||
}
|
},
|
||||||
|
|
||||||
|
label: this._defaults.languageId
|
||||||
});
|
});
|
||||||
|
|
||||||
this._client = this._worker.getProxy();
|
this._client = this._worker.getProxy();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue