feat: add first-class Neovim support with enhanced formatting

- Add modern Lua implementation with modular architecture
- Implement HEREDOC preservation and smart comment indentation
- Create dual implementation (Neovim Lua + VimScript fallback)
- Add comprehensive health check and configuration system
- Enhance formatting engine with state machine for context awareness
- Update documentation with Lua configuration examples
- Add memory files for development workflow and conventions
This commit is contained in:
2025-09-09 21:13:38 +03:00
parent 710f68a6e5
commit ce620cd035
18 changed files with 1656 additions and 52 deletions

View File

@@ -0,0 +1,203 @@
# Code Style and Conventions
## EditorConfig Settings
All files follow these rules from `.editorconfig`:
- **Charset**: UTF-8
- **Line endings**: LF (Unix-style)
- **Indentation**: 2 spaces (no tabs)
- **Max line length**: 160 characters
- **Final newline**: Required
- **Trim trailing whitespace**: Yes
### Special Cases
- **Markdown files**: Don't trim trailing whitespace (for hard line breaks)
- **Makefiles**: Use tabs with width 4
## Lua Code Conventions (New)
### Module Structure
```lua
-- Module header with description
local M = {}
-- Import dependencies at top
local config = require('shellspec.config')
-- Private functions (local)
local function private_helper() end
-- Public functions (M.function_name)
function M.public_function() end
return M
```
### Function Names
- Use `snake_case` for all functions
- Private functions: `local function name()`
- Public functions: `function M.name()` or `M.name = function()`
- Descriptive names, avoid abbreviations
### Variable Names
- Local variables: `local variable_name`
- Constants: `local CONSTANT_NAME` (uppercase)
- Table keys: `snake_case`
### Documentation
- Use LuaDoc style comments for public functions
- Include parameter and return type information
```lua
--- Format lines with ShellSpec DSL rules
-- @param lines table: Array of strings to format
-- @return table: Array of formatted strings
function M.format_lines(lines) end
```
### Error Handling
- Use `pcall()` for operations that might fail
- Provide meaningful error messages
- Use `vim.notify()` for user-facing messages
## Vim Script Conventions (Enhanced)
### Function Names
- Use `snake_case#function_name()` format
- Functions in autoload use namespace prefix: `shellspec#function_name()`
- Guard clauses with `abort` keyword: `function! shellspec#format_buffer() abort`
- Private functions: `s:function_name()`
### Variable Names
- Local variables: `l:variable_name`
- Global variables: `g:variable_name`
- Buffer-local: `b:variable_name`
- Script-local: `s:variable_name`
### State Management
- Use descriptive state names: `'normal'`, `'heredoc'`
- Document state transitions in comments
- Initialize state variables clearly
### Code Structure
```vim
" File header with description and author
if exists('g:loaded_plugin')
finish
endif
let g:loaded_plugin = 1
" Helper functions (private)
function! s:private_function() abort
endfunction
" Public functions
function! public#function() abort
endfunction
" Commands, autocommands at end
```
### Comments
- Use `"` for comments
- Include descriptive headers for functions
- Comment complex logic blocks and state changes
- Document HEREDOC patterns and detection logic
## Shell Script Style (bin/shellspec-format)
- Use `#!/bin/bash` shebang
- Double quote variables: `"$variable"`
- Use `[[ ]]` for conditionals instead of `[ ]`
- Proper error handling with exit codes
- Function names in `snake_case`
## Configuration Files
- **YAML**: 2-space indentation, 200 character line limit
- **JSON**: Pretty formatted, no trailing commas
- **Markdown**: 200 character line limit (relaxed from default 80)
- **Lua**: Follow Neovim Lua style guide
## Naming Conventions
- **Files**: lowercase with hyphens (`shellspec-format`)
- **Directories**: lowercase (`autoload`, `syntax`, `ftdetect`)
- **Lua modules**: lowercase with dots (`shellspec.format`)
- **Functions**: namespace#function_name format (VimScript), snake_case (Lua)
- **Variables**: descriptive names, avoid abbreviations
## Architecture Patterns
### Dual Implementation Pattern
```vim
" Detect environment and choose implementation
if has('nvim-0.7')
" Use Lua implementation
lua require('module').function()
else
" Fall back to VimScript
call legacy#function()
endif
```
### State Machine Pattern (Both Lua and VimScript)
```lua
-- Lua version
local state = State.NORMAL
if state == State.NORMAL then
-- handle normal formatting
elseif state == State.IN_HEREDOC then
-- preserve heredoc content
end
```
```vim
" VimScript version
let l:state = 'normal'
if l:state ==# 'normal'
" handle normal formatting
elseif l:state ==# 'heredoc'
" preserve heredoc content
endif
```
### Configuration Pattern
```lua
-- Lua: Use vim.tbl_deep_extend for merging
local config = vim.tbl_deep_extend("force", defaults, user_opts)
```
```vim
" VimScript: Use get() with defaults
let l:option = get(g:, 'plugin_option', default_value)
```
## Testing Conventions
- Create test files with `.spec.sh` extension
- Test both Lua and VimScript implementations
- Include HEREDOC and comment test cases
- Use descriptive test names matching actual ShellSpec patterns
## Documentation Standards
- Update README.md with new features
- Include both Lua and VimScript configuration examples
- Provide clear examples of HEREDOC and comment behavior
- Document breaking changes and migration paths

