diff --git a/extensions/ql-vscode/language-configuration.json b/extensions/ql-vscode/language-configuration.json index 7e1bb0e09..2a367d4f3 100644 --- a/extensions/ql-vscode/language-configuration.json +++ b/extensions/ql-vscode/language-configuration.json @@ -1,72 +1,38 @@ { - "comments": { - // symbol used for single line comment. Remove this entry if your language does not support line comments - "lineComment": "//", - // symbols used for start and end a block comment. Remove this entry if your language does not support block comments - "blockComment": [ - "/*", - "*/" - ] - }, - // symbols used as brackets - "brackets": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ] - ], - // symbols that are auto closed when typing - "autoClosingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "\"", - "\"" - ], - [ - "'", - "'" - ] - ], - // symbols that that can be used to surround a selection - "surroundingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "\"", - "\"" - ], - [ - "'", - "'" - ] - ] -} \ No newline at end of file + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "'", "close": "'", "notIn": ["string", "comment"] }, + { "open": "\"", "close": "\"", "notIn": ["string"] }, + { "open": "/**", "close": " */", "notIn": ["string"] } + ], + "autoCloseBefore": ";:.=}])> \n\t", + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["'", "'"], + ["\"", "\""] + ], + "folding": { + "markers": { + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" + } + }, + "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\.\\<\\>\\/\\?\\s]+)", + "indentationRules": { + "increaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]].*$", + "decreaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"']*|\\([^)\"']*|\\[[^\\]\"']*)$" + } +} diff --git a/extensions/ql-vscode/src/extension.ts b/extensions/ql-vscode/src/extension.ts index 9b3476fcd..d1ee9de5d 100644 --- a/extensions/ql-vscode/src/extension.ts +++ b/extensions/ql-vscode/src/extension.ts @@ -4,6 +4,7 @@ import { testExplorerExtensionId, TestHub } from 'vscode-test-adapter-api'; import * as archiveFilesystemProvider from './archive-filesystem-provider'; import { CodeQLCliServer } from './cli'; import { DistributionConfigListener, QueryHistoryConfigListener, QueryServerConfigListener } from './config'; +import * as languageSupport from './languageSupport'; import { DatabaseManager } from './databases'; import { DatabaseUI } from './databases-ui'; import { TemplateQueryDefinitionProvider, TemplateQueryReferenceProvider } from './definitions'; @@ -78,6 +79,7 @@ export async function activate(ctx: ExtensionContext): Promise { logger.log('Starting CodeQL extension'); initializeLogging(ctx); + languageSupport.install(); const distributionConfigListener = new DistributionConfigListener(); ctx.subscriptions.push(distributionConfigListener); diff --git a/extensions/ql-vscode/src/languageSupport.ts b/extensions/ql-vscode/src/languageSupport.ts new file mode 100644 index 000000000..40a999cdf --- /dev/null +++ b/extensions/ql-vscode/src/languageSupport.ts @@ -0,0 +1,52 @@ +import { IndentAction, languages } from "vscode"; + + +/** + * OnEnterRules are available in language-configurations, but you cannot specify them in the language-configuration.json. + * They can only be specified programmatically. + * + * Also, we should keep the language-configuration.json as a json file and register it in the package.json because + * it is registered first, before the extension is activated, so language features are available quicker. + * + * See https://github.com/microsoft/vscode/issues/11514 + * See https://github.com/microsoft/vscode/blob/master/src/vs/editor/test/common/modes/supports/javascriptOnEnterRules.ts + */ +export function install() { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const langConfig = require('../language-configuration.json'); + // setLanguageConfiguration requires a regexp for the wordpattern, not a string + langConfig.wordPattern = new RegExp(langConfig.wordPattern); + langConfig.onEnterRules = onEnterRules; + + languages.setLanguageConfiguration('ql', langConfig); + languages.setLanguageConfiguration('qll', langConfig); + languages.setLanguageConfiguration('dbscheme', langConfig); + +} + +const onEnterRules = [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: IndentAction.IndentOutdent, appendText: ' * ' } + }, { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: IndentAction.None, appendText: ' * ' } + }, { + // e.g. * ...| + beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, + oneLineAboveText: /^(\s*(\/\*\*|\*)).*/, + action: { indentAction: IndentAction.None, appendText: '* ' } + }, { + // e.g. */| + beforeText: /^(\t|[ ])*[ ]\*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + }, + { + // e.g. *-----*/| + beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/, + action: { indentAction: IndentAction.None, removeText: 1 } + } +];