-
Notifications
You must be signed in to change notification settings - Fork 730
/
Copy pathruby.kak
194 lines (166 loc) · 10.1 KB
/
ruby.kak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# http://ruby-lang.org
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufCreate .*(([.](rb))|(irbrc)|(pryrc)|(Brewfile)|(Capfile|[.]cap)|(Gemfile|[.]gemspec)|(Guardfile)|(Rakefile|[.]rake)|(Thorfile|[.]thor)|(Vagrantfile)) %{
set-option buffer filetype ruby
}
# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
hook global WinSetOption filetype=ruby %{
require-module ruby
set-option window static_words %opt{ruby_static_words}
hook window ModeChange pop:insert:.* -group ruby-trim-indent ruby-trim-indent
hook window InsertChar .* -group ruby-indent ruby-indent-on-char
hook window InsertChar \n -group ruby-indent ruby-indent-on-new-line
hook window InsertChar \n -group ruby-insert ruby-insert-on-new-line
alias window alt ruby-alternative-file
hook -once -always window WinSetOption filetype=.* %{
remove-hooks window ruby-.+
unalias window alt ruby-alternative-file
}
}
hook -group ruby-highlight global WinSetOption filetype=ruby %{
add-highlighter window/ruby ref ruby
hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/ruby }
}
provide-module ruby %§
# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾
add-highlighter shared/ruby regions
add-highlighter shared/ruby/code default-region group
add-highlighter shared/ruby/double_symbol region ':"' (?<!\\)(\\\\)*" regions
add-highlighter shared/ruby/single_symbol region ":'" (?<!\\)(\\\\)*' fill variable
add-highlighter shared/ruby/double_string region '"' (?<!\\)(\\\\)*" regions
add-highlighter shared/ruby/single_string region "'" (?<!\\)(\\\\)*' fill string
add-highlighter shared/ruby/backtick region '(?<![$:])`' (?<!\\)(\\\\)*` regions
add-highlighter shared/ruby/regex region '(?<![$:])/' (?<!\\)(\\\\)*/[imox]* regions
add-highlighter shared/ruby/ region '#' '$' fill comment
add-highlighter shared/ruby/ region ^=begin ^=end fill comment
add-highlighter shared/ruby/ region -recurse \( '%[qwQW]?\(' \) fill string
add-highlighter shared/ruby/ region -recurse \{ '%[qwQW]?\{' \} fill string
add-highlighter shared/ruby/ region -recurse \[ '%[qwQW]?\[' \] fill string
add-highlighter shared/ruby/ region -recurse < '%[qwQW]?<' > fill string
add-highlighter shared/ruby/ region -recurse \( '%[isIS]\(' \) fill variable
add-highlighter shared/ruby/ region -recurse \{ '%[isIS]\{' \} fill variable
add-highlighter shared/ruby/ region -recurse \[ '%[isIS]\[' \] fill variable
add-highlighter shared/ruby/ region -recurse < '%[isIS]<' > fill variable
add-highlighter shared/ruby/ region -recurse \( '%[rxRX]\(' \) fill meta
add-highlighter shared/ruby/ region -recurse \{ '%[rxRX]\{' \} fill meta
add-highlighter shared/ruby/ region -recurse \[ '%[rxRX]\[' \] fill meta
add-highlighter shared/ruby/ region -recurse < '%[rxRX]<' > fill meta
add-highlighter shared/ruby/ region -match-capture '%[qwQW]?([^\s0-9A-Za-z\(\{\[<>\]\}\)])' ([^\s0-9A-Za-z\(\{\[<>\]\}\)]) fill string
add-highlighter shared/ruby/ region -match-capture '%[isIS]([^\s0-9A-Za-z\(\{\[<>\]\}\)])' ([^\s0-9A-Za-z\(\{\[<>\]\}\)]) fill variable
add-highlighter shared/ruby/ region -match-capture '%[rxRX]([^\s0-9A-Za-z\(\{\[<>\]\}\)])' ([^\s0-9A-Za-z\(\{\[<>\]\}\)]) fill meta
add-highlighter shared/ruby/heredoc region -match-capture '<<[-~]?(?!self)(\w+)' '^\h*(\w+)$' fill string
add-highlighter shared/ruby/division region '[\w\)\]]\K(/|(\h+/\h+))' '\w' group # Help Kakoune to better detect /…/ literals
# Regular expression flags are: i → ignore case, m → multi-lines, o → only interpolate #{} blocks once, x → extended mode (ignore white spaces)
# Literals are: i → array of symbols, q → string, r → regular expression, s → symbol, w → array of words, x → capture shell result
add-highlighter shared/ruby/double_string/ default-region fill string
add-highlighter shared/ruby/double_string/interpolation region -recurse \{ \Q#{ \} fill meta
add-highlighter shared/ruby/double_symbol/ default-region fill variable
add-highlighter shared/ruby/double_symbol/interpolation region -recurse \{ \Q#{ \} fill meta
add-highlighter shared/ruby/backtick/ default-region fill meta
add-highlighter shared/ruby/backtick/interpolation region -recurse \{ \Q#{ \} fill meta
add-highlighter shared/ruby/regex/ default-region fill meta
add-highlighter shared/ruby/regex/interpolation region -recurse \{ \Q#{ \} fill meta
evaluate-commands %sh{
# Grammar
# Keywords are collected searching for keywords at
# https://github.com/ruby/ruby/blob/trunk/parse.y
keywords="alias|and|begin|break|case|class|def|defined|do|else|elsif|end"
keywords="${keywords}|ensure|false|for|if|in|module|next|nil|not|or|private|protected|public|redo"
keywords="${keywords}|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield"
attributes="attr_reader|attr_writer|attr_accessor"
values="false|true|nil"
meta="require|require_relative|include|extend"
# Add the language's grammar to the static completion list
printf %s\\n "declare-option str-list ruby_static_words ${keywords} ${attributes} ${values} ${meta}" | tr '|' ' '
# Highlight keywords
printf %s "
add-highlighter shared/ruby/code/ regex \b(${keywords})[^0-9A-Za-z_!?] 1:keyword
add-highlighter shared/ruby/code/ regex \b(${attributes})\b 0:attribute
add-highlighter shared/ruby/code/ regex \b(${values})\b 0:value
add-highlighter shared/ruby/code/ regex \b(${meta})\b 0:meta
"
}
add-highlighter shared/ruby/code/ regex \b(\w+:(?!:))|(:?(\$(-[0FIKWadilpvw]|["'`/~&+=!$*,:.\;<>?@\\])|(\$|@@?)\w+))|((?<!:):(![~=]|=~|>[=>]?|<((=>?)|<)?|[+\-]@?|\*\*?|===?|[/`%&!^|~]|(\w+[=?!]?)|(\[\]=?)))|([A-Z]\w*|^|\h)\K::(?=[A-Z]) 0:variable
# Commands
# ‾‾‾‾‾‾‾‾
define-command ruby-alternative-file -docstring 'Jump to the alternate file (implementation ↔ test)' %{ evaluate-commands %sh{
case $kak_buffile in
*spec/*_spec.rb)
altfile=$(eval echo $(echo $kak_buffile | sed s+spec/+'*'/+';'s/_spec//))
[ ! -f $altfile ] && echo "fail 'implementation file not found'" && exit
;;
*test/*_test.rb)
altfile=$(eval echo $(echo $kak_buffile | sed s+test/+'*'/+';'s/_test//))
[ ! -f $altfile ] && echo "fail 'implementation file not found'" && exit
;;
*.rb)
altfile=""
altdir=""
path=$kak_buffile
dirs=$(while [ $path ]; do echo $path; path=${path%/*}; done | tail -n +2)
for dir in $dirs; do
altdir=$dir/spec && suffix=spec
[ ! -d $altdir ] && altdir=$dir/test && suffix=test
if [ -d $altdir ]; then
altfile=$altdir/$(realpath $kak_buffile --relative-to $dir | sed s+[^/]'*'/++';'s/.rb$/_${suffix}.rb/)
break
fi
done
[ ! -d "$altdir" ] && echo "fail 'spec/ and test/ not found'" && exit
;;
*)
echo "fail 'alternative file not found'" && exit
;;
esac
echo "edit $altfile"
}}
define-command -hidden ruby-trim-indent %{
evaluate-commands -no-hooks -draft -itersel %{
execute-keys x
# remove trailing white spaces
try %{ execute-keys -draft s \h + $ <ret> d }
}
}
define-command -hidden ruby-indent-on-char %{
evaluate-commands -no-hooks -draft -itersel %{
# align middle and end structures to start
try %{ execute-keys -draft x <a-k> ^ \h * (else) $ <ret> <a-a> i <a-semicolon> <a-?> ^ \h * (if|case) <ret> <a-S> 1<a-&> }
try %{ execute-keys -draft x <a-k> ^ \h * (elsif) $ <ret> <a-a> i <a-semicolon> <a-?> ^ \h * (if) <ret> <a-S> 1<a-&> }
try %{ execute-keys -draft x <a-k> ^ \h * (when) $ <ret> <a-a> i <a-semicolon> <a-?> ^ \h * (case) <ret> <a-S> 1<a-&> }
try %{ execute-keys -draft x <a-k> ^ \h * (rescue) $ <ret> <a-a> i <a-semicolon> <a-?> ^ \h * (begin|def) <ret> <a-S> 1<a-&> }
}
}
define-command -hidden ruby-indent-on-new-line %{
evaluate-commands -no-hooks -draft -itersel %{
# preserve previous line indent
try %{ execute-keys -draft K <a-&> }
# filter previous line
try %{ execute-keys -draft k : ruby-trim-indent <ret> }
# indent after start structure
try %{ execute-keys -draft k x <a-k> ^ \h * (begin|case|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|.+\bdo$|.+\bdo\h\|.+(?=\|)) [^0-9A-Za-z_!?] <ret> j <a-gt> }
}
}
define-command -hidden ruby-insert-on-new-line %[
evaluate-commands -no-hooks -draft -itersel %[
# copy _#_ comment prefix and following white spaces
try %{ execute-keys -draft k x s ^\h*\K#\h* <ret> y jgi P }
# wisely add end structure
evaluate-commands -save-regs x %[
try %{ execute-keys -draft k x s ^ \h + <ret> \" x y } catch %{ reg x '' }
try %[
evaluate-commands -draft %[
# Check if previous line opens a block
execute-keys -draft kx <a-k>^<c-r>x(begin|case|class|def|for|if|module|unless|until|while|.+\bdo$|.+\bdo\h\|.+(?=\|))[^0-9A-Za-z_!?]<ret>
# Check that we do not already have an end for this indent level which is first set via `ruby-indent-on-new-line` hook
execute-keys -draft }i J x <a-K> ^<c-r>x(end|else|elsif|rescue|when)[^0-9A-Za-z_!?]<ret>
]
execute-keys -draft o<c-r>xend<esc> # insert a new line with containing end
]
]
]
]
§