1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 17:20:04 +08:00

feat(repl): rewrite repl plugin in lua

This commit is contained in:
Eric Wong 2023-08-31 22:07:56 +08:00 committed by GitHub
parent 7e81ce1019
commit 6f0728c625
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 264 additions and 5 deletions

View File

@ -6,6 +6,38 @@
" License: GPLv3 " License: GPLv3
"============================================================================= "=============================================================================
if has('nvim-0.9.0')
function! SpaceVim#plugins#repl#send(type, ...) abort
if a:type == 'raw'
lua require('spacevim.plugin.repl').send(
\ require('spacevim').eval('a:type'),
\ require('spacevim').eval("get(a:000, 0, '')")
\ )
else
lua require('spacevim.plugin.repl').send(
\ require('spacevim').eval('a:type')
\ )
endif
endfunction
function! SpaceVim#plugins#repl#start(ft) abort
lua require("spacevim.plugin.repl").start(
\ require("spacevim").eval("a:ft")
\ )
endfunction
function! SpaceVim#plugins#repl#status() abort
return luaeval('require("spacevim.plugin.repl").status()')
endfunction
function! SpaceVim#plugins#repl#reg(ft, execute) abort
lua require("spacevim.plugin.repl").reg(
\ require("spacevim").eval("a:ft"),
\ require("spacevim").eval("a:execute")
\ )
endfunction
finish
endif
"" ""
" @section repl, usage-repl " @section repl, usage-repl
" @parentsection usage " @parentsection usage
@ -97,10 +129,6 @@ function! s:start(exe) abort
call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 3, 0, ['[REPL executable] ' . string(a:exe), '', repeat('-', 20)]) call s:BUFFER.buf_set_lines(s:bufnr, s:lines , s:lines + 3, 0, ['[REPL executable] ' . string(a:exe), '', repeat('-', 20)])
call s:WINDOW.set_cursor(s:winid, [s:BUFFER.line_count(s:bufnr), 0]) call s:WINDOW.set_cursor(s:winid, [s:BUFFER.line_count(s:bufnr), 0])
let s:lines += 3 let s:lines += 3
let s:_out_data = ['']
let s:_current_line = ''
" this only for has('nvim') && exists('*chanclose')
let s:_out_data = ['']
let s:job_id = s:JOB.start(a:exe,{ let s:job_id = s:JOB.start(a:exe,{
\ 'on_stdout' : function('s:on_stdout'), \ 'on_stdout' : function('s:on_stdout'),
\ 'on_stderr' : function('s:on_stderr'), \ 'on_stderr' : function('s:on_stderr'),
@ -123,7 +151,7 @@ function! s:on_stdout(job_id, data, event) abort
let s:lines += len(a:data) let s:lines += len(a:data)
if s:WINDOW.get_cursor(s:winid)[0] == s:BUFFER.line_count(s:bufnr) - len(a:data) if s:WINDOW.get_cursor(s:winid)[0] == s:BUFFER.line_count(s:bufnr) - len(a:data)
call s:WINDOW.set_cursor(s:winid, [s:BUFFER.line_count(s:bufnr), 0]) call s:WINDOW.set_cursor(s:winid, [s:BUFFER.line_count(s:bufnr), 0])
endi endif
call s:update_statusline() call s:update_statusline()
endif endif
endfunction endfunction

View File

@ -226,6 +226,7 @@ function M.send(id, data) -- {{{
end end
elseif type(data) == 'string' then elseif type(data) == 'string' then
stdin:write(data) stdin:write(data)
stdin:write('\n')
elseif data == nil then elseif data == nil then
stdin:write('', function() stdin:write('', function()
stdin:shutdown(function() stdin:shutdown(function()

View File

@ -0,0 +1,18 @@
local M = {}
function M.setlocalopt(buf, win, opts)
for o, value in pairs(opts) do
local info = vim.api.nvim_get_option_info2(o, {})
if info.scope == 'win' then
vim.api.nvim_set_option_value(o, value, {
win = win,
})
elseif info.scope == 'buf' then
vim.api.nvim_set_option_value(o, value, {
buf = buf,
})
end
end
end
return M

View File

@ -0,0 +1,212 @@
--=============================================================================
-- repl.lua --- REPL for spacevim
-- Copyright (c) 2016-2022 Wang Shidong & Contributors
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local vopt = require('spacevim.api.vim.option')
local str = require('spacevim.api.data.string')
local log = require('spacevim.logger').derive('repl')
local lines = 0
local bufnr = -1
local winid = -1
local status = {}
local start_time
local end_time
local job_id = 0
local exes = {}
local M = {}
local function close()
if job_id > 0 then
job.stop(job_id)
job_id = 0
end
if vim.api.nvim_buf_is_valid(bufnr) then
vim.cmd('bd ' .. bufnr)
end
end
local function insert()
vim.fn.inputsave()
local input = vim.fn.input('input >')
if vim.fn.empty(input) == 0 then
if job_id == 0 then
nt.notify('please restart the REPL', 'WarningMsg')
else
job.send(job_id, input)
end
end
vim.api.nvim_echo({}, false, {})
vim.fn.inputrestore()
end
local function close_repl()
if job_id > 0 then
job.stop(job_id)
job_id = 0
end
end
local function open_windows()
if vim.api.nvim_buf_is_valid(bufnr) then
vim.cmd('bd ' .. bufnr)
end
local previous_win = vim.api.nvim_get_current_win()
vim.cmd('botright split __REPL__')
bufnr = vim.api.nvim_get_current_buf()
winid = vim.api.nvim_get_current_win()
local l = math.floor(vim.o.lines * 30 / 100)
vim.cmd('resize ' .. l)
vim.api.nvim_set_current_win(previous_win)
vopt.setlocalopt(bufnr, winid, {
buftype = 'nofile',
bufhidden = 'wipe',
buflisted = false,
list = false,
swapfile = false,
wrap = false,
cursorline = true,
spell = false,
number = false,
relativenumber = false,
winfixheight = true,
modifiable = false,
filetype = 'SpaceVimREPL',
})
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'q', '', {
callback = close,
})
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'i', '', {
callback = insert,
})
local id = vim.api.nvim_create_augroup('spacevim_repl', {
clear = true,
})
vim.api.nvim_create_autocmd({ 'BufWipeout' }, {
group = id,
buffer = bufnr,
callback = close_repl,
})
end
local function on_stdout(_, data)
if vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(bufnr, lines, lines + 1, false, data)
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
lines = lines + #data
local cursor = vim.api.nvim_win_get_cursor(winid)
if cursor[1] == vim.api.nvim_buf_line_count(bufnr) - #data then
vim.api.nvim_win_set_cursor(winid, { vim.api.nvim_buf_line_count(bufnr), 0 })
end
end
end
local function on_stderr(_, data)
status.has_errors = true
on_stdout(_, data)
end
local function on_exit(id, code, single)
end_time = vim.fn.reltime(start_time)
status.is_exit = true
status.exit_code = code
local done = {'', '[Done] exited with code=' .. code .. ' in ' .. str.trim(vim.fn.reltimestr(end_time)) .. ' seconds'}
if vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(bufnr, lines, lines + 1, false, done)
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
job_id = 0
end
local function start(exe)
lines = 0
status = {
is_running = true,
is_exit = false,
has_errors = false,
exit_code = 0,
}
start_time = vim.fn.reltime()
open_windows()
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(
bufnr,
lines,
lines + 3,
false,
{ '[REPL executable] ' .. vim.fn.string(exe), '', string.rep('-', 20) }
)
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
vim.api.nvim_win_set_cursor(winid, { vim.api.nvim_buf_line_count(bufnr), 0 })
lines = lines + 3
job_id = job.start(exe, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
function M.start(ft)
log.info('start repl for filetype:' .. ft)
local exe = exes[ft] or ''
log.debug('get the command:' .. vim.inspect(exe))
if exe ~= '' then
start(exe)
else
vim.api.nvim_echo({ { 'no REPL executable for ' .. ft, 'WarningMsg' } }, false, {})
end
end
function M.send(t, ...)
if job_id == 0 then
nt.notify('please restart the REPL', 'WarningMsg')
else
if t == 'line' then
job.send(job_id, { vim.api.nvim_get_current_line(), '' })
elseif t == 'buffer' then
local data = vim.fn.getline(1, '$')
table.insert(data, '')
job.send(job_id, data)
elseif t == 'raw' then
local context = select(1, ...)
if type(context) == "string" then
job.send(job_id, context)
end
elseif t == 'selection' then
local b = vim.fn.getpos("'<")
local e = vim.fn.getpos("'>")
if b[2] ~= 0 and e[2] ~= 0 then
local data = vim.fn.getline(b[2], e[2])
table.insert(data, '')
job.send(job_id, data)
else
nt.notify('no selection text', 'WarningMsg')
end
end
end
end
function M.reg(ft, execute)
exes[ft] = execute
end
function M.status()
if status.is_running then
return 'running'
elseif status.is_exit then
return 'exit code:' .. status.exit_code .. ' time:' .. str.trim(vim.fn.reltimestr(end_time))
end
end
return M