Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/intrntbrn/awesomewm-vim-tmux-navigator

Navigate seamlessly between system windows, vim splits and tmux panes by only using awesomewm navigation keybindings.
https://github.com/intrntbrn/awesomewm-vim-tmux-navigator

List: awesomewm-vim-tmux-navigator

awesome awesomewm control focus hotkeys keybinds navigation navigator nvim pane split tmux unixporn usability vim vim-tmux-navigator

Last synced: about 1 month ago
JSON representation

Navigate seamlessly between system windows, vim splits and tmux panes by only using awesomewm navigation keybindings.

Awesome Lists containing this project

README

        

# AwesomeWM - Vim - Tmux Navigator



Usually vim and tmux have their own dedicated keybinds for navigation.
Christoomey's plugin [vim-tmux-navigator](https://github.com/christoomey/vim-tmux-navigator) allows you to the use the same keybinds for both of them.
This might be sufficient for floating wm users, but when using a tiling wm like awesomewm we can do better and add another layer.

`awesomewm-vim-tmux-navigator` lets you navigate seamlessly between system windows, (n)vim splits and tmux panes by only using your awesomewm navigation keybinds (e.g. Mod4+hjkl).
Every split and pane is treated like a standalone system window, allowing you to forget your vim/tmux specific navigation hotkeys.

## 💡 How does it work?

It essentially works by emulating the correct keypresses based on the context.
Therefore the plugin has to detect whether the current focused application is vim, tmux, vim inside tmux (etc.) or any other system window.

The plugin offers two methods of determining the focused application:

1. By using dynamic titles. The plugin tries to change the title of your terminal in order to differentiate between applications. However, not every shell-terminal-stack supports dynamic titles or is configured correctly out of the box.

2. By using `pstree`. This should theoretically work on every setup, but it might perform slightly slower due to having an extra process to spawn.

By default the plugin uses awesomewm's builtin implementation (`root.fake_input`) to emulate keypresses.

## 📦 Installation

The configuration of vim or tmux is optional if you only use one of them.

### awesomewm:

Clone the repo:

```
git clone https://github.com/intrntbrn/awesomewm-vim-tmux-navigator ~/.config/awesome/awesomewm-vim-tmux-navigator
```

Import and configure the module:

```
require("awesomewm-vim-tmux-navigator")({
mod = "Mod4",
mod_keysym = "Super_L", -- comment out to autodetect
up = { "Up", "k" },
down = { "Down", "j" },
left = { "Left", "h" },
right = { "Right", "l" },

tmux = {
mods = { "Control_L" },
up = "Up",
down = "Down",
left = "Left",
right = "Right",
},

vim = {
mods = { "Control_L" },
up = "k",
down = "j",
left = "h",
right = "l",
},

-- focus = require("awful").client.focus.global_bydirection,
-- debug = print,

-- dont_restore_mods = true, -- prevent sticky mods (see troubleshooting)
-- use_pstree = true, -- detect app by using pstree instead of dynamic titles
-- use_xdotool = true, -- emulate keypresses using xdotool instead of builtin
})
```

If the awesomewm navigation keybinds are already in use, you have to **remove them manually**
in your `rc.lua`.

The corresponding keysym names can be retrieved by running the terminal command `xev -event keyboard`.
If `mod_keysym` is nil the plugin tries to detect your modifier.

### vim:

This plugin replaces `christoomey/vim-tmux-navigator`. Therefore you have to
replace it in your plugin manager with `intrntbrn/awesomewm-vim-tmux-navigator`.
However, both plugins share the same keybind commands, so it's not necessary to
adjust already configured custom keybinds.
Custom keybinds have to match your awesomewm configuration.

lazy.nvim (lua):

```lua
{
"intrntbrn/awesomewm-vim-tmux-navigator",
event = "VeryLazy",
build = "git -C ~/.config/awesome/awesomewm-vim-tmux-navigator/ pull",
init = function()
vim.g.tmux_navigator_no_mappings = 1
-- vim.g.tmux_navigator_no_dynamic_title = 1
-- vim.g.tmux_navigator_save_on_switch = 1
-- vim.g.tmux_navigator_disable_when_zoomed = 1
-- vim.g.tmux_navigator_preserve_zoom = 1

vim.keymap.set("n", "", ":TmuxNavigateLeft", { noremap = true, silent = true })
vim.keymap.set("n", "", ":TmuxNavigateDown", { noremap = true, silent = true })
vim.keymap.set("n", "", ":TmuxNavigateUp", { noremap = true, silent = true })
vim.keymap.set("n", "", ":TmuxNavigateRight", { noremap = true, silent = true })
end,
}
```

vim-plug (VimL):

