Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collapse the many forks? #51

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c0172e6
Filter blank completions
gpanders Sep 13, 2019
129fee7
Handle escaped quotes in the fishString syntax definition.
Jan 4, 2020
3a93992
When mimicking funced for new fish files in the ~/.config/fish/functi…
Jan 5, 2020
d09755b
Define b:undo_ftplugin and fix b:match_words
lilyball Jul 14, 2014
5af7761
Improve fish#Indent()
Raimondi Jun 12, 2015
b005e8c
Small improvements.
Raimondi Jun 19, 2015
3253058
Add comment explaining our funced BufRead autocommand.
Jan 5, 2020
0dfeda7
Handle new and old file names for both the fish univeral env var file…
Jan 5, 2020
8c034e8
For funced just retab instead of doing a full format (eventually want…
Jan 5, 2020
fc758c6
Fix funced handling and funced emulation.
Feb 8, 2020
8b20c17
Remove '/' from iskeyword so that 'w' doesn't skip over entire paths.
Mar 22, 2020
b1c1f13
Filter man through `col` to remove ^H characters
novadev94 Mar 7, 2020
cdf9584
Better syntax highlighting
novadev94 Mar 15, 2020
10d1162
Continuation adds 4 spaces as done by fish_indent
novadev94 Mar 15, 2020
6d2619e
Fix 'switch' with endwise causing added 'end' to be unindented
novadev94 Mar 15, 2020
1ec83b2
Better syntax highlighting (2)
novadev94 Mar 16, 2020
4efc119
Add missing fish_ commands
novadev94 Mar 16, 2020
6cf217b
Add UNIX commands
novadev94 Mar 16, 2020
248778b
Complete now matches prefix
novadev94 Mar 16, 2020
eee7e06
Update errorformat for fish v3.1.0
novadev94 Mar 17, 2020
4a4c402
Support range operator
novadev94 Mar 18, 2020
e2398cb
Enhanced errorformat
novadev94 Mar 18, 2020
68f039b
Update b:match_skip for matchit.vim
novadev94 Mar 18, 2020
013fe91
A bit better errorformat
novadev94 Mar 18, 2020
6651405
Use :Man for showing man pages on K
novadev94 Mar 19, 2020
bfdab2c
Remove '/' from iskeyword
novadev94 Mar 19, 2020
7344a2f
Drop range operator
novadev94 Mar 19, 2020
ea5c553
Multiple dereferencing
novadev94 Mar 22, 2020
d28d491
Errorformat change again
novadev94 Mar 25, 2020
acf2311
Syntax: Dereferencing extension
novadev94 Mar 26, 2020
c200bfa
Add string escape highlight
novadev94 Apr 2, 2020
de92515
Fix syntax for fish \e character
novadev94 Apr 4, 2020
83f8bdb
Add \0 to fishCharacteR
novadev94 Apr 5, 2020
2870a29
Indent command substitution
novadev94 Apr 7, 2020
9e48a9d
Fix fish escaping $
novadev94 Apr 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 167 additions & 21 deletions autoload/fish.vim
Original file line number Diff line number Diff line change
@@ -1,23 +1,122 @@
function! s:IsString(lnum, col)
" Returns "true" if syntax item at the given position is part of fishString.
let l:stack = map(synstack(a:lnum, a:col), 'synIDattr(v:val, "name")')
return len(filter(l:stack, 'v:val ==# "fishString"'))
endfunction

function! s:IsContinuedLine(lnum)
" Returns "true" if the given line is a continued line.
return getline(a:lnum - 1) =~ '\v\\$'
endfunction

function! s:IsInSubstitution(lnum)
" Returns "true" if the given line is a continued line.
return getline(a:lnum - 1) =~ '\v\($'
endfunction

function! s:FindPrevLnum(lnum)
" Starting on the given line, search backwards for a line that is not
" empty, not part of a string and not a continued line.
if a:lnum < 1 || a:lnum > line('$')
" First line or wrong value, follow prevnonblank() behaviour and
" return zero.
return 0
endif
let l:lnum = prevnonblank(a:lnum)
while l:lnum > 0 && ( s:IsContinuedLine(l:lnum) || s:IsString(l:lnum, 1) )
let l:lnum = prevnonblank(l:lnum - 1)
endwhile
return l:lnum
endfunction

function! s:IsSwitch(lnum)
" Returns "true" if the given line is part of a switch block.
let l:lnum = a:lnum
let l:line = getline(l:lnum)
let l:in_block = 0
let l:stop_pat = '\v^\s*%(if|else|while|for|begin)>'
let l:block_start_pat = '\v^\s*%(if|while|for|switch|begin)>'
while l:lnum > 0
let l:lnum = prevnonblank(l:lnum - 1)
let l:line = getline(l:lnum)
if l:line =~# '\v^\s*end>'
let l:in_block += 1
elseif l:in_block && l:line =~# l:block_start_pat
let l:in_block -= 1
elseif !l:in_block && l:line =~# l:stop_pat
return 0
elseif !l:in_block && l:line =~# '\v^\s*switch>'
return 1
endif
endwhile
return 0
endfunction

function! fish#Indent()
let l:shiftwidth = shiftwidth()
let l:prevlnum = prevnonblank(v:lnum - 1)
if l:prevlnum ==# 0
let l:line = getline(v:lnum)
if s:IsString(v:lnum, 1)
return indent(v:lnum)
endif
" shiftwidth can be misleading in recent versions, use shiftwidth() if
" it is available.
if exists('*shiftwidth')
let l:shiftwidth = shiftwidth()
else
let l:shiftwidth = &shiftwidth
endif
let l:prevlnum = s:FindPrevLnum(v:lnum - 1)
if l:prevlnum == 0
return 0
endif
let l:indent = 0
let l:shift = 0
let l:prevline = getline(l:prevlnum)
if l:prevline =~# '\v^\s*switch>'
let l:indent = l:shiftwidth * 2
elseif l:prevline =~# '\v^\s*%(begin|if|else|while|for|function|case)>'
let l:indent = l:shiftwidth
let l:previndent = indent(l:prevlnum)
if s:IsContinuedLine(v:lnum)
" It is customary to increment indentation of continued lines by four
" or a custom value defined by the user if available.
let l:previndent = indent(v:lnum - 1)
if s:IsContinuedLine(v:lnum - 1)
return l:previndent
elseif exists('g:fish_indent_cont')
return l:previndent + g:fish_indent_cont
elseif exists('g:indent_cont')
return l:previndent + g:indent_cont
else
return l:previndent + l:shiftwidth
endif
endif
let l:line = getline(v:lnum)
if l:line =~# '\v^\s*end>'
return indent(v:lnum) - (l:indent ==# 0 ? l:shiftwidth : l:indent)
elseif l:line =~# '\v^\s*%(case|else)>'
return indent(v:lnum) - l:shiftwidth
if l:prevline =~ '(\s*$'
" Inside a substitution
let l:shift += 1
endif
if l:line =~ '^\s*)'
" Outside a substitution
let l:shift -= 1
endif
if l:prevline =~# '\v^\s*%(begin|if|else|while|for|function|case|switch)>'
" First line inside a block, increase by one.
let l:shift += 1
endif
if l:line =~# '\v^\s*%(end|case|else)>'
" "end", "case" or "else", decrease by one.
let l:shift -= 1
endif
if l:line =~# '\v^\s*<case>' && l:prevline =~# '\v<switch>'
" "case" following "switch", increase by one.
let l:shift += 1
endif
if l:line =~# '\v\s*end>' && l:prevline !~# '\v<switch>' && s:IsSwitch(v:lnum)
" "end" ends switch block, but not immediately following "switch"
" decrease by one more so it matches the indentation of "switch".
let l:shift -= 1
endif
if l:prevline =~# '\v^\s*%(if|while|for|else|switch|end)>.*<begin>'
" "begin" after start of block, increase by one.
let l:shift += 1
endif
return indent(l:prevlnum) + l:indent
let l:indent = l:previndent + l:shift * l:shiftwidth
" Only return zero or positive numbers.
return l:indent < 0 ? 0 : l:indent
endfunction

function! fish#Format()
Expand All @@ -27,6 +126,8 @@ function! fish#Format()
let l:command = v:lnum.','.(v:lnum+v:count-1).'!fish_indent'
echo l:command
execute l:command
" Fix indentation and replace tabs with spaces if necessary.
normal! '[=']
endif
endfunction

Expand All @@ -50,18 +151,63 @@ function! fish#Complete(findstart, base)
endif
let l:results = []
let l:completions =
\ system('fish -c "complete -C'.shellescape(a:base).'"')
let l:cmd = substitute(a:base, '\v\S+$', '', '')
for l:line in split(l:completions, '\n')
\ system('fish -c "complete -C'.shellescape(a:base).'"')
let l:sufpos = match(a:base, '\v\S+$')
if l:sufpos >= 0
let l:cmd = a:base[:l:sufpos-1]
let l:arg = a:base[l:sufpos:]
else
let l:cmd = a:base
let l:arg = ''
endif
for l:line in filter(split(l:completions, '\n'), '!empty(v:val)')
let l:tokens = split(l:line, '\t')
call add(l:results, {'word': l:cmd.l:tokens[0],
\'abbr': l:tokens[0],
\'menu': get(l:tokens, 1, '')})
let l:term = l:tokens[0]
if l:term =~? '^\V'.l:arg
call add(l:results, {
\ 'word': l:cmd.l:term,
\ 'abbr': l:term,
\ 'menu': get(l:tokens, 1, ''),
\ 'dup': 1
\ })
endif
endfor
return l:results
endif
endfunction

function! fish#errorformat()
return '%Afish: %m,%-G%*\\ ^,%-Z%f (line %l):%s'
return '%A<%t> fish: %m,%Efish: %m,%E%f (line %l): %m,%E%f (line %l):%.%#,%-Z%p^,%Ein %m,%Z called on line %l of file %f,%Ein %m,%C%s,%-G%.%#'
endfunction

function! fish#Help(ref) abort
let l:ref = a:ref
if empty(a:ref)
" let l:ref = &filetype ==# 'man' ? expand('<cWORD>') : expand('<cword>')
let l:ref = expand('<cword>')
if empty(l:ref)
call s:fish_help_error('no identifier under cursor')
return
endif
endif
let l:output = systemlist('fish -c "man -w ' . shellescape(l:ref) . '"')
if v:shell_error
call s:fish_help_error(printf('command exited with code %d: %s', v:shell_error, join(l:output)))
return
endif
aug ft_man_fish
au FileType man
\ setlocal nobuflisted
\ | setlocal keywordprg=:FishHelp'
\ | nnoremap <silent> <buffer> K :FishHelp<cr>
\ | nnoremap <silent> <buffer> <C-]> :FishHelp<cr>
aug END
execute 'Man ' . l:output[0]
silent aug! ft_man_fish
endfunction

function! s:fish_help_error(message)
echohl ErrorMsg
echon 'FishHelp: ' a:message
echohl NONE
endfunction
2 changes: 1 addition & 1 deletion bin/man.fish
Original file line number Diff line number Diff line change
@@ -1 +1 @@
man $argv
man $argv | col -bf
2 changes: 1 addition & 1 deletion compiler/fish.vim
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ endif
let current_compiler = 'fish'

CompilerSet makeprg=fish\ --no-execute\ %
execute 'CompilerSet errorformat='.escape(fish#errorformat(), ' ')
execute 'CompilerSet errorformat='.escape(fish#errorformat(), ' ')
22 changes: 6 additions & 16 deletions ftdetect/fish.vim
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
autocmd BufRead,BufNewFile *.fish setfiletype fish

" Set filetype when using funced.
autocmd BufRead fish_funced.* setfiletype fish

" Fish histories are YAML documents.
autocmd BufRead,BufNewFile ~/.config/fish/fish_{read_,}history setfiletype yaml

" Detect fish scripts by the shebang line.
autocmd BufRead *
\ if getline(1) =~# '\v^#!%(\f*/|/usr/bin/env\s*<)fish>' |
\ setlocal filetype=fish |
\ endif

" Move cursor to first empty line when using funced.
autocmd BufRead fish_funced_*_*.fish call search('^$')

" Fish histories are YAML documents.
autocmd BufRead,BufNewFile ~/.config/fish/fish_{read_,}history setfiletype yaml

" Universal variable storages should not be hand edited.
autocmd BufRead,BufNewFile ~/.config/fish/fishd.* setlocal readonly

" Mimic `funced` when manually creating functions.
autocmd BufNewFile ~/.config/fish/functions/*.fish
\ call append(0, ['function '.expand('%:t:r'),
\'',
\'end']) |
\ 2
38 changes: 33 additions & 5 deletions ftplugin/fish.vim
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
if exists('b:did_ftplugin')
finish
end
let b:did_ftplugin = 1

let s:save_cpo = &cpo
set cpo&vim

setlocal comments=:#
setlocal commentstring=#%s
setlocal define=\\v^\\s*function>
setlocal foldexpr=fish#Fold()
setlocal formatoptions+=ron1
setlocal formatoptions-=t
setlocal include=\\v^\\s*\\.>
setlocal iskeyword=@,48-57,-,_,.,/
setlocal iskeyword=@,48-57,+,-,_,.
setlocal suffixesadd^=.fish

" Use the 'j' format option when available.
Expand All @@ -29,11 +37,31 @@ endif
" Use the 'man' wrapper function in fish to include fish's man pages.
" Have to use a script for this; 'fish -c man' would make the the man page an
" argument to fish instead of man.
execute 'setlocal keywordprg=fish\ '.fnameescape(expand('<sfile>:p:h:h').'/bin/man.fish')
" execute 'setlocal keywordprg=fish\ '.fnameescape(expand('<sfile>:p:h:h').'/bin/man.fish')
setlocal keywordprg=:FishHelp

let b:match_words =
\ escape('<%(begin|function|if|switch|while|for)>:<end>', '<>%|)')
let b:match_ignorecase = 0
if has('patch-7.3.1037')
let s:if = '%(else\s\+)\@15<!if'
else
let s:if = '%(else\s\+)\@<!if'
endif

let b:match_words = escape(
\'<%(begin|function|'.s:if.'|switch|while|for)>:<else\s\+if|case>:<else>:<end>'
\, '<>%|)')
let b:match_skip = 's:comment\|string\|deref'

let b:endwise_addition = 'end'
let b:endwise_words = 'begin,function,if,switch,while,for'
let b:endwise_syngroups = 'fishKeyword,fishConditional,fishRepeat'
let b:endwise_syngroups = 'fishBlock,fishFunction,fishConditional,fishRepeat'

let b:undo_ftplugin = "
\ setlocal comments< commentstring< define< foldexpr< formatoptions<
\|setlocal include< iskeyword< suffixesadd<
\|setlocal formatexpr< omnifunc< path< keywordprg<
\|unlet! b:match_words b:endwise_addition b:endwise_words b:endwise_syngroups
\"

let &cpo = s:save_cpo
unlet s:save_cpo
1 change: 1 addition & 0 deletions indent/fish.vim
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
setlocal indentexpr=fish#Indent()
setlocal indentkeys=!^F,o,O
setlocal indentkeys+==end,=else,=case
21 changes: 21 additions & 0 deletions plugin/fish.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
if get(g:, 'loaded_fish', 0)
finish
endif
let loaded_fish = 1

" Universal variable storages should not be hand edited.
autocmd BufRead,BufNewFile ~/.config/fish/fishd.*,~/.config/fish/fish_variables
\ setlocal readonly

" When using funced:
" - Reindent (because funced adds a tab on the first empty line and the user may
" have set expandtab).
" - Move the cursor to the first empty line.
autocmd BufRead fish_funced.*,fish_funced_*_*.fish,/tmp/fish.*/*.fish
\ retab | call search('^\s*\zs$')

" Mimic `funced` when manually creating functions.
autocmd BufNewFile ~/.config/fish/functions/*.fish
\ call setline(1, ['function '.expand('%:t:r'), '', 'end']) | 2

command! -nargs=? FishHelp call fish#Help(<q-args>)
Loading