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

Implement ActivatePaneOrWindowDirection #3007

Open
alfa07 opened this issue Jan 25, 2023 · 0 comments
Open

Implement ActivatePaneOrWindowDirection #3007

alfa07 opened this issue Jan 25, 2023 · 0 comments
Labels
enhancement New feature or request

Comments

@alfa07
Copy link
Contributor

alfa07 commented Jan 25, 2023

Is your feature request related to a problem? Please describe.
Similar to ActivatePaneDirection it would be awesome to have ActivatePaneOrWindowDirection - it is very handy when using multiple monitors and could be a killer feature in these situations.

Describe the solution you'd like
One option is to implement a bare minimum in wezterm and allow users to take it from there. See #3006 and lua config attached below.
The bare minimum:

  1. gui_window:get_position() - allows finding window relative to the current, see find_window_direction function below
  2. tab:get_pane_direction(direction) - gets pane in the given direction in the current tab or returns nil if there is none

Describe alternatives you've considered
I've tried to implement it in lua without changes to wezterm but it turns out we are not exposing enough API to do it.

Additional context
Here is screen recording of me using Ctrl-hjkl to navigate between windows.

And here is config:

local wezterm = require 'wezterm'
local act = wezterm.action
local os = require("os")

local function active_tab(window)
  for _, t in pairs(window:tabs_with_info()) do
    if t.is_active then
      return t.tab
    end
  end
end

