Skip to content

Commit

Permalink
endregion snippet extraction does not require tag
Browse files Browse the repository at this point in the history
The snippet extraction via region syntax from VSCode does not require the endregion to have a matching tag
  • Loading branch information
johnsimons committed Nov 26, 2024
1 parent 2397e08 commit b09446e
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 19 deletions.
143 changes: 142 additions & 1 deletion __tests__/unit/node/markdown/plugins/snippet.test.ts
Original file line number Diff line number Diff line change
@@ -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 = <T extends Record<string, unknown>>(obj: T) => {
return Object.fromEntries(
Expand Down Expand Up @@ -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 = `<!-- #region foo -->
<h1>Hello world</h1>
<!-- #endregion foo -->
<p>more text</p>`.split('\n')
const result = findRegion(lines, 'foo')

expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' <h1>Hello world</h1>'
)
})
test('when html region is indented with spaces and no matching tag', () => {
const lines = ` <!-- #region foo -->
<h1>Hello world</h1>
<!-- #endregion foo -->
<p>more text</p>`.split('\n')
const result = findRegion(lines, 'foo')

expect(lines.slice(result?.start, result?.end).join('\n')).toBe(
' <h1>Hello world</h1>'
)
})
})
})
46 changes: 28 additions & 18 deletions src/node/markdown/plugins/snippet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,38 +59,42 @@ 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<string>, regionName: string) {
const regionRegexps = [
/^\/\/ ?#?((?:end)?region) ([\w*-]+)$/, // javascript, typescript, java
/^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/, // css, less, scss
/^#pragma ((?:end)?region) ([\w*-]+)$/, // C, C++
/^<!-- #?((?:end)?region) ([\w*-]+) -->$/, // 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++
[/^<!-- #?(region) ([\w*-]+) -->$/, /^<!-- #?(endregion) ?([\w*-]*) -->$/], // 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
let regexp: RegExp[] = []
let start = -1

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 }
}
}
Expand Down Expand Up @@ -181,7 +185,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')
)
}
Expand Down

0 comments on commit b09446e

Please sign in to comment.