Skip to content

Commit

Permalink
feat: item hierarchies and directory grouping
Browse files Browse the repository at this point in the history
  • Loading branch information
folke committed May 30, 2024
1 parent de08657 commit d2ed413
Show file tree
Hide file tree
Showing 13 changed files with 465 additions and 153 deletions.
85 changes: 68 additions & 17 deletions lua/trouble/config/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,9 @@ local defaults = {
auto_close = false,
auto_preview = true,
pinned = false,
---@type trouble.Render.opts
render = {
multiline = true, -- render multi-line messages
-- stylua: ignore
---@type trouble.Indent.symbols
indent = {
top = "",
middle = "├╴",
last = "└╴",
-- last = "╰╴", -- rounded
fold_open = "",
fold_closed = "",
ws = " ",
},
---@type table<string, trouble.Formatter>
formatters = {}, -- custom formatters
},
multiline = true, -- render multi-line messages
---@type table<string, trouble.Formatter>
formatters = {}, -- custom formatters
---@type table<string, trouble.FilterFn>
filters = {}, -- custom filters
---@type table<string, trouble.SorterFn>
Expand Down Expand Up @@ -79,6 +65,71 @@ local defaults = {
mode = "diagnostics",
filter = { buf = 0 },
},
symbols = {
mode = "lsp_document_symbols",
win = { position = "right" },
filter = {
kind = {
"Class",
"Constructor",
"Enum",
"Field",
"Function",
"Interface",
"Method",
"Module",
"Namespace",
"Package", -- remove package since luals uses it for control flow structures
"Property",
"Struct",
"Trait",
},
},
},
},
-- stylua: ignore
icons = {
---@type trouble.Indent.symbols
indent = {
top = "",
middle = "├╴",
last = "└╴",
-- last = "-╴",
-- last = "╰╴", -- rounded
fold_open = "",
fold_closed = "",
ws = " ",
},
folder_closed = "",
folder_open = "",
kinds = {
Array = "",
Boolean = "󰨙 ",
Class = "",
Constant = "󰏿 ",
Constructor = "",
Enum = "",
EnumMember = "",
Event = "",
Field = "",
File = "",
Function = "󰊕 ",
Interface = "",
Key = "",
Method = "󰊕 ",
Module = "",
Namespace = "󰦮 ",
Null = "",
Number = "󰎠 ",
Object = "",
Operator = "",
Package = "",
Property = "",
String = "",
Struct = "󰆼 ",
TypeParameter = "",
Variable = "󰀫 ",
},
},
}

Expand Down
4 changes: 4 additions & 0 deletions lua/trouble/filter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ M.filters = {
end
return false
end,
kind = function(item, kind, view)
kind = type(kind) == "table" and kind or { kind }
return vim.tbl_contains(kind, item.kind)
end,
}

---@param item trouble.Item
Expand Down
39 changes: 35 additions & 4 deletions lua/trouble/format.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local M = {}
---@alias trouble.Format {text:string, hl?:string}

---@alias trouble.Formatter fun(ctx: trouble.Formatter.ctx): trouble.spec.format?
---@alias trouble.Formatter.ctx {item: trouble.Item, node:trouble.Node, field:string, value:string, opts:trouble.Render.opts}
---@alias trouble.Formatter.ctx {item: trouble.Item, node:trouble.Node, field:string, value:string, view:trouble.View}

