mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-26 02:15:14 +00:00
* feat: Add comprehensive bash language support
Implement BashLanguageServer using bash-language-server (v5.4.0)
- Add automatic Node.js/npm dependency management
- Support .sh and .bash file extensions
- Include cross-platform compatibility (Windows .cmd handling)
- Add comprehensive test infrastructure with realistic bash scripts
- Integrate bash into Language enum and language server factory
- Add bash pytest marker for selective testing
- Include bash_language_server fixture for tests
Features:
* LSP capabilities: text sync, completion, hover, document symbols
* Runtime dependency installation via npm
* Symbol recognition for functions, variables, conditionals
* Proper LSP initialization and error handling
* Test repository with main.sh, utils.sh, and config.sh examples
Files:
+ src/solidlsp/language_servers/bash_language_server.py (new implementation)
+ test/solidlsp/bash/test_bash_basic.py (comprehensive test suite)
+ test/resources/repos/bash/test_repo/ (test scripts)
* src/solidlsp/ls_config.py (add BASH enum and file patterns)
* src/solidlsp/ls.py (integrate bash language server)
* pyproject.toml (add bash pytest marker)
* test/conftest.py (add bash_language_server fixture)
Tests: 2 passed, 7 appropriately skipped
All existing tests continue to pass (288 passed total)
* trigger flow
* feat: enhance bash function detection with hybrid LSP + regex approach
- Upgrade bash-language-server from 5.4.0 to 5.6.0 for better capabilities
- Add hybrid function detection: primary LSP + regex fallback when needed
- Implement _detect_bash_functions() with regex patterns for both syntax types:
* function name() { } (function keyword syntax)
* name() { } (regular function syntax)
- Add _find_function_end() with brace matching for accurate function boundaries
- Enhance request_document_symbols() with intelligent fallback logic
- Add comprehensive test suite with 4 new test functions:
* test_bash_function_detection_hybrid_approach
* test_bash_function_detection_with_body
* test_bash_regex_fallback_detection
* test_bash_function_syntax_patterns
- All tests passing: 6 passed, 7 skipped, 0 failed
- Maintains 100% backward compatibility
- Enables full symbolic operations for bash functions: find_symbol, replace_symbol_body, etc.
* remove trash
* clean: remove debug changes from Python services.py
- Remove 'MODIFIED VIA SYMBOLIC OPERATIONS!' debug comments
- Remove debug print statements added during testing
- Restore original clean docstring and code
- No functional changes to bash language support implementation
* fix: Remove non-bash specific directory ignoring from BashLanguageServer
- Removes is_ignored_dirname override that included generic directories like node_modules, .cache, tmp, temp
- These directories aren't bash-specific and gitignore already handles file exclusion
- Addresses PR feedback: 'that doesn't seem bash related. Note that gitignored files are ignored anyway'
* fix: Restructure bash tests to follow standard patterns and remove pytest.skip
- Replace custom bash_language_server fixture with standard parametrized language_server fixture
- Remove all pytest.skip statements and replace with proper assertions or failures
- Remove tests for non-existent methods (get_symbols_for_document, get_workspace_symbols, etc.)
- Keep only tests that use actual SolidLanguageServer methods like request_document_symbols
- All bash tests now pass successfully
- Addresses PR feedback about test structure and pytest.skip removal
* docs: Add bash language support to README
- Add Bash to the list of directly supported languages
- Note that it requires Node.js and npm for bash-language-server installation
- Addresses PR feedback about missing README extension for bash support
* docs: Add bash language support to CHANGELOG
- Document comprehensive bash language support with bash-language-server integration
- Highlight key features: .sh/.bash extensions, hybrid function detection, automatic dependency management
- Note cross-platform compatibility including Windows support
- Addresses PR feedback about missing CHANGELOG extension for bash support
* refactor: Change regex fallback to always-on hybrid detection for bash functions
- Remove conditional logic that only ran regex when LSP found no functions
- Implement always-on hybrid approach that runs both LSP and regex detection
- Add comprehensive documentation explaining bash-language-server limitations
- Add new _merge_function_detections method to combine results without duplicates
- Addresses reviewer feedback about files with mixed function notation styles
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
150 lines
4.5 KiB
Python
150 lines
4.5 KiB
Python
import logging
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from sensai.util.logging import configure
|
|
|
|
from serena.constants import SERENA_MANAGED_DIR_IN_HOME
|
|
from serena.project import Project
|
|
from serena.util.file_system import GitignoreParser
|
|
from solidlsp.ls import SolidLanguageServer
|
|
from solidlsp.ls_config import Language, LanguageServerConfig
|
|
from solidlsp.ls_logger import LanguageServerLogger
|
|
from solidlsp.settings import SolidLSPSettings
|
|
|
|
configure(level=logging.ERROR)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def resources_dir() -> Path:
|
|
"""Path to the test resources directory."""
|
|
current_dir = Path(__file__).parent
|
|
return current_dir / "resources"
|
|
|
|
|
|
class LanguageParamRequest:
|
|
param: Language
|
|
|
|
|
|
def get_repo_path(language: Language) -> Path:
|
|
return Path(__file__).parent / "resources" / "repos" / language / "test_repo"
|
|
|
|
|
|
def create_ls(
|
|
language: Language,
|
|
repo_path: str | None = None,
|
|
ignored_paths: list[str] | None = None,
|
|
trace_lsp_communication: bool = False,
|
|
log_level: int = logging.ERROR,
|
|
) -> SolidLanguageServer:
|
|
ignored_paths = ignored_paths or []
|
|
if repo_path is None:
|
|
repo_path = str(get_repo_path(language))
|
|
gitignore_parser = GitignoreParser(str(repo_path))
|
|
for spec in gitignore_parser.get_ignore_specs():
|
|
ignored_paths.extend(spec.patterns)
|
|
config = LanguageServerConfig(code_language=language, ignored_paths=ignored_paths, trace_lsp_communication=trace_lsp_communication)
|
|
logger = LanguageServerLogger(log_level=log_level)
|
|
return SolidLanguageServer.create(
|
|
config, logger, repo_path, solidlsp_settings=SolidLSPSettings(solidlsp_dir=SERENA_MANAGED_DIR_IN_HOME)
|
|
)
|
|
|
|
|
|
def create_default_ls(language: Language) -> SolidLanguageServer:
|
|
repo_path = str(get_repo_path(language))
|
|
return create_ls(language, repo_path)
|
|
|
|
|
|
def create_default_project(language: Language) -> Project:
|
|
repo_path = str(get_repo_path(language))
|
|
return Project.load(repo_path)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def repo_path(request: LanguageParamRequest) -> Path:
|
|
"""Get the repository path for a specific language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("repo_path", [Language.PYTHON], indirect=True)
|
|
def test_python_repo(repo_path):
|
|
assert (repo_path / "src").exists()
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
return get_repo_path(language)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def language_server(request: LanguageParamRequest):
|
|
"""Create a language server instance configured for the specified language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True)
|
|
def test_python_server(language_server: SyncLanguageServer) -> None:
|
|
# Use the Python language server
|
|
pass
|
|
```
|
|
|
|
You can also test multiple languages in a single test:
|
|
```
|
|
@pytest.mark.parametrize("language_server", [Language.PYTHON, Language.TYPESCRIPT], indirect=True)
|
|
def test_multiple_languages(language_server: SyncLanguageServer) -> None:
|
|
# This test will run once for each language
|
|
pass
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
server = create_default_ls(language)
|
|
server.start()
|
|
try:
|
|
yield server
|
|
finally:
|
|
server.stop()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def project(request: LanguageParamRequest):
|
|
"""Create a Project for the specified language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("project", [Language.PYTHON], indirect=True)
|
|
def test_python_project(project: Project) -> None:
|
|
# Use the Python project to test something
|
|
pass
|
|
```
|
|
|
|
You can also test multiple languages in a single test:
|
|
```
|
|
@pytest.mark.parametrize("project", [Language.PYTHON, Language.TYPESCRIPT], indirect=True)
|
|
def test_multiple_languages(project: SyncLanguageServer) -> None:
|
|
# This test will run once for each language
|
|
pass
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
yield create_default_project(language)
|
|
|
|
|
|
|