local function find_window_direction(window, direction)
  local wx = {}
  local p0 = window:get_position()
  local sz0 = window:get_dimensions()
  for _, w in pairs(wezterm.mux.all_windows()) do
    local x = 0
    local x0 = 0
    local p = w:gui_window():get_position()
    local sz = w:gui_window():get_dimensions()
    if direction == 'Left' then
      x = p.x + sz.pixel_width
      x0 = p0.x
    elseif direction == 'Right' then
      x = p.x
      x0 = p0.x + sz0.pixel_width
    elseif direction == 'Up' then
      x = p.y + sz.pixel_height
      x0 = p0.y
    elseif direction == 'Down' then
      x = p.y
      x0 = p0.y + sz0.pixel_height
    end
    if (direction == 'Left' or direction == 'Up') and x < x0 then
      wx[#wx + 1] = { x0 - x, w }
    elseif (direction == 'Right' or direction == 'Down') and x > x0 then
      wx[#wx + 1] = { x - x0, w }
    end
  end
  table.sort(wx, function(a, b) return a[1] < b[1] end)
  if #wx > 0 then
    return wx[1][2]
  end
  return nil
end

-- Nvim navigator implementation
-- The usage of NVIM_LISTEN_ADDRESS is depricated see https://github.com/neovim/neovim/pull/11009
-- see https://github.com/wez/wezterm/discussions/995
-- see https://github.com/aca/wezterm.nvim
local move_around = function(window, pane, direction_wez, direction_nvim)
  local result = os.execute("env NVIM_LISTEN_ADDRESS=/tmp/nvim" ..
    pane:pane_id() .. " wezterm.nvim.navigator " .. direction_nvim)
  if result then
    print("vim window")
    window:perform_action(wezterm.action({ SendString = "\x17" .. direction_nvim }), pane)
  else
    local t = pane:tab()
    if not t then
      -- Debug panes do not have tabs :(
      t = active_tab(window:mux_window())
    end
    if t:get_pane_direction(direction_wez) then
      print("wez pane")
      window:perform_action(wezterm.action({ ActivatePaneDirection = direction_wez }), pane)
    else
      print("wez window")
      local w = find_window_direction(window, direction_wez)
      if w then
        print("wez window focus")
        w:gui_window():focus()
      end
    end
  end
end

wezterm.on("move-left", function(window, pane)
  move_around(window, pane, "Left", "h")
end)

wezterm.on("move-right", function(window, pane)
  move_around(window, pane, "Right", "l")
end)

wezterm.on("move-up", function(window, pane)
  move_around(window, pane, "Up", "k")
end)

wezterm.on("move-down", function(window, pane)
  move_around(window, pane, "Down", "j")
end)

local function window_index_from_tab_info(tab_info)
  for idx, window in pairs(wezterm.gui.gui_windows()) do
    if tab_info.window_id == window:window_id() then
      return idx -- lua indices are 1-based, but we want 0-based
    end
  end
  return 0 -- didn't find it, guess?
end

wezterm.on('format-window-title', function(tab, pane, tabs, panes, config)
  local index = window_index_from_tab_info(tab)
  return "[" .. index .. "] " .. tab.active_pane.title
end)

wezterm.on('open-uri', function(window, pane, uri)
  print(uri)
  local start, match_end = uri:find 'edit:'
  if start == 1 then
    local file_and_loc = uri:sub(match_end + 1)
    local i1 = file_and_loc:find ':'
    local file = file_and_loc:sub(1, i1 - 1)
    local loc = file_and_loc:sub(i1 + 1, file_and_loc:len())
    local i2 = loc:find ':'
    local line = loc:sub(1, i2 - 1)
    print(file, line)

    for _, p in ipairs(pane:tab():panes()) do
      print("scanning", p:pane_id())
      if p:pane_id() ~= pane:pane_id() then
        print("sending keys")
        p:send_text("\x1b")
        p:send_text(string.format(":e +%s %s\n", line, file))
        p:send_text("zz")
        return false
      end
    end
    return false
  end
end)

return {
  -- font = wezterm.font 'Fira Code',
  -- You can specify some parameters to influence the font selection;
  -- for example, this selects a Bold, Italic font variant.
  enable_tab_bar = true,
  term = "xterm-256color",
  font = wezterm.font('JetBrainsMono Nerd Font', { weight = 'Regular' }),
  font_size = 16,
  leader = { key = 'Space', mods = 'CTRL', timeout_milliseconds = 1000 },
  keys = {
    {
      key = 's',
      mods = 'LEADER',
      action = wezterm.action.SplitVertical { domain = 'CurrentPaneDomain' },
    },
    {
      key = 'v',
      mods = 'LEADER',
      action = wezterm.action.SplitHorizontal { domain = 'CurrentPaneDomain' },
    },
    {
      key = 'g',
      mods = 'LEADER',
      action = wezterm.action.SpawnCommandInNewTab {
        args = { 'lazygit' },
      },
    },
    {
      key = 'k',
      mods = 'LEADER',
      action = wezterm.action.CloseCurrentTab {
        confirm = true,
      },
    },
    {
      key = 'c',
      mods = 'LEADER',
      action = act.SpawnTab 'CurrentPaneDomain',
    },
    {
      key = 'r',
      mods = 'CMD|SHIFT',
      action = wezterm.action.ReloadConfiguration,
    },
    {
      key = '1',
      mods = 'CMD|ALT',
      action = wezterm.action.ActivateWindow(0),
    },
    {
      key = '2',
      mods = 'CMD|ALT',
      action = wezterm.action.ActivateWindow(1),
    },
    {
      key = '3',
      mods = 'CMD|ALT',
      action = wezterm.action.ActivateWindow(2),
    },
    {
      key = '4',
      mods = 'CMD|ALT',
      action = wezterm.action.ActivateWindow(3),
    },
    {
      key = '5',
      mods = 'CMD|ALT',
      action = wezterm.action.ActivateWindow(4),
    },
    { key = "h", mods = "CTRL", action = wezterm.action({ EmitEvent = "move-left" }) },
    { key = "l", mods = "CTRL", action = wezterm.action({ EmitEvent = "move-right" }) },
    { key = "k", mods = "CTRL", action = wezterm.action({ EmitEvent = "move-up" }) },
    { key = "j", mods = "CTRL", action = wezterm.action({ EmitEvent = "move-down" }) },
    {
      key = 'w',
      mods = 'CTRL|SHIFT|ALT',
      action = act.CloseCurrentPane { confirm = false },
    },
  },
  color_scheme = "Builtin Solarized Light",
  -- window_decorations = "TITLE",
  hyperlink_rules = {
    -- Linkify things that look like URLs and the host has a TLD name.
    -- Compiled-in default. Used if you don't specify any hyperlink_rules.
    {
      regex = '\\S*:\\d+:\\d+\\b',
      format = 'edit:$0',
    },
    -- Make task numbers clickable
    -- The first matched regex group is captured in $1.
    {
      regex = [[\b[tT](\d+)\b]],
      format = 'https://example.com/tasks/?t=$1',
    },
  }
}
@alfa07 alfa07 added the enhancement New feature or request label Jan 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant