diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 9f94a1b4f82..2066a317d0c 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -175,16 +175,22 @@ export class ViewController { } } - // Check if current token is a string. + // Expand to the contiguous run of string tokens (StandardTokenType.String) around the click position. const lineTokens = tokens.getLineTokens(lineNumber); - const index = lineTokens.findTokenIndexAtOffset(column - 1); - if (lineTokens.getStandardTokenType(index) !== StandardTokenType.String) { - return undefined; + let startIndex = lineTokens.findTokenIndexAtOffset(column - 1); + let endIndex = startIndex; + while (startIndex > 0 && + lineTokens.getStandardTokenType(startIndex - 1) === StandardTokenType.String) { + startIndex--; + } + while (endIndex + 1 < lineTokens.getCount() && + lineTokens.getStandardTokenType(endIndex + 1) === StandardTokenType.String) { + endIndex++; } // Verify the click is after starting or before closing quote. - const tokenStart = lineTokens.getStartOffset(index); - const tokenEnd = lineTokens.getEndOffset(index); + const tokenStart = lineTokens.getStartOffset(startIndex); + const tokenEnd = lineTokens.getEndOffset(endIndex); if (column !== tokenStart + 2 && column !== tokenEnd) { return undefined; } diff --git a/src/vs/editor/test/browser/view/viewController.test.ts b/src/vs/editor/test/browser/view/viewController.test.ts index 95d44801cb7..1a7f4faf2e0 100644 --- a/src/vs/editor/test/browser/view/viewController.test.ts +++ b/src/vs/editor/test/browser/view/viewController.test.ts @@ -309,6 +309,23 @@ suite('ViewController - String content selection', () => { assert.strictEqual(doubleClickAt(controller, new Position(1, 10)), 'hello'); }); + test('Select string content containing escape characters', () => { + // 0123456789... + const text = 'var x = "hello\\"world";'; + // Token layout: [0..8) Other [8..22) String("hello\"world") [22..23) Other + const controller = createViewControllerWithTokens(text, [ + { startIndex: 0, type: StandardTokenType.Other }, + { startIndex: 8, type: StandardTokenType.String }, + { startIndex: 9, type: StandardTokenType.String }, + { startIndex: 14, type: StandardTokenType.String }, + { startIndex: 16, type: StandardTokenType.String }, + { startIndex: 21, type: StandardTokenType.String }, + { startIndex: 22, type: StandardTokenType.Other }, + ]); + // Column right after opening quote: offset 9 → column 10 + assert.strictEqual(doubleClickAt(controller, new Position(1, 10)), 'hello\\"world'); + }); + // -- Click in middle of string should NOT select the whole string -- test('Click in middle of string does not select whole string', () => {