Namu.nvim

September 24, 2025 Β· View on GitHub

🌿 Jump to symbols in your code with live preview, built-in fuzzy finding, and more. Inspired by Zed, it preserves symbol order while guiding you through your codebase. Supports LSP, Treesitter, ctags, and works across buffers and workspaces.

Warning

🚧 Beta: This plugin is in beta. Breaking changes may occur.

https://github.com/user-attachments/assets/a97ff3b1-8b25-4da1-b276-f623e37d0368

🧩 Built-in Modules

ModuleDescription
🏷️ symbolsLSP symbols for current buffer
🌐 workspaceLSP workspace symbols, interactive, live preview
πŸ“‚ watchtowerSymbols from all open buffers (LSP or Treesitter)
🩺 diagnosticsDiagnostics for buffer or full workspace, live filter
πŸ”— call_hierarchyCall hierarchy (in/out/both) for symbol
🏷️ ctagsctags-based symbols (buffer or watchtower)
πŸͺŸ ui_selectWrapper for vim.ui.select with enhanced UI

What Makes It Special

  • πŸ” Live Preview: See exactly where you'll land before you jump
  • 🌳 Order Preservation: Maintains symbol order as they appear in your code, even after filtering
  • πŸ—‚οΈ Hierarchy Preservation: Keeps the parent-child structure of your code symbols intact, so you always see context.
  • πŸ“ Smart Auto-resize: Window adapts to your content in real-time as you type and filter, no need for a big window with only a couple of items
  • πŸš€ Zero Dependencies: Works with any LSP-supported language out of the box
  • 🎯 Context Aware: Always shows your current location in the codebase
  • ⚑ Powerful Filtering:
    • Live filtering through /xx such as /fn for fcuntions or /bf: for buffer names if watchtower module.
    • Built-in fuzzy finding that understands code structure
    • Filter by symbol types (functions, classes, methods)
    • Use regex patterns (e.g., ^__ to filter out Python's __init__ methods)
  • 🎨 Quality of Life:
    • Auto-select when only one match remains
    • Remembers cursor position when you cancel
    • Customizable window style and behavior
  • βœ‚οΈ Multi-Action Workflow: Perform multiple operations while Namu is open (or close it after, you choose!):
    • Delete, yank, and add to CodeCompanion chat (more plugins coming soon)
    • Works with both single and multiple selected symbols
  • πŸŒ‘ Initially Hidden Mode: Start with an empty list and populate it dynamically as you type, just like the command palette in Zed and VS Code

Table of Contents

⚑ Requirements

  • LSP server for your language (Treesitter fallback for some modules)
  • Treesitter (for live preview)
  • ctags (for ctags module, optional)

Installation

Lazy.nvim

Using lazy.nvim:

{
    "bassamsdata/namu.nvim",
    opts = {
        global = { },
        namu_symbols = { -- Specific Module options
            options = {},
        },
    },
    -- === Suggested Keymaps: ===
    vim.keymap.set("n", "<leader>ss", ":Namu symbols<cr>", {
        desc = "Jump to LSP symbol",
        silent = true,
    }),
    vim.keymap.set("n", "<leader>sw", ":Namu workspace<cr>", {
        desc = "LSP Symbols - Workspace",
        silent = true,
    })
}
πŸ“¦ Paq.nvim
require "paq" {
  "bassamsdata/namu.nvim"
}
πŸ“¦ Mini.deps
require("mini.deps").add("bassamsdata/namu.nvim")

Features

  • Live kind filtering for all symbol modules (/fn, /me, etc.) and then start type like /fnmain to filter more see demo
  • Filter by buffer name in watchtower: /bf:buffer_name see demo
  • Combine filters: /bf:name:fn (buffer and function) see demo
  • Diagnostics filtering: /er (errors), /wa (warnings), /hi (hints), /in (info) see demo
  • Two display styles: tree_guides or indent [see pictures](## Display Styles)
  • Configurable prefix icon for current item
  • All operations are asynchronous (non-blocking)
  • No dependencies except Neovim, LSP, and optional ctags
  • Hierarchy Preservation: Keeps the parent-child structure of your code symbols intact, so you always see context.

Keymaps

Show keymaps
KeyAction
<CR>Select item
<Esc>Close picker
<C-n>Next item
<C-p>Previous item
<Tab>Toggle multiselect
<C-a>Select all
<C-l>Clear all
<C-y>Yank symbol(s)
<C-d>Delete symbol(s)
<C-v>Open symbol in vertical split
<C-h>Open symbol in horizontal split
<C-o>Add symbol(s) to CodeCompanion chat

Change Keymaps:

change the default keymaps:
-- in namu_symbols.options
  movement = {
    next = { "<C-n>", "<DOWN>" }, -- Support multiple keys
    previous = { "<C-p>", "<UP>" }, -- Support multiple keys
    close = { "<ESC>" }, -- close mapping
    select = { "<CR>" }, -- select mapping
    delete_word = {}, -- delete word mapping
    clear_line = {}, -- clear line mapping
  },
  multiselect = {
    enabled = false,
    indicator = "●", -- or "βœ“"β—‰
    keymaps = {
      toggle = "<Tab>",
      select_all = "<C-a>",
      clear_all = "<C-l>",
      untoggle = "<S-Tab>",
    },
    max_items = nil, -- No limit by default
  },
  custom_keymaps = {
    yank = {
      keys = { "<C-y>" }, -- yank symbol text
    },
    delete = {
      keys = { "<C-d>" }, -- delete symbol text
    },
    vertical_split = {
      keys = { "<C-v>" }, -- open in vertical split
    },
    horizontal_split = {
      keys = { "<C-h>" }, -- open in horizontal split
    },
    codecompanion = {
      keys = "<C-o>", -- Add symbols to CodeCompanion
    },
    avante = {
      keys = "<C-t>", -- Add symbol to Avante
    },
  },

Commands

CommandArgumentsDescription
:Namu symbolsfunction, class, method…Show buffer symbols, filter by kind
:Namu workspaceSearch workspace symbols
:Namu watchtowerSymbols from all open buffers, it fallbacks to treesitter
:Namu diagnosticsbuffers, workspaceDiagnostics for buffer or workspace (not only open buffers)
:Namu call in/out/bothin/out/bothCall hierarchy for symbol
:Namu ctags [watchtower]watchtowerctags symbols (buffer or watchtower)
:Namu help [topic]symbols/analysisShow help

Make It Yours

You can check the configuration documentation for details on each option.

Here's the full setup with defaults:
{ -- Those are the default options
  "bassamsdata/namu.nvim",
    opts = {
      -- Enable symbols navigator which is the default
      namu_symbols = {
        enable = true,
        ---@type NamuConfig
        options = {
          AllowKinds = {
            default = {
              "Function",
              "Method",
              "Class",
              "Module",
              "Property",
              "Variable",
              -- "Constant",
              -- "Enum",
              -- "Interface",
              -- "Field",
              -- "Struct",
            },
            go = {
              "Function",
              "Method",
              "Struct", -- For struct definitions
              "Field", -- For struct fields
              "Interface",
              "Constant",
              -- "Variable",
              "Property",
              -- "TypeParameter", -- For type parameters if using generics
            },
            lua = { "Function", "Method", "Table", "Module" },
            python = { "Function", "Class", "Method" },
            -- Filetype specific
            yaml = { "Object", "Array" },
            json = { "Module" },
            toml = { "Object" },
            markdown = { "String" },
          },
          BlockList = {
            default = {},
            -- Filetype-specific
            lua = {
              "^vim%.", -- anonymous functions passed to nvim api
              "%.%.%. :", -- vim.iter functions
              ":gsub", -- lua string.gsub
              "^callback$", -- nvim autocmds
              "^filter$",
              "^map$", -- nvim keymaps
            },
            -- another example:
            -- python = { "^__" }, -- ignore __init__ functions
          },
          display = {
            mode = "icon", -- "icon" or "raw"
            padding = 2,
          },
          -- This is a preset that let's set window without really get into the hassle of tuning window options
          -- top10 meaning top 10% of the window
          row_position = "top10", -- options: "center"|"top10"|"top10_right"|"center_right"|"bottom",
          preview = {
            highlight_on_move = true, -- Whether to highlight symbols as you move through them
            -- still needs implmenting, keep it always now
            highlight_mode = "always", -- "always" | "select" (only highlight when selecting)
          },
          window = {
            auto_size = true,
            min_height = 1,
            min_width = 20,
            max_width = 120,
            max_height = 30,
            padding = 2,
            border = "rounded",
            title_pos = "left",
            show_footer = true,
            footer_pos = "right",
            relative = "editor",
            style = "minimal",
            width_ratio = 0.6,
            height_ratio = 0.6,
            title_prefix = "σ± ¦ ",
          },
          debug = false,
          focus_current_symbol = true,
          auto_select = false,
          initially_hidden = false,
          multiselect = {
            enabled = true,
            indicator = "βœ“", -- or "βœ“"●
            keymaps = {
              toggle = "<Tab>",
              untoggle = "<S-Tab>",
              select_all = "<C-a>",
              clear_all = "<C-l>",
            },
            max_items = nil, -- No limit by default
          },
          actions = {
            close_on_yank = false, -- Whether to close picker after yanking
            close_on_delete = true, -- Whether to close picker after deleting
          },
          movement = {-- Support multiple keys
            next = { "<C-n>", "<DOWN>" },
            previous = { "<C-p>", "<UP>" },
            close = { "<ESC>" }, -- "<C-c>" can be added as well
            select = { "<CR>" },
            delete_word = {}, -- it can assign "<C-w>"
            clear_line = {}, -- it can be "<C-u>"
          },
          custom_keymaps = {
            yank = {
              keys = { "<C-y>" },
              desc = "Yank symbol text",
            },
            delete = {
              keys = { "<C-d>" },
              desc = "Delete symbol text",
            },
            vertical_split = {
              keys = { "<C-v>" },
              desc = "Open in vertical split",
            },
            horizontal_split = {
              keys = { "<C-h>" },
              desc = "Open in horizontal split",
            },
            codecompanion = {
              keys = "<C-o>",
              desc = "Add symbol to CodeCompanion",
            },
            avante = {
              keys = "<C-t>",
              desc = "Add symbol to Avante",
            },
          },
          icon = "σ± ¦", -- σ± ¦ -  -  -- 󰚟
          kindText = {
            Function = "function",
            Class = "class",
            Module = "module",
            Constructor = "constructor",
            Interface = "interface",
            Property = "property",
            Field = "field",
            Enum = "enum",
            Constant = "constant",
            Variable = "variable",
          },
          kindIcons = {
            File = "σ°ˆ™",
            Module = "󰏗",
            Namespace = "σ°Œ—",
            Package = "󰏖",
            Class = "σ°Œ—",
            Method = "󰆧",
            Property = "󰜒",
            Field = "󰜒",
            Constructor = "󰆧",
            Enum = "σ°’»",
            Interface = "σ°•˜",
            Function = "σ°Š•",
            Variable = "󰀫",
            Constant = "󰏿",
            String = "󰀬",
            Number = "󰎠",
            Boolean = "󰨙",
            Array = "σ°…ͺ",
            Object = "σ°…©",
            Key = "σ°Œ‹",
            Null = "󰟒",
            EnumMember = "σ°’»",
            Struct = "σ°Œ—",
            Event = "󰉁",
            Operator = "󰆕",
            TypeParameter = "σ°Š„",
          },
          highlight = "NamuPreview",
          highlights = {
            parent = "NamuParent",
            nested = "NamuNested",
            style = "NamuStyle",
          },
          kinds = {
            prefix_kind_colors = true,
            enable_highlights = true,
            highlights = {
              PrefixSymbol = "NamuPrefixSymbol",
              Function = "NamuSymbolFunction",
              Method = "NamuSymbolMethod",
              Class = "NamuSymbolClass",
              Interface = "NamuSymbolInterface",
              Variable = "NamuSymbolVariable",
              Constant = "NamuSymbolConstant",
              Property = "NamuSymbolProperty",
              Field = "NamuSymbolField",
              Enum = "NamuSymbolEnum",
              Module = "NamuSymbolModule",
            },
          },
        }
      }
      ui_select = { enable = false }, -- vim.ui.select() wrapper
    }
  end,
}

Tips

  • Type to filter symbols - it's fuzzy, so no need to be exact, though it prioritizes exact words first
  • Use regex patterns for precise filtering (e.g., ^test_ for test functions)
  • Press <CR> to jump, <Esc> to cancel

Feature Demos

🌳 Order Preservation Maintains symbol order as they appear in your code, even after filtering

https://github.com/user-attachments/assets/2f84f1b0-3fb7-4d69-81ea-8ec70acb5b80

symbols
  • Shows LSP symbols for current buffer.
  • Filter by kind: :Namu symbols function
  • Live kind filtering: /fn for fucntion , /me for methods, etc.
  • Live preview as you move.

https://github.com/user-attachments/assets/bb2a14da-cba0-4ae7-b826-4ceb1c828b79

workspace
  • Interactive workspace symbol search (LSP).
  • Start typing to see results, live preview.

https://github.com/user-attachments/assets/e548c3ea-6cdb-4f20-9569-175c57b31039

watchtower
  • Shows symbols from all open buffers (LSP or Treesitter fallback).
  • Filter by buffer: /bf:buffer_name
  • Combine with kind: /bf:name:fn

https://github.com/user-attachments/assets/76c637d2-30d3-4f54-9290-510a51dcbe7e

diagnostics
  • Shows diagnostics for buffer or workspace.
  • Filter by severity: /er, /wa, /hi, /in
  • Live preview and navigation.

https://github.com/user-attachments/assets/02dc0ce5-c87a-445f-a477-ac4f411c6592

call_hierarchy
  • Show incoming, outgoing, or both calls for a symbol.
  • Usage: :Namu call in, :Namu call out, :Namu call both

https://github.com/user-attachments/assets/5d30214a-a5d8-46e3-89d4-be71203501e7

ctags
  • Show ctags-based symbols for buffer or watchtower.
  • Requires ctags installed.
  • Usage: :Namu ctags, :Namu ctags watchtower

https://github.com/user-attachments/assets/09ccc178-c067-45bb-8f86-3f8aa183e69d

Display Styles

Show display style examples
  • options.display.format = "tree_guides": tree_guides

  • options.display.format = "indent": indent

Highlights

Show highlight groups
GroupDescription
NamuPrefixPrefix highlight
NamuMatchMatched characters in search
NamuFilterFilter prompt
NamuPromptPrompt window
NamuSelectedSelected item in multiselect
NamuFooterFooter text
NamuCurrentItemCurrent item highlight
NamuPrefixSymbolSymbol prefix
LSP KINDS HIGHLIGHTS-----------------
NamuSymbolFunctionFunction symbol
NamuSymbolMethodMethod symbol
NamuSymbolClassClass symbol
NamuSymbolInterfaceInterface symbol
NamuSymbolVariableVariable symbol
NamuSymbolConstantConstant symbol
NamuSymbolPropertyProperty symbol
NamuSymbolFieldField symbol
NamuSymbolEnumEnum symbol
NamuSymbolModuleModule symbol
Some Other Styles--------------------
NamuTreeGuidesTree guide lines
NamuFileInfoFile info text
NamuPreviewPreview window highlight
NamuParentParent item highlight
NamuNestedNested item highlight
NamuStyleStyle elements highlight
NamuCursorCursor highlight during Picker active

Contributing

I made this plugin for fun at first and didn't know I could replicate what Zed has, and to be independent and free from any pickers. Pull requests are welcome! Just please be kind and respectful. Any suggestions to improve and integrate with other plugins are also welcome.

Naming:

β€œNamu” means β€œtreeπŸŒ³β€ in Korean, just like how it helps you navigate the structure of your code.

Credits & Acknowledgements

  • Zed editor for the idea.
  • Mini.pick @echasnovski for the idea of getchar(), without which this plugin wouldn't exist.
  • Magnet module (couldn’t find it anymore on GitHub, sorry!), which intrigued me a lot.
  • @folke for handling multiple versions of Neovim LSP requests and treesitter "locals" in Snacks.nvim.
  • tests and ci structure and vimdocs, thanks to @Oli CodeCompanion
  • A simple mechanism to persist the colorscheme, thanks to this Reddit comment.
  • Aerial.nvim and @Stevearc for borroing some treesitter queries.