dropbar.nvim icon indicating copy to clipboard operation
dropbar.nvim copied to clipboard

navigating menu siblings directly from the bar.

Open bheadwhite opened this issue 9 months ago • 3 comments
trafficstars

hi. of course let me begin, thanks for creating this great plugin! i have a use case that im exploring and i wonder if im just going about it all wrong.

step one: i'd like to enter the dropbar focus using api:pick, and focus on the dropbar symbol that is relevant to my cursor position. step two: i'd like to traverse up and down in that menu (this works beautifully) step three: i'd like to traverse to the sibling top level drop bar menus. aka... if i enter pick mode and i only have 3 options (a, b, c) i get into c, by way of my keyboard shortcut, and then if i can call pick again on a relative number :pick(-1) or :pick(+1)... id like move from c => b, and then back to c

i was able to hack my way to that behavior on version 10 (commit d0c78c570db0f5941f85ba54522c0f01427cdf67) ... the commit right after that breaks my workaround.

is this behavior currently supported and im just missing it in the docs or is it within the scope of the project to support? im couped to version 10 for now to support my use cases.. thanks so much!

local initial_idx = nil
local current_bar = nil

function activate_top_level_components()
  current_bar = require("dropbar.utils").bar.get_current()
  if not current_bar then
    return
  end

  for _, component in ipairs(current_bar.components) do
    if component.name_hl == "DropBarFileName" then
      if current_bar.components[component.bar_idx + 1] ~= nil then
        current_idx = component.bar_idx + 1
      else
        current_idx = component.bar_idx
      end
      initial_idx = current_idx
      break
    end
  end
end

function handleEnterDropBarUp()
  local dropbar_t = require("dropbar.utils").bar.get_current()
  if not dropbar_t then
    -- send up key
    vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Up>", true, true, true), "n", true)
    return
  end

  activate_top_level_components()
  if not current_bar then
    return
  end

  if not current_idx or current_bar.components[current_idx] == nil then
    return
  end

  current_bar:pick(current_idx)
end

function handleEnterDropBarDown()
  local dropbar_t = require("dropbar.utils").bar.get_current()
  if not dropbar_t then
    -- send up key
    vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Down>", true, true, true), "n", true)
    return
  end
  activate_top_level_components()
  if not current_bar then
    return
  end
  if not current_idx or current_bar.components[current_idx] == nil then
    return
  end

  current_bar:pick(current_idx)
end

vim.keymap.set("n", "K", handleEnterDropBarUp, { noremap = true, silent = true })
vim.keymap.set("n", "J", handleEnterDropBarDown, { noremap = true, silent = true })
vim.keymap.set("n", "H", function()
  local dropbar = require("dropbar.api").get_current_dropbar()

  if dropbar == nil then
    local menu = require("dropbar.utils").menu.get_current()
    if menu == nil or current_bar == nil or current_idx == 1 then
      return
    end

    current_idx = current_idx - 1

    menu:close()
    current_bar:pick(current_idx)
    return
  end

  if not dropbar.in_pick_mode then
    vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("_", true, true, true), "n", true)
    return
  end
end, { noremap = true, silent = true })

vim.keymap.set("n", "L", function()
  local dropbar = require("dropbar.api").get_current_dropbar()

  if dropbar == nil then
    local menu = require("dropbar.utils").menu.get_current()
    if menu == nil or current_idx + 1 > initial_idx or current_bar == nil then
      return
    end

    current_idx = current_idx + 1
    menu:close()

    current_bar:pick(current_idx)
    return
  end

  if not dropbar.in_pick_mode then
    vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("$", true, true, true), "n", true)
    return
  end
end, { noremap = true, silent = true })

bheadwhite avatar Feb 14 '25 17:02 bheadwhite

I suspect commit c824f033d0e6b3a4cce550d7a767a516b99cee56 breaks this, not sure because I haven't tested it on my machine.

:pick(-1) or :pick(+1)

I will consider adding builtin support for this in the future. PR welcome ofc.

Bekaboo avatar Feb 14 '25 18:02 Bekaboo

I would like to share my prefered navigation flow - which I used to use in VSCode.

It goes like this:

  • h closes the dropdown menu and moves to the parent, or if there is no parent moves to the breadcrumb before
  • l expands the current selected item:
A > [B] > C > D           -->           A > [B] > C > D
      |                                      |
      |-- b1                                 |-- b1
      |-- [b2]                               |-- [b2] > |
      |-- b3                                 |          |-- [b21]
                                             |          |-- b22
                                             |          |-- b23
                                             |-- b3
  • <C-h> moves directly to the previous breadcrumb (closing all dropdowns)
A > [B] > C > D           -->           [A] > B > C > D
      |                                  |
      |-- b1                             |-- [a1]
      |-- [b2] > |                       |-- a2
      |          |-- [b21]               |-- a3
      |          |-- b22
      |          |-- b23
      |-- b3
  • <C-l> moves directly to the next breadcrumb (closing all dialogs)
A > [B] > C > D           -->           A > B > [C] > D
      |                                          |
      |-- b1                                     |-- [c1]
      |-- [b2] > |                               |-- c2
      |          |-- [b21]                       |-- c3
      |          |-- b22
      |          |-- b23
      |-- b3

I've come close to doing that with dropbar.nvim - but my naive implementation runs into problems with indexes sometimes. I believe this are reasonable motions to have.

druskus20 avatar Apr 17 '25 18:04 druskus20

Hey, don't know if it's of any help, but here follows what worked for me:

{
  keymaps = {
    ["H"] = function()
      local root = require("dropbar.utils").menu.get_current():root()
      root:close()

      local dropbar = require("dropbar.api").get_dropbar(vim.api.nvim_win_get_buf(root.prev_win), root.prev_win)
      if not dropbar then
        root:toggle()
        return
      end

      local current_idx
      for idx, component in ipairs(dropbar.components) do
        if component.menu == root then
          current_idx = idx
          break
        end
      end

      if current_idx == nil or current_idx == 0 then
        root:toggle()
        return
      end

      vim.defer_fn(function() dropbar:pick(current_idx - 1) end, 100)
    end,

    ["L"] = function()
      local root = require("dropbar.utils").menu.get_current():root()
      root:close()

      local dropbar = require("dropbar.api").get_dropbar(vim.api.nvim_win_get_buf(root.prev_win), root.prev_win)
      if not dropbar then
        dropbar = require("dropbar.utils").bar.get_current()
        if not dropbar then
          root:toggle()
          return
        end
      end

      local current_idx
      for idx, component in ipairs(dropbar.components) do
        if component.menu == root then
          current_idx = idx
          break
        end
      end

      if current_idx == nil or current_idx == #dropbar.components then
        root:toggle()
        return
      end

      vim.defer_fn(function() dropbar:pick(current_idx + 1) end, 100)
    end,
  },
}

edygar avatar Jul 06 '25 05:07 edygar