diff --git a/lua/luadev.lua b/lua/luadev.lua index 67d7f5e..478aa9d 100644 --- a/lua/luadev.lua +++ b/lua/luadev.lua @@ -1,8 +1,8 @@ local a = vim.api -if __lua_dev_state == nil then - __lua_dev_state = {} +if _G.__lua_dev_state == nil then + _G.__lua_dev_state = {} end -local s = __lua_dev_state +local s = _G.__lua_dev_state local function create_buf(window) if s.buf ~= nil then @@ -22,18 +22,44 @@ local function create_buf(window) s.buf = buf end +local function dosplit(str, delimiter) + local result = { } + local from = 1 + local delim_from, delim_to = string.find( str, delimiter, from ) + while delim_from do + table.insert( result, string.sub( str, from , delim_from-1 ) ) + from = delim_to + 1 + delim_from, delim_to = string.find( str, delimiter, from ) + end + table.insert( result, string.sub( str, from ) ) + return result +end + +local function splitlines(str) + return dosplit(str, "\n") +end + local function append_buf(lines, hl) + if s.buf == nil then + return + end local l0 = a.nvim_buf_line_count(s.buf) if type(lines) == type("") then - unimplemented() + lines = splitlines(lines) end a.nvim_buf_set_lines(s.buf, l0, l0, true, lines) + local l1 = a.nvim_buf_line_count(s.buf) if hl ~= nil then - for i = l0, a.nvim_buf_line_count(s.buf)-1 do + for i = l0, l1-1 do a.nvim_buf_add_highlight(s.buf, -1, hl, i, 0, -1) end end - -- TODO: scroll! + local curwin = a.nvim_get_current_win() + for _,win in ipairs(a.nvim_list_wins()) do + if a.nvim_win_get_buf(win) == s.buf and win ~= curwin then + a.nvim_win_set_cursor(win, {l1, 1e9}) + end + end return l0 end @@ -42,17 +68,52 @@ local function luadev_print(x) -- TODO: ... append_buf({str}) end +local function dedent(str, leave_indent) + -- find minimum common indent across lines + local indent = nil + for line in str:gmatch('[^\n]+') do + local line_indent = line:match('^%s+') or '' + if indent == nil or #line_indent < #indent then + indent = line_indent + end + end + if indent == nil or #indent == 0 then + -- no minimum common indent + return str + end + local left_indent = (' '):rep(leave_indent or 0) + -- create a pattern for the indent + indent = indent:gsub('%s', '[ \t]') + -- strip it from the first line + str = str:gsub('^'..indent, left_indent) + -- strip it from the remaining lines + str = str:gsub('[\n]'..indent, '\n' .. left_indent) + return str +end + local function exec(str) - local s, err = loadstring(str,"g") - if s == nil then + local chunk, err = loadstring(str,"g") + local inlines = splitlines(dedent(str)) + if inlines[#inlines] == "" then + inlines[#inlines] = nil + end + for i,l in ipairs(inlines) do + inlines[i] = "> "..l + end + append_buf({""}) + local start = append_buf(inlines) + for i,_ in ipairs(inlines) do + a.nvim_buf_add_highlight(s.buf, -1, "Question", start+i-1, 0, 2) + end + if chunk == nil then append_buf({err},"WarningMsg") else local oldprint = _G.print _G.print = luadev_print - s, err = pcall(s) + local st, err2 = pcall(chunk) _G.print = oldprint - if s == false then - append_buf({err},"WarningMsg") + if st == false then + append_buf({err2},"WarningMsg") end end end @@ -61,9 +122,19 @@ local function start() create_buf(true) end -return { +local mod = { start=start, exec=exec, print=luadev_print, append_buf=append_buf } + +-- TODO: export abstraction for autoreload +if s.mod == nil then + s.mod = mod +else + for k,v in pairs(mod) do + s.mod[k] = v + end +end +return s.mod diff --git a/plugin/luadev.vim b/plugin/luadev.vim index ebd71a3..7e9886a 100644 --- a/plugin/luadev.vim +++ b/plugin/luadev.vim @@ -1,3 +1,20 @@ command! Luadev lua require'luadev'.start() -nnoremap (Luadev-Run) lua require'luadev'.exec(vim.api.nvim_get_current_line()) +noremap (Luadev-RunLine) lua require'luadev'.exec(vim.api.nvim_get_current_line()) +vnoremap (Luadev-Run) :call luaeval("require'luadev'.exec(_A)", get_visual_selection()) + +" thanks to @xolox on stackoverflow +function! s:get_visual_selection() + let [lnum1, col1] = getpos("'<")[1:2] + let [lnum2, col2] = getpos("'>")[1:2] + + if lnum1 > lnum2 + let [lnum1, col1, lnum2, col2] = [lnum2, col2, lnum1, col1] + endif + + let lines = getline(lnum1, lnum2) + let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)] + let lines[0] = lines[0][col1 - 1:] + return join(lines, "\n")."\n" +endfunction +