Skip to content

Commit

Permalink
feat: Add multiline input for repl
Browse files Browse the repository at this point in the history
  • Loading branch information
LiadOz committed May 3, 2024
1 parent 6ae8a14 commit f357e74
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 6 deletions.
1 change: 1 addition & 0 deletions lua/dap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ local DAP_QUICKFIX_CONTEXT = DAP_QUICKFIX_TITLE
---@field options nil|AdapterOptions
---@field enrich_config? fun(config: Configuration, on_config: fun(config: Configuration))
---@field reverse_request_handlers? table<string, fun(session: Session, request: dap.Request)>
---@field is_multiline? fun(current_inputs: string[]): boolean

---@class AdapterOptions
---@field initialize_timeout_sec nil|number
Expand Down
67 changes: 61 additions & 6 deletions lua/dap/repl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,31 @@ local function get_session()
return require('dap').session()
end

local repl
local execute -- required for forward reference
local function execute_current(opts)
local current_text = api.nvim_buf_get_lines(repl.buf, -2, -1, false)[1]
local prompt_length = #vim.fn.prompt_getprompt(repl.buf)
execute(string.sub(current_text, prompt_length + 1), opts)
end


local MULTILINE_INPUT = 'MULTILINE_INPUT'

---@param buf number
---@return string[]
local function get_multiline_input(buf)
return vim.b[buf][MULTILINE_INPUT] or {}
end

local function get_prompt(buf)
buf = buf or repl.buf
if #get_multiline_input(buf) == 0 then
return 'dap> '
else
return '...> '
end
end


local function new_buf()
Expand All @@ -34,7 +58,11 @@ local function new_buf()
api.nvim_buf_set_keymap(buf, 'n', 'o', "<Cmd>lua require('dap.ui').trigger_actions()<CR>", {})
api.nvim_buf_set_keymap(buf, 'i', '<up>', "<Cmd>lua require('dap.repl').on_up()<CR>", {})
api.nvim_buf_set_keymap(buf, 'i', '<down>', "<Cmd>lua require('dap.repl').on_down()<CR>", {})
vim.fn.prompt_setprompt(buf, 'dap> ')

-- CR keybindings may require additional configuration for some terminals, see https://stackoverflow.com/a/42461580
vim.keymap.set('i', '<S-CR>', function() execute_current({force_multiline = true}) end, {buffer = buf})
vim.keymap.set('i', '<C-CR>', function() execute_current({force_finish = true}) end, {buffer = buf})
vim.fn.prompt_setprompt(buf, get_prompt(buf))
vim.fn.prompt_setcallback(buf, execute)
if vim.fn.has('nvim-0.7') == 1 then
vim.keymap.set('n', 'G', function()
Expand Down Expand Up @@ -67,7 +95,7 @@ local function new_win(buf, winopts, wincmd)
return win
end

local repl = ui.new_view(
repl = ui.new_view(
new_buf,
new_win, {
before_open = function()
Expand Down Expand Up @@ -212,7 +240,34 @@ local function print_threads(threads)
end


function execute(text)
---@return string|nil full_input nil if input is incomplete
local function handle_multiline_input(last_line, force_multiline, force_finish)
local session = get_session()
if not session then
return last_line
end
local current_inputs = get_multiline_input(repl.buf)
table.insert(current_inputs, last_line)
local is_multiline = session.adapter.is_multiline
if not force_finish and (force_multiline or (is_multiline and is_multiline(current_inputs))) then
vim.b[repl.buf][MULTILINE_INPUT] = current_inputs
if #current_inputs == 1 then
vim.fn.prompt_setprompt(repl.buf, get_prompt())
end
return nil
end
vim.b[repl.buf][MULTILINE_INPUT] = nil
vim.fn.prompt_setprompt(repl.buf, get_prompt())
return table.concat(current_inputs, '\n')
end

function execute(text, opts)
opts = opts or {}
text = handle_multiline_input(text, opts.force_multiline, opts.force_finish)
if text == nil then
return
end

if text == '' then
if history.last then
text = history.last
Expand Down Expand Up @@ -337,9 +392,9 @@ local function select_history(delta)
history.idx = 1
end
local text = history.entries[history.idx]
if text then
if text and string.find(text, '\n') == nil then
local lnum = vim.fn.line('$')
api.nvim_buf_set_lines(repl.buf, lnum - 1, lnum, true, {'dap> ' .. text })
api.nvim_buf_set_lines(repl.buf, lnum - 1, lnum, true, {get_prompt() .. text })
vim.fn.setcursorcharpos({ lnum, vim.fn.col('$') }) -- move cursor to the end of line
end
end
Expand Down Expand Up @@ -439,7 +494,7 @@ do
local session = get_session()
local col = api.nvim_win_get_cursor(0)[2]
local line = api.nvim_get_current_line()
local offset = vim.startswith(line, 'dap> ') and 5 or 0
local offset = vim.startswith(line, get_prompt()) and 5 or 0
local line_to_cursor = line:sub(offset + 1, col)
local text_match = vim.fn.match(line_to_cursor, '\\k*$')
if vim.startswith(line_to_cursor, '.') or base ~= '' then
Expand Down

0 comments on commit f357e74

Please sign in to comment.