fix(tui): preserve dunder identifiers in markdown
This commit is contained in:
@@ -46,7 +46,7 @@ const renderPlain = (node: React.ReactNode) => {
|
|||||||
describe('INLINE_RE emphasis', () => {
|
describe('INLINE_RE emphasis', () => {
|
||||||
it('matches word-boundary italic/bold', () => {
|
it('matches word-boundary italic/bold', () => {
|
||||||
expect(matches('say _hi_ there')).toEqual(['_hi_'])
|
expect(matches('say _hi_ there')).toEqual(['_hi_'])
|
||||||
expect(matches('very __bold__ move')).toEqual(['__bold__'])
|
expect(matches('very __bold move__ today')).toEqual(['__bold move__'])
|
||||||
expect(matches('(_paren_) and [_bracket_]')).toEqual(['_paren_', '_bracket_'])
|
expect(matches('(_paren_) and [_bracket_]')).toEqual(['_paren_', '_bracket_'])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -58,6 +58,12 @@ describe('INLINE_RE emphasis', () => {
|
|||||||
expect(matches('foo__bar__baz')).toEqual([])
|
expect(matches('foo__bar__baz')).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('keeps Python dunder identifiers literal', () => {
|
||||||
|
expect(matches('if __name__ == "__main__":')).toEqual([])
|
||||||
|
expect(matches('def __init__(self):')).toEqual([])
|
||||||
|
expect(matches('print(__file__)')).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
it('still matches asterisk emphasis intraword', () => {
|
it('still matches asterisk emphasis intraword', () => {
|
||||||
expect(matches('a*b*c')).toEqual(['*b*'])
|
expect(matches('a*b*c')).toEqual(['*b*'])
|
||||||
expect(matches('a**bold**c')).toEqual(['**bold**'])
|
expect(matches('a**bold**c')).toEqual(['**bold**'])
|
||||||
@@ -93,7 +99,12 @@ describe('stripInlineMarkup', () => {
|
|||||||
it('strips word-boundary emphasis only', () => {
|
it('strips word-boundary emphasis only', () => {
|
||||||
expect(stripInlineMarkup('say _hi_ there')).toBe('say hi there')
|
expect(stripInlineMarkup('say _hi_ there')).toBe('say hi there')
|
||||||
expect(stripInlineMarkup('browser_screenshot_ecc.png')).toBe('browser_screenshot_ecc.png')
|
expect(stripInlineMarkup('browser_screenshot_ecc.png')).toBe('browser_screenshot_ecc.png')
|
||||||
expect(stripInlineMarkup('__bold__ and foo__bar__')).toBe('bold and foo__bar__')
|
expect(stripInlineMarkup('__bold move__ and foo__bar__')).toBe('bold move and foo__bar__')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('preserves Python dunder identifiers', () => {
|
||||||
|
expect(stripInlineMarkup('if __name__ == "__main__":')).toBe('if __name__ == "__main__":')
|
||||||
|
expect(stripInlineMarkup('class X: def __init__(self): pass')).toBe('class X: def __init__(self): pass')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('leaves ~!/~? kaomoji alone and still handles real subscript', () => {
|
it('leaves ~!/~? kaomoji alone and still handles real subscript', () => {
|
||||||
@@ -216,6 +227,24 @@ describe('Md wrapping', () => {
|
|||||||
|
|
||||||
expect(lines.some(line => line.startsWith(' hi ok'))).toBe(true)
|
expect(lines.some(line => line.startsWith(' hi ok'))).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('renders Python dunder identifiers literally outside code fences', () => {
|
||||||
|
const lines = renderPlain(
|
||||||
|
React.createElement(
|
||||||
|
Box,
|
||||||
|
{ width: 80 },
|
||||||
|
React.createElement(Md, {
|
||||||
|
t: DEFAULT_THEME,
|
||||||
|
text: 'if __name__ == "__main__":\n obj.__init__()'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const rendered = lines.join('\n')
|
||||||
|
|
||||||
|
expect(rendered).toContain('if __name__ == "__main__":')
|
||||||
|
expect(rendered).toContain('obj.__init__()')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Md link labels', () => {
|
describe('Md link labels', () => {
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ const NUMBERED_RE = /^(\s*)(\d+)[.)]\s+(.*)$/
|
|||||||
const QUOTE_RE = /^\s*(?:>\s*)+/
|
const QUOTE_RE = /^\s*(?:>\s*)+/
|
||||||
const TABLE_DIVIDER_CELL_RE = /^:?-{3,}:?$/
|
const TABLE_DIVIDER_CELL_RE = /^:?-{3,}:?$/
|
||||||
const MD_URL_RE = '((?:[^\\s()]|\\([^\\s()]*\\))+?)'
|
const MD_URL_RE = '((?:[^\\s()]|\\([^\\s()]*\\))+?)'
|
||||||
|
const MD_IDENTIFIER_RE = '[A-Za-z_][A-Za-z0-9_]*'
|
||||||
|
const MD_DUNDER_IDENTIFIER_RE = `(?:${MD_IDENTIFIER_RE}__(?!\\w))`
|
||||||
|
const MD_UNDERSCORE_BOLD_RE = `(?<!\\w)__(?!${MD_DUNDER_IDENTIFIER_RE})(.+?)__(?!\\w)`
|
||||||
|
const MD_UNDERSCORE_ITALIC_RE = `(?<![\\w_])_(?!_)(.+?)(?<!_)_(?![\\w_])`
|
||||||
|
const STRIP_UNDERSCORE_BOLD_RE = new RegExp(MD_UNDERSCORE_BOLD_RE, 'g')
|
||||||
|
const STRIP_UNDERSCORE_ITALIC_RE = new RegExp(MD_UNDERSCORE_ITALIC_RE, 'g')
|
||||||
|
|
||||||
// Display math openers: `$$ ... $$` (TeX) and `\[ ... \]` (LaTeX). The
|
// Display math openers: `$$ ... $$` (TeX) and `\[ ... \]` (LaTeX). The
|
||||||
// opener is matched only when `$$` / `\[` appears at the very start of the
|
// opener is matched only when `$$` / `\[` appears at the very start of the
|
||||||
@@ -107,9 +113,9 @@ export const INLINE_RE = new RegExp(
|
|||||||
`~~(.+?)~~`, // 6 strike
|
`~~(.+?)~~`, // 6 strike
|
||||||
`\`([^\\\`]+)\``, // 7 code
|
`\`([^\\\`]+)\``, // 7 code
|
||||||
`\\*\\*(.+?)\\*\\*`, // 8 bold *
|
`\\*\\*(.+?)\\*\\*`, // 8 bold *
|
||||||
`(?<!\\w)__(.+?)__(?!\\w)`, // 9 bold _
|
MD_UNDERSCORE_BOLD_RE, // 9 bold _
|
||||||
`\\*(.+?)\\*`, // 10 italic *
|
`\\*(.+?)\\*`, // 10 italic *
|
||||||
`(?<!\\w)_(.+?)_(?!\\w)`, // 11 italic _
|
MD_UNDERSCORE_ITALIC_RE, // 11 italic _
|
||||||
`==(.+?)==`, // 12 highlight
|
`==(.+?)==`, // 12 highlight
|
||||||
`\\[\\^([^\\]]+)\\]`, // 13 footnote ref
|
`\\[\\^([^\\]]+)\\]`, // 13 footnote ref
|
||||||
`\\^([^^\\s][^^]*?)\\^`, // 14 superscript
|
`\\^([^^\\s][^^]*?)\\^`, // 14 superscript
|
||||||
@@ -190,9 +196,9 @@ export const stripInlineMarkup = (v: string) =>
|
|||||||
.replace(/~~(.+?)~~/g, '$1')
|
.replace(/~~(.+?)~~/g, '$1')
|
||||||
.replace(/`([^`]+)`/g, '$1')
|
.replace(/`([^`]+)`/g, '$1')
|
||||||
.replace(/\*\*(.+?)\*\*/g, '$1')
|
.replace(/\*\*(.+?)\*\*/g, '$1')
|
||||||
.replace(/(?<!\w)__(.+?)__(?!\w)/g, '$1')
|
.replace(STRIP_UNDERSCORE_BOLD_RE, '$1')
|
||||||
.replace(/\*(.+?)\*/g, '$1')
|
.replace(/\*(.+?)\*/g, '$1')
|
||||||
.replace(/(?<!\w)_(.+?)_(?!\w)/g, '$1')
|
.replace(STRIP_UNDERSCORE_ITALIC_RE, '$1')
|
||||||
.replace(/==(.+?)==/g, '$1')
|
.replace(/==(.+?)==/g, '$1')
|
||||||
.replace(/\[\^([^\]]+)\]/g, '[$1]')
|
.replace(/\[\^([^\]]+)\]/g, '[$1]')
|
||||||
.replace(/\^([^^\s][^^]*?)\^/g, '^$1')
|
.replace(/\^([^^\s][^^]*?)\^/g, '^$1')
|
||||||
|
|||||||
Reference in New Issue
Block a user