Skip to content

Commit

Permalink
mvp
Browse files Browse the repository at this point in the history
  • Loading branch information
igorlfs committed Nov 12, 2024
1 parent 575a0c3 commit 36f8d4d
Show file tree
Hide file tree
Showing 21 changed files with 504 additions and 52 deletions.
5 changes: 3 additions & 2 deletions .stylua.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
column_width = 120
column_width = 100
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 2
indent_width = 4
quote_style = "AutoPreferDouble"
no_call_parentheses = false
collapse_simple_statement = "FunctionOnly"
30 changes: 30 additions & 0 deletions lua/dap-view.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
local actions = require("dap-view.actions")

local M = {}

M.config = require("dap-view.config").config

---@param config Config?
M.setup = function(config)
if config then
assert(
vim.tbl_contains(config.winbar.sections, config.winbar.default_section),
"Default section must be a defined section"
)
end
M.config = vim.tbl_deep_extend("force", M.config, config or {})
end

M.open = function()
actions.open(M.config)
end

M.close = function()
actions.close()
end

M.toggle = function()
actions.toggle(M.config)
end

return M
78 changes: 78 additions & 0 deletions lua/dap-view/actions.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
local winbar = require("dap-view.winbar")
local util = require("dap-view.util")
local state = require("dap-view.state")
local settings = require("dap-view.settings")
local events = require("dap-view.events")
local globals = require("dap-view.globals")

---@class Actions
local M = {}

---@param config Config
M.toggle = function(config)
if state.bufnr then
M.close()
else
M.open(config)
end
end

M.close = function()
if state.winnr then
vim.api.nvim_win_close(state.winnr, true)
state.winnr = nil
end
if state.bufnr then
vim.api.nvim_buf_delete(state.bufnr, { force = true })
state.bufnr = nil
end
end

-- TODO showing breakpoint info may be outdated if not in a session
-- we could use another approach to track breakpoint (instead of looking at the QF list)

---@param config Config
M.open = function(config)
M.close()

local bufnr = vim.api.nvim_create_buf(false, false)

assert(bufnr ~= 0, "Failed to create dap-view buffer")

state.bufnr = bufnr

-- TODO move this to close?
local prev_buf = util.get_buf(globals.MAIN_BUF_NAME)
if prev_buf then
vim.api.nvim_buf_delete(prev_buf, { force = true })
end
vim.api.nvim_buf_set_name(bufnr, globals.MAIN_BUF_NAME)

local winnr = vim.api.nvim_open_win(bufnr, false, {
split = "below",
win = 0,
height = 15,
})

assert(winnr ~= 0, "Failed to create dap-view window")

state.winnr = winnr

settings.set_options()

-- TODO perhaps there's a better spot to handle
-- but currently only works if it's here
events.listen_breakpoints()

local winbar_config = config.winbar
winbar.set_winbar(winbar_config.default_section, winbar_config.sections)

-- Properly handle exiting the window
vim.api.nvim_create_autocmd({ "BufDelete", "WinClosed" }, {
buffer = state.bufnr,
once = true,
callback = M.close,
})
end

return M
89 changes: 89 additions & 0 deletions lua/dap-view/breakpoints/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
local util = require("dap-view.util")
local state = require("dap-view.state")
local vendor = require("dap-view.breakpoints.vendor")
local extmarks = require("dap-view.extmarks")

local api = vim.api

local M = {}

M.namespace = api.nvim_create_namespace("dap-view")

---@param row integer
---@param len_path integer
---@param len_lnum integer
local highlight_file_name_and_line_number = function(row, len_path, len_lnum)
if state.bufnr then
local lnum_start = len_path + 1

api.nvim_buf_set_extmark(
state.bufnr,
M.namespace,
row,
0,
{ end_col = len_path, hl_group = "qfFileName" }
)

api.nvim_buf_set_extmark(
state.bufnr,
M.namespace,
row,
lnum_start,
{ end_col = lnum_start + len_lnum, hl_group = "qfLineNr" }
)

-- TODO highlight the actual line of code using treesitter
-- Since the "text" property also contains some extra text (when using the QuickFix List)
-- eg, ", Condition" if breakpoint has a condition
-- We have to not consider the extra text when highlighting
end
end

local populate_buf_with_breakpoints = function()
if state.bufnr then
-- Clear previous content
api.nvim_buf_set_lines(state.bufnr, 0, -1, true, {})

-- TODO: decide between getting breakpoints
-- (A) by getting placed signs (nvim-dap approach)
-- (B) by listing breakpoints via QuickFix list (might have some issues if using the qflist for something else)
local breakpoints = vendor.get()

local line_count = 0

for buf, buf_entries in pairs(breakpoints) do
local relative_path = util.get_relative_path(buf)

for _, entry in pairs(buf_entries) do
local line_content = {}

local buf_lines = api.nvim_buf_get_lines(buf, entry.lnum - 1, entry.lnum, true)
local text = table.concat(buf_lines, "\n")

table.insert(line_content, relative_path .. "|" .. entry.lnum .. "|" .. text)

api.nvim_buf_set_lines(state.bufnr, line_count, line_count, false, line_content)

local col_offset = #relative_path + #tostring(entry.lnum) + 2

extmarks.copy_extmarks(buf, entry.lnum - 1, state.bufnr, line_count, col_offset)

