Skip to content

Commit c626b7b

Browse files
committed
feat(threads): custom formatting
1 parent 6ccf536 commit c626b7b

File tree

7 files changed

+121
-27
lines changed

7 files changed

+121
-27
lines changed

docs/sidebar.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ export const sidebar = {
5757
title: "Advanced 'switchbuf'",
5858
to: '/advanced-switchbuf'
5959
},
60+
{
61+
title: 'Custom Formatting',
62+
to: '/custom-formatting'
63+
},
64+
{
65+
title: 'Custom Views',
66+
to: '/custom-views'
67+
},
6068
{
6169
title: "Dynamic Layout",
6270
to: '/dynamic-layout',
@@ -65,10 +73,6 @@ export const sidebar = {
6573
title: 'Hide Terminal',
6674
to: '/hide-terminal'
6775
},
68-
{
69-
title: 'Custom Views',
70-
to: '/custom-views'
71-
},
7276
{
7377
title: 'Restoring Sessions',
7478
to: '/restoring-sessions'
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Custom Formatting
3+
category: Recipes
4+
---
5+
6+
You can control how the text is displayed for some views, using special `format` functions. Each customizable view has its own parameters, but the expected return type is the same: an array of `{part: string, hl?: string}`. The `part` is the "content" itself, and `hl` is one of `nvim-dap-view`'s [highlight groups](./highlight-groups) (without the `NvimDapView` prefix).
7+
8+
## Threads
9+
10+
You can manipulate the frame _name_ (usually the function name), its line and path.
11+
12+
### Examples
13+
14+
#### Display just the file name, instead of relative path
15+
16+
```lua
17+
return {
18+
render = {
19+
threads = {
20+
format = function(name, line, path)
21+
return {
22+
{ part = name, separator = " " },
23+
-- See :h filename-modifiers
24+
{ part = vim.fn.fnamemodify(buf_name, ":t"), hl = "FileName", separator = ":" },
25+
{ part = line, hl = "LineNumber" },
26+
}
27+
end,
28+
},
29+
},
30+
}
31+
```
32+
33+
#### Restore pre v1.0.0 behavior
34+
35+
```lua
36+
return {
37+
render = {
38+
threads = {
39+
format = function(name, line, path)
40+
return {
41+
{ part = path, hl = "FileName" },
42+
{ part = line, hl = "LineNumber" },
43+
{ part = name },
44+
}
45+
end,
46+
},
47+
},
48+
}
49+
```

lua/dap-view/config.lua

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ local M = {}
1010

1111
---@alias dapview.Position 'right' | 'left' | 'above' | 'below'
1212

13+
---@class dapview.Content
14+
---@field part string
15+
---@field hl? string|boolean
16+
---@field separator? string
17+
1318
---@class dapview.TerminalConfig
1419
---@field hide string[] List of adapters for which the terminal should be hidden
1520
---@field position dapview.Position|fun(position: dapview.Position): dapview.Position Can be a function, receiving the main window's position as its argument
@@ -68,8 +73,12 @@ local M = {}
6873
---@class dapview.HelpConfig
6974
---@field border? string|string[] Override `winborder` in the help window
7075

76+
---@class dapview.RenderThreadsConfig
77+
---@field format fun(name: string, line: string, path: string): dapview.Content[]
78+
7179
---@class dapview.RenderConfig
7280
---@field sort_variables? fun(lhs: dap.Variable, rhs: dap.Variable): boolean Override order of variables
81+
---@field threads dapview.RenderThreadsConfig
7382

7483
---@class (exact) dapview.ConfigStrict
7584
---@field winbar dapview.WinbarConfig
@@ -175,6 +184,15 @@ M.config = {
175184
},
176185
render = {
177186
sort_variables = nil,
187+
threads = {
188+
format = function(name, line, path)
189+
return {
190+
{ part = name, separator = " " },
191+
{ part = path, hl = "FileName", separator = ":" },
192+
{ part = line, hl = "LineNumber" },
193+
}
194+
end,
195+
},
178196
},
179197
switchbuf = "usetab,uselast",
180198
auto_toggle = false,

lua/dap-view/listeners.lua

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
local dap = require("dap")
22

33
local state = require("dap-view.state")
4-
local breakpoints = require("dap-view.breakpoints.view")
54
local util = require("dap-view.util")
65
local term = require("dap-view.console.view")
76
local setup = require("dap-view.setup")

lua/dap-view/setup/validate/render.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ function M.validate(config)
66

77
validate("render", {
88
sort_variables = { config.sort_variables, { "function", "nil" } },
9+
threads = { config.threads, { "table" } },
910
}, config)
11+
12+
local threads = config.threads
13+
validate("render.threads", {
14+
format = { threads.format, { "function" } },
15+
}, threads)
1016
end
1117

1218
return M

lua/dap-view/threads/view.lua

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ local setup = require("dap-view.setup")
88

99
local M = {}
1010

11-
---@class dapview.Label
12-
---@field labels {part: string, hl?: string}[]
13-
---@field id string
11+
---@class dapview.Frame
12+
---@field path string
13+
---@field line string
14+
---@field name string
15+
---@field id number
16+
17+
---@class dapview.FrameContent
18+
---@field content dapview.Content[]
19+
---@field id number
1420

1521
M.show = function()
1622
-- We have to check if the win is valid, since this function may be triggered by an event when the window is closed
@@ -45,17 +51,18 @@ M.show = function()
4551
end
4652

4753
local line = 0
54+
local config = setup.config
4855

4956
if state.threads_filter ~= "" then
50-
local filter = setup.config.icons["filter"] .. " "
57+
local filter = config.icons["filter"] .. " "
5158
local filter_icon_len = #filter
5259

5360
filter = filter .. state.threads_filter
5461

5562
local omit_icon_len = 0
5663

5764
if state.threads_filter_invert then
58-
local omit_icon = " " .. setup.config.icons["negate"]
65+
local omit_icon = " " .. config.icons["negate"]
5966
omit_icon_len = #omit_icon
6067
filter = filter .. omit_icon
6168
end
@@ -75,13 +82,14 @@ M.show = function()
7582

7683
for k, thread in pairs(session.threads) do
7784
local is_stopped_thread = session.stopped_thread_id == thread.id
78-
local thread_name = is_stopped_thread and thread.name .. " " .. setup.config.icons["pause"] or thread.name
85+
local thread_name = is_stopped_thread and thread.name .. " " .. config.icons["pause"] or thread.name
7986
util.set_lines(state.bufnr, line, line, true, { thread_name })
8087

8188
hl.hl_range(is_stopped_thread and "ThreadStopped" or "Thread", { line, 0 }, { line, -1 })
8289

8390
line = line + 1
8491

92+
---@type dap.StackFrame[]
8593
local valid_frames = vim.iter(thread.frames or {})
8694
:filter(
8795
---@param f dap.StackFrame
@@ -99,7 +107,7 @@ M.show = function()
99107
line = line + 1
100108
end
101109
else
102-
---@type dapview.Label[]
110+
---@type dapview.Frame[]
103111
local frames = vim.iter(valid_frames):fold(
104112
{},
105113
---@param acc string[]
@@ -116,25 +124,31 @@ M.show = function()
116124
state.frame_line_by_frame_id[f.id] = f.line
117125

118126
table.insert(acc, {
119-
labels = {
120-
{ part = relative_path, hl = "FileName" },
121-
{ part = tostring(f.line), hl = "LineNumber" },
122-
{ part = f.name },
123-
},
127+
path = relative_path,
128+
line = tostring(f.line),
129+
name = f.name,
124130
id = f.id,
125131
})
126132
end
127133
return acc
128134
end
129135
)
130136

131-
---@type dapview.Label[]
132-
local filtered_frames = vim.iter(frames)
137+
local formated_frames = vim.iter(frames):map(
138+
---@param frame dapview.Frame
139+
function(frame)
140+
local format = config.render.threads.format(frame.name, frame.line, frame.path)
141+
return { content = format, id = frame.id }
142+
end
143+
)
144+
145+
---@type dapview.FrameContent[]
146+
local filtered_frames = formated_frames
133147
:filter(
134-
---@param f dapview.Label
148+
---@param f dapview.FrameContent
135149
function(f)
136150
local label = ""
137-
for _, l in ipairs(f.labels) do
151+
for _, l in ipairs(f.content) do
138152
label = label .. l.part
139153
end
140154
local match = label:match(state.threads_filter)
@@ -147,13 +161,13 @@ M.show = function()
147161
---@type string[]
148162
local content = vim.iter(filtered_frames)
149163
:map(
150-
---@param f dapview.Label
164+
---@param f dapview.FrameContent
151165
function(f)
152166
local label = "\t"
153-
for n, l in ipairs(f.labels) do
167+
for n, l in ipairs(f.content) do
154168
label = label .. l.part
155-
if n ~= #f.labels then
156-
label = label .. "|"
169+
if n ~= #f.content then
170+
label = label .. (l.separator or "|")
157171
end
158172
end
159173
return label
@@ -170,10 +184,11 @@ M.show = function()
170184
hl.hl_range("FrameCurrent", { actual_line, 0 }, { actual_line, -1 })
171185
else
172186
local hl_init = 1
173-
for _, p in ipairs(f.labels) do
187+
for _, p in ipairs(f.content) do
174188
local hl_end = hl_init + #p.part
175189

176-
if p.hl then
190+
if type(p.hl) == "string" then
191+
---@cast p {hl: string}
177192
hl.hl_range(p.hl, { actual_line, hl_init }, { actual_line, hl_end })
178193
end
179194

lua/dap-view/types.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
---@field base_sections? table<dapview.Section,dapview.SectionConfigPartial>
1414
---@field controls? dapview.ControlsConfigPartial
1515

16+
---@class dapview.RenderConfigPartial : dapview.RenderConfig, {}
17+
---@field threads? dapview.RenderThreadsConfig
18+
1619
---@class dapview.HelpConfigPartial : dapview.HelpConfig, {}
1720

1821
---@class dapview.RenderConfigPartial : dapview.RenderConfig, {}

0 commit comments

Comments
 (0)