summaryrefslogtreecommitdiff
path: root/autoload/filetype/go.kak
blob: 4f8407cdb285328551c323b81fbd8c1e084453d9 (plain)
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
# https://golang.org/
#

# Detection
# ‾‾‾‾‾‾‾‾‾

hook global BufCreate .*\.go %{
    set-option buffer filetype go
}

# Initialization
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾

hook global WinSetOption filetype=go %{
    require-module go

    set-option window static_words %opt{go_static_words}

    # cleanup trailing whitespaces when exiting insert mode
    hook window ModeChange pop:insert:.* -group go-trim-indent %{ try %{ execute-keys -draft xs^\h+$<ret>d } }
    hook window InsertChar \n -group go-indent go-indent-on-new-line
    hook window InsertChar \{ -group go-indent go-indent-on-opening-curly-brace
    hook window InsertChar \} -group go-indent go-indent-on-closing-curly-brace
    hook window InsertChar \n -group go-comment-insert go-insert-comment-on-new-line
    hook window InsertChar \n -group go-closing-delimiter-insert go-insert-closing-delimiter-on-new-line

    alias window alt go-alternative-file

    hook -once -always window WinSetOption filetype=.* %{
        remove-hooks window go-.+
        unalias window alt go-alternative-file
    }
}

hook -group go-highlight global WinSetOption filetype=go %{
    add-highlighter window/go ref go
    hook -once -always window WinSetOption filetype=.* %{ remove-highlighter window/go }
}

provide-module go %§

# Highlighters
# ‾‾‾‾‾‾‾‾‾‾‾‾

add-highlighter shared/go regions
add-highlighter shared/go/code default-region group
add-highlighter shared/go/back_string region '`' '`' fill string
add-highlighter shared/go/double_string region '"' (?<!\\)(\\\\)*" fill string
add-highlighter shared/go/single_string region "'" (?<!\\)(\\\\)*' fill string
add-highlighter shared/go/comment region /\* \*/ fill comment
add-highlighter shared/go/comment_line region '//' $ fill comment

add-highlighter shared/go/code/numeric regex %{-?([0-9]*\.(?!0[xX]))?\b([0-9]+|0[xX][0-9a-fA-F]+)\.?([eE][+-]?[0-9]+)?i?\b} 0:value
add-highlighter shared/go/code/function regex "\b(\w*)\b\h*(?:\[[\w\s\.,]*\])?\h*\(" 1:function
add-highlighter shared/go/code/operator regex "(\+|-|\*|/|%|\+\+|--|\+=|-=|\*=|/=|%=|==|!=|>|<|>=|<=|&|&&|\|\||!|<-|:=|\.\.\.)" 1:operator

evaluate-commands %sh{
    # Grammar
    keywords='break default func interface select case defer go map struct
              chan else goto package switch const fallthrough if range type
              continue for import return var'
    types='any bool byte chan comparable complex128 complex64 error float32 float64 int int16 int32
           int64 int8 interface intptr map rune string struct uint uint16 uint32 uint64 uint8 uintptr'
    values='false true nil iota'
    functions='append cap close complex copy delete imag len make new panic print println real recover'

    join() { sep=$2; eval set -- $1; IFS="$sep"; echo "$*"; }

    # Add the language's grammar to the static completion list
    printf %s\\n "declare-option str-list go_static_words $(join "${keywords} ${attributes} ${types} ${values} ${functions}" ' ')"

    # Highlight keywords
    printf %s "
        add-highlighter shared/go/code/keyword   regex \b($(join "${keywords}" '|'))\b 0:keyword
        add-highlighter shared/go/code/attribute regex \b($(join "${attributes}" '|'))\b 0:attribute
        add-highlighter shared/go/code/type      regex \b($(join "${types}" '|'))\b 0:type
        add-highlighter shared/go/code/value     regex \b($(join "${values}" '|'))\b 0:value
        add-highlighter shared/go/code/builtin   regex \b($(join "${functions}" '|'))\b 0:builtin
    "
}

