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
|
# http://kakoune.org
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
# Detection
# ‾‾‾‾‾‾‾‾‾
hook global BufCreate (.*/)?(\.Rprofile|.*\.[rR]) %{
set-option buffer filetype r
}
provide-module r %§
# Highlighters & Completion
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
add-highlighter shared/r regions
add-highlighter shared/r/code default-region group
add-highlighter shared/r/double_string region '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/r/single_string region "'" (?<!\\)(\\\\)*' fill string
add-highlighter shared/r/comment region '#' '$' fill comment
add-highlighter shared/r/identifier region '`' (?<!\\)(\\\\)*` fill attribute
# see base::NumericConstants
add-highlighter shared/r/code/ regex '(?i)\b(?<![.\d])\d+(\.\d*)?(e[-+]?\d+)?(?I)[iL]?(?![\d.e\w])' 0:value
add-highlighter shared/r/code/ regex '(?i)(?<![.\d\w])\.\d+(e[-+]?\d+)?(?I)[iL]?(?![\d.e])' 0:value
add-highlighter shared/r/code/ regex '(?i)\b(?<![.\d])0x[0-9a-f]+?(p[-+]?\d+)?(?I)[iL]?(?![\d.e\w])' 0:value
evaluate-commands %sh{
# see base::Reserved
values="TRUE|FALSE|NULL|Inf|NaN|NA|NA_integer_|NA_real_|NA_complex_|NA_character_|\.{3}|\.{2}\d+|"
keywords="if|else|repeat|while|function|for|in|next|break"
# see base::Ops and methods::Ops
math_functions="abs|sign|sqrt|floor|ceiling|trunc|round|signif|exp|log|expm1|log1p|cos|sin|tan|cospi|sinpi|tanpi|acos|asin|atan|cosh|sinh|tanh|acosh|asinh|atanh|lgamma|gamma|digamma|trigamma"
summary_functions="all|any|sum|prod|min|max|range"
complex_functions="Arg|Conj|Im|Mod|Re"
# Add the language's grammar to the static completion list
printf %s\\n "hook global WinSetOption filetype=python %{
set-option window static_words ${values} ${keywords} ${math_functions} ${summary_functions} ${complex_functions}
}" | tr '|' ' '
printf %s "
add-highlighter shared/r/code/ regex '\b(${values})\b' 0:value
add-highlighter shared/r/code/ regex '\b(${keywords})\b' 0:keyword
add-highlighter shared/r/code/ regex '\b(${math_functions}|${summary_functions}|${complex_functions})\b' 0:function
"
}
# see base::Syntax
add-highlighter shared/r/code/ regex (?<=[\w\s\d'"_)])(\$|@|\^|-|\+|%[^%^\n]+%|\*|/|<|>|<=|>=|!|&{1,2}|\|{1,2}|~|\?|:{1,3}|\[{1,2}|\]{1,2}|={1,2}|<{1,2}-|->{1,2}|!=|%%) 0:operator
# Commands
# ‾‾‾‾‾‾‾‾
define-command -hidden r-trim-indent %{
# remove the line if it's empty when leaving the insert mode
try %{ execute-keys -draft x 1s^(\h+)$<ret> d }
}
define-command -hidden r-indent-on-newline %< evaluate-commands -draft -itersel %<
execute-keys <semicolon>
try %<
# if previous line closed a paren (possibly followed by words and a comment),
# copy indent of the opening paren line
execute-keys -draft kx 1s(\))(\h+\w+)*\h*(\;\h*)?(?:#[^\n]+)?\n\z<ret> m<a-semicolon>J <a-S> 1<a-&>
> catch %<
# else indent new lines with the same level as the previous one
execute-keys -draft K <a-&>
>
# remove previous empty lines resulting from the automatic indent
try %< execute-keys -draft k x <a-k>^\h+$<ret> Hd >
# indent after an opening brace or parenthesis at end of line
try %< execute-keys -draft k x s[{(]\h*$<ret> j <a-gt> >
# indent after a statement not followed by an opening brace
try %< execute-keys -draft k x s\)\h*(?:#[^\n]+)?\n\z<ret> \
<a-semicolon>mB <a-k>\A\b(if|for|while)\b<ret> <a-semicolon>j <a-gt> >
try %< execute-keys -draft k x s \belse\b\h*(?:#[^\n]+)?\n\z<ret> \
j <a-gt> >
# deindent after a single line statement end
try %< execute-keys -draft K x <a-k>\;\h*(#[^\n]+)?$<ret> \
K x s\)(\h+\w+)*\h*(#[^\n]+)?\n([^\n]*\n){2}\z<ret> \
MB <a-k>\A\b(if|for|while)\b<ret> <a-S>1<a-&> >
try %< execute-keys -draft K x <a-k>\;\h*(#[^\n]+)?$<ret> \
K x s \belse\b\h*(?:#[^\n]+)?\n([^\n]*\n){2}\z<ret> \
<a-S>1<a-&> >
# align to the opening parenthesis or opening brace (whichever is first)
# on a previous line if its followed by text on the same line
try %< evaluate-commands -draft %<
# Go to opening parenthesis and opening brace, then select the most nested one
try %< execute-keys [c [({],[)}] <ret> >
# Validate selection and get first and last char
execute-keys <a-k>\A[{(](\h*\S+)+\n<ret> <a-K>"(([^"]*"){2})*<ret> <a-K>'(([^']*'){2})*<ret> <a-:><a-semicolon>L <a-S>
# Remove possibly incorrect indent from new line which was copied from previous line
try %< execute-keys -draft , <a-h> s\h+<ret> d >
# Now indent and align that new line with the opening parenthesis/brace
execute-keys 1<a-&> &
> >
> >
define-command -hidden r-indent-on-opening-curly-brace %[
# align indent with opening paren when { is entered on a new line after the closing paren
try %[ execute-keys -draft -itersel h<a-F>)M <a-k> \A\(.*\)\h*\n\h*\{\z <ret> <a-S> 1<a-&> ]
]
define-command -hidden r-indent-on-closing-curly-brace %[
# align to opening curly brace when alone on a line
try %[
# in case open curly brace follows a closing paren, align indent with opening paren
execute-keys -itersel -draft <a-h><a-:><a-k>^\h+\}$<ret>hm <a-F>)M <a-k> \A\(.*\)\h\{.*\}\z <ret> <a-S>1<a-&>
] catch %[
# otherwise align with open curly brace
execute-keys -itersel -draft <a-h><a-:><a-k>^\h+\}$<ret>hm<a-S>1<a-&>
] catch %[]
]
define-command -hidden r-insert-on-newline %[ evaluate-commands -itersel -draft %[
execute-keys <semicolon>
try %[
evaluate-commands -draft -save-regs '/"' %[
# copy the commenting prefix
execute-keys -save-regs '' k x1s^\h*(#+\h*)<ret> y
try %[
# if the previous comment isn't empty, create a new one
execute-keys x<a-K>^\h*#+\h*$<ret> jxs^\h*<ret>P
] catch %[
# if there is no text in the previous comment, remove it completely
execute-keys d
]
]
]
] ]
§
# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
hook -group r-highlight global WinSetOption filetype=r %{
require-module r
add-highlighter window/r ref r
hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/r }
}
hook global WinSetOption filetype=r %~
require-module r
hook window ModeChange pop:insert:.* r-trim-indent
hook window InsertChar \n r-insert-on-newline
hook window InsertChar \n r-indent-on-newline
hook window InsertChar \{ r-indent-on-opening-curly-brace
hook window InsertChar \} r-indent-on-closing-curly-brace
hook -once -always window WinSetOption filetype=.* %{ remove-hooks window r-.+ }
~
|