better lexer guessing

This commit is contained in:
Will McGugan
2025-10-08 17:55:19 +01:00
parent de663435a4
commit d497bc711a
3 changed files with 22 additions and 10 deletions

View File

@@ -64,19 +64,28 @@ def guess_language(code: str, path: str) -> str:
The language, suitable for use with Pygments. The language, suitable for use with Pygments.
""" """
if path is not None and os.path.splitext(path)[-1] == ".tcss": if path and os.path.splitext(path)[-1] == ".tcss":
# A special case for TCSS files which aren't known outside of Textual # A special case for TCSS files which aren't known outside of Textual
return "scss" return "scss"
lexer: Lexer | None = None lexer: Lexer | None = None
lexer_name = "default" lexer_name = "default"
if code: if code:
try: if path:
lexer = guess_lexer_for_filename(path, code) try:
except ClassNotFound: lexer = guess_lexer_for_filename(path, code)
pass except ClassNotFound:
pass
if not lexer: if lexer is None:
from pygments.lexers import guess_lexer
try:
lexer = guess_lexer(code)
except Exception:
pass
if not lexer and path:
try: try:
_, ext = os.path.splitext(path) _, ext = os.path.splitext(path)
if ext: if ext:
@@ -113,9 +122,7 @@ def highlight(
Returns: Returns:
A Content instance which may be used in a widget. A Content instance which may be used in a widget.
""" """
if language is None: if not language:
if path is None:
raise RuntimeError("One of 'language' or 'path' must be supplied.")
language = guess_language(code, path) language = guess_language(code, path)
assert language is not None assert language is not None

View File

@@ -870,12 +870,13 @@ class MarkdownFence(MarkdownBlock):
self.lexer = token.info self.lexer = token.info
self._highlighted_code = self.highlight(self.code, self.lexer) self._highlighted_code = self.highlight(self.code, self.lexer)
@property
def allow_horizontal_scroll(self) -> bool: def allow_horizontal_scroll(self) -> bool:
return True return True
@classmethod @classmethod
def highlight(cls, code: str, language: str) -> Content: def highlight(cls, code: str, language: str) -> Content:
return highlight(code, language=language) return highlight(code, language=language or None)
def _copy_context(self, block: MarkdownBlock) -> None: def _copy_context(self, block: MarkdownBlock) -> None:
if isinstance(block, MarkdownFence): if isinstance(block, MarkdownFence):

View File

@@ -19,9 +19,13 @@ def test_highlight() -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"code,path,language", "code,path,language",
[ [
("", "", "default"),
("# Don't matter", "foo.tcss", "scss"),
("import this", "foo.py", "python"), ("import this", "foo.py", "python"),
("<xml>", "foo.xml", "xml"), ("<xml>", "foo.xml", "xml"),
("{}", "data.json", "json"), ("{}", "data.json", "json"),
("#! python", "", "python"),
("", "foo.py", "python"),
], ],
) )
def test_guess_language(code: str, path: str, language: str) -> None: def test_guess_language(code: str, path: str, language: str) -> None: