diff --git a/extensions/configuration-editing/src/configurationEditingMain.ts b/extensions/configuration-editing/src/configurationEditingMain.ts index f63aa685cbe..224a57370b4 100644 --- a/extensions/configuration-editing/src/configurationEditingMain.ts +++ b/extensions/configuration-editing/src/configurationEditingMain.ts @@ -40,8 +40,8 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { provideCompletionItems(document, position, _token) { const location = getLocation(document.getText(), document.offsetAt(position)); if (isCompletingInsidePropertyStringValue(document, location, position)) { - let range = document.getWordRangeAtPosition(position, /\$\{[^\}]*\}/); - if (!range || range.end.isEqual(position) || range.start.isEqual(position)) { + let range = document.getWordRangeAtPosition(position, /\$\{[^"\}]*\}?/); + if (!range || range.start.isEqual(position) || range.end.isEqual(position) && document.getText(range).endsWith('}')) { range = new vscode.Range(position, position); } diff --git a/extensions/configuration-editing/src/settingsDocumentHelper.ts b/extensions/configuration-editing/src/settingsDocumentHelper.ts index a4c0e3945d8..ab41c8220c2 100644 --- a/extensions/configuration-editing/src/settingsDocumentHelper.ts +++ b/extensions/configuration-editing/src/settingsDocumentHelper.ts @@ -96,8 +96,8 @@ export class SettingsDocument { return completions; } - let range = this.document.getWordRangeAtPosition(pos, /\$\{[^\}]*\}/); - if (!range || range.end.isEqual(pos) || range.start.isEqual(pos)) { + let range = this.document.getWordRangeAtPosition(pos, /\$\{[^"\}]*\}?/); + if (!range || range.start.isEqual(pos) || range.end.isEqual(pos) && this.document.getText(range).endsWith('}')) { range = new vscode.Range(pos, pos); } diff --git a/extensions/configuration-editing/src/test/completion.test.ts b/extensions/configuration-editing/src/test/completion.test.ts index 3df7024fa12..e5aec5fc46a 100644 --- a/extensions/configuration-editing/src/test/completion.test.ts +++ b/extensions/configuration-editing/src/test/completion.test.ts @@ -73,6 +73,20 @@ suite('Completions in settings.json', () => { const expected = { label: '${activeEditorMedium}', resultText }; await testCompletion(testFile, 'jsonc', content, expected); } + { // replacing a partial variable + const content = [ + '{', + ' "window.title": "${a|"', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "window.title": "${dirty}"', + '}', + ].join('\n'); + const expected = { label: '${dirty}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } { // inserting a literal const content = [ '{', @@ -382,6 +396,32 @@ suite('Completions in launch.json', () => { const expected = { label: '${cwd}', resultText }; await testCompletion(testFile, 'jsonc', content, expected); } + { + const content = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Do It",', + ' "program": "${workspace|"', + ' }', + ' ]', + '}', + ].join('\n'); + const resultText = [ + '{', + ' "version": "0.2.0",', + ' "configurations": [', + ' {', + ' "name": "Do It",', + ' "program": "${cwd}"', + ' }', + ' ]', + '}', + ].join('\n'); + const expected = { label: '${cwd}', resultText }; + await testCompletion(testFile, 'jsonc', content, expected); + } }); });