```viml
let g:tmux_navigator_no_mappings = 1
noremap :TmuxNavigateLeft
noremap :TmuxNavigateDown
noremap :TmuxNavigateUp
noremap :TmuxNavigateRight
" let g:tmux_navigator_no_dynamic_title = 1
" let g:tmux_navigator_save_on_switch = 1
" let g:tmux_navigator_disable_when_zoomed = 1
" let g:tmux_navigator_preserve_zoom = 1

Plug 'intrntbrn/awesomewm-vim-tmux-navigator', { do = 'git -C ~/.config/awesome/awesomewm-vim-tmux-navigator/ pull' }
```

### tmux:

Add the following to your `tmux.conf`:

```tmux
# smart pane switching with awareness of vim splits and awesomewm windows
is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"
bind-key -n 'C-Left' if-shell "$is_vim" { send-keys C-h } { if-shell -F '#{pane_at_left}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"left\")" ' } { select-pane -L } }
bind-key -n 'C-Right' if-shell "$is_vim" { send-keys C-l } { if-shell -F '#{pane_at_right}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"right\")" ' } { select-pane -R } }
bind-key -n 'C-Up' if-shell "$is_vim" { send-keys C-k } { if-shell -F '#{pane_at_top}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"up\")" ' } { select-pane -U } }
bind-key -n 'C-Down' if-shell "$is_vim" { send-keys C-j } { if-shell -F '#{pane_at_bottom}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"down\")" ' } { select-pane -D } }
bind-key -T copy-mode-vi 'C-Left' if-shell "$is_vim" { send-keys C-h } { if-shell -F '#{pane_at_left}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"left\")" ' } { select-pane -L } }
bind-key -T copy-mode-vi 'C-Right' if-shell "$is_vim" { send-keys C-l } { if-shell -F '#{pane_at_right}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"right\")" ' } { select-pane -R } }
bind-key -T copy-mode-vi 'C-Up' if-shell "$is_vim" { send-keys C-k } { if-shell -F '#{pane_at_top}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"up\")" ' } { select-pane -U } }
bind-key -T copy-mode-vi 'C-Down' if-shell "$is_vim" { send-keys C-j } { if-shell -F '#{pane_at_bottom}' {run-shell 'awesome-client "awesome.emit_signal(\"navigator::focus\", \"down\")" ' } { select-pane -D } }

# set title suffix to "- TMUX" (optional when using pstree method)
set-option -g set-titles on
set-option -g set-titles-string '#S: #W - TMUX'
```

Please note that if you're using custom vim keybinds, you have to edit the `{ send-keys }` section for each tmux bind to match your vim configuration.

## ❓ Troubleshooting

### Setup:

1. Enable debug mode:

```lua
debug = function(msg) require("naughty").notify({ text = msg }) end
```

2. Make sure there are no conflicting keybinds.
You can bypass conflicts in awesomewm by invoking the plugin from the terminal for verification:

```bash
echo "select a window" && sleep 2 && awesome-client 'awesome.emit_signal("navigator::navigate", "up")'
```

3. Verify if dynamic titles are working. The title of (n)vim and tmux
applications should end with "- (N)VIM" or "- TMUX" respectively.
If you don't have a titlebar, you can use the terminal command `xprop | grep WM_NAME`.
If dynamic titles are not working, set `use_pstree` to true or configure
your shell-terminal-stack correctly. Minimal configurations are provided for `zsh` and `bash`:

```
echo "source ~/.config/awesome/awesomewm-vim-tmux-navigator/dynamictitles.zsh" >> ~/.zshrc
```

```
echo "source ~/.config/awesome/awesomewm-vim-tmux-navigator/dynamictitles.bash" >> ~/.bashrc
```

4. Check https://github.com/christoomey/vim-tmux-navigator#troubleshooting.

5. Create an issue.

### Sticky Mods:

In order to emulate keypresses in vim/tmux, the plugin needs to release your wm
modifier (e.g. mod4) temporarily and restore it afterwards.
There is a race condition if the user was fast enough to release the modifier
during this operation resulting in _sticky_ mods. This issue is very unlikely to be ever solved.

Restoring mods can be disabled by setting the `dont_restore_mods` option.
Please note that it's not possible to hold down the modifier for consecutive
actions using this option.
However, this side effect can be circumvented by assigning combo-keybinds using custom
keyboards (qmk or similar software/firmware).

## 📡 API

- **navigate**: directional vim/tmux aware navigation
- **focus**: regular directional system window navigation

awesomewm:

```lua
awesome.emit_signal("navigator::navigate", "left")
awesome.emit_signal("navigator::focus", "right")
```

shell:

```bash
awesome-client 'awesome.emit_signal("navigator::navigate", "up")'
awesome-client 'awesome.emit_signal("navigator::focus", "down")'
```