Skip to content

Commit ecd7a96

Browse files
Augment Vim v0.3.0
1 parent 76b0339 commit ecd7a96

File tree

10 files changed

+483
-71
lines changed

10 files changed

+483
-71
lines changed

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,47 @@ The following commands are provided:
6464
:Augment enable " Globally enable suggestions (on by default)
6565
:Augment disable " Globally disable suggestions
6666
:Augment log " View the plugin log
67+
:Augment chat " Start a chat with Augment AI
6768
```
6869
70+
## Chat
71+
72+
The chat command allows you to interact with Augment AI in a conversational
73+
manner. You can use it in two ways:
74+
75+
1. Direct command with message:
76+
77+
```vim
78+
:Augment chat How do I implement binary search?
79+
```
80+
81+
2. With selected text:
82+
83+
- Select text in visual mode
84+
85+
- Type `:Augment chat` followed by your question about the selection
86+
87+
The response will appear in a new buffer with markdown formatting. Note that
88+
chat is currently limited to single-turn conversations - each chat command
89+
starts a new conversation.
90+
91+
## Workspace Folders
92+
93+
Workspace folders help Augment understand your codebase better by providing
94+
additional context. You can configure workspace folders by setting
95+
`g:augment_workspace_folders` in your vimrc:
96+
97+
```vim
98+
let g:augment_workspace_folders = ['/path/to/project', '~/another-project']
99+
```
100+
101+
Workspace folders can be specified using absolute paths or paths relative to
102+
your home directory (~). Adding your project's root directory as a workspace
103+
folder helps Augment generate completions that match your codebase's patterns
104+
and conventions.
105+
106+
Note: This option must be set before the plugin is loaded.
107+
69108
## Alternate Keybinds
70109
71110
By default, tab is used to accept a suggestion. If you want to use a
@@ -85,6 +124,11 @@ inoremap <cr> <cmd>call augment#Accept("\n")<cr>
85124
The default tab mapping can be disabled by setting
86125
`g:augment_disable_tab_mapping = v:true` before the plugin is loaded.
87126
127+
If another plugin uses tab in insert mode, the Augment tab mapping may be
128+
overridden depending on the order in which the plugins are loaded. If tab isn't
129+
working for you, the `imap <tab>` command can be used to check if the mapping is
130+
present.
131+
88132
## Licensing and Distribution
89133
90134
This repository includes two main components:

autoload/augment.vim

Lines changed: 91 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ endfunction
1212

1313
let s:NOT_RUNNING_MSG = 'The Augment language server is not running. See ":Augment log" for more details.'
1414

15+
" Get the text of the current buffer, accounting for the newline at the end
16+
function! s:GetBufText() abort
17+
return join(getline(1, '$'), "\n") . "\n"
18+
endfunction
19+
1520
" Notify the server that a buffer has been opened
1621
function! s:OpenBuffer() abort
1722
if !s:IsRunning()
@@ -23,7 +28,7 @@ function! s:OpenBuffer() abort
2328
call luaeval('require("augment").open_buffer(_A[1], _A[2])', [client.client_id, bufnr('%')])
2429
else
2530
let uri = 'file://' . expand('%:p')
26-
let text = join(getline(1, '$'), "\n")
31+
let text = s:GetBufText()
2732
call client.Notify('textDocument/didOpen', {
2833
\ 'textDocument': {
2934
\ 'uri': uri,
@@ -51,7 +56,7 @@ function! s:UpdateBuffer() abort
5156
let b:_augment_buf_tick = b:changedtick
5257

5358
let uri = 'file://' . expand('%:p')
54-
let text = join(getline(1, '$'), "\n")
59+
let text = s:GetBufText()
5560
call augment#client#Client().Notify('textDocument/didChange', {
5661
\ 'textDocument': {
5762
\ 'uri': uri,
@@ -96,12 +101,12 @@ function! s:RequestCompletion() abort
96101
endfunction
97102

98103
" Show the log
99-
function! s:CommandLog() abort
104+
function! s:CommandLog(...) abort
100105
call augment#log#Show()
101106
endfunction
102107

103108
" Send sign-in request to the language server
104-
function! s:CommandSignIn() abort
109+
function! s:CommandSignIn(...) abort
105110
if !s:IsRunning()
106111
echohl WarningMsg
107112
echo s:NOT_RUNNING_MSG
@@ -113,7 +118,7 @@ function! s:CommandSignIn() abort
113118
endfunction
114119

115120
" Send sign-out request to the language server
116-
function! s:CommandSignOut() abort
121+
function! s:CommandSignOut(...) abort
117122
if !s:IsRunning()
118123
echohl WarningMsg
119124
echo s:NOT_RUNNING_MSG
@@ -124,15 +129,15 @@ function! s:CommandSignOut() abort
124129
call augment#client#Client().Request('augment/logout', {})
125130
endfunction
126131

127-
function! s:CommandEnable() abort
132+
function! s:CommandEnable(...) abort
128133
let g:augment_enabled = v:true
129134
endfunction
130135

131-
function! s:CommandDisable() abort
136+
function! s:CommandDisable(...) abort
132137
let g:augment_enabled = v:false
133138
endfunction
134139

135-
function! s:CommandStatus() abort
140+
function! s:CommandStatus(...) abort
136141
if !s:IsRunning()
137142
echohl WarningMsg
138143
echo s:NOT_RUNNING_MSG
@@ -143,6 +148,73 @@ function! s:CommandStatus() abort
143148
call augment#client#Client().Request('augment/status', {})
144149
endfunction
145150

151+
function! s:CommandChat(range, args) abort
152+
if exists('g:augment_enabled') && !g:augment_enabled
153+
echohl WarningMsg
154+
echo 'Augment: Not enabled. Run ":Augment enable" to enable the plugin.'
155+
echohl None
156+
return
157+
endif
158+
159+
if !s:IsRunning()
160+
echohl WarningMsg
161+
echo s:NOT_RUNNING_MSG
162+
echohl None
163+
return
164+
endif
165+
166+
" If range arguments were provided (when using :Augment chat) or in visual
167+
" mode, get the selected text
168+
if a:range == 2 || mode() ==# 'v' || mode() ==# 'V'
169+
let selected_text = augment#chat#GetSelectedText()
170+
else
171+
let selected_text = ''
172+
endif
173+
174+
" Use the message from the additional command arguments if provided, or
175+
" prompt the user for a message
176+
let message = empty(a:args) ? input('Message: ') : a:args
177+
178+
" Handle cancellation or empty input
179+
if message ==# '' || message =~# '^\s*$'
180+
redraw
181+
echo 'Chat cancelled'
182+
return
183+
endif
184+
185+
" Create new buffer for chat response
186+
let chat_bufname = 'AugmentChat-' . strftime("%Y%m%d-%H%M%S")
187+
let current_win = bufwinid(bufnr('%'))
188+
call augment#chat#CreateBuffer(chat_bufname)
189+
call win_gotoid(current_win)
190+
191+
call augment#log#Info(
192+
\ 'Making chat request in buffer ' . chat_bufname
193+
\ . ' with selected_text="' . selected_text
194+
\ . '"' . ' message="' . message . '"')
195+
196+
let params = {
197+
\ 'textDocumentPosition': {
198+
\ 'textDocument': {
199+
\ 'uri': 'file://' . expand('%:p'),
200+
\ },
201+
\ 'position': {
202+
\ 'line': line('.') - 1,
203+
\ 'character': col('.') - 1,
204+
\ },
205+
\ },
206+
\ 'message': message,
207+
\ 'partialResultToken': chat_bufname,
208+
\ }
209+
210+
" Add selected text if available
211+
if !empty(selected_text)
212+
let params['selectedText'] = selected_text
213+
endif
214+
215+
call augment#client#Client().Request('augment/chat', params)
216+
endfunction
217+
146218
" Handle user commands
147219
let s:command_handlers = {
148220
\ 'log': function('s:CommandLog'),
@@ -151,24 +223,30 @@ let s:command_handlers = {
151223
\ 'enable': function('s:CommandEnable'),
152224
\ 'disable': function('s:CommandDisable'),
153225
\ 'status': function('s:CommandStatus'),
226+
\ 'chat': function('s:CommandChat'),
154227
\ }
155228

156-
function! augment#Command(command) abort
157-
if empty(a:command)
229+
function! augment#Command(range, args) abort range
230+
if empty(a:args)
158231
call s:command_handlers['status']()
159232
return
160233
endif
161234

235+
let command = split(a:args)[0]
162236
for [name, Handler] in items(s:command_handlers)
163237
" Note that ==? is case-insensitive comparison
164-
if a:command ==? name
165-
call Handler()
238+
if command ==? name
239+
" Call the command handler with the count of range arguments as
240+
" the first parameter, followed by the rest of the arguments to
241+
" the command as a single string
242+
let command_args = substitute(a:args, '^\S*\s*', '', '')
243+
call Handler(a:range, command_args)
166244
return
167245
endif
168246
endfor
169247

170248
echohl WarningMsg
171-
echo 'Augment: Unknown command: "' . a:command . '"'
249+
echo 'Augment: Unknown command: "' . command . '"'
172250
echohl None
173251
endfunction
174252

autoload/augment/chat.vim

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
" Copyright (c) 2025 Augment
2+
" MIT License - See LICENSE.md for full terms
3+
4+
" Utilities for chat
5+
6+
function! s:GetBufSelection(line_start, col_start, line_end, col_end) abort
7+
if a:line_start == a:line_end
8+
return getline(a:line_start)[a:col_start - 1:a:col_end - 1]
9+
endif
10+
11+
let lines = []
12+
call add(lines, getline(a:line_start)[a:col_start - 1:])
13+
call extend(lines, getline(a:line_start + 1, a:line_end - 1))
14+
call add(lines, getline(a:line_end)[0:a:col_end - 1])
15+
return join(lines, "\n")
16+
endfunction
17+
18+
function! augment#chat#GetSelectedText() abort
19+
" If in visual mode use the current selection
20+
if mode() ==# 'v' || mode() ==# 'V'
21+
let [line_one, col_one] = getpos('.')[1:2]
22+
let [line_two, col_two] = getpos('v')[1:2]
23+
24+
" . may be before or after v, so need to do some sorting
25+
if line_one < line_two
26+
let line_start = line_one
27+
let col_start = col_one
28+
let line_end = line_two
29+
let col_end = col_two
30+
elseif line_one > line_two
31+
let line_start = line_two
32+
let col_start = col_two
33+
let line_end = line_one
34+
let col_end = col_one
35+
else
36+
" If the lines are the same, the columns may be different
37+
let line_start = line_one
38+
let line_end = line_two
39+
if col_one <= col_two
40+
let col_start = col_one
41+
let col_end = col_two
42+
else
43+
let col_start = col_two
44+
let col_end = col_one
45+
endif
46+
endif
47+
48+
" . and v return column positions one lower than '< and '>
49+
let col_start += 1
50+
let col_end += 1
51+
52+
" In visual line mode, the columns will be incorrect
53+
if mode() ==# 'V'
54+
let col_start = 1
55+
let col_end = v:maxcol
56+
endif
57+
58+
return s:GetBufSelection(line_start, col_start, line_end, col_end)
59+
endif
60+
61+
" Otherwise, assume '< and '> are populated with the correct selection
62+
let [line_start, col_start] = getpos("'<")[1:2]
63+
let [line_end, col_end] = getpos("'>")[1:2]
64+
return s:GetBufSelection(line_start, col_start, line_end, col_end)
65+
endfunction
66+
67+
function! augment#chat#CreateBuffer(bufname) abort
68+
botright vnew
69+
setlocal buftype=nofile
70+
setlocal bufhidden=hide
71+
setlocal noswapfile
72+
setlocal wrap
73+
setlocal linebreak
74+
execute 'file ' . a:bufname
75+
setlocal readonly
76+
setlocal filetype=markdown
77+
endfunction

0 commit comments

Comments
 (0)