feat: plugin code and updates

This commit is contained in:
2025-09-08 00:34:38 +03:00
parent 0d4380f491
commit 710f68a6e5
15 changed files with 367 additions and 20 deletions

View File

@@ -12,6 +12,7 @@ A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce**
Steps to reproduce the behavior: Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
3. Scroll down to '....' 3. Scroll down to '....'
@@ -24,15 +25,17 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):** **Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari] - OS: [e.g. iOS]
- Version [e.g. 22] - Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):** **Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1] - Device: [e.g. iPhone6]
- Browser [e.g. stock browser, safari] - OS: [e.g. iOS8.1]
- Version [e.g. 22] - Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context** **Additional context**
Add any other context about the problem here. Add any other context about the problem here.

View File

@@ -1,6 +1,6 @@
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends": [
"github>ivuorinen/renovate-config" "github>ivuorinen/renovate-config"
] ]
} }

View File

@@ -32,15 +32,15 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 uses: github/codeql-action/init@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.30.1
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
queries: security-and-quality queries: security-and-quality
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 uses: github/codeql-action/autobuild@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.30.1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@3c3833e0f8c1c83d449a7478aa59c036a9165498 # v3.29.11 uses: github/codeql-action/analyze@f1f6e5f6af878fb37288ce1c627459e94dbf7d01 # v3.30.1
with: with:
category: '/language:${{matrix.language}}' category: '/language:${{matrix.language}}'

View File

@@ -27,4 +27,4 @@ jobs:
steps: steps:
- name: Run PR Lint - name: Run PR Lint
# https://github.com/ivuorinen/actions # https://github.com/ivuorinen/actions
uses: ivuorinen/actions/pr-lint@8e88bf4cdb14c38c929ad2a89687d6eb635a3967 # 25.8.25 uses: ivuorinen/actions/pr-lint@71b97baa7c71a55b48413309b86843b1b125e149 # 25.8.31

View File

@@ -23,4 +23,4 @@ jobs:
issues: write issues: write
pull-requests: write pull-requests: write
steps: steps:
- uses: ivuorinen/actions/stale@8e88bf4cdb14c38c929ad2a89687d6eb635a3967 # 25.8.25 - uses: ivuorinen/actions/stale@71b97baa7c71a55b48413309b86843b1b125e149 # 25.8.31

View File

@@ -38,4 +38,4 @@ jobs:
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- name: ⤵️ Sync Latest Labels Definitions - name: ⤵️ Sync Latest Labels Definitions
uses: ivuorinen/actions/sync-labels@8e88bf4cdb14c38c929ad2a89687d6eb635a3967 # 25.8.25 uses: ivuorinen/actions/sync-labels@71b97baa7c71a55b48413309b86843b1b125e149 # 25.8.31

View File

@@ -34,7 +34,7 @@ repos:
- id: yamllint - id: yamllint
- repo: https://github.com/scop/pre-commit-shfmt - repo: https://github.com/scop/pre-commit-shfmt
rev: v3.11.0-1 rev: v3.12.0-2
hooks: hooks:
- id: shfmt - id: shfmt
@@ -51,12 +51,12 @@ repos:
args: ['-shellcheck='] args: ['-shellcheck=']
- repo: https://github.com/renovatebot/pre-commit-hooks - repo: https://github.com/renovatebot/pre-commit-hooks
rev: 41.82.10 rev: 41.97.9
hooks: hooks:
- id: renovate-config-validator - id: renovate-config-validator
- repo: https://github.com/bridgecrewio/checkov.git - repo: https://github.com/bridgecrewio/checkov.git
rev: '3.2.467' rev: '3.2.469'
hooks: hooks:
- id: checkov - id: checkov
args: args:

View File

81
README.md Normal file
View File

