Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Syntax.guess_lexer, add support for more lexers (e.g. Django templates etc.) #1869

Merged
merged 6 commits into from
Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Tidying up Syntax.guess_lexer, adding test
  • Loading branch information
darrenburns committed Jan 25, 2022
commit 15e72ab4332eef81ed4e834633c700dc13d17cae
38 changes: 25 additions & 13 deletions rich/syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,12 @@ def from_path(

@classmethod
def guess_lexer(cls, path: AnyStr, code: Optional[str] = None) -> str:
"""Guess the name of the Pygments lexer to use based on path and optional string of code.
Initially looks at file extension and falls back to analysing the code, if supplied.
"""Guess the alias of the Pygments lexer to use based on a path and an optional string of code.
If code is supplied, it will use a combination of the code and the filename to determine the
best lexer to use. For example, if the file is ``index.html`` and the file contains Django
templating syntax, then "html+django" will be returned. If the file is ``index.html``, and no
templating language is used, the "html" lexer will be used. If no string of code
is supplied, the lexer will be chosen based on the file extension..

Args:
path (AnyStr): The path to the file containing the code you wish to know the lexer for.
Expand All @@ -333,21 +337,29 @@ def guess_lexer(cls, path: AnyStr, code: Optional[str] = None) -> str:
Returns:
str: The name of the Pygments lexer that best matches the supplied path/code.
"""
lexer = None
lexer: Optional[Lexer] = None
lexer_name = "default"
try:
_, ext = os.path.splitext(path)
if ext:
extension = ext.lstrip(".").lower()
lexer = get_lexer_by_name(extension)
lexer_name = lexer.name
except ClassNotFound:
pass
if code and lexer is None:
if code:
try:
lexer_name = guess_lexer_for_filename(path, code).name
lexer: Lexer = guess_lexer_for_filename(path, code)
except ClassNotFound:
pass

if not lexer:
try:
_, ext = os.path.splitext(path)
if ext:
extension = ext.lstrip(".").lower()
lexer = get_lexer_by_name(extension)
except ClassNotFound:
pass

if lexer:
if lexer.aliases:
lexer_name = lexer.aliases[0]
else:
lexer_name = lexer.name

return lexer_name

def _get_base_style(self) -> Style:
Expand Down
17 changes: 12 additions & 5 deletions tests/test_syntax.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# coding=utf-8

import os
import sys
import os, tempfile
import tempfile

import pytest
from .render import render
from pygments.lexers import PythonLexer

from rich.panel import Panel
from rich.style import Style
from rich.syntax import Syntax, ANSISyntaxTheme, PygmentsSyntaxTheme, Color, Console

from pygments.lexers import PythonLexer
from rich.syntax import ANSISyntaxTheme, Color, Console, PygmentsSyntaxTheme, Syntax

from .render import render

CODE = '''\
def loop_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]:
Expand Down Expand Up @@ -266,6 +266,13 @@ def test_from_file_unknown_lexer():
os.remove(path)


def test_syntax_guess_lexer():
assert Syntax.guess_lexer("banana.py", "import this") == "python"
assert Syntax.guess_lexer("banana.html", "<a href='#'>hello</a>") == "html"
assert Syntax.guess_lexer("banana.html", "<%= @foo %>") == "rhtml"
assert Syntax.guess_lexer("banana.html", "{{something|filter:3}}") == "html+django"


if __name__ == "__main__":
syntax = Panel.fit(
Syntax(
Expand Down