Allow using tree-sitter-language-pack if installed#6344
Allow using tree-sitter-language-pack if installed#6344dhirschfeld wants to merge 2 commits intoTextualize:mainfrom
tree-sitter-language-pack if installed#6344Conversation
|
bump! |
|
🙏 |
There was a problem hiding this comment.
Pull request overview
This pull request adds support for the tree-sitter-language-pack package as an alternative way to load tree-sitter language parsers in Textual. The implementation creates a fallback chain: if tree-sitter-language-pack is installed, it will be used to load languages; otherwise, Textual falls back to loading individual tree-sitter-{language} packages as before.
Changes:
- Restructured the tree-sitter import logic to support optional tree-sitter-language-pack
- Maintained backward compatibility with individual tree-sitter language packages
- Preserved consistent error handling and logging across both code paths
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try: | ||
| import tree_sitter_language_pack as tslp | ||
|
|
||
| except ImportError: | ||
| _LANGUAGE_CACHE: dict[str, Language] = {} | ||
|
|
||
| def get_language(language_name: str) -> Language | None: | ||
| if language_name in _LANGUAGE_CACHE: | ||
| return _LANGUAGE_CACHE[language_name] | ||
|
|
||
| def get_language(language_name: str) -> Language | None: | ||
| if language_name in _LANGUAGE_CACHE: | ||
| return _LANGUAGE_CACHE[language_name] | ||
|
|
||
| try: | ||
| module = import_module(f"tree_sitter_{language_name}") | ||
| except ImportError: | ||
| return None | ||
| else: | ||
| try: | ||
| if language_name == "xml": | ||
| # xml uses language_xml() instead of language() | ||
| # it's the only outlier amongst the languages in the `textual[syntax]` extra | ||
| language = Language(module.language_xml()) | ||
| else: | ||
| language = Language(module.language()) | ||
| except (OSError, AttributeError): | ||
| log.warning(f"Could not load language {language_name!r}.") | ||
| module = import_module(f"tree_sitter_{language_name}") | ||
| except ImportError: | ||
| return None | ||
| else: | ||
| _LANGUAGE_CACHE[language_name] = language | ||
| return language | ||
| try: | ||
| if language_name == "xml": | ||
| # xml uses language_xml() instead of language() | ||
| # it's the only outlier amongst the languages in the `textual[syntax]` extra | ||
| language = Language(module.language_xml()) | ||
| else: | ||
| language = Language(module.language()) | ||
| except (OSError, AttributeError): | ||
| log.warning(f"Could not load language {language_name!r}.") | ||
| return None | ||
| else: | ||
| _LANGUAGE_CACHE[language_name] = language | ||
| return language | ||
|
|
||
| except ImportError: | ||
| _tree_sitter = False | ||
| else: | ||
|
|
||
| def get_language(language_name: str) -> Language | None: | ||
| return None | ||
| def get_language(language_name: str) -> Language | None: | ||
| try: | ||
| return tslp.get_language(language_name) | ||
| except LookupError: | ||
| log.warning(f"Could not load language {language_name!r}.") | ||
| return None |
There was a problem hiding this comment.
The new tree-sitter-language-pack integration lacks test coverage. Consider adding tests that verify:
- The fallback chain works correctly (tslp -> individual packages -> None)
- get_language returns the correct Language object when using tslp
- Warning messages are logged appropriately when language loading fails via tslp
- The behavior is consistent between tslp and individual package loading
This is important because the new code path has not been validated through automated testing, which could lead to runtime issues if the tslp package behaves differently than expected.
| def get_language(language_name: str) -> Language | None: | ||
| try: | ||
| return tslp.get_language(language_name) | ||
| except LookupError: | ||
| log.warning(f"Could not load language {language_name!r}.") | ||
| return None |
There was a problem hiding this comment.
The XML language special case handling (using language_xml() instead of language()) is only present in the individual package loading path but not in the tree-sitter-language-pack path. This assumes that tree-sitter-language-pack handles the XML special case internally.
Please verify that tree-sitter-language-pack correctly handles XML language loading, or add explicit handling for XML in the tslp code path if needed. If the special case is indeed handled by tslp, consider adding a comment explaining why the special case is not needed here.
| else: | ||
| _tree_sitter = True | ||
| try: | ||
| import tree_sitter_language_pack as tslp |
There was a problem hiding this comment.
I have a no abbreviation policy in Textual. I know its verbose, but let's not alias this.
Resolves #6324