До этого я выполнял домашки через nvim + lf + DrRacket.
И это всё прекрасно работало (в том числе для домашек с картинками). Но было это и немножко неудобно: постоянно переключать окна и всё такое.
repl для racket идёт вместе собственно с racket и одна из проблем которая тут же вылезает это вот такая дичь:
C:\>racket -I sicp
Welcome to Racket v8.11.1 [cs].
> (list 1 2 3 4)
(mcons 1 (mcons 2 (mcons 3 (mcons 4 '()))))
>
это читать невозможно поэтому бежим гуглить, узнаем много нового о том как это настроить
шаги следующие:
> racket
Welcome to Racket v8.11.1 [cs].
> (require setup/dirs)
> (find-user-pkgs-dir)
переходим по пути и заходим в файл ./sicp/sicp/main.rkt
это по-сути файл который даёт определения языку
ничего особо не трогаем и добавляем просто 3 строчки в конце:
;; FIX racket repl from displaying (mcons (mcons ))
(print-as-expression #f)
(print-pair-curly-braces #t)
(print-mpair-curly-braces #f)
и наслаждаемся тем, что теперь всё красиво отображается в repl:
Welcome to Racket v8.11.1 [cs].
> (list 1 2 3 4)
(1 2 3 4)
> (cons 1 2)
(1 . 2)
>
Есть уже готовые разные плагины вроде slimv, vim-slime, reply и т.д. Вы можете поковыряться с этими вариантами.
Но я пойду немножко другим путём, потому что я не хочу учить ничего. Поэтому минимальное взаимодействие с repl напишем сами.
Самое простое, что хочется, это научиться отправлять скопированный текст и вообще произвольный текст в repl.
Для этого мы будем использовать встроенную функцию chansend.
Идём в окно с терминалом и пишем:
echo b:terminal_job_id, получаем например 3
Теперь откуда угодно мы можем вызвать функцию chansend.
И отправить немножко вещей прямо в терминал:
call chansend(3, "Hello World")
Осталось это только всё автоматизировать.
Нам нужно следующее поведение:
if (_G.sniff) then
error("Sniff: global name clash")
end
_G.sniff = {}
local newline = vim.fn.has("win32") and "\r\n"
or "\n"
function sniff:terminal()
if (not vim.b.terminal_job_id) then
vim.api.nvim_err_writeln("Sniff: not a terminal")
return false
end
self.job = vim.b.terminal_job_id
vim.cmd([[echo "Sniff: connected ]] .. self.job .. '"')
return true
end
function sniff:send(text)
if (not self.job) then
vim.api.nvim_err_writeln("Sniff: no job selected")
return false
end
vim.fn.chansend(self.job, text)
return true
end
function sniff:sendln(text)
sniff:send(text .. newline)
end
и кладём его в папку plugin, рядом с init.vim
после чего мы теперь сможем вызывать
:lua sniff::terminal()
:lua snif::send("Hello world\r\n")
идём в init.vim и заполняем так как мы хотим
" move between terminal and window
" via \[ and \]
map <C-\><C-]> <C-w>li
tmap <C-\><C-[> <C-\><C-n><C-w>h
" bind terminal
nmap \. :lua sniff:terminal()<CR>
" send yanked text
nmap \p :lua sniff:send(vim.fn.getreg('"'))<CR>
" send newline
nmap \<CR> :lua sniff:sendln("")<CR>
" send yanked text and newline
nmap \; \p\<CR>
" send quote
nmap \' :lua sniff:send("'")<CR>
" send opening bracket
nmap \9 :lua sniff:send("(")<CR>
" send closing bracket
nmap \0 :lua sniff:send(")")<CR>
" yank current list and send it
nmap \( ya(\;
" enter file
nmap \> :lua sniff:sendln(',enter (file "'..string.gsub(vim.fn.expand("%"), [[\]], [[\\]])..'")')<CR><CR>
" go upper
nmap \< :lua sniff:sendln(",top")
я например поставил следующие: Cntrl-\ Cntrl-] –> переход в insert mode repl Cntrl-\ Cntrl-[ –> переход обратно в левое окно
в теории то, что выше можно круче сделать, но я не стал заморачиваться
\p я забиндил на отправить текст из copy-регистра то есть теперь я могу что-то скопировать и отправить напрямую в repl
\Enter я забиндил на отправку новой строки
( на отправку целого списка
и самое интересное > на ,enter (file filename)
чтобы с лёгкостью исполнять файлы над которыми работаю