{"id":13895740,"url":"https://github.com/meznaric/conmenu","last_synced_at":"2025-04-30T15:47:09.089Z","repository":{"id":50637079,"uuid":"421097055","full_name":"meznaric/conmenu","owner":"meznaric","description":"Powerful but minimal context menu plugin for neovim.","archived":false,"fork":false,"pushed_at":"2024-06-26T09:59:20.000Z","size":119,"stargazers_count":66,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-30T15:47:06.013Z","etag":null,"topics":["lua","neovim"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meznaric.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-25T16:15:06.000Z","updated_at":"2025-04-28T23:30:55.000Z","dependencies_parsed_at":"2024-11-25T01:30:35.227Z","dependency_job_id":"1d8457ee-3b45-4fc7-890f-c4fb2cc79ef0","html_url":"https://github.com/meznaric/conmenu","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meznaric%2Fconmenu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meznaric%2Fconmenu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meznaric%2Fconmenu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meznaric%2Fconmenu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meznaric","download_url":"https://codeload.github.com/meznaric/conmenu/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251734154,"owners_count":21635079,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","neovim"],"created_at":"2024-08-06T18:02:26.382Z","updated_at":"2025-04-30T15:47:09.048Z","avatar_url":"https://github.com/meznaric.png","language":"Lua","funding_links":[],"categories":["Lua"],"sub_categories":[],"readme":"\u003c!-- panvimdoc-ignore-start --\u003e\n\n# ConMenu\n\nPowerful but minimal context menu for neovim.\n\n![Example_1](./example.jpg)\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n\n# Features\n\n - Quick and easy way to build menus \u0026 submenus with automatic hotkey bindings\n - Appears next to your cursor (you are probably looking there anyways!)\n - Context based (optionally based on the filetype or custom filter function)\n - Icon unicode support (via dev icons, you need patched fonts)\n - Configure with Vimscript or Lua\n\nOpinionated / optional / language specific features:\n\n - Helpers for NPM projects and Lerna monorepos\n - Helpers for git worktree workflows\n\n# Requirements\n\n - Neovim (tested with v0.5.0)\n\nOptional 1/2:\nif you want better integration with javascript ecosystem. Specifically for `fromNpm` and `fromLerna`:\n\n - [vim-dispatch](https://github.com/tpope/vim-dispatch) - For dispatching\n   jobs in the background\n - [jq](https://github.com/stedolan/jq) - For parsing package.json\n - yarn - I'll make this configurable at some point so you can use NPM instead\n\nOptional 2/2:\n[git-worktree.nvim](https://github.com/ThePrimeagen/git-worktree.nvim) - If you are going to be using `createWorktree`, `selectWorktree`, `removeWorktree`.\n\n\u003c!-- panvimdoc-ignore-start --\u003e\n\n# Installation\n\nPlug with vimscript:\n```vim\nPlug 'meznaric/conmenu'\n\n\" Configure ConMenu\nlet g:conmenu#shortcut_highlight_group = \"KeyHighlight\";\n```\n\nLazy.nvim with lua:\n```lua\n{\n\t\"meznaric/conmenu\",\n    init = function()\n        -- Configure it in \"init\"\n        vim.api.nvim_set_keymap(\"n\", \"\u003cleader\u003e\", \":ConMenu\u003cCR\u003e\", { silent = true })\n        vim.g[\"conmenu#default_menu\"] = {...}\n        vim.api.nvim_set_hl(0, \"KeyHighlight\", { fg = \"#569CD6\" })\n        vim.g[\"conmenu#shortcut_highlight_group\"] = \"KeyHighlight\"\n    end,\n}\n```\n\nFeel free to open a pull request if you have install instructions for other systems.\n\n\u003c!-- panvimdoc-ignore-end --\u003e\n\n# Usage\n\n### Commands\n```\n\" You probably only need this one\n:ConMenu\n\" These commands are used by binds inside a menu\n:ConMenuNext\n:ConMenuPrevious\n:ConMenuConfirm\n:ConMenuClose\n:ConMenuUpdateRender\n```\n\n# Configuration\n\nSee [example below](#example) if you just want a quick start.\n\n**Menu**\n\nIn the documentation below `Menu` represents the array of `MenuItem`s.\n\n**MenuItem**\n\nWhich is defined as an array of 3 items:\n\n - `Name` is the name of the entry in the menu list. What you see.\n - `Menu` or command or a lua function\n - `Options` defines when `MenuListItem` is shown. If you define multiple options\n    for example `onlyTypes` and `onlyWorkingDirectories` it will show the menu list\n    item only when both conditions are true, *not* when either is true. This is\n    optional. Menu items will be always shown if options are not defined.\n\n**Options**\n\n - `onlyTypes` array of file types\n - `filter` global lua or vimscript function, if it returns true, menu item will be shown\n - `onlyWorkingDirectories` array of path globs. If current working directory\n    matches any of the globs then the MenuItem will be shown.\n - `onlyBufferPaths` array of path globs. If current buffer path matches any of the\n    globs then the MenuItem will be shown. Empty glob `''`, will match :new buffer.\n\n### Vimscript Reference\n\n```\nfunction! AlwaysShow()\n  \" Check if in the right folder, or the path is right, or whatever...\n  return v:true\nendfunction\n\nlet s:onlyProjectFolders = [ '/Users/otiv/Projects/*' ]\nlet s:onlyTsFiles = [ '*.ts' ]\nlet s:myFileTypes = ['typescript', 'typescriptreact']\nlet s:myOptions = {\n  \\ 'onlyTypes': s:myFileTypes,\n  \\ 'filter': 'AlwaysShow',\n  \\ 'onlyWorkingDirectories': s:onlyProjectFolders,\n  \\ 'onlyBufferPaths': s:onlyTsFiles,\n  \\ }\n\nlet s:menuItem = [name, commandOrMenu, s:myOptions]\nlet s:nestedMenu = [name, [s:menuItem, s:menuItem], s:myOptions]\nlet s:divider = ['──────────────────────────', v:null, s:myOptions]\n\nlet g:conmenu#default_menu = [menuItem, divider, menuItem, nestedMenu]\n```\n\n### Lua Reference\n\n```lua\nfunction AlwaysShow()\n  -- Check if in the right folder, or the path is right, or whatever...\n  return true\nend\n\nlocal options = {\n  onlyTypes = { 'typescript', 'typescriptreact' },\n  onlyBufferPaths: { path1, path2 },\n  onlyWorkingDirectories: { path3, path4 },\n  filter = 'AlwaysShow',\n}\nlocal menuItem = {name, \":echo hey\", options}\nlocal nestedMenu = {name, {menuItem, menuItem}, options}\nlocal divider = {'──────────────────────────', nil, options}\nlocal callbackExample = {\n    'Press Me',\n    function() \n        print(\"Pressed!\")\n    end\n}\n\nvim.g['conmenu#default_menu'] = { menuItem, divider, menuItem, nestedMenu }\n```\n\n## Global Conmenu Options\n\n```vim\n\" Default menu that opens when you execute ConMenu\nlet g:conmenu#default_menu = [];\n\n\" Only these keys will be bound if found in menu item name\n\" If you want to use numbers for shortcuts too extend this\nlet g:conmenu#available_bindings = 'wertyuiopasdfghlzxcvbnm';\n\n\" \u003e is the default, but you can use - or something else.\n\" Note: unicode characters have different width and we do not consider this yet, so shortcut highlights will be off\n\" Use only normal 1 byte characters, such as `-`, `~`\nlet g:conmenu#cursor_character = '\u003e';\n\n\" We use simple Popup Buffer, so NormalFloat and FloatBorder define the colors\n\" On top of that create a new highlight group shortcut_highlight_group\nlet g:conmenu#shortcut_highlight_group = 'KeyHighlight';\n\n\" These options are just passed on to nvim_open_win:\n\" border values: none, single, double, rounded, solid, shadow\nlet g:conmenu#border = 'rounded';\n\" relative values: cursor, mouse, win, editor\nlet g:conmenu#relative = 'cursor'\n\" relative values: NW, NE, SW, SE\nlet g:conmenu#anchor = 'NW'\nlet g:conmenu#row = get(g:, 'conmenu#row', 0)\nlet g:conmenu#col = get(g:, 'conmenu#col', 0)\n\n\" Not yet implemented\nlet g:conmenu#close_keys = ['q', '\u003cesc\u003e']\nlet g:conmenu#js#package_manager = 'yarn'\n```\n\n\n## API\n```\n\" Opens default menu (defined at g:conmenu#default_menu)\nopen()\n\" Opens custom menu\nopenCustom(menu, window_options)\nclose()\n\nexecuteItem()\nswitchItem(number)\n\n-- Javascript helpers\nfromNpm()\nfromLerna()\n\n-- Git Worktree helpers\ncreateWorktree()\nremoveWorktree()\nselectWorktree()\n\n-- Used by bindings generated by this script\nexecuteItemNum()\nupdateRender()\n```\n\n# Integrations\n\n## JavaScript integration\n\nRequires [jq](https://github.com/stedolan/jq) so we can parse what scripts there\nare in package.json. There is a built in filter `IsInNodeProject`, that you can\nuse to hide this menu if not inside a node project.\n\n - Use `fromLerna` to see a list of projects / packages\n - Use `fromNpm` to see a list of available scripts in package.json\n\n### Example\n```\nlet g:conmenu#default_menu = [\n  \\['Scripts', \":lua require('conmenu').fromNpm()\",\n    \\{ 'filter': 'IsInNodeProject' }],\n  \\['Lerna Projects', \":lua require('conmenu').fromLerna()\",\n    \\{ 'filter': 'IsInNodeProject' }],\n\\]\n```\n\n## git-worktree.nvim integration\n\n\nRequires [git-worktree.nvim](https://github.com/ThePrimeagen/git-worktree.nvim).\nThere are 3 methods for you to use `createWorktree()`, `selectWorktree()` and\n`removeWorktree()`. On top of that there is a built in filter \"IsInGitWorktree\",\nthat you can use so this menu item is shown only when you are editing inside git repositroy.\n\n### Example\n```\nlet g:conmenu#default_menu = [\n  \\['Git', [\n    \\['Status', ':Git'],\n    \\['Blame', ':Git blame'],\n    \\['Why', ':GitMessenger'],\n    \\['────────────────────────────'],\n    \\['Create Worktree', \":lua require('conmenu').createWorktree()\"],\n    \\['Select Worktree', \":lua require('conmenu').selectWorktree()\"],\n    \\['Remove Worktree', \":lua require('conmenu').removeWorktree()\"],\n    \\], { 'filter': 'IsInGitWorktree' }],\n  \\]\n```\n\n# Example\n\nHere is the example of how I use it, it depends on bunch of other plugins so don't expect to\ncopy and paste as it's not going to work.\n\nI'll try to breakdown important lines here.\n\nShow menu item or nested menu item only in specific file types.\n```\n\\['  Code Diagnostics',[\n  ...\n  \\], { 'onlyTypes': s:javascriptTypes }],\n```\n\n\nIs `IsInNodeProject` and `IsInGitWorktree` are built in filters that you can use \nin combination with few helper functions explained above.\n```\n\\['  Scripts', \":lua require('conmenu').fromNpm()\",\n  \\{ 'filter': 'IsInNodeProject' }],\n```\n\nShows an example of how to build a custom menu.\nThe function itself is called from Harpoon menu item at the bottom.\n```\nfunction ShowHarpoonMenu()\n```\n\nUse this to get some ideas what you can do:\n```vim\n\" Map \u003cleader\u003em to open default menu.\nnoremap \u003csilent\u003e \u003cleader\u003em :ConMenu\u003cCR\u003e\n\n\" Some of the menu items should only be available in javascript files\nlet s:javascriptTypes = ['typescriptreact', 'typescript', 'javascript', 'javascript.jsx', 'json']\n\" By default numbers are not bound, but we we want to bind numbers too\nlet g:conmenu#available_bindings = '1234567890wertyuiopasdfghlzxcvbnm'\n\n\" This generates a new menu programatically\nfunction ShowHarpoonMenu()\n  local marks = require(\"harpoon\").get_mark_config().marks;\n  local marksCount = table.maxn(marks)\n  -- Default entries, that are always shown\n  local menuEntries = {\n    { 'Show all', ':lua require(\"harpoon.ui\").toggle_quick_menu()' },\n    { 'Add current File', ':lua require(\"harpoon.mark\").add_file()' },\n  };\n  -- Add divider if we have marks\n  if (marksCount \u003e 0) then\n    table.insert(menuEntries, { '────────────────────────────'})\n  end\n\n  -- Prepare navigation marks\n  for i,v in ipairs(marks) do\n    -- Get just the filename from entire path\n    local file = string.match(\"/\" .. v.filename, \".*/(.*)$\")\n    -- Add menu entry\n    table.insert(menuEntries, {i .. \" \" .. file, \"lua require('harpoon.ui').nav_file(\".. i ..\")\"})\n  end\n  -- Show menu\n  require('conmenu').openCustom(menuEntries)\nend\nEND\n\n\" Find icons here: https://www.nerdfonts.com/cheat-sheet\nlet g:conmenu#default_menu = [\n\\['  Code Actions', [\n  \\['  Rename', \":call CocActionAsync('rename')\"],\n  \\['  Fix', ':CocFix'],\n  \\['  Cursor', \":call CocActionAsync('codeAction', 'cursor')\"],\n  \\['  Refactor', \":call CocActionAsync('refactor')\"],\n  \\['  Selection', \"execute 'normal gv' | call CocActionAsync('codeAction', visualmode())\"],\n  \\['  Definition', \":call CocActionAsync('jumpDefinition')\"],\n  \\['  Declaration', \":call CocActionAsync('jumpDeclaration')\"],\n  \\['  Type Definition', \":call CocActionAsync('jumpTypeDefinition')\"],\n  \\['  Implementation', \":call CocActionAsync('jumpImplementation')\"],\n  \\['  References', \":call CocActionAsync('jumpReferences')\"],\n  \\['  Usages', \":call CocActionAsync('jumpUsed')\"],\n  \\['  Test Nearest', ':TestNearest'],\n  \\['﬍  File Outline', ':CocOutline'],\n  \\['   Format File', ':PrettierAsync'],\n  \\['   UnMinify JS', ':call UnMinify()'],\n  \\['   Organise Imports', \":call CocAction('organizeImport')\"],\n  \\], { 'onlyTypes': s:javascriptTypes }],\n\\['  Code Diagnostics',[\n  \\['  List Diagnostics', ':CocList diagnostics'],\n  \\['  Previous', \":call CocActionAsync('diagnosticPrevious')\"],\n  \\['  Next', \":call CocActionAsync('diagnosticNext')\"],\n  \\['  Info', \":call CocActionAsync('diagnosticInfo')\"]\n  \\], { 'onlyTypes': s:javascriptTypes }],\n\\['  Scripts', \":lua require('conmenu').fromNpm()\",\n  \\{ 'filter': 'IsInNodeProject' }],\n\\['  Lerna Projects', \":lua require('conmenu').fromLerna()\",\n  \\{ 'filter': 'IsInNodeProject' }],\n\\['────────────────────────────', v:null, { 'onlyTypes': s:javascriptTypes}],\n\\['  Navigate', [\n  \\['  Fuzzy', ':Files'],\n  \\['  Recent Files', ':CtrlPMRUFiles'],\n  \\['  Mixed', ':CtrlPMixed'],\n  \\['  Marks', ':Marks' ],\n  \\['────────────────────────────'],\n  \\['﬍  Explorer', ':CocCommand explorer'],\n  \\['﬍  Highlight in Explorer', ':CocCommand explorer --reveal'],\n  \\['  Lines in file', ':CocList outline'],\n  \\]],\n\\['  Utils', [\n  \\['  Git', ':call ToggleTerm(\"lazygit\")', { 'filter': 'IsInGitWorktree' }],\n  \\['  Docker', ':call ToggleTerm(\"lazydocker\")'],\n  \\['  Databases', ':DBUI'],\n  \\['  Terminal', ':terminal'],\n  \\['  Dev Docs', \":call devdocs#open(expand('\u003ccword\u003e'))\"],\n  \\['  Help', ':call ShowDocumentation()'],\n  \\['────────────────────────────'],\n  \\['  Delete All Marks', ':delmarks A-Z0-9a-z'],\n  \\['  Configs', [\n    \\[' neovim', ':e ~/.config/nvim/init.vim'],\n    \\[' zsh', ':e ~/.zshrc'],\n    \\[' coc.nvim', ':CocConfig'],\n    \\]],\n  \\['────────────────────────────'],\n  \\['  Buffer in Finder', ':silent exec \"!open %:p:h\"'],\n  \\['  Project in Finder', ':silent exec \"!open $(pwd)\"'],\n  \\['פּ  TreeSitter Playground', ':TSPlaygroundToggle'],\n  \\]],\n\\['﬘  Buffers', [\n  \\['﬘  Show All', ':Buffers'],\n  \\['﬘  Close All', ':silent bufdo BD!'],\n  \\]],\n\\['  Git', [\n  \\['Status', ':Git'],\n  \\['Blame', ':Git blame'],\n  \\['Why', ':GitMessenger'],\n  \\['────────────────────────────'],\n  \\['Create Worktree', \":lua require('conmenu').createWorktree()\"],\n  \\['Select Worktree', \":lua require('conmenu').selectWorktree()\"],\n  \\['Remove Worktree', \":lua require('conmenu').removeWorktree()\"],\n  \\], { 'filter': 'IsInGitWorktree' }],\n\\['  Harpoon', ':lua ShowHarpoonMenu()'],\n\\]\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeznaric%2Fconmenu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeznaric%2Fconmenu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeznaric%2Fconmenu/lists"}