From 4bf4b86e92d6d37f4a23811420d7d22d14691936 Mon Sep 17 00:00:00 2001 From: John Simons Date: Tue, 15 Oct 2024 16:42:49 +1000 Subject: [PATCH] endregion snippet extraction does not require tag The snippet extraction via region syntax from VSCode does not require the endregion to have a matching tag --- .../node/markdown/plugins/snippet.test.ts | 143 +++++++++++++++++- src/node/markdown/plugins/snippet.ts | 49 +++--- 2 files changed, 172 insertions(+), 20 deletions(-) diff --git a/__tests__/unit/node/markdown/plugins/snippet.test.ts b/__tests__/unit/node/markdown/plugins/snippet.test.ts index 0ae97dd2afcd..0781b3738a60 100644 --- a/__tests__/unit/node/markdown/plugins/snippet.test.ts +++ b/__tests__/unit/node/markdown/plugins/snippet.test.ts @@ -1,4 +1,9 @@ -import { dedent, rawPathToToken } from 'node/markdown/plugins/snippet' +import { + dedent, + findRegion, + rawPathToToken +} from 'node/markdown/plugins/snippet' +import { expect } from 'vitest' const removeEmptyKeys = >(obj: T) => { return Object.fromEntries( @@ -99,4 +104,140 @@ describe('node/markdown/plugins/snippet', () => { expect(removeEmptyKeys(rawPathToToken(rawPath))).toEqual(token) }) }) + + describe('findRegion', () => { + test('when c# region with matching tag', () => { + const lines = `Console.WriteLine("Before region"); +#region hello +Console.WriteLine("Hello, World!"); +#endregion hello +Console.WriteLine("After region");`.split('\n') + const result = findRegion(lines, 'hello') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + }) + test('when c# region is not indented with spaces and no matching tag', () => { + const lines = `Console.WriteLine("Before region"); +#region hello +Console.WriteLine("Hello, World!"); +#endregion +Console.WriteLine("After region");`.split('\n') + const result = findRegion(lines, 'hello') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + }) + test('when c# region is indented with spaces and no matching tag', () => { + const lines = ` Console.WriteLine("Before region"); + #region hello + Console.WriteLine("Hello, World!"); + #endregion hello + Console.WriteLine("After region");`.split('\n') + const result = findRegion(lines, 'hello') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + ' Console.WriteLine("Hello, World!");' + ) + }) + test('when c# region with matching tag', () => { + const lines = `Console.WriteLine("Before region"); +#region hello +Console.WriteLine("Hello, World!"); +#endregion hello +Console.WriteLine("After region");`.split('\n') + const result = findRegion(lines, 'hello') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + }) + test('when c# region is not indented with spaces and no matching tag', () => { + const lines = `Console.WriteLine("Before region"); +#region hello +Console.WriteLine("Hello, World!"); +#endregion +Console.WriteLine("After region");`.split('\n') + const result = findRegion(lines, 'hello') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + 'Console.WriteLine("Hello, World!");' + ) + }) + + test('when typescript region has matching tag', () => { + const lines = `let regexp: RegExp[] = [] +// #region foo +let start = -1 +// #endregion foo`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + 'let start = -1' + ) + }) + test('when typescript region is indented with spaces and no matching tag', () => { + const lines = ` let regexp: RegExp[] = [] + // #region foo + let start = -1 + // #endregion`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + ' let start = -1' + ) + }) + + test('when css region has matching tag', () => { + const lines = `.body-content { +/* #region foo */ + padding-left: 15px; +/* #endregion foo */ + padding-right: 15px; +}`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + ' padding-left: 15px;' + ) + }) + test('when css region is indented with spaces and no matching tag', () => { + const lines = `.body-content { + /* #region foo */ + padding-left: 15px; + /* #endregion */ + padding-right: 15px; +}`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + ' padding-left: 15px;' + ) + }) + + test('when html region has matching tag', () => { + const lines = ` +

Hello world

+ +

more text

`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + '

Hello world

' + ) + }) + test('when html region is indented with spaces and no matching tag', () => { + const lines = ` +

Hello world

+ +

more text

`.split('\n') + const result = findRegion(lines, 'foo') + + expect(lines.slice(result?.start, result?.end).join('\n')).toBe( + '

Hello world

' + ) + }) + }) }) diff --git a/src/node/markdown/plugins/snippet.ts b/src/node/markdown/plugins/snippet.ts index 17131de2472e..8b8251661640 100644 --- a/src/node/markdown/plugins/snippet.ts +++ b/src/node/markdown/plugins/snippet.ts @@ -59,38 +59,43 @@ function testLine( ) { const [full, tag, name] = regexp.exec(line.trim()) || [] - return ( - full && - tag && - name === regionName && - tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/) - ) + return full && tag && end + ? true + : name === regionName && + tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/) } export function findRegion(lines: Array, regionName: string) { const regionRegexps = [ - /^\/\/ ?#?((?:end)?region) ([\w*-]+)$/, // javascript, typescript, java - /^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/, // css, less, scss - /^#pragma ((?:end)?region) ([\w*-]+)$/, // C, C++ - /^$/, // HTML, markdown - /^#((?:End )Region) ([\w*-]+)$/, // Visual Basic - /^::#((?:end)region) ([\w*-]+)$/, // Bat - /^# ?((?:end)?region) ([\w*-]+)$/ // C#, PHP, Powershell, Python, perl & misc + [ + /^[ \t]*\/\/ ?#?(region) ([\w*-]+)$/, + /^[ \t]*\/\/ ?#?(endregion) ?([\w*-]*)$/ + ], // javascript, typescript, java + [ + /^\/\* ?#(region) ([\w*-]+) ?\*\/$/, + /^\/\* ?#(endregion) ?([\w*-]*) ?\*\/$/ + ], // css, less, scss + [/^#pragma (region) ([\w*-]+)$/, /^#pragma (endregion) ?([\w*-]*)$/], // C, C++ + [/^$/, /^$/], // HTML, markdown + [/^[ \t]*#(Region) ([\w*-]+)$/, /^[ \t]*#(End Region) ?([\w*-]*)$/], // Visual Basic + [/^::#(region) ([\w*-]+)$/, /^::#(endregion) ?([\w*-]*)$/], // Bat + [/^[ \t]*# ?(region) ([\w*-]+)$/, /^[ \t]*# ?(endregion) ?([\w*-]*)$/] // C#, PHP, Powershell, Python, perl & misc ] - let regexp = null + // #reqion foo + let regexp: RegExp[] = [] let start = -1 - + // #endregion for (const [lineId, line] of lines.entries()) { - if (regexp === null) { + if (regexp.length === 0) { for (const reg of regionRegexps) { - if (testLine(line, reg, regionName)) { + if (testLine(line, reg[0], regionName)) { start = lineId + 1 regexp = reg break } } - } else if (testLine(line, regexp, regionName, true)) { + } else if (testLine(line, regexp[1], regionName, true)) { return { start, end: lineId, regexp } } } @@ -181,7 +186,13 @@ export const snippetPlugin = (md: MarkdownIt, srcDir: string) => { content = dedent( lines .slice(region.start, region.end) - .filter((line) => !region.regexp.test(line.trim())) + .filter((line) => { + const trimmed = line.trim() + return ( + !region.regexp[0].test(trimmed) && + !region.regexp[1].test(trimmed) + ) + }) .join('\n') ) }