-
-
Notifications
You must be signed in to change notification settings - Fork 320
/
code-to-tokens-ansi.ts
98 lines (85 loc) · 2.96 KB
/
code-to-tokens-ansi.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { createAnsiSequenceParser, createColorPalette, namedColors } from 'ansi-sequence-parser'
import type { ThemeRegistrationResolved, ThemedToken, TokenizeWithThemeOptions } from './types'
import { FontStyle } from './types'
import { applyColorReplacements, splitLines } from './utils'
export function tokenizeAnsiWithTheme(
theme: ThemeRegistrationResolved,
fileContents: string,
options?: TokenizeWithThemeOptions,
): ThemedToken[][] {
const colorReplacements = {
...theme.colorReplacements,
...options?.colorReplacements,
}
const lines = splitLines(fileContents)
const colorPalette = createColorPalette(
Object.fromEntries(
namedColors.map(name => [
name,
theme.colors?.[`terminal.ansi${name[0].toUpperCase()}${name.substring(1)}`],
]),
) as any,
)
const parser = createAnsiSequenceParser()
return lines.map(line =>
parser.parse(line[0]).map((token): ThemedToken => {
let color: string
let bgColor: string | undefined
if (token.decorations.has('reverse')) {
color = token.background ? colorPalette.value(token.background) : theme.bg
bgColor = token.foreground ? colorPalette.value(token.foreground) : theme.fg
}
else {
color = token.foreground ? colorPalette.value(token.foreground) : theme.fg
bgColor = token.background ? colorPalette.value(token.background) : undefined
}
color = applyColorReplacements(color, colorReplacements)
bgColor = applyColorReplacements(bgColor, colorReplacements)
if (token.decorations.has('dim'))
color = dimColor(color)
let fontStyle: FontStyle = FontStyle.None
if (token.decorations.has('bold'))
fontStyle |= FontStyle.Bold
if (token.decorations.has('italic'))
fontStyle |= FontStyle.Italic
if (token.decorations.has('underline'))
fontStyle |= FontStyle.Underline
return {
content: token.value,
offset: line[1], // TODO: more accurate offset? might need to fork ansi-sequence-parser
color,
bgColor,
fontStyle,
}
}),
)
}
/**
* Adds 50% alpha to a hex color string or the "-dim" postfix to a CSS variable
*/
function dimColor(color: string) {
const hexMatch = color.match(/#([0-9a-f]{3})([0-9a-f]{3})?([0-9a-f]{2})?/)
if (hexMatch) {
if (hexMatch[3]) {
// convert from #rrggbbaa to #rrggbb(aa/2)
const alpha = Math.round(Number.parseInt(hexMatch[3], 16) / 2)
.toString(16)
.padStart(2, '0')
return `#${hexMatch[1]}${hexMatch[2]}${alpha}`
}
else if (hexMatch[2]) {
// convert from #rrggbb to #rrggbb80
return `#${hexMatch[1]}${hexMatch[2]}80`
}
else {
// convert from #rgb to #rrggbb80
return `#${Array.from(hexMatch[1])
.map(x => `${x}${x}`)
.join('')}80`
}
}
const cssVarMatch = color.match(/var\((--[\w-]+-ansi-[\w-]+)\)/)
if (cssVarMatch)
return `var(${cssVarMatch[1]}-dim)`
return color
}