|
| 1 | +" Copyright (c) 2025 Augment |
| 2 | +" MIT License - See LICENSE.md for full terms |
| 3 | + |
| 4 | +" Handlers for autocommands and keybinds |
| 5 | + |
| 6 | +" Check whether the server started. Errors to start should be reported in the |
| 7 | +" Augment-log. |
| 8 | +function! s:IsRunning() abort |
| 9 | + let client = augment#client#Client() |
| 10 | + return exists('client.client_id') || exists('client.job') |
| 11 | +endfunction |
| 12 | + |
| 13 | +let s:NOT_RUNNING_MSG = 'The Augment language server is not running. See ":Augment log" for more details.' |
| 14 | + |
| 15 | +" Notify the server that a buffer has been opened |
| 16 | +function! s:OpenBuffer() abort |
| 17 | + if !s:IsRunning() |
| 18 | + return |
| 19 | + endif |
| 20 | + |
| 21 | + let client = augment#client#Client() |
| 22 | + if has('nvim') |
| 23 | + call luaeval('require("augment").open_buffer(_A[1], _A[2])', [client.client_id, bufnr('%')]) |
| 24 | + else |
| 25 | + let uri = 'file://' . expand('%:p') |
| 26 | + let text = join(getline(1, '$'), "\n") |
| 27 | + call client.Notify('textDocument/didOpen', { |
| 28 | + \ 'textDocument': { |
| 29 | + \ 'uri': uri, |
| 30 | + \ 'languageId': &filetype, |
| 31 | + \ 'version': b:changedtick, |
| 32 | + \ 'text': text, |
| 33 | + \ }, |
| 34 | + \ }) |
| 35 | + endif |
| 36 | +endfunction |
| 37 | + |
| 38 | +" Notify the server that a buffer has been updated |
| 39 | +function! s:UpdateBuffer() abort |
| 40 | + if !s:IsRunning() |
| 41 | + return |
| 42 | + endif |
| 43 | + |
| 44 | + " The nvim lsp client does this automatically |
| 45 | + if !has('nvim') |
| 46 | + " Only send a change notification if the buffer has changed (as |
| 47 | + " tracked by b:changedtick) |
| 48 | + if exists('b:_augment_buf_tick') && b:_augment_buf_tick == b:changedtick |
| 49 | + return |
| 50 | + endif |
| 51 | + let b:_augment_buf_tick = b:changedtick |
| 52 | + |
| 53 | + let uri = 'file://' . expand('%:p') |
| 54 | + let text = join(getline(1, '$'), "\n") |
| 55 | + call augment#client#Client().Notify('textDocument/didChange', { |
| 56 | + \ 'textDocument': { |
| 57 | + \ 'uri': uri, |
| 58 | + \ 'version': b:changedtick, |
| 59 | + \ }, |
| 60 | + \ 'contentChanges': [{'text': text}], |
| 61 | + \ }) |
| 62 | + endif |
| 63 | +endfunction |
| 64 | + |
| 65 | +" Request a completion from the server |
| 66 | +function! s:RequestCompletion() abort |
| 67 | + if !s:IsRunning() |
| 68 | + return |
| 69 | + endif |
| 70 | + |
| 71 | + " Don't send a request if disabled |
| 72 | + if exists('g:augment_enabled') && !g:augment_enabled |
| 73 | + return |
| 74 | + endif |
| 75 | + |
| 76 | + " If there was a previous completion request with the same buffer version |
| 77 | + " (tracked by b:changedtick), don't send another |
| 78 | + if exists('b:_augment_comp_tick') && b:_augment_comp_tick == b:changedtick |
| 79 | + return |
| 80 | + endif |
| 81 | + let b:_augment_comp_tick = b:changedtick |
| 82 | + |
| 83 | + let uri = 'file://' . expand('%:p') |
| 84 | + let text = join(getline(1, '$'), "\n") |
| 85 | + " TODO: remove version-- we use it elsewhere but it's not in the spec |
| 86 | + call augment#client#Client().Request('textDocument/completion', { |
| 87 | + \ 'textDocument': { |
| 88 | + \ 'uri': uri, |
| 89 | + \ 'version': b:changedtick, |
| 90 | + \ }, |
| 91 | + \ 'position': { |
| 92 | + \ 'line': line('.') - 1, |
| 93 | + \ 'character': col('.') - 1, |
| 94 | + \ }, |
| 95 | + \ }) |
| 96 | +endfunction |
| 97 | + |
| 98 | +" Show the log |
| 99 | +function! s:CommandLog() abort |
| 100 | + call augment#log#Show() |
| 101 | +endfunction |
| 102 | + |
| 103 | +" Send sign-in request to the language server |
| 104 | +function! s:CommandSignIn() abort |
| 105 | + if !s:IsRunning() |
| 106 | + echohl WarningMsg |
| 107 | + echo s:NOT_RUNNING_MSG |
| 108 | + echohl None |
| 109 | + return |
| 110 | + endif |
| 111 | + |
| 112 | + call augment#client#Client().Request('augment/login', {}) |
| 113 | +endfunction |
| 114 | + |
| 115 | +" Send sign-out request to the language server |
| 116 | +function! s:CommandSignOut() abort |
| 117 | + if !s:IsRunning() |
| 118 | + echohl WarningMsg |
| 119 | + echo s:NOT_RUNNING_MSG |
| 120 | + echohl None |
| 121 | + return |
| 122 | + endif |
| 123 | + |
| 124 | + call augment#client#Client().Request('augment/logout', {}) |
| 125 | +endfunction |
| 126 | + |
| 127 | +function! s:CommandEnable() abort |
| 128 | + let g:augment_enabled = v:true |
| 129 | +endfunction |
| 130 | + |
| 131 | +function! s:CommandDisable() abort |
| 132 | + let g:augment_enabled = v:false |
| 133 | +endfunction |
| 134 | + |
| 135 | +function! s:CommandStatus() abort |
| 136 | + if !s:IsRunning() |
| 137 | + echohl WarningMsg |
| 138 | + echo s:NOT_RUNNING_MSG |
| 139 | + echohl None |
| 140 | + return |
| 141 | + endif |
| 142 | + |
| 143 | + call augment#client#Client().Request('augment/status', {}) |
| 144 | +endfunction |
| 145 | + |
| 146 | +" Handle user commands |
| 147 | +let s:command_handlers = { |
| 148 | + \ 'log': function('s:CommandLog'), |
| 149 | + \ 'signin': function('s:CommandSignIn'), |
| 150 | + \ 'signout': function('s:CommandSignOut'), |
| 151 | + \ 'enable': function('s:CommandEnable'), |
| 152 | + \ 'disable': function('s:CommandDisable'), |
| 153 | + \ 'status': function('s:CommandStatus'), |
| 154 | + \ } |
| 155 | + |
| 156 | +function! augment#Command(command) abort |
| 157 | + if empty(a:command) |
| 158 | + call s:command_handlers['status']() |
| 159 | + return |
| 160 | + endif |
| 161 | + |
| 162 | + for [name, Handler] in items(s:command_handlers) |
| 163 | + " Note that ==? is case-insensitive comparison |
| 164 | + if a:command ==? name |
| 165 | + call Handler() |
| 166 | + return |
| 167 | + endif |
| 168 | + endfor |
| 169 | + |
| 170 | + echohl WarningMsg |
| 171 | + echo 'Augment: Unknown command: "' . a:command . '"' |
| 172 | + echohl None |
| 173 | +endfunction |
| 174 | + |
| 175 | +function! augment#CommandComplete(ArgLead, CmdLine, CursorPos) abort |
| 176 | + return keys(s:command_handlers)->join("\n") |
| 177 | +endfunction |
| 178 | + |
| 179 | +" Autocommand handlers |
| 180 | +function! augment#OnVimEnter() abort |
| 181 | + call augment#client#Client() |
| 182 | +endfunction |
| 183 | + |
| 184 | +function! augment#OnBufEnter() abort |
| 185 | + call s:OpenBuffer() |
| 186 | +endfunction |
| 187 | + |
| 188 | +function! augment#OnTextChanged() abort |
| 189 | + call s:UpdateBuffer() |
| 190 | +endfunction |
| 191 | + |
| 192 | +function! augment#OnTextChangedI() abort |
| 193 | + " Since CursorMovedI is always called before TextChangedI, the suggestion will already be cleared |
| 194 | + call s:UpdateBuffer() |
| 195 | + call s:RequestCompletion() |
| 196 | +endfunction |
| 197 | + |
| 198 | +function! augment#OnCursorMovedI() abort |
| 199 | + call augment#suggestion#Clear() |
| 200 | +endfunction |
| 201 | + |
| 202 | +function! augment#OnInsertEnter() abort |
| 203 | + call s:UpdateBuffer() |
| 204 | + call s:RequestCompletion() |
| 205 | +endfunction |
| 206 | + |
| 207 | +function! augment#OnInsertLeavePre() abort |
| 208 | + call augment#suggestion#Clear() |
| 209 | +endfunction |
| 210 | + |
| 211 | +" Accept the currently active suggestion if one is available, otherwise insert |
| 212 | +" the fallback text provided as the first argument |
| 213 | +function! augment#Accept(...) abort |
| 214 | + " If no fallback was provided, don't add any text |
| 215 | + let fallback = a:0 >= 1 ? a:1 : '' |
| 216 | + |
| 217 | + if !augment#suggestion#Accept() |
| 218 | + call feedkeys(fallback, 'nt') |
| 219 | + endif |
| 220 | +endfunction |
0 commit comments