@@ -0,0 +1,81 @@
# Neovim ShellSpec DSL Support
Language support and formatter for ShellSpec DSL testing framework.
## Installation
### With [lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
{
"ivuorinen/nvim-shellspec",
ft = "shellspec",
}
```
### With [vim-plug](https://github.com/junegunn/vim-plug)
```vim
Plug 'ivuorinen/nvim-shellspec'
```
### Manual Installation
```bash
git clone https://github.com/ivuorinen/nvim-shellspec.git ~/.config/nvim/pack/plugins/start/nvim-shellspec
```
## Features
- **Syntax highlighting** for all ShellSpec DSL keywords
- **Automatic indentation** for block structures
- **Filetype detection** for `*_spec.sh`, `*.spec.sh`, and `spec/*.sh`
- **Formatting commands** with proper indentation
## Usage
### Commands
- `:ShellSpecFormat` - Format entire buffer
- `:ShellSpecFormatRange` - Format selected lines
### Auto-format
Add to your config to enable auto-format on save:
```vim
let g:shellspec_auto_format = 1
```
### File Types
Plugin activates for files matching:
- `*_spec.sh`
- `*.spec.sh`
- `spec/*.sh`
- `test/*.sh`
## Configuration
```vim
" Enable auto-formatting on save
let g:shellspec_auto_format = 1
" Custom keybindings
autocmd FileType shellspec nnoremap <buffer> <leader>f :ShellSpecFormat<CR>
autocmd FileType shellspec vnoremap <buffer> <leader>f :ShellSpecFormatRange<CR>
```
## Contributing
Contributions welcome! Please open issues and pull requests at:
<https://github.com/ivuorinen/nvim-shellspec>
## License
MIT License - see repository for details.
## Related
- [ShellSpec](https://github.com/shellspec/shellspec) - BDD testing framework for shell scripts

56
autoload/shellspec.vim Normal file
View File

@@ -0,0 +1,56 @@
" ShellSpec DSL formatter functions
function! shellspec#format_buffer() abort
let l:pos = getpos('.')
let l:lines = getline(1, '$')
let l:formatted = shellspec#format_lines(l:lines)
silent! %delete _
call setline(1, l:formatted)
call setpos('.', l:pos)
endfunction
function! shellspec#format_lines(lines) abort
let l:result = []
let l:indent = 0
for l:line in a:lines
let l:trimmed = trim(l:line)
" Skip empty lines and comments
if l:trimmed == '' || l:trimmed =~ '^#'
call add(l:result, l:line)
continue
endif
" Decrease indent for End
if l:trimmed =~ '^End\s*$'
let l:indent = max([0, l:indent - 1])
endif
" Apply current indentation
let l:formatted = repeat(' ', l:indent) . l:trimmed
call add(l:result, l:formatted)
" Increase indent after block keywords
if l:trimmed =~ '^\(Describe\|Context\|ExampleGroup\|It\|Specify\|Example\)'
let l:indent += 1
elseif l:trimmed =~ '^\([xf]\)\(Describe\|Context\|ExampleGroup\|It\|Specify\|Example\)'
let l:indent += 1
elseif l:trimmed =~ '^\(Data\|Parameters\)\s*$'
let l:indent += 1
endif
endfor
return l:result
endfunction
function! shellspec#format_selection() abort
let l:start = line("'<")
let l:end = line("'>")
let l:lines = getline(l:start, l:end)
let l:formatted = shellspec#format_lines(l:lines)
call deletebufline('%', l:start, l:end)
call append(l:start - 1, l:formatted)
endfunction

45
bin/shellspec-format Executable file
View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Standalone ShellSpec DSL formatter
format_shellspec() {
local indent=0
local line
while IFS= read -r line; do
local trimmed=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Skip empty lines and comments
if [[ -z "$trimmed" || "$trimmed" =~ ^# ]]; then
echo "$line"
continue
fi
# Decrease indent for End
if [[ "$trimmed" =~ ^End[[:space:]]*$ ]]; then
((indent > 0)) && ((indent--))
fi
# Apply indentation
printf "%*s%s\n" $((indent * 2)) "" "$trimmed"
# Increase indent after block keywords
if [[ "$trimmed" =~ ^(Describe|Context|ExampleGroup|It|Specify|Example) ]] ||
[[ "$trimmed" =~ ^[xf](Describe|Context|ExampleGroup|It|Specify|Example) ]] ||
[[ "$trimmed" =~ ^(Data|Parameters)[[:space:]]*$ ]]; then
((indent++))
fi
done
}
# Main execution
if [[ $# -eq 0 ]]; then
format_shellspec
else
for file in "$@"; do
if [[ -f "$file" ]]; then
format_shellspec < "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
else
echo "Error: File not found: $file" >&2
fi
done
fi

5
ftdetect/shellspec.vim Normal file
View File

@@ -0,0 +1,5 @@
" Filetype detection for ShellSpec DSL
autocmd BufRead,BufNewFile *_spec.sh setfiletype shellspec
autocmd BufRead,BufNewFile *.spec.sh setfiletype shellspec
autocmd BufRead,BufNewFile spec/*.sh setfiletype shellspec
autocmd BufRead,BufNewFile test/*.sh setfiletype shellspec

46
indent/shellspec.vim Normal file
View File

@@ -0,0 +1,46 @@
" Indentation for ShellSpec DSL
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetShellSpecIndent()
setlocal indentkeys=!^F,o,O,e,=End
function! GetShellSpecIndent()
let line = getline(v:lnum)
let prevline = getline(v:lnum - 1)
" Don't change indentation for comments
if line =~ '^\s*#'
return -1
endif
" End decreases indent
if line =~ '^\s*End\s*$'
return indent(v:lnum - 1) - &shiftwidth
endif
" After block start keywords, increase indent
if prevline =~ '^\s*\(Describe\|Context\|ExampleGroup\|It\|Specify\|Example\)'
return indent(v:lnum - 1) + &shiftwidth
endif
" After prefixed block keywords
if prevline =~ '^\s*\([xf]\)\(Describe\|Context\|ExampleGroup\|It\|Specify\|Example\)'
return indent(v:lnum - 1) + &shiftwidth
endif
" After Data blocks
if prevline =~ '^\s*Data\s*$'
return indent(v:lnum - 1) + &shiftwidth
endif
" After Parameters blocks
if prevline =~ '^\s*Parameters'
return indent(v:lnum - 1) + &shiftwidth
endif
" Keep same indent for most lines
return indent(v:lnum - 1)
endfunction

29
plugin/shellspec.vim Normal file
View File

@@ -0,0 +1,29 @@
" ShellSpec DSL plugin
" Neovim language support for ShellSpec testing framework
" Repository: https://github.com/ivuorinen/nvim-shellspec
" Author: Ismo Vuorinen
if exists('g:loaded_shellspec')
finish
endif
let g:loaded_shellspec = 1
" Commands
command! ShellSpecFormat call shellspec#format_buffer()
command! -range ShellSpecFormatRange call shellspec#format_selection()
" 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
" 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

82
syntax/shellspec.vim Normal file
View File

@@ -0,0 +1,82 @@
" Syntax highlighting for ShellSpec DSL
if exists("b:current_syntax")
finish
endif
" Keywords - Block structures
syn keyword shellspecBlock Describe Context ExampleGroup It Specify Example Todo End
syn keyword shellspecBlock xDescribe xContext xExampleGroup xIt xSpecify xExample
syn keyword shellspecBlock fDescribe fContext fExampleGroup fIt fSpecify fExample
" Keywords - Control flow
syn keyword shellspecControl Pending Skip
syn match shellspecControl "\<Skip\s\+if\>"
" Keywords - Evaluation
syn keyword shellspecEval When call run command script source
" Keywords - Expectation
syn keyword shellspecExpect The Assert should
syn keyword shellspecExpect output stdout error stderr status variable path
syn match shellspecExpect "\<should\s\+not\>"
" Keywords - Hooks
syn keyword shellspecHook BeforeEach AfterEach BeforeAll AfterAll Before After
syn keyword shellspecHook BeforeCall AfterCall BeforeRun AfterRun
" Keywords - Helpers
syn keyword shellspecHelper Dump Include Set Path File Dir Data Parameters
syn match shellspecHelper "\<Data:expand\>"
syn match shellspecHelper "\<Parameters:\(value\|matrix\|dynamic\)\>"
" Language chains
syn keyword shellspecChain a an as the
" Matchers and modifiers
syn keyword shellspecMatcher equal eq be exist valid satisfy
syn keyword shellspecModifier line word length contents result first second third
syn keyword shellspecModifier of
" Tags - for example groups and examples
syn match shellspecTag "\<\w\+:\w\+\>" contained
" Strings
syn region shellspecString start=+"+ skip=+\\"+ end=+"+ contains=shellspecVariable
syn region shellspecString start=+'+ end=+'+
syn match shellspecVariable "\$\w\+" contained
syn match shellspecVariable "\${\w\+}" contained
" Comments
syn match shellspecComment "#.*$" contains=shellspecTodo
syn keyword shellspecTodo TODO FIXME XXX NOTE contained
" Data blocks
syn match shellspecDataMarker "^#|" contained
syn region shellspecDataBlock start="Data\s*$" end="End" contains=shellspecDataMarker
" Numbers
syn match shellspecNumber "\<\d\+\>"
" Shell code in functions
syn include @shellCode $VIMRUNTIME/syntax/sh.vim
syn region shellspecShellCode start="^\s*\w\+\s*(" end="}" contains=@shellCode
" Highlighting groups
hi def link shellspecBlock Statement
hi def link shellspecControl Conditional
hi def link shellspecEval Function
hi def link shellspecExpect Keyword
hi def link shellspecHook PreProc
hi def link shellspecHelper Special
hi def link shellspecChain Operator
hi def link shellspecMatcher Function
hi def link shellspecModifier Type
hi def link shellspecTag Label
hi def link shellspecString String
hi def link shellspecVariable Identifier
hi def link shellspecComment Comment
hi def link shellspecTodo Todo
hi def link shellspecDataMarker SpecialChar
hi def link shellspecNumber Number
let b:current_syntax = "shellspec"