diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 297e5fc..8094e5b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,13 +42,13 @@ repos: rev: v0.11.0 hooks: - id: shellcheck - args: ['--severity=warning'] + args: ["--severity=warning"] - repo: https://github.com/rhysd/actionlint rev: v1.7.7 hooks: - id: actionlint - args: ['-shellcheck='] + args: ["-shellcheck="] - repo: https://github.com/renovatebot/pre-commit-hooks rev: 41.97.9 @@ -56,8 +56,8 @@ repos: - id: renovate-config-validator - repo: https://github.com/bridgecrewio/checkov.git - rev: '3.2.469' + rev: "3.2.469" hooks: - id: checkov args: - - '--quiet' + - "--quiet" diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 0000000..14d86ad --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1 @@ +/cache diff --git a/.serena/memories/code_style_conventions.md b/.serena/memories/code_style_conventions.md new file mode 100644 index 0000000..c23209c --- /dev/null +++ b/.serena/memories/code_style_conventions.md @@ -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 diff --git a/.serena/memories/codebase_structure.md b/.serena/memories/codebase_structure.md new file mode 100644 index 0000000..410f89c --- /dev/null +++ b/.serena/memories/codebase_structure.md @@ -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 diff --git a/.serena/memories/project_overview.md b/.serena/memories/project_overview.md new file mode 100644 index 0000000..deceffa --- /dev/null +++ b/.serena/memories/project_overview.md @@ -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 `<sf', 'ShellSpecFormat', { desc = 'Format ShellSpec buffer' }) +vim.keymap.set('v', 'sf', 'ShellSpecFormatRange', { desc = 'Format ShellSpec selection' }) +``` + +### Vim/Legacy Configuration + ```vim " Enable auto-formatting on save let g:shellspec_auto_format = 1 +" Enable comment indentation (default: 1) +let g:shellspec_indent_comments = 1 + " Custom keybindings autocmd FileType shellspec nnoremap f :ShellSpecFormat autocmd FileType shellspec vnoremap f :ShellSpecFormatRange ``` +## Examples + +### HEREDOC Formatting + +The formatter intelligently handles HEREDOC blocks: + +```shellspec +Describe "HEREDOC handling" + It "preserves original formatting within HEREDOC" + When call cat < "${file}.tmp" && mv "${file}.tmp" "$file" + format_shellspec <"$file" >"${file}.tmp" && mv "${file}.tmp" "$file" else echo "Error: File not found: $file" >&2 fi diff --git a/lua/shellspec/autocmds.lua b/lua/shellspec/autocmds.lua new file mode 100644 index 0000000..3359590 --- /dev/null +++ b/lua/shellspec/autocmds.lua @@ -0,0 +1,102 @@ +-- Neovim-native autocommands for ShellSpec +local config = require("shellspec.config") +local format = require("shellspec.format") +local M = {} + +-- Autocommand group +local augroup = vim.api.nvim_create_augroup("ShellSpec", { clear = true }) + +-- Setup buffer-local settings +local function setup_buffer(bufnr) + -- Set buffer options + vim.api.nvim_set_option_value("commentstring", "# %s", { buf = bufnr }) + vim.api.nvim_set_option_value("foldmethod", "indent", { buf = bufnr }) + vim.api.nvim_set_option_value("shiftwidth", config.get("indent_size"), { buf = bufnr }) + vim.api.nvim_set_option_value("tabstop", config.get("indent_size"), { buf = bufnr }) + vim.api.nvim_set_option_value("expandtab", config.get("use_spaces"), { buf = bufnr }) + + -- Buffer-local commands + vim.api.nvim_buf_create_user_command(bufnr, "ShellSpecFormat", function() + format.format_buffer(bufnr) + end, { desc = "Format ShellSpec buffer" }) + + vim.api.nvim_buf_create_user_command(bufnr, "ShellSpecFormatRange", function(opts) + format.format_selection(bufnr, opts.line1, opts.line2) + end, { + range = true, + desc = "Format ShellSpec selection", + }) + + -- Optional: Set up LSP-style formatting + if vim.fn.has("nvim-0.8") == 1 then + vim.api.nvim_buf_set_option(bufnr, "formatexpr", 'v:lua.require("shellspec.format").format_buffer()') + end +end + +-- Create all autocommands +function M.setup() + -- FileType detection and setup + vim.api.nvim_create_autocmd("FileType", { + group = augroup, + pattern = "shellspec", + callback = function(args) + setup_buffer(args.buf) + end, + desc = "Setup ShellSpec buffer", + }) + + -- Auto-format on save (if enabled) + if config.get("auto_format") then + vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup, + pattern = { "*.spec.sh", "*_spec.sh" }, + callback = function(args) + -- Only format if it's a shellspec buffer + local filetype = vim.api.nvim_get_option_value("filetype", { buf = args.buf }) + if filetype == "shellspec" then + format.format_buffer(args.buf) + end + end, + desc = "Auto-format ShellSpec files on save", + }) + end + + -- Enhanced filetype detection with better patterns + vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + group = augroup, + pattern = { + "*_spec.sh", + "*.spec.sh", + "spec/*.sh", + "test/*.sh", + }, + callback = function(args) + -- Set filetype to shellspec + vim.api.nvim_set_option_value("filetype", "shellspec", { buf = args.buf }) + end, + desc = "Detect ShellSpec files", + }) + + -- Additional pattern for nested spec directories + vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + group = augroup, + pattern = "**/spec/**/*.sh", + callback = function(args) + vim.api.nvim_set_option_value("filetype", "shellspec", { buf = args.buf }) + end, + desc = "Detect ShellSpec files in nested spec directories", + }) +end + +-- Cleanup function +function M.cleanup() + vim.api.nvim_clear_autocmds({ group = augroup }) +end + +-- Update configuration and refresh autocommands +function M.refresh() + M.cleanup() + M.setup() +end + +return M diff --git a/lua/shellspec/config.lua b/lua/shellspec/config.lua new file mode 100644 index 0000000..67ef7f3 --- /dev/null +++ b/lua/shellspec/config.lua @@ -0,0 +1,51 @@ +-- ShellSpec configuration management +local M = {} + +-- Default configuration +M.defaults = { + -- Auto-format on save + auto_format = false, + + -- Indentation settings + indent_size = 2, + use_spaces = true, + + -- HEREDOC handling + heredoc_patterns = { + "<<[A-Z_][A-Z0-9_]*", -- < 0 or nvim_version.minor >= 7 then + health.report_ok(string.format("Neovim version %d.%d.%d >= 0.7.0", nvim_version.major, nvim_version.minor, nvim_version.patch)) + else + health.report_warn(string.format("Neovim version %d.%d.%d < 0.7.0, some features may not work", nvim_version.major, nvim_version.minor, nvim_version.patch)) + end + + -- Check if module can be loaded + local ok, config = pcall(require, "shellspec.config") + if ok then + health.report_ok("ShellSpec configuration module loaded successfully") + + -- Report current configuration + local current_config = config.config + if current_config then + health.report_info("Configuration:") + health.report_info(" Auto-format: " .. tostring(current_config.auto_format)) + health.report_info(" Indent size: " .. tostring(current_config.indent_size)) + health.report_info(" Use spaces: " .. tostring(current_config.use_spaces)) + health.report_info(" Indent comments: " .. tostring(current_config.indent_comments)) + end + else + health.report_error("Failed to load ShellSpec configuration: " .. config) + return + end + + -- Check formatting module + local ok_format, format = pcall(require, "shellspec.format") + if ok_format then + health.report_ok("ShellSpec formatting module loaded successfully") + else + health.report_error("Failed to load ShellSpec formatting module: " .. format) + end + + -- Check autocommands module + local ok_autocmds, autocmds = pcall(require, "shellspec.autocmds") + if ok_autocmds then + health.report_ok("ShellSpec autocommands module loaded successfully") + else + health.report_error("Failed to load ShellSpec autocommands module: " .. autocmds) + end + + -- Check if we're in a ShellSpec buffer + local filetype = vim.bo.filetype + if filetype == "shellspec" then + health.report_ok("Current buffer is ShellSpec filetype") + + -- Check buffer-local settings + local shiftwidth = vim.bo.shiftwidth + local expandtab = vim.bo.expandtab + local commentstring = vim.bo.commentstring + + health.report_info("Buffer settings:") + health.report_info(" shiftwidth: " .. tostring(shiftwidth)) + health.report_info(" expandtab: " .. tostring(expandtab)) + health.report_info(" commentstring: " .. tostring(commentstring)) + else + health.report_info("Current buffer filetype: " .. (filetype or "none")) + health.report_info("Open a ShellSpec file (*.spec.sh) to test buffer-specific features") + end + + -- Check for common ShellSpec files in project + local cwd = vim.fn.getcwd() + local spec_dirs = { "spec", "test" } + local found_specs = false + + for _, dir in ipairs(spec_dirs) do + local spec_dir = cwd .. "/" .. dir + if vim.fn.isdirectory(spec_dir) == 1 then + local files = vim.fn.glob(spec_dir .. "/*.sh", false, true) + if #files > 0 then + found_specs = true + health.report_ok("Found " .. #files .. " ShellSpec files in " .. dir .. "/") + break + end + end + end + + if not found_specs then + local spec_files = vim.fn.glob("**/*_spec.sh", false, true) + local spec_files2 = vim.fn.glob("**/*.spec.sh", false, true) + local total_specs = #spec_files + #spec_files2 + + if total_specs > 0 then + health.report_ok("Found " .. total_specs .. " ShellSpec files in project") + else + health.report_info("No ShellSpec files found in current directory") + health.report_info("ShellSpec files typically match: *_spec.sh, *.spec.sh, spec/*.sh") + end + end + + -- Check commands availability + local commands = { "ShellSpecFormat", "ShellSpecFormatRange" } + for _, cmd in ipairs(commands) do + if vim.fn.exists(":" .. cmd) == 2 then + health.report_ok("Command :" .. cmd .. " is available") + else + health.report_error("Command :" .. cmd .. " is not available") + end + end +end + +return M diff --git a/lua/shellspec/init.lua b/lua/shellspec/init.lua new file mode 100644 index 0000000..b0ab8ad --- /dev/null +++ b/lua/shellspec/init.lua @@ -0,0 +1,90 @@ +-- Main ShellSpec module for Neovim +local M = {} + +-- Lazy-load submodules +local config = require("shellspec.config") +local format = require("shellspec.format") +local autocmds = require("shellspec.autocmds") + +-- Version info +M._VERSION = "2.0.0" + +-- Setup function for Lua configuration +function M.setup(opts) + opts = opts or {} + + -- Setup configuration + config.setup(opts) + + -- Setup autocommands + autocmds.setup() + + -- Create global commands for compatibility + vim.api.nvim_create_user_command("ShellSpecFormat", function() + format.format_buffer() + end, { desc = "Format current ShellSpec buffer" }) + + vim.api.nvim_create_user_command("ShellSpecFormatRange", function(cmd_opts) + format.format_selection(0, cmd_opts.line1, cmd_opts.line2) + end, { + range = true, + desc = "Format ShellSpec selection", + }) + + -- Optional: Enable auto-format if configured + if config.get("auto_format") then + autocmds.refresh() -- Refresh to pick up auto-format settings + end +end + +-- Format functions (for external use) +M.format_buffer = format.format_buffer +M.format_selection = format.format_selection +M.format_lines = format.format_lines + +-- Configuration access +M.config = config + +-- Health check function for :checkhealth +function M.health() + local health = vim.health or require("health") + + health.report_start("ShellSpec.nvim") + + -- Check Neovim version + if vim.fn.has("nvim-0.7") == 1 then + health.report_ok("Neovim version >= 0.7.0") + else + health.report_warn("Neovim version < 0.7.0, some features may not work") + end + + -- Check configuration + local current_config = config.config + if current_config then + health.report_ok("Configuration loaded successfully") + health.report_info("Auto-format: " .. tostring(current_config.auto_format)) + health.report_info("Indent size: " .. tostring(current_config.indent_size)) + health.report_info("Use spaces: " .. tostring(current_config.use_spaces)) + else + health.report_error("Configuration not loaded") + end + + -- Check if in ShellSpec buffer + local filetype = vim.bo.filetype + if filetype == "shellspec" then + health.report_ok("Current buffer is ShellSpec filetype") + else + health.report_info("Current buffer filetype: " .. (filetype or "none")) + end +end + +-- Backward compatibility function for VimScript +function M.format_buffer_compat() + format.format_buffer() +end + +function M.format_selection_compat(start_line, end_line) + format.format_selection(0, start_line, end_line) +end + +return M diff --git a/plugin/shellspec.vim b/plugin/shellspec.vim index 7de603f..e0344c3 100644 --- a/plugin/shellspec.vim +++ b/plugin/shellspec.vim @@ -8,22 +8,37 @@ if exists('g:loaded_shellspec') endif let g:loaded_shellspec = 1 -" Commands -command! ShellSpecFormat call shellspec#format_buffer() -command! -range ShellSpecFormatRange call shellspec#format_selection() +" Detect Neovim and use appropriate implementation +if has('nvim-0.7') + " Use modern Neovim Lua implementation + lua require('shellspec.autocmds').setup() -" Auto commands -augroup ShellSpec - autocmd! - autocmd FileType shellspec setlocal commentstring=#\ %s - autocmd FileType shellspec setlocal foldmethod=indent - autocmd FileType shellspec setlocal shiftwidth=2 tabstop=2 expandtab -augroup END + " Create commands that delegate to Lua + command! ShellSpecFormat lua require('shellspec').format_buffer() + command! -range ShellSpecFormatRange lua require('shellspec').format_selection(0, , ) -" Optional: Auto-format on save -if get(g:, 'shellspec_auto_format', 0) - augroup ShellSpecAutoFormat + " Optional: Auto-format on save (handled in Lua) + " This is now managed by the Lua autocmds module based on configuration + +else + " Fallback to VimScript implementation for older Vim + " Commands + command! ShellSpecFormat call shellspec#format_buffer() + command! -range ShellSpecFormatRange call shellspec#format_selection() + + " Auto commands + augroup ShellSpec autocmd! - autocmd BufWritePre *.spec.sh,*_spec.sh ShellSpecFormat + autocmd FileType shellspec setlocal commentstring=#\ %s + autocmd FileType shellspec setlocal foldmethod=indent + autocmd FileType shellspec setlocal shiftwidth=2 tabstop=2 expandtab augroup END + + " Optional: Auto-format on save + if get(g:, 'shellspec_auto_format', 0) + augroup ShellSpecAutoFormat + autocmd! + autocmd BufWritePre *.spec.sh,*_spec.sh ShellSpecFormat + augroup END + endif endif diff --git a/test_example.spec.sh b/test_example.spec.sh new file mode 100755 index 0000000..9bcd219 --- /dev/null +++ b/test_example.spec.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +Describe "ShellSpec formatting test" +# This is a top-level comment +Context "when testing HEREDOC support" +# Comment inside Context +It "should preserve HEREDOC formatting" +# Comment inside It block +When call cat <