mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-15 22:15:07 +00:00
Add comprehensive bash language support (#375)
* 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>
This commit is contained in:
1 parent
7158aa4870
commit
ec1277167b
12 files changed
+787
No files matched your search
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration script for project setup
|
||||
|
||||
# Environment variables
|
||||
export PROJECT_NAME="bash-test-project"
|
||||
export PROJECT_VERSION="1.0.0"
|
||||
export LOG_LEVEL="INFO"
|
||||
export CONFIG_DIR="./config"
|
||||
|
||||
# Default settings
|
||||
DEFAULT_TIMEOUT=30
|
||||
DEFAULT_RETRIES=3
|
||||
DEFAULT_PORT=8080
|
||||
|
||||
# Configuration arrays
|
||||
declare -A ENVIRONMENTS=(
|
||||
["dev"]="development"
|
||||
["prod"]="production"
|
||||
["test"]="testing"
|
||||
)
|
||||
|
||||
declare -A DATABASE_CONFIGS=(
|
||||
["host"]="localhost"
|
||||
["port"]="5432"
|
||||
["name"]="myapp_db"
|
||||
["user"]="dbuser"
|
||||
)
|
||||
|
||||
# Function to load configuration
|
||||
load_config() {
|
||||
local env="${1:-dev}"
|
||||
local config_file="${CONFIG_DIR}/${env}.conf"
|
||||
|
||||
if [[ -f "$config_file" ]]; then
|
||||
echo "Loading configuration from $config_file"
|
||||
source "$config_file"
|
||||
else
|
||||
echo "Warning: Configuration file $config_file not found, using defaults"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to validate configuration
|
||||
validate_config() {
|
||||
local errors=0
|
||||
|
||||
if [[ -z "$PROJECT_NAME" ]]; then
|
||||
echo "Error: PROJECT_NAME is not set" >&2
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
if [[ -z "$PROJECT_VERSION" ]]; then
|
||||
echo "Error: PROJECT_VERSION is not set" >&2
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
if [[ $DEFAULT_PORT -lt 1024 || $DEFAULT_PORT -gt 65535 ]]; then
|
||||
echo "Error: Invalid port number $DEFAULT_PORT" >&2
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
return $errors
|
||||
}
|
||||
|
||||
# Function to print configuration
|
||||
print_config() {
|
||||
echo "=== Current Configuration ==="
|
||||
echo "Project Name: $PROJECT_NAME"
|
||||
echo "Version: $PROJECT_VERSION"
|
||||
echo "Log Level: $LOG_LEVEL"
|
||||
echo "Default Port: $DEFAULT_PORT"
|
||||
echo "Default Timeout: $DEFAULT_TIMEOUT"
|
||||
echo "Default Retries: $DEFAULT_RETRIES"
|
||||
|
||||
echo "\n=== Environments ==="
|
||||
for env in "${!ENVIRONMENTS[@]}"; do
|
||||
echo " $env: ${ENVIRONMENTS[$env]}"
|
||||
done
|
||||
|
||||
echo "\n=== Database Configuration ==="
|
||||
for key in "${!DATABASE_CONFIGS[@]}"; do
|
||||
echo " $key: ${DATABASE_CONFIGS[$key]}"
|
||||
done
|
||||
}
|
||||
|
||||
# Initialize configuration if this script is run directly
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
load_config "$1"
|
||||
validate_config
|
||||
print_config
|
||||
fi
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Main script demonstrating various bash features
|
||||
|
||||
# Global variables
|
||||
readonly SCRIPT_NAME="Main Script"
|
||||
COUNTER=0
|
||||
declare -a ITEMS=("item1" "item2" "item3")
|
||||
|
||||
# Function definitions
|
||||
function greet_user() {
|
||||
local username="$1"
|
||||
local greeting_type="${2:-default}"
|
||||
|
||||
case "$greeting_type" in
|
||||
"formal")
|
||||
echo "Good day, ${username}!"
|
||||
;;
|
||||
"casual")
|
||||
echo "Hey ${username}!"
|
||||
;;
|
||||
*)
|
||||
echo "Hello, ${username}!"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
function process_items() {
|
||||
local -n items_ref=$1
|
||||
local operation="$2"
|
||||
|
||||
for item in "${items_ref[@]}"; do
|
||||
case "$operation" in
|
||||
"count")
|
||||
((COUNTER++))
|
||||
echo "Processing item $COUNTER: $item"
|
||||
;;
|
||||
"uppercase")
|
||||
echo "${item^^}"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown operation: $operation"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo "Starting $SCRIPT_NAME"
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "Usage: $0 <username> [greeting_type]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local user="$1"
|
||||
local greeting="${2:-default}"
|
||||
|
||||
greet_user "$user" "$greeting"
|
||||
|
||||
echo "Processing items..."
|
||||
process_items ITEMS "count"
|
||||
|
||||
echo "Script completed successfully"
|
||||
}
|
||||
|
||||
# Run main function with all arguments
|
||||
main "$@"
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Utility functions for bash scripting
|
||||
|
||||
# String manipulation functions
|
||||
function to_uppercase() {
|
||||
echo "${1^^}"
|
||||
}
|
||||
|
||||
function to_lowercase() {
|
||||
echo "${1,,}"
|
||||
}
|
||||
|
||||
function trim_whitespace() {
|
||||
local var="$1"
|
||||
var="${var#"${var%%[![:space:]]*}"}"
|
||||
var="${var%"${var##*[![:space:]]}"}"
|
||||
echo "$var"
|
||||
}
|
||||
|
||||
# File operations
|
||||
function backup_file() {
|
||||
local file="$1"
|
||||
local backup_dir="${2:-./backups}"
|
||||
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "Error: File '$file' does not exist" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$backup_dir"
|
||||
cp "$file" "${backup_dir}/$(basename "$file").$(date +%Y%m%d_%H%M%S).bak"
|
||||
echo "Backup created for $file"
|
||||
}
|
||||
|
||||
# Array operations
|
||||
function contains_element() {
|
||||
local element="$1"
|
||||
shift
|
||||
local array=("$@")
|
||||
|
||||
for item in "${array[@]}"; do
|
||||
if [[ "$item" == "$element" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Logging functions
|
||||
function log_message() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
case "$level" in
|
||||
"ERROR")
|
||||
echo "[$timestamp] ERROR: $message" >&2
|
||||
;;
|
||||
"WARN")
|
||||
echo "[$timestamp] WARN: $message" >&2
|
||||
;;
|
||||
"INFO")
|
||||
echo "[$timestamp] INFO: $message"
|
||||
;;
|
||||
"DEBUG")
|
||||
[[ "${DEBUG:-false}" == "true" ]] && echo "[$timestamp] DEBUG: $message"
|
||||
;;
|
||||
*)
|
||||
echo "[$timestamp] $message"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Validation functions
|
||||
function is_valid_email() {
|
||||
local email="$1"
|
||||
[[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]
|
||||
}
|
||||
|
||||
function is_number() {
|
||||
[[ $1 =~ ^[0-9]+$ ]]
|
||||
}
|
||||
Reference in new issue
Block a user