# Commands
# ‾‾‾‾‾‾‾‾

define-command go-alternative-file -docstring 'Jump to the alternate file (implementation ↔ test)' %{ evaluate-commands %sh{
    case $kak_buffile in
        *_test.go)
            altfile=${kak_buffile%_test.go}.go
            test ! -f "$altfile" && echo "fail 'implementation file not found'" && exit
        ;;
        *.go)
            altfile=${kak_buffile%.go}_test.go
            test ! -f "$altfile" && echo "fail 'test file not found'" && exit
        ;;
        *)
            echo "fail 'alternative file not found'" && exit
        ;;
    esac
    printf "edit -- '%s'" "$(printf %s "$altfile" | sed "s/'/''/g")"
}}

define-command -hidden go-indent-on-new-line %~
    evaluate-commands -draft -itersel %=
        # preserve previous line indent
        try %{ execute-keys -draft <semicolon>K<a-&> }
        # cleanup trailing white spaces on the previous line
        try %{ execute-keys -draft kx s \h+$ <ret>d }
        try %<
            try %{ # line comment
                execute-keys -draft kx s ^\h*// <ret>
            } catch %{ # block comment
                execute-keys -draft <a-?> /\* <ret> <a-K>\*/<ret>
            }
        > catch %<
            # indent after lines with an unclosed { or (
            try %< execute-keys -draft [c[({],[)}] <ret> <a-k> \A[({][^\n]*\n[^\n]*\n?\z <ret> j<a-gt> >
            # indent after a switch's case/default statements
            try %[ execute-keys -draft kx <a-k> ^\h*(case|default).*:$ <ret> j<a-gt> ]
            # deindent closing brace(s) when after cursor
            try %[ execute-keys -draft x <a-k> ^\h*[})] <ret> gh / [})] <ret> m <a-S> 1<a-&> ]
        >
    =
~

define-command -hidden go-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> s \A|.\z <ret> 1<a-&> ]
]

define-command -hidden go-indent-on-closing-curly-brace %[
    # align to opening curly brace when alone on a line
    try %[ execute-keys -itersel -draft <a-h><a-k>^\h+\}$<ret>hms\A|.\z<ret>1<a-&> ]
]

define-command -hidden go-insert-comment-on-new-line %[
    evaluate-commands -no-hooks -draft -itersel %[
        # copy // comments prefix and following white spaces
        try %{ execute-keys -draft <semicolon><c-s>kx s ^\h*\K/{2,}\h* <ret> y<c-o>P<esc> }
    ]
]

define-command -hidden go-insert-closing-delimiter-on-new-line %[
    evaluate-commands -no-hooks -draft -itersel %[
        # Wisely add '}'.
        evaluate-commands -save-regs x %[
            # Save previous line indent in register x.
            try %[ execute-keys -draft kxs^\h+<ret>"xy ] catch %[ reg x '' ]
            try %[
                # Validate previous line and that it is not closed yet.
                execute-keys -draft kx <a-k>^<c-r>x.*\{\h*\(?\h*$<ret> j}iJx <a-K>^<c-r>x\)?\h*\}<ret>
                # Insert closing '}'.
                execute-keys -draft o<c-r>x}<esc>
                # Delete trailing '}' on the line below the '{'.
                execute-keys -draft xs\}$<ret>d
            ]
        ]

        # Wisely add ')'.
        evaluate-commands -save-regs x %[
            # Save previous line indent in register x.
            try %[ execute-keys -draft kxs^\h+<ret>"xy ] catch %[ reg x '' ]
            try %[
                # Validate previous line and that it is not closed yet.
                execute-keys -draft kx <a-k>^<c-r>x.*\(\h*$<ret> J}iJx <a-K>^<c-r>x\)<ret>
                # Insert closing ')'.
                execute-keys -draft o<c-r>x)<esc>
                # Delete trailing ')' on the line below the '('.
                execute-keys -draft xs\)\h*\}?\h*$<ret>d
            ]
        ]
    ]
]

§