-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add REPL buffer to kakoune #8
Comments
To be honest, I have mixed feelings which I've never quite sorted out about adding a REPL buffer: Basically, as common as it is for nice lisp editors to have REPL buffers, the REPL buffer is basically a terminal, and we should already have a terminal. Granted, this doesn't work as smoothly as I'd like. I'm curious to see what you currently have though. |
Unfortunately after some days using it, I'm noticing some serious deficiencies in my implementation. I'm currently creating a scratch buffer and writing the output of My initial approach was using a fifo buffer, but I gave up on that after I realized that apparently I don't completely know what I'm doing with fifos. This is what I've got though: declare-option -hidden str rep_buffer false
declare-option -hidden str rep_selection
hook global WinSetOption ^filetype=rep$ %{
add-highlighter window/clojure ref clojure
set-option buffer readonly true
}
define-command -override -hidden rep-find-namespace %{
evaluate-commands -draft %{
set-option buffer rep_namespace ''
# Probably will get messed up if the file starts with comments
# containing parens.
execute-keys 'gkm'
evaluate-commands %sh{
ns=$(rep --port="@.nrepl-port@${kak_buffile-.}" -- "(second '$kak_selection)" 2>/dev/null)
if [ $? -ne 0 ]; then
printf 'fail "could not parse namespace"\n'
else
printf 'set-option buffer rep_namespace %s\n' "$ns"
rep --port="@.nrepl-port@${kak_buffile-.}" -- "(require '$kak_selection)" 1>/dev/null 2>/dev/null
fi
}
}
}
define-command -hidden create-rep-buffer %{
evaluate-commands %sh{
if [ "$kak_opt_rep_buffer" = true ]; then
printf '%s\n' "
evaluate-commands -try-client '$kak_opt_toolsclient' %{
buffer *rep*
}
"
else
printf '%s\n' "
set-option global rep_buffer true
evaluate-commands -try-client '$kak_opt_toolsclient' %{
edit -scratch *rep*
set-option buffer filetype rep
}
"
fi
}
}
define-command \
-params 0.. \
-docstring %{rep-evaluate-selection: Evaluate selected code in REPL and write the result to *rep*.
Switches:
-namespace <ns> Evaluate in <ns>. Default is the current file's ns or user if not found.} \
rep-evaluate-selection-fifo %{
evaluate-commands %{
set-option global rep_evaluate_output ''
set-option global rep_selection %val{selection}
try %{ rep-find-namespace }
evaluate-commands -itersel -draft %{
evaluate-commands %sh{
add_port() {
if [ -n "$kak_buffile" ]; then
rep_command="$rep_command --port=\"@.nrepl-port@$kak_buffile\""
fi
}
add_file_line_and_column() {
anchor="${kak_selection_desc%,*}"
anchor_line="${anchor%.*}"
anchor_column="${anchor#*.}"
cursor="${kak_selection_desc#*,}"
cursor_line="${cursor%.*}"
cursor_column="${cursor#*.}"
if [ $anchor_line -lt $cursor_line ]; then
start="$anchor_line:$anchor_column"
elif [ $anchor_line -eq $cursor_line ] && [ $anchor_column -lt $cursor_column ]; then
start="$anchor_line:$anchor_column"
else
start="$cursor_line:$cursor_column"
fi
rep_command="$rep_command --line=\"$kak_buffile:$start\""
}
add_namespace() {
ns="$kak_opt_rep_namespace"
while [ $# -gt 0 ]; do
case "$1" in
-namespace) shift; ns="$1";;
esac
shift
done
if [ -n "$ns" ]; then
rep_command="$rep_command --namespace=$ns"
fi
}
error_file=$(mktemp)
rep_command='value=$(rep'
add_port
add_file_line_and_column
add_namespace "$@"
pprint="(set! nrepl.middleware.print/*print-fn* clojure.pprint/pprint)"
rep_command="$rep_command"' -- "$pprint $kak_selection" 2>"$error_file" |sed -e "s/'"'"'/'"''"'/g")'
printf '%s\n' "echo -debug %{[rep] $rep_command}"
eval "$rep_command"
error=$(sed "s/'/''/g" <"$error_file")
rm -f "$error_file"
printf "set-option -add global rep_evaluate_output '%s'\n" "$value"
[ -n "$error" ] && printf "set-option -add global rep_evaluate_output '\n%s'\n" "$error"
}
}
create-rep-buffer
evaluate-commands -draft -no-hooks -buffer *rep* %sh{
in="$(printf '%s\n' "$kak_opt_rep_selection" |
sed 's/</<lt>/g' |
sed 's/{/⸨/g' |
sed 's/}/⸩/g'
)"
out="$(printf '%s\n' "$kak_opt_rep_evaluate_output" |
tail -n+2
sed 's/</<lt>/g' |
sed 's/{/⸨/g' |
sed 's/}/⸩/g'
)"
printf 'echo -debug %%{[rep] in=%s}\n' "$in" | kak -p "$kak_session"
printf 'echo -debug %%{[rep] out=%s}\n' "$out" | kak -p "$kak_session"
printf '%s\n' "
set-option buffer readonly false
execute-keys -draft %{gj"\\"o$in<ret>$out<ret><esc>}
try %{ execute-keys -draft '%s⸨<ret>c{<esc>%s⸩<ret>c}<esc>' }
set-option buffer readonly true
"
}
try %{ execute-keys -client %opt{toolsclient} gj }
}
}
map -docstring 'evaluate the selection in the FIFO REPL' global rep e ': rep-evaluate-selection-fifo<ret>'
map -docstring 'evaluate the selection in the echo REPL' global rep E ': rep-evaluate-selection<ret>' |
You remind me that when I was first thinking about connecting Kakoune to a REPL, I was thinking of some daemonized, persistent process (to support a buffer). The However, to get incremental output, you could do something like (following is completely untested):
The idea is that each incremental response packet is translated into shell for asynchronously updating the buffer. Shell instead of just making Kakoune commands is because I'm pretty sure that EDIT: That clearly has a number of shell quoting issues, if double quotes or single quotes appear in the output. I would be up for adding modifiers to the print formats to shell-quote the result. |
Actually, maybe a |
My initial approach to getting incremental output working was to create a
temp directory with a normal file (call it rep/in) and a fifo (rep/out) and
spawn a background process `tail -f rep/in > rep/out` that lives for as
long as the repl buffer (which is a fifo buffer reading from rep/out)
exists.
Then each invocation of rep would append it's output to rep/in.
However this approach did not work, and I'm not sure why. If it's possible
to get working then it is rather convenient, since it doesn't involve any
complicated escaping hacks to communicate with kakoune over execute-keys.
…On Wed, May 5, 2021, 12:17 Jason Felice ***@***.***> wrote:
Actually, maybe a --shell-interpret option that, for each reply message,
converts the whole packet into correctly quoted shell variables and runs a
user-supplied shell function, e.g. "out='foo' err='bar'
rep_reply_received". This seems like an obvious way I should have
implemented formats in the first place.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#8 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABMYDJL57CCBODIGN7FSULTMFVSDANCNFSM433TM4YQ>
.
|
I've extended rep to have it write repl I/O to a dedicated
*rep*
buffer in kakoune. This is necessary for how our clojure build system works at my job for... reasons. But it also has some advantages, like being able to interact with repl output with the full facilities of kakoune.I'd be happy to clean this up and submit a PR if you think it's in scope for this project.
The text was updated successfully, but these errors were encountered: