diff --git a/users/jrpotter/neovim/config/utils/dap.lua b/users/jrpotter/neovim/config/utils/dap.lua index 6874ca3..462a480 100644 --- a/users/jrpotter/neovim/config/utils/dap.lua +++ b/users/jrpotter/neovim/config/utils/dap.lua @@ -14,7 +14,7 @@ local function query_launch() return end - return parts[1], {unpack(parts, 2, #parts)} + return parts[1], { unpack(parts, 2, #parts) } end -- Adaptation of https://github.com/mfussenegger/nvim-dap/blob/e154fdb6d70b3765d71f296e718b29d8b7026a63/lua/dap.lua#L413. @@ -42,10 +42,10 @@ local function select_config_and_run() dap_ui.pick_if_many( configs, 'Configuration: ', - function(c) -- Label function + function(c) -- Label function return c.name end, - function(c) -- Callback + function(c) -- Callback if not c then vim.api.nvim_err_writeln('No configuration selected.') return @@ -61,35 +61,24 @@ local function select_config_and_run() ) end -local function sidebar_new(widget) - return dap_ui_widgets.sidebar(widget, { width = 40 }, '') -end - -local function sidebar_is_open(sidebar) - return sidebar.win and vim.api.nvim_win_is_valid(sidebar.win) -end - -- Setup buffer-local DAP mappings. This function is expected to be called in -- a filetype plugin, e.g. `nvim/after/ftplugin/c.lua`. function M.buffer_map() - local function set_nnoremap(key, func) - vim.keymap.set( - 'n', - string.format('%s', key), - func, - { buffer = true } - ) + local function sidebar_new(widget) + return dap_ui_widgets.sidebar(widget, { width = 32 }, '') end local sidebars = { - expression = sidebar_new(dap_ui_widgets.expression), frames = sidebar_new(dap_ui_widgets.frames), scopes = sidebar_new(dap_ui_widgets.scopes), - sessions = sidebar_new(dap_ui_widgets.sessions), threads = sidebar_new(dap_ui_widgets.threads), } - local function any_sidebar_open() + local function sidebar_is_open(sb) + return sb.win and vim.api.nvim_win_is_valid(sb.win) + end + + local function sidebar_any_open() for _, sb in pairs(sidebars) do if sidebar_is_open(sb) then return true @@ -98,22 +87,119 @@ function M.buffer_map() return false end - local function toggle_sidebar(sidebar) + local function sidebar_toggle(sidebar) if sidebar_is_open(sidebar) then sidebar.close({ mode = 'toggle' }) else local win_id = vim.fn.win_getid() - vim.cmd.wincmd('t') -- Move to topleft-most window. - vim.cmd(any_sidebar_open() and 'leftabove split' or 'vertical topleft split') + vim.cmd.wincmd('t') -- Move to topleft-most window. + vim.cmd(sidebar_any_open() and 'leftabove split' or 'vertical topleft split') sidebar.open() vim.fn.win_gotoid(win_id) -- Update state of windows. vim.api.nvim_win_set_option(sidebar.win, 'colorcolumn', '') vim.api.nvim_win_set_option(sidebar.win, 'list', false) vim.api.nvim_win_set_option(sidebar.win, 'wrap', false) + vim.api.nvim_win_set_option(sidebar.win, 'winfixwidth', true) end end + local function sidebar_only(sidebar) + for _, sb in pairs(sidebars) do + if sb ~= sidebar and sidebar_is_open(sb) then + sb.close({ mode = 'toggle' }) + end + end + if not sidebar_is_open(sidebar) then + sidebar_toggle(sidebar) + end + end + + local function find_bufnr_by_pattern(pattern) + for _, bufnr in pairs(vim.api.nvim_list_bufs()) do + if vim.fn.bufname(bufnr):match(pattern) then + return bufnr + end + end + return nil + end + + local function is_bufnr_open(bufnr) + if not bufnr then + return false + end + local windows = vim.fn.win_findbuf(bufnr) + for _, _ in pairs(windows) do + return true + end + return false + end + + local function repl_is_open() + return is_bufnr_open(find_bufnr_by_pattern("^%[dap%-repl]")) + end + + local function term_is_open() + return is_bufnr_open(find_bufnr_by_pattern("^%[dap%-terminal]")) + end + + local function repl_open(opts) + if repl_is_open() then + return + end + local height = opts.height or 10 + local win_id = vim.fn.win_getid() + vim.cmd.wincmd('b') -- Move to bottomright-most window. + dap.repl.open({}, term_is_open() and + 'vertical rightbelow split' or + string.format('rightbelow %dsplit', height)) + vim.api.nvim_win_set_option(0, 'winfixheight', true) + vim.fn.win_gotoid(win_id) + end + + local function term_open(opts) + if term_is_open() then + return + end + local height = opts.height or 10 + local win_id = vim.fn.win_getid() + vim.cmd.wincmd('b') -- Move to bottomright-most window. + vim.cmd(repl_is_open() and + 'vertical rightbelow split' or + string.format('rightbelow %dsplit', height)) + vim.api.nvim_win_set_option(0, 'winfixheight', true) + vim.api.nvim_win_set_buf(0, find_bufnr_by_pattern("^%[dap%-terminal]")) + vim.fn.win_gotoid(win_id) + end + + local function repl_close() + dap.repl.close() + end + + local function term_close() + if not term_is_open() then + return + end + local bufnr = find_bufnr_by_pattern("^%[dap%-terminal]") + local windows = vim.fn.win_findbuf(bufnr) + for _, win in pairs(windows) do + vim.api.nvim_win_close(win, --[[force=]] true) + end + end + + local function repl_toggle(opts) + if repl_is_open() then repl_close() else repl_open(opts) end + end + + local function term_toggle(opts) + if term_is_open() then term_close() else term_open(opts) end + end + + local function set_nnoremap(key, func) + local input = string.format('%s', key) + vim.keymap.set('n', input, func, { buffer = true }) + end + set_nnoremap('', select_config_and_run) set_nnoremap('b', dap.toggle_breakpoint) set_nnoremap('c', function() @@ -123,6 +209,7 @@ function M.buffer_map() end dap.continue() end) + set_nnoremap('d', dap.down) set_nnoremap('i', dap.step_into) set_nnoremap('n', dap.step_over) @@ -131,23 +218,23 @@ function M.buffer_map() set_nnoremap('r', dap.run_to_cursor) set_nnoremap('u', dap.up) set_nnoremap('x', dap.clear_breakpoints) - set_nnoremap('we', function() - toggle_sidebar(sidebars.expression) + + set_nnoremap('wf', function() sidebar_toggle(sidebars.frames) end) + set_nnoremap('wh', function() sidebar_toggle(sidebars.threads) end) + set_nnoremap('wr', function() repl_toggle({ height = 10 }) end) + set_nnoremap('ws', function() sidebar_toggle(sidebars.scopes) end) + set_nnoremap('wt', function() term_toggle({ height = 10 }) end) + + set_nnoremap('wF', function() sidebar_only(sidebars.frames) end) + set_nnoremap('wH', function() sidebar_only(sidebars.threads) end) + set_nnoremap('wR', function() + term_close() + repl_open({ height = 10 }) end) - set_nnoremap('wf', function() - toggle_sidebar(sidebars.frames) - end) - set_nnoremap('wc', function() - toggle_sidebar(sidebars.scopes) - end) - set_nnoremap('wr', function() - dap.repl.toggle({ height = 10 }) - end) - set_nnoremap('ws', function() - toggle_sidebar(sidebars.sessions) - end) - set_nnoremap('wt', function() - toggle_sidebar(sidebars.threads) + set_nnoremap('wS', function() sidebar_only(sidebars.scopes) end) + set_nnoremap('wT', function() + repl_close() + term_open({ height = 10 }) end) end diff --git a/users/jrpotter/neovim/default.nix b/users/jrpotter/neovim/default.nix index 81575e1..8c7580b 100644 --- a/users/jrpotter/neovim/default.nix +++ b/users/jrpotter/neovim/default.nix @@ -47,10 +47,15 @@ let nvim-dap = { plugin = utils.pluginGit - "e154fdb6d70b3765d71f296e718b29d8b7026a63" + "fc880e82059eb21c0fa896be60146e5f17680648" "mfussenegger/nvim-dap"; config = '' - require('dap').defaults.fallback.terminal_win_cmd = 'below 10split new' + require("dap").defaults.fallback.terminal_win_cmd = function() + return vim.api.nvim_create_buf( + true, -- listed + true -- scratch + ) + end ${config.programs.neovim.nvim-dap} ''; };