/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /* -------------------------------------------------------------------------------------------- * Includes code from typescript-sublime-plugin project, obtained from * https://github.com/microsoft/TypeScript-Sublime-Plugin/blob/master/TypeScript%20Indent.tmPreferences * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import { Disposable } from '../utils/dispose'; import * as languageModeIds from '../utils/languageModeIds'; const jsTsLanguageConfiguration: vscode.LanguageConfiguration = { indentationRules: { decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]].*$/, increaseIndentPattern: /^((?!\/\/).)*(\{([^}"'`]*|(\t|[ ])*\/\/.*)|\([^)"'`]*|\[[^\]"'`]*)$/, // e.g. * ...| or */| or *-----*/| unIndentedLinePattern: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$|^(\t|[ ])*[ ]\*\/\s*$|^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/ }, wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, onEnterRules: [ { // e.g. /** | */ beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, afterText: /^\s*\*\/$/, action: { indentAction: vscode.IndentAction.IndentOutdent, appendText: ' * ' }, }, { // e.g. /** ...| beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, action: { indentAction: vscode.IndentAction.None, appendText: ' * ' }, }, { // e.g. * ...| beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, previousLineText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, action: { indentAction: vscode.IndentAction.None, appendText: '* ' }, }, { // e.g. */| beforeText: /^(\t|[ ])*[ ]\*\/\s*$/, action: { indentAction: vscode.IndentAction.None, removeText: 1 }, }, { // e.g. *-----*/| beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/, action: { indentAction: vscode.IndentAction.None, removeText: 1 }, }, { beforeText: /^\s*(\bcase\s.+:|\bdefault:)$/, afterText: /^(?!\s*(\bcase\b|\bdefault\b))/, action: { indentAction: vscode.IndentAction.Indent }, } ] }; const EMPTY_ELEMENTS: string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr']; const jsxTagsLanguageConfiguration: vscode.LanguageConfiguration = { wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, onEnterRules: [ { beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w\\-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i, action: { indentAction: vscode.IndentAction.IndentOutdent } }, { beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w\\-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), action: { indentAction: vscode.IndentAction.Indent } }, { // `beforeText` only applies to tokens of a given language. Since we are dealing with jsx-tags, // make sure we apply to the closing `>` of a tag so that mixed language spans // such as `
` are handled properly. beforeText: /^>$/, afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i, action: { indentAction: vscode.IndentAction.IndentOutdent } }, { beforeText: /^>$/, action: { indentAction: vscode.IndentAction.Indent } }, ], }; export class LanguageConfigurationManager extends Disposable { constructor() { super(); const standardLanguages = [ languageModeIds.javascript, languageModeIds.javascriptreact, languageModeIds.typescript, languageModeIds.typescriptreact, ]; for (const language of standardLanguages) { this.registerConfiguration(language, jsTsLanguageConfiguration); } this.registerConfiguration(languageModeIds.jsxTags, jsxTagsLanguageConfiguration); } private registerConfiguration(language: string, config: vscode.LanguageConfiguration) { this._register(vscode.languages.setLanguageConfiguration(language, config)); } }