Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Options for custom user logic #34

Open
wants to merge 1 commit into
base: release/2.0
Choose a base branch
from

Conversation

nkgm
Copy link

@nkgm nkgm commented May 6, 2023

hint.pre_assign_chars: this started out as an experiment of unifying the familiar HJKL window navigation hints with the amazing features this plugin has to offer, and evolved into this generalized option.

process_unknown_char: this is required in order to handle (control-) chars not available as hints. The original intention was to quickly switch between the last 2 windows using <C-w><C-w>, but in its general form could cover more potential use-cases.

This is the lazy.nvim config I'm using with the current branch and it's working really well for me so far.

function winid_from_winnr(arg)
  local nr
  if arg then
    nr = vim.fn.winnr(arg)
  else
    nr = vim.fn.winnr()
  end
  if nr then
    return vim.fn.win_getid(nr)
  else
    return nil
  end
end

return {
  's1n7ax/nvim-window-picker',
  branch = 'release/2.0',
  keys = {
    "<C-w>"
  },
  opts = {
    hint = {

      -- Get a chance to assign keys to windows based on user-defined logic
      -- before window-picker assigns them from available selection_chars.
      -- windowlist: sparse list winid -> char (char initialized as false)
      -- Should return the updated windowlist with pre-assigned chars.
      pre_assign_chars = function(windowlist)
        -- Show H/J/K/L hints where you would expect them
        local keys = { 'h', 'j', 'k', 'l', }
        for _, k in ipairs(keys) do
          local winid = winid_from_winnr(k)
          if winid and windowlist[winid] ~= nil then
            windowlist[winid] = k:upper()
          end
        end
        return windowlist
      end,
    },

    -- Get a last chance to match a window when user presses a key not assigned in
    -- windowlist. 
    -- Returns winid for the unknown char (doesn't have to be a winid present on the
    -- windowlist - the windowlist arg is provided for completeness). Alternatively, user 
    -- can return nil and run nvim_set_current_win or any custom logic.
    process_unknown_char = function(char, windowlist)
      vim.print(windowlist)
      local cw = vim.api.nvim_replace_termcodes("<C-w>", true, true, true)
      if char == cw then
        -- always go to last window
        return winid_from_winnr("#")
      else
        -- could also nvim_set_current_win here as long as we return nil
        return nil
      end
    end,

    autoselect_one = true,
    include_current_win = false,
    selection_chars = 'FDG' .. 'UI' .. 'RET' .. 'VN' .. 'MC' .. 'WOQP',
  },
  config = function(_, opts)
    local picker = require("window-picker")
    picker.setup(opts)
    vim.keymap.set("n", "<C-w>", function()
      local win = picker.pick_window(opts)
      if (win) then
        api.nvim_set_current_win(win)
      end
    end, { desc = "Pick a window" })
  end
}

I understand the api for 2.0 is still in flux and things are bound to change, so please re-arrange as you see fit, as long as we maintain enough flexibility to cover use-cases like the ones outlined above.

@nkgm
Copy link
Author

nkgm commented May 7, 2023

As a separate suggestion, it would be nice if pick_window() would also return the char pressed along with the window id like so:

{
  char = "f",
  winid = 1005
}

Example use-case: neo-tree has integration commands like split_with_window_picker and vsplit_with_window_picker. It would be nice if we could differentiate between f/F so we know to open the split before or after the targeted window.

IndianBoy42 added a commit to IndianBoy42/nvim-window-picker that referenced this pull request Jun 19, 2023
IndianBoy42 added a commit to IndianBoy42/nvim-window-picker that referenced this pull request Jun 19, 2023
@s1n7ax
Copy link
Owner

s1n7ax commented Dec 17, 2023

@nkgm Hi, super late but I don't quite understand the feature. How is this different from selection_chars = 'FJDKSLA;CMRUEIWOQP' configuration value?

@nkgm
Copy link
Author

nkgm commented Dec 29, 2023

Hi @s1n7ax, apologies for the late response!

pre_assign_chars will work in harmony with selection_chars, except pre_assign_chars will be assigned with higher priority. The logic by which they will be assigned is left to the user config. My config listed above will assign HJKL to their "natural" position ie H will be used as a hint to the left of the current window, L to the right and so on. My user config pre-assigns windows in a similar way with <C-w>{H,J,K,L}. This pre-assigned mapping of winid -> char is then returned to the plugin and the remaining windows are assigned hints from selection_chars in the usual way.

process_unknown_char is a generalization of this concept, so for example, you can have a hook that looks for when the user pressed w and switch to the last window like <C-w>w. Using these options, you could use <C-w> as your main picker key, and still maintain most default functionality of the "nnoremapped" <C-w>.

As for my second comment about pick_window(), consider this example: you are currently in a Neotree window and you want to open the selected file as a split to the left or right of the picked window. If pick_window() would also return the actual key pressed by the user, you could eg differentiate between f/F to open the split before/after the targeted window.

Please note, all opinionated behavior listed above is implemented in user config. This PR merely adds enough flexibility to the core, so the opinionated parts may reside in the user's config, and should be backwards compatible with the existing config options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants