Skip to content

Commit 33faf55

Browse files
CIAvashalecthomas
authored andcommitted
Improve fish lexer. Add syntax highlighting for commands
- Commands are syntax highlighted as functions - Command options are highlighted as attributes - Added more built-ins and operators - Added Hashbang - Added and improved syntax highlighting for function, variable and keywords - Added test files
1 parent 35539cf commit 33faf55

File tree

3 files changed

+1545
-7
lines changed

3 files changed

+1545
-7
lines changed

lexers/f/fish.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,36 +17,65 @@ var Fish = internal.Register(MustNewLazyLexer(
1717
))
1818

1919
func fishRules() Rules {
20+
keywords := []string{
21+
`begin`, `end`, `if`, `else`, `while`, `break`, `for`, `return`, `function`, `block`,
22+
`case`, `continue`, `switch`, `not`, `and`, `or`, `set`, `echo`, `exit`, `pwd`, `true`,
23+
`false`, `cd`, `cdh`, `count`, `test`,
24+
}
25+
keywordsPattern := Words(`\b`, `\b`, keywords...)
26+
27+
builtins := []string{
28+
`alias`, `bg`, `bind`, `breakpoint`, `builtin`, `argparse`, `abbr`, `string`, `command`,
29+
`commandline`, `complete`, `contains`, `dirh`, `dirs`, `disown`, `emit`, `eval`, `exec`,
30+
`fg`, `fish`, `fish_add_path`, `fish_breakpoint_prompt`, `fish_command_not_found`,
31+
`fish_config`, `fish_git_prompt`, `fish_greeting`, `fish_hg_prompt`, `fish_indent`,
32+
`fish_is_root_user`, `fish_key_reader`, `fish_mode_prompt`, `fish_opt`, `fish_pager`,
33+
`fish_prompt`, `fish_right_prompt`, `fish_status_to_signal`, `fish_svn_prompt`,
34+
`fish_title`, `fish_update_completions`, `fish_vcs_prompt`, `fishd`, `funced`,
35+
`funcsave`, `functions`, `help`, `history`, `isatty`, `jobs`, `math`, `mimedb`, `nextd`,
36+
`open`, `prompt_pwd`, `realpath`, `popd`, `prevd`, `psub`, `pushd`, `random`, `read`,
37+
`set_color`, `source`, `status`, `suspend`, `trap`, `type`, `ulimit`, `umask`, `vared`,
38+
`fc`, `getopts`, `hash`, `kill`, `printf`, `time`, `wait`,
39+
}
40+
2041
return Rules{
2142
"root": {
2243
Include("basic"),
23-
Include("data"),
2444
Include("interp"),
45+
Include("data"),
2546
},
2647
"interp": {
2748
{`\$\(\(`, Keyword, Push("math")},
2849
{`\(`, Keyword, Push("paren")},
2950
{`\$#?(\w+|.)`, NameVariable, nil},
3051
},
3152
"basic": {
32-
{`\b(begin|end|if|else|while|break|for|in|return|function|block|case|continue|switch|not|and|or|set|echo|exit|pwd|true|false|cd|count|test)(\s*)\b`, ByGroups(Keyword, Text), nil},
33-
{`\b(alias|bg|bind|breakpoint|builtin|command|commandline|complete|contains|dirh|dirs|emit|eval|exec|fg|fish|fish_config|fish_indent|fish_pager|fish_prompt|fish_right_prompt|fish_update_completions|fishd|funced|funcsave|functions|help|history|isatty|jobs|math|mimedb|nextd|open|popd|prevd|psub|pushd|random|read|set_color|source|status|trap|type|ulimit|umask|vared|fc|getopts|hash|kill|printf|time|wait)\s*\b(?!\.)`, NameBuiltin, nil},
53+
{Words(`(?<=(?:^|\A|;|&&|\|\||\||`+keywordsPattern+`)\s*)`, `(?=;?\b)`, keywords...), Keyword, nil},
54+
{`(?<=for\s+\S+\s+)in\b`, Keyword, nil},
55+
{Words(`\b`, `\s*\b(?!\.)`, builtins...), NameBuiltin, nil},
56+
{`#!.*\n`, CommentHashbang, nil},
3457
{`#.*\n`, Comment, nil},
3558
{`\\[\w\W]`, LiteralStringEscape, nil},
3659
{`(\b\w+)(\s*)(=)`, ByGroups(NameVariable, Text, Operator), nil},
37-
{`[\[\]()=]`, Operator, nil},
60+
{`[\[\]()={}]`, Operator, nil},
61+
{`(?<=\[[^\]]+)\.\.|-(?=[^\[]+\])`, Operator, nil},
3862
{`<<-?\s*(\'?)\\?(\w+)[\w\W]+?\2`, LiteralString, nil},
63+
{`(?<=set\s+(?:--?[^\d\W][\w-]*\s+)?)\w+`, NameVariable, nil},
64+
{`(?<=for\s+)\w[\w-]*(?=\s+in)`, NameVariable, nil},
65+
{`(?<=function\s+)\w(?:[^\n])*?(?= *[-\n])`, NameFunction, nil},
66+
{`(?<=(?:^|\b(?:and|or|sudo)\b|;|\|\||&&|\||\(|(?:\b\w+\s*=\S+\s)) *)\w[\w-]*`, NameFunction, nil},
3967
},
4068
"data": {
4169
{`(?s)\$?"(\\\\|\\[0-7]+|\\.|[^"\\$])*"`, LiteralStringDouble, nil},
4270
{`"`, LiteralStringDouble, Push("string")},
4371
{`(?s)\$'(\\\\|\\[0-7]+|\\.|[^'\\])*'`, LiteralStringSingle, nil},
4472
{`(?s)'.*?'`, LiteralStringSingle, nil},
4573
{`;`, Punctuation, nil},
46-
{`&|\||\^|<|>`, Operator, nil},
74+
{`&&|\|\||&|\||\^|<|>`, Operator, nil},
4775
{`\s+`, Text, nil},
48-
{`\d+(?= |\Z)`, LiteralNumber, nil},
49-
{"[^=\\s\\[\\]{}()$\"\\'`\\\\<&|;]+", Text, nil},
76+
{`\b\d+\b`, LiteralNumber, nil},
77+
{`--?[^\d][\w-]*`, NameAttribute, nil},
78+
{".+?", Text, nil},
5079
},
5180
"string": {
5281
{`"`, LiteralStringDouble, Pop(1)},

lexers/testdata/fish.actual

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
#!/usr/bin/env fish
2+
3+
echo hello > output.txt
4+
5+
alias something=echo
6+
7+
sudo systemctl start postgresql
8+
9+
# Outputs 'image.png'.
10+
echo (basename image.jpg .jpg).png
11+
12+
echo some text for testing
13+
14+
# Convert all JPEG files in the current directory to the
15+
# PNG format using the 'convert' program.
16+
for i in *.jpg; convert $i (basename $i .jpg).png; end
17+
18+
# Set the ``data`` variable to the contents of 'data.txt'
19+
# without splitting it into a list.
20+
begin; set -l IFS; set data (cat data.txt); end
21+
22+
# Set ``$data`` to the contents of data, splitting on NUL-bytes.
23+
set data (cat data | string split0)
24+
25+
grep fish myanimallist1 | wc -l
26+
27+
echo input.{c,h,txt}
28+
29+
echo {$dogs}dog
30+
31+
echo (seq 10)[1 2 3]
32+
echo (seq 10)[2..5 1..3]
33+
echo (seq 10)[-1..1]
34+
set PATH $PATH[-1..1]
35+
36+
set foo banana
37+
foo=gagaga echo $foo # prints gagaga, while in other shells it might print "banana"
38+
foo=gagaga somecommand $foo # prints gagaga, while in other shells it might print "banana"
39+
40+
function some func
41+
echo 'function' with space
42+
end
43+
44+
function dirs --description 'Print directory stack'
45+
set -l options h/help c
46+
argparse -n dirs --max-args=0 $options -- $argv
47+
or return
48+
49+
if set -q _flag_help
50+
__fish_print_help dirs
51+
return 0
52+
end
53+
54+
if set -q _flag_c
55+
# Clear directory stack.
56+
set -e -g dirstack
57+
return 0
58+
end
59+
60+
# Replace $HOME with ~.
61+
string replace -r '^'"$HOME"'($|/)' '~$1' -- $PWD $dirstack | string join " "
62+
end
63+
64+
function ytdl_files -d "Download videos from text files with youtube-dl and put them into folders"
65+
argparse --name=ytdl_files 's/shutdown' -- $argv
66+
67+
for file in $argv
68+
echo "Operating on $file"
69+
youtube-dl -a $file -i -o (dirname $file)"/"(basename $file .txt)"/%(autonumber)s-%(title)s.%(ext)s"
70+
end
71+
72+
if test -n "$_flag_shutdown"
73+
echo "poweroff"
74+
end
75+
end
76+
77+
function cheat -d 'Get programming language cheat sheets from cheat.sh'
78+
if test $argv[1]
79+
curl https://cheat.sh/$argv[1]
80+
else
81+
curl https://cheat.sh
82+
end
83+
end
84+
85+
function dut -d 'Get top paths with most disk usage'
86+
du -hs $argv[2]/* | sort -rh | head -$argv[1]
87+
end
88+
89+
function m2d --description 'Move to desktop -- m2d program_name desktop_num'
90+
bspc node (xdo id -N $argv[1]) -d $argv[2]
91+
end
92+
93+
set -x no_proxy 'localhost,127.0.0.1'
94+
95+
function toggle_proxy
96+
if not set -q HTTP_PROXY
97+
for proxy in HTTP_PROXY HTTPS_PROXY http_proxy https_proxy
98+
set -gx $proxy 'http://127.0.0.1:8118'
99+
end
100+
echo 'Proxy On'
101+
else
102+
set -e {HTTP_PROXY,HTTPS_PROXY,http_proxy,https_proxy}
103+
echo 'proxy Off'
104+
end
105+
end
106+
107+
function wttr -d 'Get weather info from wttr.in'
108+
if test $argv[1]
109+
curl https://wttr.in/$argv[1]
110+
else
111+
curl https://wttr.in/
112+
end
113+
end
114+
115+
function fish_config --description "Launch fish's web based configuration"
116+
argparse h/help -- $argv
117+
or return
118+
119+
if set -q _flag_help
120+
__fish_print_help fish_config
121+
return 0
122+
end
123+
124+
set -l cmd $argv[1]
125+
set -e argv[1]
126+
127+
set -q cmd[1]
128+
or set cmd browse
129+
130+
# The web-based configuration UI
131+
# Also opened with just `fish_config` or `fish_config browse`.
132+
if contains -- $cmd browse
133+
set -lx __fish_bin_dir $__fish_bin_dir
134+
if set -l python (__fish_anypython)
135+
$python "$__fish_data_dir/tools/web_config/webconfig.py" $argv
136+
else
137+
echo (set_color $fish_color_error)Cannot launch the web configuration tool:(set_color normal)
138+
echo (set_color -o)"fish_config browse"(set_color normal) requires Python.
139+
echo Installing python will fix this, and also enable completions to be
140+
echo automatically generated from man pages.\n
141+
echo To change your prompt, use (set_color -o)"fish_config prompt"(set_color normal) or create a (set_color -o)"fish_prompt"(set_color normal) function.
142+
echo To list the samples use (set_color -o)"fish_config prompt show"(set_color normal).\n
143+
144+
echo You can tweak your colors by setting the (set_color $fish_color_search_match)\$fish_color_\*(set_color normal) variables.
145+
end
146+
return 0
147+
end
148+
149+
if not contains -- $cmd prompt
150+
echo No such subcommand: $cmd >&2
151+
return 1
152+
end
153+
154+
# prompt - for prompt switching
155+
set -l cmd $argv[1]
156+
set -e argv[1]
157+
158+
if contains -- $cmd list; and set -q argv[1]
159+
echo "Too many arguments" >&2
160+
return 1
161+
end
162+
163+
set -l prompt_dir $__fish_data_dir/sample_prompts $__fish_data_dir/tools/web_config/sample_prompts
164+
switch $cmd
165+
case show
166+
set -l fish (status fish-path)
167+
set -l prompts $prompt_dir/$argv.fish
168+
set -q prompts[1]; or set prompts $prompt_dir/*.fish
169+
for p in $prompts
170+
if not test -e "$p"
171+
continue
172+
end
173+
set -l promptname (string replace -r '.*/([^/]*).fish$' '$1' $p)
174+
echo -s (set_color --underline) $promptname (set_color normal)
175+
$fish -c "functions -e fish_right_prompt; source $p;
176+
false
177+
fish_prompt
178+
echo (set_color normal)
179+
if functions -q fish_right_prompt;
180+
echo right prompt: (false; fish_right_prompt)
181+
end"
182+
echo
183+
end
184+
case list ''
185+
string replace -r '.*/([^/]*).fish$' '$1' $prompt_dir/*.fish
186+
return
187+
case choose
188+
if set -q argv[2]
189+
echo "Too many arguments" >&2
190+
return 1
191+
end
192+
if not set -q argv[1]
193+
echo "Too few arguments" >&2
194+
return 1
195+
end
196+
197+
set -l have 0
198+
for f in $prompt_dir/$argv[1].fish
199+
if test -f $f
200+
source $f
201+
set have 1
202+
break
203+
end
204+
end
205+
if test $have -eq 0
206+
echo "No such prompt: '$argv[1]'" >&2
207+
return 1
208+
end
209+
case save
210+
read -P"Overwrite prompt? [y/N]" -l yesno
211+
if string match -riq 'y(es)?' -- $yesno
212+
echo Overwriting
213+
cp $__fish_config_dir/functions/fish_prompt.fish{,.bak}
214+
215+
if set -q argv[1]
216+
set -l have 0
217+
for f in $prompt_dir/$argv[1].fish
218+
if test -f $f
219+
set have 1
220+
source $f
221+
or return 2
222+
end
223+
end
224+
if test $have -eq 0
225+
echo "No such prompt: '$argv[1]'" >&2
226+
return 1
227+
end
228+
end
229+
230+
funcsave fish_prompt
231+
or return
232+
233+
functions -q fish_right_prompt
234+
and funcsave fish_right_prompt
235+
236+
return
237+
else
238+
echo Not overwriting
239+
return 1
240+
end
241+
end
242+
243+
return 0
244+
end

0 commit comments

Comments
 (0)