Last active
July 12, 2025 17:05
-
-
Save Nimmidev/2cf4d5cc80dce32d0240ec7b3cfe090f to your computer and use it in GitHub Desktop.
tmux copy mode with line numbers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
declare -r LINE_NUMBER_PANE_WIDTH=3 | |
declare -r LINE_NUMBER_UPDATE_DELAY=0.1 | |
declare -r COLOR_NUMBERS_RGB="101;112;161" | |
declare -r COLOR_ACTIVE_NUMBER_RGB="255;158;100" | |
open_line_number_split(){ | |
local self_path=$(realpath $0) | |
local pane_id=$(tmux display-message -pF "#{pane_id}") | |
pgrep -f "$self_path $pane_id" > /dev/null && return | |
tmux split-window -h -l $LINE_NUMBER_PANE_WIDTH -b "$self_path $pane_id" | |
tmux select-pane -l | |
} | |
enter_copy_mode(){ | |
local target_pane=$1 | |
tmux copy-mode -t "$target_pane" | |
} | |
get_cursor_line(){ | |
local output=$(tmux display-message -pt "$target_pane" -F '#{copy_cursor_y}') | |
echo "${output:-0}" | |
} | |
is_in_copy_mode(){ | |
local mode=$(tmux display-message -p -t "$target_pane" -F '#{pane_mode}') | |
! [ -z $mode ] | |
} | |
redraw_line_numbers(){ | |
local cursor_line=$1 | |
local lines=$(tput lines) | |
clear | |
printf "\e[38;2;$COLOR_NUMBERS_RGB;2m" | |
seq $cursor_line -1 1 | |
printf "\e[0m" | |
printf "\e[38;2;$COLOR_ACTIVE_NUMBER_RGB;1m 0\e[0m" | |
if [ $lines -gt $(($cursor_line + 1)) ]; then | |
echo | |
printf "\e[38;2;$COLOR_NUMBERS_RGB;2m" | |
seq 1 $(($lines - $cursor_line - 2)) | |
printf $((lines - $cursor_line - 1)) | |
printf "\e[0m" | |
fi | |
} | |
update_loop(){ | |
local cursor_line="" | |
local last_cursor_line="-1" | |
while is_in_copy_mode; do | |
cursor_line=$(get_cursor_line) | |
if [ $cursor_line -ne $last_cursor_line ]; then | |
redraw_line_numbers $cursor_line | |
last_cursor_line=$cursor_line | |
fi | |
sleep $LINE_NUMBER_UPDATE_DELAY | |
done | |
} | |
restore_pane_width(){ | |
local target_pane=$1 | |
tmux resize-pane -t "$target_pane" -L $(($LINE_NUMBER_PANE_WIDTH + 1)) | |
} | |
main(){ | |
local target_pane=$1 | |
if [ -z $target_pane ]; then | |
open_line_number_split | |
exit 0 | |
else | |
enter_copy_mode $target_pane | |
fi | |
update_loop | |
restore_pane_width $target_pane | |
} | |
main "$@" |
thank you for this! little tweak so it doesn't open twice
open_line_number_split() { local self_path pane_id self_path="$(realpath "$0")" pane_id="$(tmux display-message -pF "#{pane_id}")" + if pgrep -f "$self_path $pane_id" >/dev/null; then + return + fi tmux split-window -h -l "$LINE_NUMBER_PANE_WIDTH" -b "$self_path $pane_id" tmux select-pane -l }
good idea, i've added it to the script.
Works like a charm thanks !!
Awesome feature! Thanks 💪
I just had to switch the shebang to #! /bin/bash
otherwise I got
/home/jb/.config/tmux/copy_mode_with_line_numbers.sh: 3: declare: not found
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thank you for this! little tweak so it doesn't open twice