folke / trouble.nvim

🚦 A pretty diagnostics, references, telescope results, quickfix and location list to help you solve all the trouble your code is causing.
Apache License 2.0
5.63k stars 177 forks source link
lua neovim neovim-lsp neovim-lua neovim-plugin

🚦 Trouble

A pretty list for showing diagnostics, references, telescope results, quickfix and location lists to help you solve all the trouble your code is causing.

image

✨ Features

📰 What's new?

This is a full rewrite of the original trouble.nvim.

The new version is much more flexible and powerful, with a lot of new features and improvements:

⚡️ Requirements

📦 Installation

Install the plugin with your preferred package manager:

lazy.nvim

{
  "folke/trouble.nvim",
  opts = {}, -- for default options, refer to the configuration section for custom setup.
  cmd = "Trouble",
  keys = {
    {
      "<leader>xx",
      "<cmd>Trouble diagnostics toggle<cr>",
      desc = "Diagnostics (Trouble)",
    },
    {
      "<leader>xX",
      "<cmd>Trouble diagnostics toggle filter.buf=0<cr>",
      desc = "Buffer Diagnostics (Trouble)",
    },
    {
      "<leader>cs",
      "<cmd>Trouble symbols toggle focus=false<cr>",
      desc = "Symbols (Trouble)",
    },
    {
      "<leader>cl",
      "<cmd>Trouble lsp toggle focus=false win.position=right<cr>",
      desc = "LSP Definitions / references / ... (Trouble)",
    },
    {
      "<leader>xL",
      "<cmd>Trouble loclist toggle<cr>",
      desc = "Location List (Trouble)",
    },
    {
      "<leader>xQ",
      "<cmd>Trouble qflist toggle<cr>",
      desc = "Quickfix List (Trouble)",
    },
  },
}

⚙️ Configuration

Setup

Trouble is highly configurable. Please refer to the default settings below.

Default Settings ```lua ---@class trouble.Mode: trouble.Config,trouble.Section.spec ---@field desc? string ---@field sections? string[] ---@class trouble.Config ---@field mode? string ---@field config? fun(opts:trouble.Config) ---@field formatters? table custom formatters ---@field filters? table custom filters ---@field sorters? table custom sorters local defaults = { auto_close = false, -- auto close when there are no items auto_open = false, -- auto open when there are items auto_preview = true, -- automatically open preview when on an item auto_refresh = true, -- auto refresh when open auto_jump = false, -- auto jump to the item when there's only one focus = false, -- Focus the window when opened restore = true, -- restores the last location in the list when opening follow = true, -- Follow the current item indent_guides = true, -- show indent guides max_items = 200, -- limit number of items that can be displayed per section multiline = true, -- render multi-line messages pinned = false, -- When pinned, the opened trouble window will be bound to the current buffer warn_no_results = true, -- show a warning when there are no results open_no_results = false, -- open the trouble window when there are no results ---@type trouble.Window.opts win = {}, -- window options for the results window. Can be a split or a floating window. -- Window options for the preview window. Can be a split, floating window, -- or `main` to show the preview in the main editor window. ---@type trouble.Window.opts preview = { type = "main", -- when a buffer is not yet loaded, the preview window will be created -- in a scratch buffer with only syntax highlighting enabled. -- Set to false, if you want the preview to always be a real loaded buffer. scratch = true, }, -- Throttle/Debounce settings. Should usually not be changed. ---@type table throttle = { refresh = 20, -- fetches new data when needed update = 10, -- updates the window render = 10, -- renders the window follow = 100, -- follows the current item preview = { ms = 100, debounce = true }, -- shows the preview for the current item }, -- Key mappings can be set to the name of a builtin action, -- or you can define your own custom action. ---@type table keys = { ["?"] = "help", r = "refresh", R = "toggle_refresh", q = "close", o = "jump_close", [""] = "cancel", [""] = "jump", ["<2-leftmouse>"] = "jump", [""] = "jump_split", [""] = "jump_vsplit", -- go down to next item (accepts count) -- j = "next", ["}"] = "next", ["]]"] = "next", -- go up to prev item (accepts count) -- k = "prev", ["{"] = "prev", ["[["] = "prev", dd = "delete", d = { action = "delete", mode = "v" }, i = "inspect", p = "preview", P = "toggle_preview", zo = "fold_open", zO = "fold_open_recursive", zc = "fold_close", zC = "fold_close_recursive", za = "fold_toggle", zA = "fold_toggle_recursive", zm = "fold_more", zM = "fold_close_all", zr = "fold_reduce", zR = "fold_open_all", zx = "fold_update", zX = "fold_update_all", zn = "fold_disable", zN = "fold_enable", zi = "fold_toggle_enable", gb = { -- example of a custom action that toggles the active view filter action = function(view) view:filter({ buf = 0 }, { toggle = true }) end, desc = "Toggle Current Buffer Filter", }, s = { -- example of a custom action that toggles the severity action = function(view) local f = view:get_filter("severity") local severity = ((f and f.filter.severity or 0) + 1) % 5 view:filter({ severity = severity }, { id = "severity", template = "{hl:Title}Filter:{hl} {severity}", del = severity == 0, }) end, desc = "Toggle Severity Filter", }, }, ---@type table modes = { -- sources define their own modes, which you can use directly, -- or override like in the example below lsp_references = { -- some modes are configurable, see the source code for more details params = { include_declaration = true, }, }, -- The LSP base mode for: -- * lsp_definitions, lsp_references, lsp_implementations -- * lsp_type_definitions, lsp_declarations, lsp_command lsp_base = { params = { -- don't include the current location in the results include_current = false, }, }, -- more advanced example that extends the lsp_document_symbols symbols = { desc = "document symbols", mode = "lsp_document_symbols", focus = false, win = { position = "right" }, filter = { -- remove Package since luals uses it for control flow structures ["not"] = { ft = "lua", kind = "Package" }, any = { -- all symbol kinds for help / markdown files ft = { "help", "markdown" }, -- default set of symbol kinds kind = { "Class", "Constructor", "Enum", "Field", "Function", "Interface", "Method", "Module", "Namespace", "Package", "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 = "󰀫 ", }, }, } ```

