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
|
from textual.widgets import Static
from textual.containers import Container
from rich.syntax import Syntax
from pygments.lexers import get_lexer_for_mimetype
from pygments.util import ClassNotFound
# mime list from gemini://geminispace.info/statistics
mimetolexer = {
"text/x-diff": "diff",
"text/x-csrc": "c",
"text/x-python": "python",
"text/markdown": "markdown",
"text/x-patch": "diff",
"text/x-c++src": "cpp",
"text/x-pascal": "pascal",
"text/x-c++hdr": "cpp",
"text/x-go": "go",
"text/x-rust": "rust",
"text/css": "css",
"text/x-php": "php",
# Hopefully, future handlers will take care of these mimes first.
"application/json": "json",
"text/html": "html",
"application/xml": "xml",
"application/atom+xml": "xml",
"text/xml": "xml",
"image/svg+xml": "xml",
# Less popular mimes will call out to get_lexer_for_mimetype
}
class HighlightedCode(Static):
"""Plaintext widget."""
def __init__(self, fp, id, mime):
super().__init__(id=id)
self.addblock(fp, mime)
def addblock(self, fp, mime):
code = ""
# Read the whole file first, then render it all.
# Hopefully not a problem, because source code should have terminal length.
for lin in fp:
line = lin
if type(line) is bytes:
line = line.decode("UTF-8")
code += line
lexer = mimetolexer[mime] if mime in mimetolexer else get_lexer_for_mimetype(mime)
self.mount(Static(Syntax(code,lexer=lexer,background_color="default")))
def can_handle_mime(mime):
if mime in mimetolexer:
return True
try:
get_lexer_for_mimetype(mime)
return True
except ClassNotFound:
pass
return False
|