From 3e06b1ecce197d9ff1b6d0d9d536a6cf3de0d848 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:36:19 -0700 Subject: [PATCH 1/3] Support OCaml-style links Fixes #171880 --- .../links/browser/terminalLinkParsing.ts | 41 ++++--------------- .../test/browser/terminalLinkParsing.test.ts | 5 +++ 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts index f6bbd5627dc8e..5bb14e02f76ef 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts @@ -53,12 +53,12 @@ const linkSuffixRegexEol = new Lazy(() => { // foo:339 // foo:339:12 // foo 339 - // foo 339:12 [#140780] + // foo 339:12 [#140780] // "foo",339 // "foo",339:12 `(?::| |['"],)${l()}(:${c()})?$`, - // The quotes below are optional [#171652] - // "foo", line 339 [#40468] + // The quotes below are optional [#171652] + // "foo", line 339 [#40468] // "foo", line 339, col 12 // "foo", line 339, column 12 // "foo":line 339 @@ -71,7 +71,10 @@ const linkSuffixRegexEol = new Lazy(() => { // "foo" on line 339, col 12 // "foo" on line 339, column 12 // "foo" line 339 column 12 - `['"]?(?:,? |: ?| on )line ${l()}(,? col(?:umn)? ${c()})?$`, + // "foo", line 339, character 12 [#171880] + // "foo", line 339, characters 12-13 [#171880] + // "foo", lines 339-340 [#171880] + `['"]?(?:,? |: ?| on )lines? ${l()}(:?-\\d+)?(,? (col(?:umn)?|characters?) ${c()}(:?-\\d+)?)?$`, // foo(339) // foo(339,12) // foo(339, 12) @@ -101,36 +104,10 @@ const linkSuffixRegex = new Lazy(() => { return `(?\\d+)`; } + // These duplicate the regex's above, just without the trailing `$` const lineAndColumnRegexClauses = [ - // foo:339 - // foo:339:12 - // foo 339 - // foo 339:12 [#140780] - // "foo",339 - // "foo",339:12 `(?::| |['"],)${l()}(:${c()})?`, - // The quotes below are optional [#171652] - // foo, line 339 [#40468] - // foo, line 339, col 12 - // foo, line 339, column 12 - // "foo":line 339 - // "foo":line 339, col 12 - // "foo":line 339, column 12 - // "foo": line 339 - // "foo": line 339, col 12 - // "foo": line 339, column 12 - // "foo" on line 339 - // "foo" on line 339, col 12 - // "foo" on line 339, column 12 - // "foo" line 339 column 12 - `['"]?(?:,? |: ?| on )line ${l()}(,? col(?:umn)? ${c()})?`, - // foo(339) - // foo(339,12) - // foo(339, 12) - // foo (339) - // ... - // foo: (339) - // ... + `['"]?(?:,? |: ?| on )lines? ${l()}(:?-\\d+)?(,? (col(?:umn)?|characters?) ${c()}(:?-\\d+)?)?`, `:? ?[\\[\\(]${l()}(?:, ?${c()})?[\\]\\)]`, ]; diff --git a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts index dbdfe673e5420..c4b9e0a2aafdc 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/test/browser/terminalLinkParsing.test.ts @@ -99,6 +99,11 @@ const testLinks: ITestLink[] = [ { link: 'foo: [339,12]', prefix: undefined, suffix: ': [339,12]', hasRow: true, hasCol: true }, { link: 'foo: [339, 12]', prefix: undefined, suffix: ': [339, 12]', hasRow: true, hasCol: true }, + // OCaml-style + { link: '"foo", line 339, character 12', prefix: '"', suffix: '", line 339, character 12', hasRow: true, hasCol: true }, + { link: '"foo", line 339, characters 12-13', prefix: '"', suffix: '", line 339, characters 12-13', hasRow: true, hasCol: true }, + { link: '"foo", lines 339-340', prefix: '"', suffix: '", lines 339-340', hasRow: true, hasCol: false }, + // Non-breaking space { link: 'foo\u00A0339:12', prefix: undefined, suffix: '\u00A0339:12', hasRow: true, hasCol: true }, { link: '"foo" on line 339,\u00A0column 12', prefix: '"', suffix: '" on line 339,\u00A0column 12', hasRow: true, hasCol: true }, From dbd3595cf32f0961697e2d2d0d8804a60caf7962 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:38:45 -0700 Subject: [PATCH 2/3] Ignore some capture groups --- .../terminalContrib/links/browser/terminalLinkParsing.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts index 5bb14e02f76ef..839ea136cfcf0 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts @@ -74,7 +74,7 @@ const linkSuffixRegexEol = new Lazy(() => { // "foo", line 339, character 12 [#171880] // "foo", line 339, characters 12-13 [#171880] // "foo", lines 339-340 [#171880] - `['"]?(?:,? |: ?| on )lines? ${l()}(:?-\\d+)?(,? (col(?:umn)?|characters?) ${c()}(:?-\\d+)?)?$`, + `['"]?(?:,? |: ?| on )lines? ${l()}(?:-\\d+)?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-\\d+)?)?$`, // foo(339) // foo(339,12) // foo(339, 12) @@ -107,7 +107,7 @@ const linkSuffixRegex = new Lazy(() => { // These duplicate the regex's above, just without the trailing `$` const lineAndColumnRegexClauses = [ `(?::| |['"],)${l()}(:${c()})?`, - `['"]?(?:,? |: ?| on )lines? ${l()}(:?-\\d+)?(,? (col(?:umn)?|characters?) ${c()}(:?-\\d+)?)?`, + `['"]?(?:,? |: ?| on )lines? ${l()}(?:-\\d+)?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-\\d+)?)?`, `:? ?[\\[\\(]${l()}(?:, ?${c()})?[\\]\\)]`, ]; From cf313e611d8c66236814de0222a9bad781dfa814 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 24 Mar 2023 16:50:11 -0700 Subject: [PATCH 3/3] Only define link regexes once in a generator function --- .../links/browser/terminalLinkParsing.ts | 47 ++++++------------- 1 file changed, 15 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts index 839ea136cfcf0..b49ae9007eb1d 100644 --- a/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts +++ b/src/vs/workbench/contrib/terminalContrib/links/browser/terminalLinkParsing.ts @@ -29,10 +29,17 @@ export interface ILinkPartialRange { text: string; } +/** + * A regex that extracts the link suffix which contains line and column information. The link suffix + * must terminate at the end of line. + */ +const linkSuffixRegexEol = new Lazy(() => generateLinkSuffixRegex(true)); /** * A regex that extracts the link suffix which contains line and column information. */ -const linkSuffixRegexEol = new Lazy(() => { +const linkSuffixRegex = new Lazy(() => generateLinkSuffixRegex(false)); + +function generateLinkSuffixRegex(eolOnly: boolean) { let ri = 0; let ci = 0; function l(): string { @@ -42,6 +49,8 @@ const linkSuffixRegexEol = new Lazy(() => { return `(?\\d+)`; } + const eolSuffix = eolOnly ? '$' : ''; + // The comments in the regex below use real strings/numbers for better readability, here's // the legend: // - Path = foo @@ -56,7 +65,7 @@ const linkSuffixRegexEol = new Lazy(() => { // foo 339:12 [#140780] // "foo",339 // "foo",339:12 - `(?::| |['"],)${l()}(:${c()})?$`, + `(?::| |['"],)${l()}(:${c()})?` + eolSuffix, // The quotes below are optional [#171652] // "foo", line 339 [#40468] // "foo", line 339, col 12 @@ -74,7 +83,7 @@ const linkSuffixRegexEol = new Lazy(() => { // "foo", line 339, character 12 [#171880] // "foo", line 339, characters 12-13 [#171880] // "foo", lines 339-340 [#171880] - `['"]?(?:,? |: ?| on )lines? ${l()}(?:-\\d+)?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-\\d+)?)?$`, + `['"]?(?:,? |: ?| on )lines? ${l()}(?:-\\d+)?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-\\d+)?)?` + eolSuffix, // foo(339) // foo(339,12) // foo(339, 12) @@ -82,33 +91,7 @@ const linkSuffixRegexEol = new Lazy(() => { // ... // foo: (339) // ... - `:? ?[\\[\\(]${l()}(?:, ?${c()})?[\\]\\)]$`, - ]; - - const suffixClause = lineAndColumnRegexClauses - // Join all clauses together - .join('|') - // Convert spaces to allow the non-breaking space char (ascii 160) - .replace(/ /g, `[${'\u00A0'} ]`); - - return new RegExp(`(${suffixClause})`); -}); - -const linkSuffixRegex = new Lazy(() => { - let ri = 0; - let ci = 0; - function l(): string { - return `(?\\d+)`; - } - function c(): string { - return `(?\\d+)`; - } - - // These duplicate the regex's above, just without the trailing `$` - const lineAndColumnRegexClauses = [ - `(?::| |['"],)${l()}(:${c()})?`, - `['"]?(?:,? |: ?| on )lines? ${l()}(?:-\\d+)?(?:,? (?:col(?:umn)?|characters?) ${c()}(?:-\\d+)?)?`, - `:? ?[\\[\\(]${l()}(?:, ?${c()})?[\\]\\)]`, + `:? ?[\\[\\(]${l()}(?:, ?${c()})?[\\]\\)]` + eolSuffix, ]; const suffixClause = lineAndColumnRegexClauses @@ -117,8 +100,8 @@ const linkSuffixRegex = new Lazy(() => { // Convert spaces to allow the non-breaking space char (ascii 160) .replace(/ /g, `[${'\u00A0'} ]`); - return new RegExp(`(${suffixClause})`, 'g'); -}); + return new RegExp(`(${suffixClause})`, eolOnly ? undefined : 'g'); +} /** * Removes the optional link suffix which contains line and column information.