highlight_file_name_and_line_number(
line_count,
#relative_path,
#tostring(entry.lnum)
)

line_count = line_count + 1
end
end
end

-- TODO: this should not be happening
-- Remove the last line, as it's empty
api.nvim_buf_set_lines(state.bufnr, -2, -1, false, {})
end

M.show = function() populate_buf_with_breakpoints() end

return M
65 changes: 65 additions & 0 deletions lua/dap-view/breakpoints/vendor/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
local M = {}

local NVIM_DAP_NAMESPACE = "dap_breakpoints"

---@class SignDict
---@field group string
---@field id integer
---@field lnum integer
---@field name string
---@field priority integer

---@class PlacedSigns
---@field bufnr integer
---@field signs SignDict

---@param bufnr? integer
---@return PlacedSigns
local function get_breakpoint_signs(bufnr)
if bufnr then
return vim.fn.sign_getplaced(bufnr, { group = NVIM_DAP_NAMESPACE })
end

local bufs_with_signs = vim.fn.sign_getplaced()

local result = {}

for _, buf_signs in ipairs(bufs_with_signs) do
buf_signs = vim.fn.sign_getplaced(buf_signs.bufnr, { group = NVIM_DAP_NAMESPACE })[1]

if #buf_signs.signs > 0 then
table.insert(result, buf_signs)
end
end

return result
end

---@param bufnr? integer
---@return table<integer, { lnum: integer }[]>
function M.get(bufnr)
local signs = get_breakpoint_signs(bufnr)

if #signs == 0 then
return {}
end

local result = {}

for _, buf_breakpoint_signs in pairs(signs) do
local breakpoints = {}
local buf = buf_breakpoint_signs.bufnr

result[buf] = breakpoints

for _, breakpoint_sign in pairs(buf_breakpoint_signs.signs) do
table.insert(breakpoints, {
lnum = breakpoint_sign.lnum,
})
end
end

return result
end

return M
19 changes: 19 additions & 0 deletions lua/dap-view/config.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---@class ConfigModule
local M = {}

---@class WinbarConfig
---@field sections SectionType[]
---@field default_section SectionType

--- @alias SectionType '"breakpoints"' | '"exceptions"' | '"watches"'

---@class Config
---@field winbar WinbarConfig
M.config = {
winbar = {
sections = { "breakpoints", "exceptions", "watches" },
default_section = "breakpoints",
},
}

return M
7 changes: 7 additions & 0 deletions lua/dap-view/debug.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
local M = {}

M.debug = function(any)
vim.inspect(vim.print(any))
end

return M
11 changes: 11 additions & 0 deletions lua/dap-view/events.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
local M = {}

M.listen_breakpoints = function()
-- TODO a better approach could be to hijack the "toggle breakpoint" command
-- and use some autocmds (eg, BufLeave/BufEnter for our buffer)
require("dap").listeners.after.setBreakpoints["dap-view"] = function()
require("dap-view.breakpoints").show()
end
end

return M
55 changes: 55 additions & 0 deletions lua/dap-view/extmarks.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
local M = {}

local api = vim.api

---@param src_bufnr integer
---@param src_row integer
---@param target_bufnr integer
---@param target_row integer
---@param col_offset integer
M.copy_extmarks = function(src_bufnr, src_row, target_bufnr, target_row, col_offset)
local extmarks = api.nvim_buf_get_extmarks(
src_bufnr,
-1,
{ src_row, 0 },
{ src_row + 1, 0 },
-- TODO perhaps it would be better to also filter by "highlight = true"
{ details = true }
)

for _, extmark in ipairs(extmarks) do
local namespace = extmark[1]
local col = extmark[3]
local opts = extmark[4]

if opts and opts.end_col then
opts.end_col = opts.end_col + col_offset
end

if opts then
api.nvim_buf_set_extmark(
target_bufnr,
opts.ns_id or M.namespace,
target_row,
col + col_offset,
{
id = namespace,
end_col = opts.end_col,
priority = opts.priority,
hl_group = opts.hl_group,
right_gravity = opts.right_gravity,
hl_eol = opts.hl_eol,
virt_text = opts.virt_text,
virt_text_pos = opts.virt_text_pos,
virt_text_win_col = opts.virt_text_win_col,
hl_mode = opts.hl_mode,
line_hl_group = opts.line_hl_group,
spell = opts.spell,
url = opts.url,
}
)
end
end
end

return M
3 changes: 3 additions & 0 deletions lua/dap-view/globals.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
return {
MAIN_BUF_NAME = "dap-view://main",
}
20 changes: 20 additions & 0 deletions lua/dap-view/settings.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
local state = require("dap-view.state")

local M = {}

M.set_options = function()
vim.wo[state.winnr][0].scrolloff = 0
vim.wo[state.winnr][0].wrap = false
vim.wo[state.winnr][0].number = false
vim.wo[state.winnr][0].relativenumber = false
vim.wo[state.winnr][0].winfixheight = true
vim.wo[state.winnr][0].cursorlineopt = "line"
vim.wo[state.winnr][0].cursorline = true
vim.wo[state.winnr][0].statuscolumn = ""
vim.wo[state.winnr][0].foldcolumn = "0"

vim.bo[state.bufnr].buftype = "nofile"
vim.bo[state.bufnr].swapfile = false
end

return M
Loading

0 comments on commit 36f8d4d

Please sign in to comment.