mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-23 13:00:04 +08:00
feat(repl): rewrite repl plugin in lua
This commit is contained in:
parent
7e81ce1019
commit
6f0728c625
@ -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
|
||||||
|
@ -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()
|
||||||
|
18
lua/spacevim/api/vim/option.lua
Normal file
18
lua/spacevim/api/vim/option.lua
Normal 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
|
212
lua/spacevim/plugin/repl.lua
Normal file
212
lua/spacevim/plugin/repl.lua
Normal 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
|
Loading…
Reference in New Issue
Block a user