---@param source string
---@param field string
Expand Down Expand Up @@ -76,7 +76,7 @@ M.formatters = {
end,
count = function(ctx)
return {
text = (" %d "):format(ctx.node.count or 0),
text = (" %d "):format(ctx.node:count()),
}
end,
filename = function(ctx)
Expand All @@ -89,6 +89,35 @@ M.formatters = {
text = vim.fn.fnamemodify(ctx.item.dirname, ":p:~:."),
}
end,
kind_icon = function(ctx)
if not ctx.item.kind then
return
end
local icon = ctx.view.opts.icons.kinds[ctx.item.kind]
if icon then
return {
text = icon,
hl = "TroubleIcon" .. ctx.item.kind,
}
end
end,
directory = function(ctx)
if ctx.node:source() == "fs" then
local directory = ctx.item.directory or ""
local parent = ctx.node:parent_item()
if parent and parent.directory then
directory = directory:sub(#parent.directory + 1)
return { text = directory, hl = "TroubleDirectory" }
end
return { text = vim.fn.fnamemodify(directory, ":~"), hl = "TroubleDirectory" }
end
end,
directory_icon = function(ctx)
if ctx.node:source() == "fs" then
local text = ctx.node.folded and ctx.view.opts.icons.folder_closed or ctx.view.opts.icons.folder_open
return { text = text, hl = "TroubleIconDirectory" }
end
end,
}
M.formatters.severity_icon = M.cached_formatter(M.formatters.severity_icon, "severity")
M.formatters.severity = M.cached_formatter(M.formatters.severity, "severity")
Expand All @@ -98,7 +127,9 @@ function M.field(ctx)
---@type trouble.Format[]
local format = { { fi = ctx.field, text = vim.trim(tostring(ctx.item[ctx.field] or "")) } }

local formatter = ctx.opts and ctx.opts.formatters and ctx.opts.formatters[ctx.field] or M.formatters[ctx.field]
local opts = ctx.view.opts

local formatter = opts.formatters and opts.formatters[ctx.field] or M.formatters[ctx.field]

if formatter then
local result = formatter(ctx)
Expand All @@ -120,7 +151,7 @@ function M.field(ctx)
end

---@param format string
---@param ctx {item: trouble.Item, node:trouble.Node, opts:trouble.Render.opts}
---@param ctx {item: trouble.Item, node:trouble.Node, view:trouble.View}
function M.format(format, ctx)
---@type trouble.Format[]
local ret = {}
Expand Down
45 changes: 36 additions & 9 deletions lua/trouble/item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ local Util = require("trouble.util")
---@alias trouble.Pos {[1]:number, [2]:number}

---@class trouble.Item: {[string]: any}
---@field idx? number
---@field id? string
---@field parent? trouble.Item
---@field buf number
---@field filename string
---@field pos trouble.Pos (1,0)-indexed
Expand All @@ -16,22 +17,31 @@ local M = {}

---@param opts trouble.Item | {filename?:string}
function M.new(opts)
local self = setmetatable(opts, M)
local self = opts
assert(self.buf, "buf is required")
assert(self.source, "source is required")
self.pos = self.pos or { 1, 0 }
self.end_pos = self.end_pos or self.pos
self.item = self.item or {}
self.filename = self.filename or vim.fn.bufname(self.buf)
self.filename = vim.fn.fnamemodify(self.filename, ":p")
self.basename = vim.fn.fnamemodify(self.filename, ":t")
self.dirname = vim.fn.fnamemodify(self.filename, ":h")
self.dirname = self.dirname or vim.fn.fnamemodify(self.filename, ":h")
self.cache = Cache.new("item")
return self
return setmetatable(self, M)
end

function M:__index(k)
if type(k) ~= "string" then
return
end
if M[k] then
return M[k]
end
local item = rawget(self, "item")
---@cast k string
if self.item[k] ~= nil then
return self.item[k]
if item and item[k] ~= nil then
return item[k]
end

local obj = self
Expand All @@ -52,8 +62,16 @@ function M:__index(k)
end
end

---@param item trouble.Item
function M:add_child(item)
item.parent = self
end

---@param items trouble.Item[]
function M.add_text(items)
---@param opts? {mode?:"range"|"full"|"after", multiline?:boolean}
function M.add_text(items, opts)
opts = opts or {}
opts.mode = opts.mode or "range"
local buf_rows = {} ---@type table<number, number[]>

for _, item in ipairs(items) do
Expand All @@ -62,6 +80,9 @@ function M.add_text(items)
buf_rows[item.buf] = buf_rows[item.buf] or {}
for r = item.pos[1], item.end_pos and item.end_pos[1] or item.pos[1] do
table.insert(buf_rows[item.buf], r)
if not opts.multiline then
break
end
end
end
end
Expand All @@ -77,13 +98,19 @@ function M.add_text(items)
for row = item.pos[1], item.end_pos[1] do
local line = buf_lines[item.buf][row] or ""
if row == item.pos[1] and row == item.end_pos[1] then
line = line
if opts.mode == "after" then
line = line:sub(item.pos[2] + 1)
elseif opts.mode == "range" then
line = line:sub(item.pos[2] + 1, item.end_pos[2])
end
elseif row == item.pos[1] then
line = line:sub(item.pos[2] + 1)
elseif row == item.end_pos[1] then
line = line:sub(1, item.end_pos[2]) --[[@as string]]
end
lines[#lines + 1] = line
if line ~= "" then
lines[#lines + 1] = line
end
end
item.item.text = table.concat(lines, "\n")
end
Expand Down
35 changes: 24 additions & 11 deletions lua/trouble/spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
---@field groups? trouble.Group.spec[]|trouble.Group.spec
---@field sort? trouble.Sort.spec
---@field filter? trouble.Filter.spec
---@field flatten? boolean when true, items with a natural hierarchy will be flattened
---@field format? string
---@field max_items? number

Expand All @@ -25,13 +26,15 @@
---@field desc? boolean

---@class trouble.Group
---@field fields string[]
---@field format string
---@field fields? string[]
---@field format? string
---@field directory? boolean

---@class trouble.Section
---@field source string
---@field groups trouble.Group[]
---@field format string
---@field flatten? boolean when true, items with a natural hierarchy will be flattened
---@field events? string[]
---@field sort? trouble.Sort[]
---@field filter? trouble.Filter
Expand All @@ -51,6 +54,7 @@ function M.section(spec)
filter = spec.filter,
format = spec.format or "{filename} {pos}",
events = spec.events,
flatten = spec.flatten,
}
-- A title is just a group without fields
if spec.title then
Expand Down Expand Up @@ -107,19 +111,28 @@ function M.group(spec)
ret.fields[#ret.fields + 1] = v
elseif k == "format" then
---@cast v string
ret.format = v
ret[k] = v
else
error("invalid `group` key: " .. k)
end
end
ret.format = ret.format and ret.format ~= "" and ret.format
or table.concat(
---@param f string
vim.tbl_map(function(f)
return "{" .. f .. "}"
end, ret.fields),
" "
)
ret.directory = vim.tbl_contains(ret.fields, "directory")
if ret.directory and #ret.fields > 1 then
error("group: cannot specify other fields with `directory`")
end
if ret.format == "" then
if ret.directory then
ret.format = "{directory_icon} {directory} {count}"
else
ret.format = table.concat(
---@param f string
vim.tbl_map(function(f)
return "{" .. f .. "}"
end, ret.fields),
" "
)
end
end
return ret
end

Expand Down
Loading

0 comments on commit d2ed413

Please sign in to comment.