Make sure to check the Examples!

🚀 Usage

Commands

The Trouble command is a wrapper around the Trouble API. It can do anything the regular API can do.

Some examples:

Please refer to the API section for more information on the available actions and options.

Modes:

Filters

Please refer to the filter docs for more information examples on filters.

API

You can use the following functions in your keybindings:

API ```lua -- Opens trouble with the given mode. -- If a view is already open with the same mode, -- it will be focused unless `opts.focus = false`. -- When a view is already open and `opts.new = true`, -- a new view will be created. ---@param opts? trouble.Mode | { new?: boolean, refresh?: boolean } | string ---@return trouble.View? require("trouble").open(opts) -- Closes the last open view matching the filter. ---@param opts? trouble.Mode|string ---@return trouble.View? require("trouble").close(opts) -- Toggle the view with the given mode. ---@param opts? trouble.Mode|string ---@return trouble.View? require("trouble").toggle(opts) -- Returns true if there is an open view matching the mode. ---@param opts? trouble.Mode|string require("trouble").is_open(opts) -- Refresh all open views. Normally this is done automatically, -- unless you disabled auto refresh. ---@param opts? trouble.Mode|string require("trouble").refresh(opts) -- Get all items from the active view for a given mode. ---@param opts? trouble.Mode|string require("trouble").get_items(opts) -- Renders a trouble list as a statusline component. -- Check the docs for examples. ---@param opts? trouble.Mode|string|{hl_group?:string} ---@return {get: (fun():string), has: (fun():boolean)} require("trouble").statusline(opts) -- Closes the preview and goes to the main window. -- The Trouble window is not closed. ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").cancel(opts) -- Open the preview ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").delete(opts) -- filter ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").filter(opts) -- Go to the first item ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").first(opts) -- Focus the trouble window ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").focus(opts) -- Fold close ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_close(opts) -- fold close all ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_close_all(opts) -- Fold close recursive ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_close_recursive(opts) -- fold disable ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_disable(opts) -- fold enable ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_enable(opts) -- fold more ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_more(opts) -- Fold open ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_open(opts) -- fold open all ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_open_all(opts) -- Fold open recursive ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_open_recursive(opts) -- fold reduce ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_reduce(opts) -- Fold toggle ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_toggle(opts) -- fold toggle enable ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_toggle_enable(opts) -- Fold toggle recursive ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_toggle_recursive(opts) -- fold update ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_update(opts) -- fold update all ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").fold_update_all(opts) -- Show the help ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").help(opts) -- Dump the item to the console ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").inspect(opts) -- Jump to the item if on an item, otherwise fold the node ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump(opts) -- Jump to the item and close the trouble window ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_close(opts) -- Jump to the item if on an item, otherwise do nothing ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_only(opts) -- Open the item in a split ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_split(opts) -- Open the item in a split and close the trouble window ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_split_close(opts) -- Open the item in a vsplit ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_vsplit(opts) -- Open the item in a vsplit and close the trouble window ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").jump_vsplit_close(opts) -- Go to the last item ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").last(opts) -- Go to the next item ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").next(opts) -- Go to the previous item ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").prev(opts) -- Open the preview ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").preview(opts) -- Refresh the trouble source ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").refresh(opts) -- Toggle the preview ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").toggle_preview(opts) -- Toggle the auto refresh ---@param opts? trouble.Mode | { new? : boolean } | string ---@return trouble.View require("trouble").toggle_refresh(opts) ```

