Skip to content

Commit af0ddc4

Browse files
LLM REPL with shell_gpt (#37)
* Added first draft working sgpt * Updated documentation * Update README.rst * Added cycling commands * Big improvements to logging * Removed uid comment
1 parent a3efa16 commit af0ddc4

File tree

4 files changed

+232
-115
lines changed

4 files changed

+232
-115
lines changed

README.rst

+74-68
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,44 @@ Vimteractive
33
============
44
:vimteractive: send commands from text files to interactive programs via vim
55
:Author: Will Handley
6-
:Version: 2.5.0
6+
:Version: 2.6.0
77
:Homepage: https://github.com/williamjameshandley/vimteractive
88
:Documentation: ``:help vimteractive``
99

1010
Vimteractive was inspired by the workflow of the
1111
`vim-ipython <https://github.com/ivanov/vim-ipython>`__ plugin.
1212

1313
This plugin is designed to extend a subset of the functionality of vim-ipython
14-
to other interpreters (including ipython). It is based around the unix
14+
to other `REPLs <https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop>`__ (including ipython). It is based around the unix
1515
philosophy of `"do one thing and do it well" <https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well>`__.
1616
Vimteractive aims to provide a robust and simple link between text files and
17-
interactive interpreters. Vimteractive will never aim to do things like
17+
language shells. Vimteractive will never aim to do things like
1818
autocompletion, leaving that to other, more developed tools such as
1919
`YouCompleteMe <https://github.com/Valloric/YouCompleteMe>`__ or
20-
`TabNine <https://tabnine.com>`__.
21-
22-
The activating commands are
23-
24-
- ipython ``:Iipython``
25-
- julia ``:Ijulia``
26-
- maple ``:Imaple``
27-
- mathematica ``:Imathematica``
28-
- bash ``:Ibash``
29-
- zsh ``:Izsh``
30-
- python ``:Ipython``
31-
- clojure ``:Iclojure``
32-
- apl ``:Iapl``
20+
`Copilot <https://github.com/features/copilot>`__.
21+
22+
The activating commands are:
23+
24+
- `ipython <https://ipython.readthedocs.io>`__ ``:Iipython``
25+
- `julia <https://julialang.org/>`__ ``:Ijulia``
26+
- `maple <https://maplesoft.com/>`__ ``:Imaple``
27+
- `mathematica <https://www.wolfram.com/mathematica/>`__ ``:Imathematica``
28+
- `bash <https://en.wikipedia.org/wiki/Bash_(Unix_shell)>`__ ``:Ibash``
29+
- `zsh <https://www.zsh.org/>`__ ``:Izsh``
30+
- `python <https://www.python.org/>`__ ``:Ipython``
31+
- `clojure <https://clojure.org/>`__ ``:Iclojure``
32+
- `apl <https://en.wikipedia.org/wiki/APL_(programming_language)>`__ ``:Iapl``
33+
- `R <https://www.r-project.org/>`__ ``:IR``
34+
- `sgpt <https://github.com/TheR1D/shell_gpt>`__ ``:Isgpt``
3335
- autodetect based on filetype ``:Iterm``
3436

35-
Commands may be sent from a text file to the chosen terminal using ``CTRL-S``.
36-
If there is no terminal, ``CTRL-S`` will automatically open one for you using
37+
Commands may be sent from a text file to the chosen REPL using ``CTRL-S``.
38+
If there is no REPL, ``CTRL-S`` will automatically open one for you using
3739
``:Iterm``.
3840

41+
For some terminals, the output of the last command may be retrieved with
42+
``CTRL-Y``.
43+
3944
Note: it's highly recommended to use IPython as your default Python
4045
interpreter. You can set it like this:
4146

@@ -49,16 +54,6 @@ Installation
4954
Since this package leverages the native vim interactive terminal, vimteractive
5055
is only compatible with vim 8 or greater.
5156

52-
To use the key-bindings, you should first disable the ``CTRL-S``
53-
default, which is a terminal command to freeze the output. You can
54-
disable this by putting
55-
56-
.. code:: bash
57-
58-
stty -ixon
59-
60-
into your ``.bashrc`` (or equivalent shell profile file).
61-
6257
Installation should be relatively painless via
6358
`the usual routes <https://vimawesome.com/plugin/vimteractive>`_ such as
6459
`Vundle <https://github.com/VundleVim/Vundle.vim>`__,
@@ -95,6 +90,17 @@ interface to the command line `maple <https://www.maplesoft.com/>`__.
9590
Usage
9691
-----
9792

93+
To use the key-bindings, you should first disable the ``CTRL-S``
94+
default, which is a terminal command to freeze the output. You can
95+
disable this by putting
96+
97+
.. code:: bash
98+
99+
stty -ixon
100+
101+
into your ``.bashrc`` (or equivalent shell profile file).
102+
103+
98104
Example usage:
99105
~~~~~~~~~~~~~~
100106

@@ -126,51 +132,68 @@ pressing ``CTRL-S``.
126132
If you switch windows with ``CTRL-W+k``, you will see the terminal buffer
127133
switch to a more usual looking normal-mode buffer, from which you can perform
128134
traditional normal mode commands. However, if you try to insert, you will enter
129-
the terminal, and be able to enter commands interactively into the prompt as if
135+
the REPL, and be able to enter commands interactively into the prompt as if
130136
you had run it in the command line. You can save this buffer if you wish to a
131137
new file if it contains valuable output
132138

133-
You may want to send lines to one terminal from two buffers. To achieve that,
139+
You may want to send lines to one REPL from two buffers. To achieve that,
134140
run ``:Iconn <buffer_name>`` where ``<buffer_name>`` is a name of buffer
135-
containing terminal. If there is only one terminal, you can use just
141+
containing REPL. If there is only one REPL, you can use just
136142
``:Iconn``.
137143

138-
Supported terminals
139-
~~~~~~~~~~~~~~~~~~~
144+
Supported REPLs
145+
~~~~~~~~~~~~~~~
140146

141-
- ``:Iipython`` Activate an ipython terminal
142-
- ``:Ijulia`` Activate a julia terminal
143-
- ``:Imaple`` Activate a maple terminal
144-
- ``:Imathematica`` Activate a mathematica terminal
145-
- ``:Ibash`` Activate a bash terminal
146-
- ``:Izsh`` Activate a zsh terminal
147-
- ``:Ipython`` Activate a python terminal
148-
- ``:Iclojure`` Activate a clojure terminal
149-
- ``:Iapl`` Activate an apl terminal
150-
- ``:Iterm`` Activate default terminal for this filetype
147+
- ``:Iipython`` Activate an ipython REPL
148+
- ``:Ijulia`` Activate a julia REPL
149+
- ``:Imaple`` Activate a maple REPL
150+
- ``:Imathematica`` Activate a mathematica REPL
151+
- ``:Ibash`` Activate a bash REPL
152+
- ``:Izsh`` Activate a zsh REPL
153+
- ``:Ipython`` Activate a python REPL
154+
- ``:Iclojure`` Activate a clojure REPL
155+
- ``:Iapl`` Activate an apl REPL
156+
- ``:IR`` Activate an R REPL
157+
- ``:Isgpt`` Activate an sgpt REPL
158+
- ``:Iterm`` Activate default REPL for this filetype
151159

152160
Sending commands
153161
~~~~~~~~~~~~~~~~
154162

155163
``CTRL-S`` sends lines of text to the interpreter in a mode-dependent manner:
156164

157-
In Normal mode, ``CTRL-S`` sends the line currently occupied by the cursor the
158-
terminal.
165+
In Normal mode, ``CTRL-S`` sends the line currently occupied by the cursor to the
166+
REPL.
159167

160168
In Insert mode, ``CTRL-S`` sends the line currently being edited, and then
161169
returns to insert mode at the same location.
162170

163-
In Visual mode, ``CTRL-S`` sends the current selection to the terminal.
171+
In Visual mode, ``CTRL-S`` sends the current selection to the REPL.
164172

165173
``ALT-S`` sends all lines from the start to the current line.
166174

167-
Connecting to an existing terminal
168-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
175+
Retrieving command outputs
176+
~~~~~~~~~~~~~~~~~~~~~~~~~~
177+
178+
CTRL-Y retrieves the output of the last command sent to the REPL. This only
179+
implemented in a subset of terminas (``:Iipython`` and ``:Isgpt``)
180+
181+
In ``Normal-mode``, CTRL-Y retrieves the output of the last command sent to the
182+
REPL and places it in the current buffer.
183+
184+
In ``Insert-mode``, CTRL-Y retrieves the output of the last command sent to the
185+
REPL and places it in the current buffer, and then returns to insert mode
186+
after the output.
187+
188+
Connecting to an existing REPL
189+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169190

170191
``:Iconn [{buffer]`` connects current buffer to REPL in ``{buffer}``. You can
171192
connect any number of buffers to one REPL. ``{buffer}`` can be omitted if there
172-
is only one terminal.
193+
is only one REPL.
173194

195+
``]v`` and ``[v`` can be used to cycle between connected buffers in the style of
196+
`unimpaired <https://github.com/tpope/vim-unimpaired>`__.
174197

175198
Common issues
176199
-------------
@@ -194,8 +217,8 @@ These options can be put in your ``.vimrc``, or run manually as desired:
194217

195218
.. code:: vim
196219
197-
let g:vimteractive_vertical = 1 " Vertically split terminals
198-
let g:vimteractive_autostart = 0 " Don't start terminals by default
220+
let g:vimteractive_vertical = 1 " Vertically split REPLs
221+
let g:vimteractive_autostart = 0 " Don't start REPLs by default
199222
200223
Extending functionality
201224
-----------------------
@@ -252,20 +275,3 @@ Similar projects
252275
- `vipy <https://github.com/johndgiese/vipy>`__
253276

254277
.. |example_usage| image:: https://raw.githubusercontent.com/williamjameshandley/vimteractive/master/images/example_usage.gif
255-
256-
Changelist
257-
----------
258-
:v2.2: `Vertical splitting option <https://github.com/williamjameshandley/vimteractive/pull/21>`__
259-
:v2.1: `Visual selection improvement <https://github.com/williamjameshandley/vimteractive/pull/15>`__
260-
:v2.0: `Multiple terminal functionality <https://github.com/williamjameshandley/vimteractive/pull/9>`__
261-
:v1.7: `Autodetection of terminals <https://github.com/williamjameshandley/vimteractive/pull/5>`__
262-
:v1.6: CtrlP `bugfix <https://github.com/williamjameshandley/vimteractive/pull/4>`__
263-
:v1.5: Added julia support
264-
:v1.4: `Buffer rename <https://github.com/williamjameshandley/vimteractive/pull/3>`_
265-
:v1.3: Added zsh support
266-
:v1.2:
267-
- no line numbers in terminal window
268-
:v1.1:
269-
- `Bracketed paste <https://cirw.in/blog/bracketed-paste>`__ seems
270-
to fix most of ipython issues.
271-
- ``ALT-S`` sends all lines from start to current line.

autoload/vimteractive.vim

+80-4
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,26 @@
44
" s:vimteractive_buffers
55
" script-local variable that keeps track of vimteractive terminal buffers
66
"
7+
" s:vimteractive_logfiles
8+
" script-local variable that keeps track of logfiles for each terminal
9+
"
710
" b:vimteractive_connected_term
811
" buffer-local variable held by buffer that indicates the name of the
912
" connected terminal buffer
1013
"
1114
" b:vimteractive_term_type
1215
" buffer-local variable held by terminal buffer that indicates the terminal type
1316

14-
1517
" Initialise the list of terminal buffer numbers on startup
1618
if !exists('s:vimteractive_buffers')
1719
let s:vimteractive_buffers = []
1820
end
1921

22+
" Initialise the list of logfiles on startup
23+
if !exists('s:vimteractive_logfiles')
24+
let s:vimteractive_logfiles = {}
25+
end
26+
2027
" Remove a terminal from the list on deletion.
2128
function! s:del_term()
2229
let l:term_bufname = expand('<afile>')
@@ -103,9 +110,8 @@ function! vimteractive#sendlines(lines)
103110
endif
104111
endfunction
105112

106-
107113
" Start a vimteractive terminal
108-
function! vimteractive#term_start(term_type)
114+
function! vimteractive#term_start(term_type, ...)
109115
if has('terminal') == 0
110116
echoerr "Your version of vim is not compiled with +terminal. Cannot use vimteractive"
111117
return
@@ -118,6 +124,9 @@ function! vimteractive#term_start(term_type)
118124
let l:term_type = a:term_type
119125
endif
120126

127+
" Name the buffer
128+
let l:term_bufname = s:new_name(l:term_type)
129+
121130
" Retrieve starting command
122131
if has_key(g:vimteractive_commands, l:term_type)
123132
let l:term_command = get(g:vimteractive_commands, l:term_type)
@@ -126,9 +135,18 @@ function! vimteractive#term_start(term_type)
126135
return
127136
endif
128137

138+
" Assign a logfile name
139+
let l:logfile = tempname() . '-' . l:term_type . '.log'
140+
let l:term_command = substitute(l:term_command, '<LOGFILE>', l:logfile, '')
141+
142+
" Pass any environment variables necessary for logging
143+
let $CHAT_CACHE_PATH="/" " sgpt logfiles
144+
145+
" Add all other arguments to the command
146+
let l:term_command = l:term_command . ' ' . join(a:000, ' ')
147+
129148
" Create a new term
130149
echom "Starting " . l:term_command
131-
let l:term_bufname = s:new_name(l:term_type)
132150
if v:version < 801
133151
call term_start(l:term_command, {
134152
\ "term_name": l:term_bufname,
@@ -147,6 +165,7 @@ function! vimteractive#term_start(term_type)
147165
" Add this terminal to the buffer list, and store type
148166
call add(s:vimteractive_buffers, bufnr(l:term_bufname))
149167
let b:vimteractive_term_type = l:term_type
168+
let s:vimteractive_logfiles[bufnr(l:term_bufname)] = l:logfile
150169

151170
" Turn line numbering off
152171
set nonumber norelativenumber
@@ -213,3 +232,60 @@ function! vimteractive#connect(...)
213232
echom "Connected " . bufname("%") . " to " . l:bufname
214233

215234
endfunction
235+
236+
function! vimteractive#get_response()
237+
let l:term_type = getbufvar(b:vimteractive_connected_term, "vimteractive_term_type")
238+
return g:vimteractive_get_response[l:term_type]()
239+
endfunction
240+
241+
" Get the last response from the terminal for sgpt
242+
function! vimteractive#get_response_sgpt()
243+
let l:logfile = s:vimteractive_logfiles[b:vimteractive_connected_term]
244+
let l:json_content = join(readfile(l:logfile), "\n")
245+
let l:json_data = json_decode(l:json_content)
246+
if len(l:json_data) > 0
247+
let l:last_response = l:json_data[-1]['content']
248+
return l:last_response
249+
endif
250+
endfunction
251+
252+
" Get the last response from the terminal for ipython
253+
function! vimteractive#get_response_ipython()
254+
let l:logfile = s:vimteractive_logfiles[b:vimteractive_connected_term]
255+
let lines = readfile(l:logfile)
256+
let block = []
257+
for i in range(len(lines) - 1, 0, -1)
258+
if match(lines[i], '^#\[Out\]#') == 0
259+
let line = substitute(lines[i], '^#\[Out\]# ', '', '')
260+
call add(block, line)
261+
else
262+
break
263+
endif
264+
endfor
265+
let block = reverse(block)
266+
return join(block, "\n")
267+
endfunction
268+
269+
" Cycle connection forward through terminal buffers
270+
function! vimteractive#next_term()
271+
let l:current_buffer = b:vimteractive_connected_term
272+
let l:current_index = index(s:vimteractive_buffers, l:current_buffer)
273+
if l:current_index == -1
274+
echom "Not in a terminal buffer"
275+
return
276+
endif
277+
let l:next_index = (l:current_index + 1) % len(s:vimteractive_buffers)
278+
call vimteractive#connect(vimteractive#buffer_list()[l:next_index])
279+
endfunction
280+
281+
" Cycle connection backward through terminal buffers
282+
function! vimteractive#prev_term()
283+
let l:current_buffer = b:vimteractive_connected_term
284+
let l:current_index = index(s:vimteractive_buffers, l:current_buffer)
285+
if l:current_index == -1
286+
echom "Not in a terminal buffer"
287+
return
288+
endif
289+
let l:prev_index = (l:current_index - 1 + len(s:vimteractive_buffers)) % len(s:vimteractive_buffers)
290+
call vimteractive#connect(vimteractive#buffer_list()[l:prev_index])
291+
endfunction

0 commit comments

Comments
 (0)