View File

@@ -0,0 +1,138 @@
# Codebase Structure
## Directory Layout
```text
nvim-shellspec/
├── lua/shellspec/ # Modern Neovim Lua implementation
│ ├── init.lua # Main module entry point & setup
│ ├── config.lua # Configuration management
│ ├── format.lua # Enhanced formatting engine
│ ├── autocmds.lua # Neovim-native autocommands
│ └── health.lua # Health check support
├── autoload/ # Plugin functions (VimScript)
│ └── shellspec.vim # Enhanced formatting with HEREDOC support
├── bin/ # Standalone executables
│ └── shellspec-format # Bash formatter script
├── ftdetect/ # Filetype detection
│ └── shellspec.vim # Auto-detect ShellSpec files
├── indent/ # Indentation rules
│ └── shellspec.vim # Smart indentation for ShellSpec DSL
├── plugin/ # Main plugin file (loaded at startup)
│ └── shellspec.vim # Neovim detection & dual implementation
├── syntax/ # Syntax highlighting
│ └── shellspec.vim # ShellSpec DSL syntax rules
└── .github/ # GitHub workflows and templates
```
## Core Files
### Lua Implementation (Neovim 0.7+)
#### lua/shellspec/init.lua
- Main module entry point with setup() function
- Lua configuration interface
- Health check integration (:checkhealth support)
- Backward compatibility functions for VimScript
#### lua/shellspec/config.lua
- Configuration management with defaults
- Validation and type checking
- Support for:
- Auto-format settings
- Indentation preferences
- HEREDOC pattern customization
- Comment indentation options
#### lua/shellspec/format.lua
- Advanced formatting engine with state machine
- HEREDOC detection and preservation
- Smart comment indentation
- Context-aware formatting (normal, in-heredoc states)
- Async formatting capabilities
#### lua/shellspec/autocmds.lua
- Neovim-native autocommands using vim.api
- Buffer-local settings and commands
- Enhanced filetype detection patterns
- Auto-format on save integration
#### lua/shellspec/health.lua
- Comprehensive health checks for :checkhealth
- Configuration validation
- Module loading verification
- Project ShellSpec file detection
### VimScript Implementation (Compatibility)
#### plugin/shellspec.vim
- **Dual Implementation Logic**: Detects Neovim 0.7+ and loads appropriate implementation
- **Neovim Path**: Loads Lua modules and creates command delegators
- **Vim Path**: Falls back to enhanced VimScript implementation
- Maintains all existing functionality
#### autoload/shellspec.vim
- **Enhanced VimScript formatter** with same features as Lua version
- HEREDOC detection patterns and state machine
- Smart comment indentation logic
- Backward compatibility with older Vim versions
### Traditional Vim Plugin Structure
#### ftdetect/shellspec.vim
- Automatic filetype detection for ShellSpec files
- Patterns: `*_spec.sh`, `*.spec.sh`, `spec/*.sh`, `test/*.sh`
- Enhanced with nested spec directory support
#### indent/shellspec.vim
- Smart indentation based on ShellSpec block structure
- Handles `Describe`, `Context`, `It` blocks and their variants
- Special handling for `End` keyword and `Data`/`Parameters` blocks
#### syntax/shellspec.vim
- Complete syntax highlighting for ShellSpec DSL
- Keywords: Block structures, control flow, evaluation, expectations, hooks
- Supports nested shell code regions
- Proper highlighting for strings, variables, comments
## Configuration Files
### Development & Quality
- `.pre-commit-config.yaml` - Pre-commit hooks configuration
- `.mega-linter.yml` - MegaLinter configuration
- `.yamllint.yml` - YAML linting rules
- `.markdownlint.json` - Markdown linting rules
- `.editorconfig` - Editor configuration
### Git & CI/CD
- `.github/workflows/` - GitHub Actions for CI
- `.gitignore` - Git ignore patterns
## ShellSpec DSL Keywords Supported
- **Blocks**: Describe, Context, ExampleGroup, It, Specify, Example
- **Prefixed blocks**: xDescribe, fDescribe (skip/focus variants)
- **Hooks**: BeforeEach, AfterEach, BeforeAll, AfterAll
- **Evaluation**: When, call, run, command, script, source
- **Expectations**: The, Assert, should, output, stdout, error, stderr
- **Helpers**: Dump, Include, Set, Path, File, Dir, Data, Parameters
## Architecture Benefits
- **Performance**: Lua implementation for better performance in Neovim
- **Modern APIs**: Uses Neovim's native autocmd and formatting APIs
- **Maintainability**: Modular structure with clear separation of concerns
- **Extensibility**: Easy to add new features through Lua configuration
- **Compatibility**: Seamless fallback ensures broad editor support

View File

@@ -0,0 +1,49 @@
# nvim-shellspec Project Overview
## Purpose
This is a Neovim/Vim plugin that provides advanced language support and formatting for the ShellSpec DSL testing framework.
ShellSpec is a BDD (Behavior-Driven Development) testing framework for shell scripts.
## Key Features
- **🚀 First-class Neovim support** with modern Lua implementation
- **🎨 Syntax highlighting** for all ShellSpec DSL keywords
- **📐 Smart indentation** for block structures
- **📄 Enhanced filetype detection** for `*_spec.sh`, `*.spec.sh`, `spec/*.sh`, `test/*.sh`, and nested spec directories
- **✨ Advanced formatting** with HEREDOC and comment support
- **⚡ Async formatting** to prevent blocking (Neovim 0.7+)
- **🔄 Backward compatibility** with Vim and older Neovim versions
## Advanced Formatting Features
- **HEREDOC Preservation**: Maintains original formatting within `<<EOF`, `<<'EOF'`, `<<"EOF"`, and `<<-EOF` blocks
- **Smart Comment Indentation**: Comments are indented to match surrounding code level
- **Context-Aware Formatting**: State machine tracks formatting context for accurate indentation
## Tech Stack
- **Primary language**: Vim script (VimL) + Lua (Neovim)
- **Target environment**: Neovim 0.7+ (with Vim fallback)
- **Architecture**: Modular Lua implementation with VimScript compatibility layer
- **Shell scripting**: Bash (for standalone formatter in `bin/shellspec-format`)
- **Configuration formats**: YAML, JSON, EditorConfig
## Dual Implementation
- **Neovim 0.7+**: Modern Lua implementation with native APIs
- **Vim/Older Neovim**: Enhanced VimScript with same formatting features
## Target Files
Plugin activates for files matching:
- `*_spec.sh`
- `*.spec.sh`
- `spec/*.sh`
- `test/*.sh`
- Files in nested `spec/` directories
## Related Project
- [ShellSpec](https://github.com/shellspec/shellspec) - BDD testing framework for shell scripts

View File

@@ -0,0 +1,203 @@
# Development Commands for nvim-shellspec
## Quality Assurance & Linting Commands
### Primary Linting Command
```bash
pre-commit run --all-files
```
This runs all configured linters and formatters including:
- ShellCheck for shell scripts
- shfmt for shell script formatting
- yamllint for YAML files
- markdownlint for Markdown files
- Various pre-commit hooks
### Individual Linters
```bash
# YAML linting
yamllint .
# Markdown linting (via npx)
npx markdownlint-cli -c .markdownlint.json --fix README.md
# Shell script linting
shellcheck bin/shellspec-format
# Shell script formatting
shfmt -w bin/shellspec-format
# Lua linting (if available)
luacheck lua/shellspec/
```
## Code Formatting
### ShellSpec DSL Formatting
```bash
# Using standalone formatter
./bin/shellspec-format file.spec.sh
# Or in Neovim/Vim
:ShellSpecFormat
:ShellSpecFormatRange (for selected lines)
```
### Testing New Lua Implementation (Neovim)
```lua
-- Test in Neovim command line
:lua require('shellspec').setup({ auto_format = true })
:lua require('shellspec').format_buffer()
-- Health check
:checkhealth shellspec
```
## Development Testing
### Manual Plugin Testing
```bash
# Create test file
touch test_example.spec.sh
# Test in Neovim
nvim test_example.spec.sh
# Verify filetype: :set filetype?
# Test formatting: :ShellSpecFormat
# Test health check: :checkhealth shellspec
```
### HEREDOC and Comment Testing
Create test content with:
```shellspec
Describe "test"
# Comment that should be indented
It "should preserve HEREDOC"
cat <<EOF
This should not be reformatted
Even with nested indentation
EOF
End
End
```
## Git Integration
```bash
# Pre-commit hooks are automatically installed
pre-commit install
# Run pre-commit on all files
pre-commit run --all-files
```
## Neovim-Specific Development
### Lua Module Testing
```bash
# Test individual modules in Neovim
:lua print(vim.inspect(require('shellspec.config').defaults))
:lua require('shellspec.format').format_buffer()
:lua require('shellspec.autocmds').setup()
```
### Health Diagnostics
```bash
# Comprehensive health check
:checkhealth shellspec
# Check if modules load correctly
:lua require('shellspec.health').check()
```
## File System Utilities (macOS/Darwin)
```bash
# File operations
ls -la # List files with details
find . -name # Find files by pattern
grep -r # Search in files (or use rg for ripgrep)
# Better alternatives available on system:
rg # ripgrep for faster searching
fd # faster find alternative
# Find all ShellSpec files in project
fd -e spec.sh
fd "_spec.sh$"
rg -t sh "Describe|Context|It" spec/
```
## Development Workflow
### Standard Development
1. Make changes to Vim script or Lua files
2. Test with sample ShellSpec files (`test_example.spec.sh`)
3. Run `pre-commit run --all-files` before committing
4. Fix any linting issues
5. Test in both Neovim (Lua path) and Vim (VimScript path)
6. Commit changes
### Feature Development
1. Update Lua implementation in `lua/shellspec/`
2. Update VimScript compatibility in `autoload/shellspec.vim`
3. Test dual implementation paths
4. Update health checks if needed
5. Update documentation
### Configuration Testing
```lua
-- Test different configurations
require('shellspec').setup({
auto_format = true,
indent_size = 4,
indent_comments = false,
heredoc_patterns = {"<<[A-Z_]+", "<<'[^']*'"}
})
```
## Performance Testing
```bash
# Test with large ShellSpec files
time nvim +':ShellSpecFormat' +':wq' large_spec_file.spec.sh
# Compare Lua vs VimScript performance
# (Use older Neovim version to force VimScript path)
```
## Plugin Integration Testing
```lua
-- Test with lazy.nvim
{
dir = "/path/to/local/nvim-shellspec",
config = function()
require("shellspec").setup({ auto_format = true })
end
}
```
## Memory and State Debugging
```lua
-- Debug configuration state
:lua print(vim.inspect(require('shellspec.config').config))
-- Debug formatting state
:lua require('shellspec.format').format_lines({"Describe 'test'", " It 'works'", " End", "End"})
```

View File

@@ -0,0 +1,242 @@
# Task Completion Checklist
When completing any development task in the nvim-shellspec project, follow this checklist:
## 1. Code Quality Checks (MANDATORY)
```bash
# Run all pre-commit hooks
pre-commit run --all-files
```
This runs:
- **ShellCheck** - Shell script linting and static analysis
- **shfmt** - Shell script formatting
- **yamllint** - YAML file validation
- **markdownlint** - Markdown linting and formatting
- **Various pre-commit hooks** - Trailing whitespace, end-of-file, etc.
## 2. EditorConfig Compliance (BLOCKING)
- All files must follow `.editorconfig` rules
- 2-space indentation, LF line endings, UTF-8 encoding
- 160 character line limit
- Trim trailing whitespace (except Markdown)
- End files with newline
## 3. Dual Implementation Testing (NEW - CRITICAL)
### 3a. Neovim Lua Implementation Testing
```bash
# Test in Neovim 0.7+
nvim test_example.spec.sh
# Verify Lua path is used
:lua print("Using Lua implementation")
:checkhealth shellspec
# Test formatting with HEREDOC
:ShellSpecFormat
# Test configuration
:lua require('shellspec').setup({auto_format = true})
```
### 3b. VimScript Fallback Testing
```bash
# Test in older Neovim or Vim
vim test_example.spec.sh # or nvim --clean with older version
# Verify VimScript path is used
:echo "Using VimScript implementation"
# Test same formatting features work
:ShellSpecFormat
```
## 4. Advanced Formatting Feature Testing
### 4a. HEREDOC Preservation Testing
Create test content:
```shellspec
Describe "HEREDOC test"
It "preserves formatting"
cat <<EOF
This should stay as-is
Even with nested indentation
Back to normal
EOF
End
End
```
Apply `:ShellSpecFormat` and verify HEREDOC content is unchanged.
### 4b. Comment Indentation Testing
Create test content:
```shellspec
Describe "Comment test"
# Top level comment
It "handles comments"
# This should be indented to It level
When call echo "test"
# This should be indented to When level
End
# Back to top level
End
```
Apply `:ShellSpecFormat` and verify comments align with code levels.
## 5. Configuration Testing
### 5a. Lua Configuration (Neovim)
```lua
-- Test different configurations
require('shellspec').setup({
auto_format = true,
indent_size = 4,
indent_comments = false,
})
```
### 5b. VimScript Configuration (Vim/Legacy)
```vim
let g:shellspec_auto_format = 1
let g:shellspec_indent_comments = 0
```
## 6. Plugin-Specific Testing
### Manual Testing Steps
1. **Create test ShellSpec file**:
```bash
cp test_example.spec.sh my_test.spec.sh
```
2. **Test filetype detection**:
```vim
# In Neovim/Vim, open the file and verify:
:set filetype? # Should show "filetype=shellspec"
```
3. **Test syntax highlighting**:
- Add ShellSpec DSL content and verify highlighting
- Test with HEREDOC blocks
- Test with various comment styles
4. **Test formatting commands**:
```vim
:ShellSpecFormat
:ShellSpecFormatRange (in visual mode)
```
5. **Test auto-format on save** (if enabled):
- Make changes and save file
- Verify automatic formatting occurs
6. **Test health check** (Neovim only):
```vim
:checkhealth shellspec
```
## 7. Standalone Formatter Testing
```bash
# Test the standalone formatter
echo 'Describe "test"
# Comment
It "works"
cat <<EOF
preserved
EOF
When call echo
The output should equal
End
End' | ./bin/shellspec-format
```
## 8. Performance Testing (NEW)
```bash
# Test with larger files
time nvim +':ShellSpecFormat' +':wq' large_spec_file.spec.sh
# Compare implementations if possible
```
## 9. Module Integration Testing (Neovim)
```lua
-- Test module loading
:lua local ok, mod = pcall(require, 'shellspec'); print(ok)
:lua print(vim.inspect(require('shellspec.config').defaults))
:lua require('shellspec.format').format_lines({"test"})
```
## 10. Git Workflow
```bash
# Stage changes
git add .
# Commit (pre-commit hooks run automatically)
git commit -m "descriptive commit message"
# Ensure both implementations are included in commit
git log --name-status -1
```
## 11. Documentation Updates
- Update README.md if adding new features
- Include both Lua and VimScript examples
- Document any breaking changes
- Update health check descriptions if modified
- Ensure all configuration examples are correct
## Error Resolution Priority
1. **EditorConfig violations** - Fix immediately (blocking)
2. **Dual implementation failures** - Both Lua and VimScript must work
3. **HEREDOC/Comment formatting issues** - Core feature failures
4. **ShellCheck errors** - Fix all warnings and errors
5. **Health check failures** - Neovim integration issues
6. **YAML/JSON syntax errors** - Must be valid
7. **Markdownlint issues** - Fix formatting and style issues
## Before Pull Request
- [ ] All linting passes without errors
- [ ] Both Lua (Neovim) and VimScript (Vim) implementations tested
- [ ] HEREDOC preservation verified
- [ ] Comment indentation working correctly
- [ ] Health check passes (`:checkhealth shellspec`)
- [ ] Manual plugin testing completed
- [ ] Documentation is updated with dual examples
- [ ] Commit messages are descriptive
- [ ] No sensitive information in commits
## Regression Testing
When modifying core formatting logic:
- [ ] Test with complex nested ShellSpec structures
- [ ] Test with mixed HEREDOC types (`<<EOF`, `<<'EOF'`, `<<"EOF"`)
- [ ] Test with edge cases (empty files, comment-only files)
- [ ] Test auto-format behavior
- [ ] Test with different indent_size configurations