Telescope

You can easily open any search results in Trouble, by defining a custom action:

local actions = require("telescope.actions")
local open_with_trouble = require("trouble.sources.telescope").open

-- Use this to add more results without clearing the trouble list
local add_to_trouble = require("trouble.sources.telescope").add

local telescope = require("telescope")

telescope.setup({
  defaults = {
    mappings = {
      i = { ["<c-t>"] = open_with_trouble },
      n = { ["<c-t>"] = open_with_trouble },
    },
  },
})

When you open telescope, you can now hit <c-t> to open the results in Trouble

fzf-lua

You can easily open any search results in Trouble, by defining a custom action:

local config = require("fzf-lua.config")
local actions = require("trouble.sources.fzf").actions
config.defaults.actions.files["ctrl-t"] = actions.open

When you open fzf-lua, you can now hit <c-t> to open the results in Trouble

Statusline Component

Example for lualine.nvim:

{
  "nvim-lualine/lualine.nvim",
  opts = function(_, opts)
    local trouble = require("trouble")
    local symbols = trouble.statusline({
      mode = "lsp_document_symbols",
      groups = {},
      title = false,
      filter = { range = true },
      format = "{kind_icon}{symbol.name:Normal}",
      -- The following line is needed to fix the background color
      -- Set it to the lualine section you want to use
      hl_group = "lualine_c_normal",
    })
    table.insert(opts.sections.lualine_c, {
      symbols.get,
      cond = symbols.has,
    })
  end,
}

🎨 Colors

The table below shows all the highlight groups defined for Trouble.

Highlight Groups | Highlight Group | Default Group | Description | | --- | --- | --- | | **TroubleBasename** | ***TroubleFilename*** | | | **TroubleCode** | ***Special*** | | | **TroubleCount** | ***TabLineSel*** | | | **TroubleDirectory** | ***Directory*** | | | **TroubleFilename** | ***Directory*** | | | **TroubleIconArray** | ***@punctuation.bracket*** | | | **TroubleIconBoolean** | ***@boolean*** | | | **TroubleIconClass** | ***@type*** | | | **TroubleIconConstant** | ***@constant*** | | | **TroubleIconConstructor** | ***@constructor*** | | | **TroubleIconDirectory** | ***Special*** | | | **TroubleIconEnum** | ***@lsp.type.enum*** | | | **TroubleIconEnumMember** | ***@lsp.type.enumMember*** | | | **TroubleIconEvent** | ***Special*** | | | **TroubleIconField** | ***@variable.member*** | | | **TroubleIconFile** | ***Normal*** | | | **TroubleIconFunction** | ***@function*** | | | **TroubleIconInterface** | ***@lsp.type.interface*** | | | **TroubleIconKey** | ***@lsp.type.keyword*** | | | **TroubleIconMethod** | ***@function.method*** | | | **TroubleIconModule** | ***@module*** | | | **TroubleIconNamespace** | ***@module*** | | | **TroubleIconNull** | ***@constant.builtin*** | | | **TroubleIconNumber** | ***@number*** | | | **TroubleIconObject** | ***@constant*** | | | **TroubleIconOperator** | ***@operator*** | | | **TroubleIconPackage** | ***@module*** | | | **TroubleIconProperty** | ***@property*** | | | **TroubleIconString** | ***@string*** | | | **TroubleIconStruct** | ***@lsp.type.struct*** | | | **TroubleIconTypeParameter** | ***@lsp.type.typeParameter*** | | | **TroubleIconVariable** | ***@variable*** | | | **TroubleIndent** | ***LineNr*** | | | **TroubleIndentFoldClosed** | ***CursorLineNr*** | | | **TroubleIndentFoldOpen** | ***TroubleIndent*** | | | **TroubleIndentLast** | ***TroubleIndent*** | | | **TroubleIndentMiddle** | ***TroubleIndent*** | | | **TroubleIndentTop** | ***TroubleIndent*** | | | **TroubleIndentWs** | ***TroubleIndent*** | | | **TroubleNormal** | ***NormalFloat*** | | | **TroubleNormalNC** | ***NormalFloat*** | | | **TroublePos** | ***LineNr*** | | | **TroublePreview** | ***Visual*** | | | **TroubleSource** | ***Comment*** | | | **TroubleText** | ***Normal*** | |