1from __future__ import annotations
2
3import argparse
4from typing import Sequence
5
6from babi.highlight import Compiler
7from babi.highlight import Grammars
8from babi.highlight import highlight_line
9from babi.theme import Style
10from babi.theme import Theme
11from babi.user_data import prefix_data
12from babi.user_data import xdg_config
13
14
15def print_styled(s: str, style: Style) -> None:
16    color_s = ''
17    undo_s = ''
18    if style.fg is not None:
19        color_s += '\x1b[38;2;{r};{g};{b}m'.format(**style.fg._asdict())
20        undo_s += '\x1b[39m'
21    if style.bg is not None:
22        color_s += '\x1b[48;2;{r};{g};{b}m'.format(**style.bg._asdict())
23        undo_s += '\x1b[49m'
24    if style.b:
25        color_s += '\x1b[1m'
26        undo_s += '\x1b[22m'
27    if style.i:
28        color_s += '\x1b[3m'
29        undo_s += '\x1b[23m'
30    if style.u:
31        color_s += '\x1b[4m'
32        undo_s += '\x1b[24m'
33    print(f'{color_s}{s}{undo_s}', end='', flush=True)
34
35
36def _highlight_output(theme: Theme, compiler: Compiler, filename: str) -> int:
37    state = compiler.root_state
38
39    if theme.default.bg is not None:
40        print('\x1b[48;2;{r};{g};{b}m'.format(**theme.default.bg._asdict()))
41    with open(filename, encoding='UTF-8') as f:
42        for line_idx, line in enumerate(f):
43            first_line = line_idx == 0
44            state, regions = highlight_line(compiler, state, line, first_line)
45            for start, end, scope in regions:
46                print_styled(line[start:end], theme.select(scope))
47    print('\x1b[m', end='')
48    return 0
49
50
51def main(argv: Sequence[str] | None = None) -> int:
52    parser = argparse.ArgumentParser()
53    parser.add_argument('--theme', default=xdg_config('theme.json'))
54    parser.add_argument('--grammar-dir', default=prefix_data('grammar_v1'))
55    parser.add_argument('filename')
56    args = parser.parse_args(argv)
57
58    with open(args.filename, encoding='UTF-8') as f:
59        first_line = next(f, '')
60
61    theme = Theme.from_filename(args.theme)
62
63    grammars = Grammars(args.grammar_dir)
64    compiler = grammars.compiler_for_file(args.filename, first_line)
65
66    return _highlight_output(theme, compiler, args.filename)
67
68
69if __name__ == '__main__':
70    exit(main())
71