diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 8f79264db20..ad756d157bf 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -33,6 +33,11 @@ "default": true, "description": "Shows possible emmet abbreviations as suggestions" }, + "emmet.includeLanguages": { + "type": "object", + "default": {}, + "description": "Enable emmet abbreviations in languages that are not supported by default. Add a mapping here between the language and emmet supported syntax.\n Eg: {\"php\": \"html\"}" + }, "emmet.variables":{ "type": "object", "properties": { diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index 6d480edda2b..8c270d2155f 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -8,7 +8,7 @@ import { expand } from '@emmetio/expand-abbreviation'; import parseStylesheet from '@emmetio/css-parser'; import parse from '@emmetio/html-matcher'; import { Node, HtmlNode, Rule } from 'EmmetNode'; -import { getNode, getInnerRange } from './util'; +import { getNode, getInnerRange, getMappedSyntax } from './util'; import { getExpandOptions, extractAbbreviation, isStyleSheet, isAbbreviationValid } from 'vscode-emmet-helper'; import { DocumentStreamReader } from './bufferStream'; @@ -204,9 +204,14 @@ function getSyntaxFromArgs(args: any): string { vscode.window.showInformationMessage('No editor is active.'); return; } - if (typeof args !== 'object' || !args['syntax']) { + if (typeof args !== 'object' || !args['language']) { vscode.window.showInformationMessage('Cannot resolve language at cursor.'); return; } - return args['syntax']; + let syntax = getMappedSyntax(args['language']); + if (syntax) { + return syntax; + } + + return getMappedSyntax(args['parentMode']); } \ No newline at end of file diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 3791acc9288..02311c5b19d 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -46,18 +46,37 @@ export function getSyntax(document: vscode.TextDocument): string { return document.languageId; } -export function getMappedModes(): any { +export function getIncludedModes(): any { let finalMappedModes = {}; - let syntaxProfileConfig = vscode.workspace.getConfiguration('emmet')['syntaxProfiles']; - let syntaxProfiles = Object.assign({}, MAPPED_MODES, syntaxProfileConfig ? syntaxProfileConfig : {}); - Object.keys(syntaxProfiles).forEach(syntax => { - if (typeof syntaxProfiles[syntax] === 'string' && LANGUAGE_MODES[syntaxProfiles[syntax]]) { - finalMappedModes[syntax] = syntaxProfiles[syntax]; + let includeLanguagesConfig = vscode.workspace.getConfiguration('emmet')['includeLanguages']; + let includeLanguages = Object.assign({}, MAPPED_MODES, includeLanguagesConfig ? includeLanguagesConfig : {}); + Object.keys(includeLanguages).forEach(syntax => { + if (typeof includeLanguages[syntax] === 'string' && LANGUAGE_MODES[includeLanguages[syntax]]) { + finalMappedModes[syntax] = includeLanguages[syntax]; } }); return finalMappedModes; } +export function getMappedSyntax(syntax: string): string { + if (!syntax) { + return; + } + if (/\b(typescriptreact|javascriptreact|jsx-tags)\b/.test(syntax)) { // treat tsx like jsx + return 'jsx'; + } + if (syntax === 'sass-indented') { // map sass-indented to sass + return 'sass'; + } + if (syntax === 'jade') { + return 'pug'; + } + if (Object.keys(LANGUAGE_MODES).indexOf(syntax) > -1) { + return syntax; + } + return getIncludedModes()[syntax]; +} + export function getExcludedModes(): string[] { let excludedConfig = vscode.workspace.getConfiguration('emmet')['excludeLanguages']; return Array.isArray(excludedConfig) ? excludedConfig : []; diff --git a/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts b/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts index dcc5e5ad74d..f97e1f467e1 100644 --- a/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts +++ b/src/vs/workbench/parts/emmet/electron-browser/editorAccessor.ts @@ -266,6 +266,19 @@ export class EditorAccessor implements emmet.Editor { return syntax; } + public getLanguage() { + let position = this._editor.getSelection().getStartPosition(); + this._editor.getModel().forceTokenization(position.lineNumber); + let languageId = this._editor.getModel().getLanguageIdAtPosition(position.lineNumber, position.column); + let language = this._languageIdentifierResolver.getLanguageIdentifier(languageId).language; + let syntax = language.split('.').pop(); + + return { + language: syntax, + parentMode: this.checkParentMode(syntax) + }; + } + private getSyntaxProfile(syntax: string): string { const profile = this._syntaxProfiles[syntax]; if (profile && typeof profile === 'string') { diff --git a/src/vs/workbench/parts/emmet/electron-browser/emmetActions.ts b/src/vs/workbench/parts/emmet/electron-browser/emmetActions.ts index d283d07d46f..595c7e06b79 100644 --- a/src/vs/workbench/parts/emmet/electron-browser/emmetActions.ts +++ b/src/vs/workbench/parts/emmet/electron-browser/emmetActions.ts @@ -314,8 +314,7 @@ export abstract class EmmetEditorAction extends EditorAction { if (configurationService.getConfiguration().emmet.useNewEmmet && (mappedCommand === 'emmet.expandAbbreviation' || mappedCommand === 'emmet.wrapWithAbbreviation')) { - let syntax = editorAccessor.getSyntax(); - return commandService.executeCommand(mappedCommand, { syntax }); + return commandService.executeCommand(mappedCommand, editorAccessor.getLanguage()); } if (!editorAccessor.isEmmetEnabledMode()) {