diff --git a/docs/src/release_notes.rst b/docs/src/release_notes.rst index d603b3f..f66e1db 100644 --- a/docs/src/release_notes.rst +++ b/docs/src/release_notes.rst @@ -12,6 +12,7 @@ Unreleased ---------- - Declare support for Python 3.12 and 3.13 (:issue:`150`) - Remove support for Python 3.7 and 3.8 (:issue:`150`) +- Fix changed whitespace handling in Pygments 2.19 (:issue:`152`) 0.15.2 (2024-06-03) ------------------- diff --git a/pyproject.toml b/pyproject.toml index cf76e98..63ea423 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ requires-python = ">=3.9" dependencies = [ "sphinx>=3.2.0", "beautifulsoup4>=4.8.1", - "pygments<2.19", ] # Keep extras in sync with requirements manually optional-dependencies = {ipython = ["ipython!=8.7.0"]} diff --git a/src/sphinx_codeautolink/extension/block.py b/src/sphinx_codeautolink/extension/block.py index d19b25c..4e08203 100644 --- a/src/sphinx_codeautolink/extension/block.py +++ b/src/sphinx_codeautolink/extension/block.py @@ -371,20 +371,22 @@ def link_html( # The builtin re doesn't support variable-width lookbehind, # so instead we use a match groups in all pre patterns to remove the non-content. -no_dot_prere = r'(?\.)()' +no_dot_pre = r'(?\.)()' # Potentially instead assert an initial closing parenthesis followed by a dot. -call_dot_prere = r'(\)\s*\.\s*)' -import_prere = ( - r'((import\s+(\(\s*)?)' - r'|(,\s*))' +call_dot_pre = r'(\)\s*\.\s*)' +no_dot_post = r'(?!(\.)|())' + +# Pygments 2.19 changed import whitespace highlighting so we need to support both +# with "w" class and raw whitespace for now (see #152) +whitespace = r'(\s*)|(\s*)' +import_pre = ( + rf'((import{whitespace}(\(\s*)?)' + rf'|(,{whitespace}))' ) -from_prere = r'(from\s+)' +import_post = r'(?=($)|(\s+)|())(?!)' -no_dot_postre = r'(?!(\.)|())' -import_postre = ( - r'(?=($)|(\s+)|(,)|(\)))(?!)' -) -from_postre = r'(?=\s*import)' +from_pre = rf'(from{whitespace})' +from_post = rf'(?={whitespace}import)' def construct_name_pattern(name: Name) -> str: @@ -395,17 +397,17 @@ def construct_name_pattern(name: Name) -> str: [first_name_pattern.format(name=parts[0])] + [name_pattern.format(name=p) for p in parts[1:]] ) - return no_dot_prere + pattern + no_dot_postre + return no_dot_pre + pattern + no_dot_post elif name.context == LinkContext.after_call: parts = name.code_str.split(".") pattern = period.join( [first_name_pattern.format(name=parts[0])] + [name_pattern.format(name=p) for p in parts[1:]] ) - return call_dot_prere + pattern + no_dot_postre + return call_dot_pre + pattern + no_dot_post elif name.context == LinkContext.import_from: pattern = import_from_pattern.format(name=name.code_str) - return from_prere + pattern + from_postre + return from_pre + pattern + from_post elif name.context == LinkContext.import_target: pattern = import_target_pattern.format(name=name.code_str) - return import_prere + pattern + import_postre + return import_pre + pattern + import_post