Last active
June 1, 2026 00:51
-
-
Save daniellin-eero/f0fcb9b6027aca7793a647bf16fc92ee to your computer and use it in GitHub Desktop.
fix lsp nvim
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
| devup() { | |
| git submodule update --init --recursive | |
| local container_id=$(docker ps -aq --filter "label=devcontainer.local_folder=$(pwd)") | |
| if [[ -z "$container_id" ]]; then | |
| # No container exists, create it | |
| devcontainer up --workspace-folder . --skip-post-create | |
| container_id=$(docker ps -aq --filter "label=devcontainer.local_folder=$(pwd)") | |
| elif [[ -z $(docker ps -q --filter "id=$container_id") ]]; then | |
| # Container exists but not running, start it | |
| docker start $container_id | |
| fi | |
| # Execute bash in the container | |
| docker exec -it -w /workspaces/$(basename $(pwd)) $container_id /bin/bash | |
| } | |
| # Clear line and run tmux-sessionizer | |
| tmux-sessionizer-widget() { | |
| BUFFER="tmux-sessionizer" | |
| zle accept-line | |
| } | |
| zle -N tmux-sessionizer-widget | |
| bindkey ^f tmux-sessionizer-widget | |
| # Session 0 | |
| tmux-sessionizer-0() { | |
| BUFFER="tmux-sessionizer -s 0" | |
| zle accept-line | |
| } | |
| zle -N tmux-sessionizer-0 | |
| bindkey '\ej' tmux-sessionizer-0 | |
| # Session 1 | |
| tmux-sessionizer-1() { | |
| BUFFER="tmux-sessionizer -s 1" | |
| zle accept-line | |
| } | |
| zle -N tmux-sessionizer-1 | |
| bindkey '\ek' tmux-sessionizer-1 | |
| # Session 2 | |
| tmux-sessionizer-2() { | |
| BUFFER="tmux-sessionizer -s 2" | |
| zle accept-line | |
| } | |
| zle -N tmux-sessionizer-2 | |
| bindkey '\el' tmux-sessionizer-2 | |
| # Session 3 | |
| tmux-sessionizer-3() { | |
| BUFFER="tmux-sessionizer -s 3" | |
| zle accept-line | |
| } | |
| zle -N tmux-sessionizer-3 | |
| bindkey '\e;' tmux-sessionizer-3 |
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
| -- [[ Configure tmux-sessionizer ]] | |
| -- (tmux manager) | |
| require "danielpclin.tmux-sessionizer-setup" |
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
| -- [[ Configure LSP ]] | |
| -- This function gets run when an LSP connects to a particular buffer. | |
| local on_attach = function(_, bufnr) | |
| -- NOTE: Remember that lua is a real programming language, and as such it is possible | |
| -- to define small helper and utility functions so you don't have to repeat yourself | |
| -- many times. | |
| -- | |
| -- In this case, we create a function that lets us more easily define mappings specific | |
| -- for LSP related items. It sets the mode, buffer and description for us each time. | |
| local nmap = function(keys, func, desc) | |
| if desc then | |
| desc = "LSP: " .. desc | |
| end | |
| vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc }) | |
| end | |
| local imap = function(keys, func, desc) | |
| if desc then | |
| desc = "LSP: " .. desc | |
| end | |
| vim.keymap.set("i", keys, func, { buffer = bufnr, desc = desc }) | |
| end | |
| nmap("<leader>rn", vim.lsp.buf.rename, "[R]e[n]ame") | |
| nmap("<leader>ca", vim.lsp.buf.code_action, "[C]ode [A]ction") | |
| nmap("gd", require("telescope.builtin").lsp_definitions, "[G]oto [D]efinition") | |
| nmap("gr", require("telescope.builtin").lsp_references, "[G]oto [R]eferences") | |
| nmap("gi", require("telescope.builtin").lsp_implementations, "[G]oto [I]mplementation") | |
| nmap("<leader>vt", require("telescope.builtin").lsp_type_definitions, "[V]iew [T]ype Definition") | |
| nmap("<leader>sd", require("telescope.builtin").lsp_document_symbols, "[S]earch [D]ocument Symbols") | |
| nmap("<leader>ss", require("telescope.builtin").lsp_dynamic_workspace_symbols, "[S]earch Workspace [S]ymbols") | |
| -- See `:help K` for why this keymap | |
| nmap("K", vim.lsp.buf.hover, "Hover Documentation") | |
| nmap("<C-s>", vim.lsp.buf.signature_help, "Signature Documentation") | |
| imap("<C-q>", vim.lsp.buf.hover, "Hover Documentation") | |
| imap("<C-s>", vim.lsp.buf.signature_help, "Signature Documentation") | |
| -- Lesser used LSP functionality | |
| -- nmap("gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") | |
| nmap("<leader>wa", vim.lsp.buf.add_workspace_folder, "[W]orkspace [A]dd Folder") | |
| nmap("<leader>wr", vim.lsp.buf.remove_workspace_folder, "[W]orkspace [R]emove Folder") | |
| nmap("<leader>wl", function() | |
| print(vim.inspect(vim.lsp.buf.list_workspace_folders())) | |
| end, "[W]orkspace [L]ist Folders") | |
| -- -- Create a command `:Format` local to the LSP buffer | |
| -- vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) | |
| -- vim.lsp.buf.format() | |
| -- end, { desc = 'Format current buffer with LSP' }) | |
| end | |
| -- nvim-cmp supports additional completion capabilities, so broadcast that to servers | |
| local capabilities = vim.lsp.protocol.make_client_capabilities() | |
| capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities) | |
| vim.lsp.config("*", { | |
| on_attach = on_attach, | |
| capabilities = capabilities, | |
| }) | |
| -- Enable the following language servers | |
| -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. | |
| -- | |
| -- Add any additional override configuration in the following tables. They will be passed to | |
| -- the `settings` field of the server config. You must look up that documentation yourself. | |
| -- | |
| -- If you want to override the default filetypes that your language server will attach to you can | |
| -- define the property 'filetypes' to the map in question. | |
| local servers = { | |
| clangd = { | |
| -- cmd = { | |
| -- "clangd", "--header-insertion=never", | |
| -- }, | |
| }, | |
| gopls = {}, | |
| pyright = {}, | |
| rust_analyzer = {}, | |
| ts_ls = {}, | |
| html = { | |
| filetypes = { "html" }, | |
| }, | |
| lua_ls = { | |
| on_init = function(client) | |
| if client.workspace_folders then | |
| local path = client.workspace_folders[1].name | |
| if | |
| path ~= vim.fn.stdpath "config" | |
| and (vim.uv.fs_stat(path .. "/.luarc.json") or vim.uv.fs_stat(path .. "/.luarc.jsonc")) | |
| then | |
| return | |
| end | |
| end | |
| client.config.settings.Lua = vim.tbl_deep_extend("force", client.config.settings.Lua, { | |
| runtime = { | |
| -- Tell the language server which version of Lua you're using (most | |
| -- likely LuaJIT in the case of Neovim) | |
| version = "LuaJIT", | |
| -- Tell the language server how to find Lua modules same way as Neovim | |
| -- (see `:h lua-module-load`) | |
| path = { | |
| "lua/?.lua", | |
| "lua/?/init.lua", | |
| }, | |
| }, | |
| -- Make the server aware of Neovim runtime files | |
| workspace = { | |
| checkThirdParty = false, | |
| library = { | |
| vim.env.VIMRUNTIME, | |
| -- Depending on the usage, you might want to add additional paths | |
| -- here. | |
| -- '${3rd}/luv/library' | |
| -- '${3rd}/busted/library' | |
| }, | |
| -- Or pull in all of 'runtimepath'. | |
| -- NOTE: this is a lot slower and will cause issues when working on | |
| -- your own configuration. | |
| -- See https://github.com/neovim/nvim-lspconfig/issues/3189 | |
| -- library = { | |
| -- vim.api.nvim_get_runtime_file('', true), | |
| -- } | |
| }, | |
| }) | |
| end, | |
| settings = { | |
| Lua = { | |
| workspace = { checkThirdParty = false }, | |
| telemetry = { enable = false }, | |
| }, | |
| }, | |
| }, | |
| dockerls = {}, | |
| docker_compose_language_service = {}, | |
| } | |
| for server_name, config in pairs(servers) do | |
| -- vim.print(server_name) | |
| -- vim.print(config) | |
| config['on_attach'] = on_attach | |
| config['capabilities'] = capabilities | |
| vim.lsp.config(server_name, config or {}) | |
| vim.lsp.enable(server_name) | |
| end | |
| require("mason").setup() | |
| require("mason-lspconfig").setup { | |
| automatic_enable = false, -- HACK: rely on lspconfig[server_name].setup to enable the LSPs. For some reason, pyright doesn't get enabled this way | |
| ensure_installed = vim.tbl_keys(servers), | |
| } | |
| require("mason-tool-installer").setup { | |
| ensure_installed = { | |
| "prettier", -- prettier formatter | |
| "stylua", -- lua formatter | |
| "isort", -- python formatter | |
| "black", -- python formatter | |
| "pylint", -- python linter | |
| "eslint_d", -- js linter | |
| "ansible-lint", --ansible linter | |
| }, | |
| } | |
| -- Setup neovim lua configuration | |
| require("neodev").setup() | |
| -- vim: ts=2 sts=2 sw=2 et |
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
| #!/usr/bin/env bash | |
| CONFIG_FILE_NAME="tmux-sessionizer.conf" | |
| CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-sessionizer" | |
| CONFIG_FILE="$CONFIG_DIR/$CONFIG_FILE_NAME" | |
| PANE_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/tmux-sessionizer" | |
| PANE_CACHE_FILE="$PANE_CACHE_DIR/panes.cache" | |
| # config file example | |
| # ------------------------ | |
| # # file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf | |
| # # If set this override the default TS_SEARCH_PATHS (~/personal ~/projects) | |
| # TS_SEARCH_PATHS=(~/) | |
| # # If set this add additional search paths to the default TS_SEARCH_PATHS | |
| # # The number prefix is the depth for the Path [OPTIONAL] | |
| # TS_EXTRA_SEARCH_PATHS=(~/ghq:3 ~/Git:3 ~/.config:2) | |
| # # if set this override the TS_MAX_DEPTH (1) | |
| # TS_MAX_DEPTH=2 | |
| # This is not meant to override .tmux-sessionizer. At first i thought this | |
| # would be a good command, but i don't think its ackshually what i want. | |
| # | |
| # Instead, its a list of commands to run on windows who's index is way outside | |
| # of the first 10 windows. This allows you to create as many windows in your | |
| # session as you would like without having your workflow interrupted by these | |
| # programatic windows | |
| # | |
| # how to use: | |
| # tmux-sessionizer -s 0 will execute the first command in window -t 69. | |
| # use single quotes to wrap the command. | |
| # TS_SESSION_COMMANDS=(<cmd1> <cmd2>) | |
| # | |
| # TS_LOG=true # will write logs to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # TS_LOG_FILE=<file> # will write logs to <file> Defaults to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # ------------------------ | |
| if [[ -f "$CONFIG_FILE" ]]; then | |
| source "$CONFIG_FILE" | |
| fi | |
| if [[ -f "$CONFIG_FILE_NAME" ]]; then | |
| source "$CONFIG_FILE_NAME" | |
| fi | |
| if [[ $TS_LOG != "true" ]]; then | |
| if [[ -z $TS_LOG_FILE ]]; then | |
| TS_LOG_FILE="$HOME/.local/share/tmux-sessionizer/tmux-sessionizer.logs" | |
| fi | |
| mkdir -p "$(dirname "$TS_LOG_FILE")" | |
| fi | |
| log() { | |
| if [[ -z $TS_LOG ]]; then | |
| return | |
| elif [[ $TS_LOG == "echo" ]]; then | |
| echo "$*" | |
| elif [[ $TS_LOG == "file" ]]; then | |
| echo "$*" >> "$TS_LOG_FILE" | |
| fi | |
| } | |
| # if TS_SEARCH_PATHS is not set use default | |
| [[ -n "$TS_SEARCH_PATHS" ]] || TS_SEARCH_PATHS=(~/personal ~/projects) | |
| # Add any extra search paths to the TS_SEARCH_PATHS array | |
| # e.g : EXTRA_SEARCH_PATHS=("$HOME/extra1:4" "$HOME/extra2") | |
| # note : Path can be suffixed with :number to limit or extend the depth of the search for the Path | |
| if [[ ${#TS_EXTRA_SEARCH_PATHS[@]} -gt 0 ]]; then | |
| TS_SEARCH_PATHS+=("${TS_EXTRA_SEARCH_PATHS[@]}") | |
| fi | |
| # utility function to find directories | |
| find_dirs() { | |
| # list TMUX sessions | |
| if [[ -n "${TMUX}" ]]; then | |
| current_session=$(tmux display-message -p '#S') | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | grep -vFx "[TMUX] $current_session" | sort -Vr | |
| else | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | sort -Vr | |
| fi | |
| # note: TS_SEARCH_PATHS is an array of paths to search for directories | |
| # if the path ends with :number, it will search for directories with a max depth of number ;) | |
| # if there is no number, it will search for directories with a max depth defined by TS_MAX_DEPTH or 1 if not set | |
| for entry in "${TS_SEARCH_PATHS[@]}"; do | |
| # Check if entry as :number as suffix then adapt the maxdepth parameter | |
| if [[ "$entry" =~ ^([^:]+):([0-9]+)$ ]]; then | |
| path="${BASH_REMATCH[1]}" | |
| depth="${BASH_REMATCH[2]}" | |
| else | |
| path="$entry" | |
| fi | |
| [[ -d "$path" ]] && find "$path" -mindepth 1 -maxdepth "${depth:-${TS_MAX_DEPTH:-1}}" -path '*/.git' -prune -o -type d -print | |
| done | sort -Vr | |
| } | |
| session_idx="" | |
| session_cmd="" | |
| user_selected="" | |
| split_type="" | |
| VERSION="0.1.0" | |
| while [[ "$#" -gt 0 ]]; do | |
| case "$1" in | |
| -h | --help) | |
| echo "Usage: tmux-sessionizer [OPTIONS] [SEARCH_PATH]" | |
| echo "" | |
| echo "A tmux session manager that creates and switches between project sessions." | |
| echo "" | |
| echo "Options:" | |
| echo " -h, --help Display this help message" | |
| echo " -v, --version Show version information" | |
| echo " -s, --session <index> Execute session command by index (requires TS_SESSION_COMMANDS)" | |
| echo " --vsplit Create vertical split for session command (use with -s)" | |
| echo " --hsplit Create horizontal split for session command (use with -s)" | |
| echo " --find-dirs List all available directories and tmux sessions" | |
| echo "" | |
| echo "Interactive Mode:" | |
| echo " When run without arguments, opens fzf to select from:" | |
| echo " - Existing tmux sessions (prefixed with [TMUX])" | |
| echo " - Project directories from configured search paths" | |
| echo "" | |
| echo " Keybindings in fzf:" | |
| echo " ENTER - Select and switch to session/directory" | |
| echo " CTRL-D - Kill selected tmux session" | |
| echo "" | |
| echo "Configuration:" | |
| echo " Config file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf" | |
| echo " See script comments for configuration options." | |
| echo "" | |
| echo "Examples:" | |
| echo " tmux-sessionizer # Interactive mode" | |
| echo " tmux-sessionizer ~/my-project # Direct path selection" | |
| echo " tmux-sessionizer -s 0 # Execute first session command" | |
| echo " tmux-sessionizer -s 1 --vsplit # Execute second command in vertical split" | |
| exit 0 | |
| ;; | |
| -s | --session) | |
| session_idx="$2" | |
| if [[ -z $session_idx ]]; then | |
| echo "Session index cannot be empty" | |
| exit 1 | |
| fi | |
| if [[ -z $TS_SESSION_COMMANDS ]]; then | |
| echo "TS_SESSION_COMMANDS is not set. Must have a command set to run when switching to a session" | |
| exit 1 | |
| fi | |
| if [[ -z "$session_idx" || "$session_idx" -lt 0 || "$session_idx" -ge "${#TS_SESSION_COMMANDS[@]}" ]]; then | |
| echo "Error: Invalid index. Please provide an index between 0 and $((${#TS_SESSION_COMMANDS[@]} - 1))." | |
| exit 1 | |
| fi | |
| session_cmd="${TS_SESSION_COMMANDS[$session_idx]}" | |
| shift | |
| ;; | |
| --vsplit) | |
| split_type="vsplit" | |
| ;; | |
| --hsplit) | |
| split_type="hsplit" | |
| ;; | |
| -v | --version) | |
| echo "tmux-sessionizer version $VERSION" | |
| exit 0 | |
| ;; | |
| --find-dirs) | |
| find_dirs | |
| exit 0 | |
| ;; | |
| *) | |
| user_selected="$1" | |
| ;; | |
| esac | |
| shift | |
| done | |
| log "tmux-sessionizer($VERSION): idx=$session_idx cmd=$session_cmd user_selected=$user_selected split_type=$split_type log=$TS_LOG log_file=$TS_LOG_FILE" | |
| # Validate split options are only used with session commands | |
| if [[ -n "$split_type" && -z "$session_idx" ]]; then | |
| echo "Error: --vsplit and --hsplit can only be used with -s/--session option" | |
| exit 1 | |
| fi | |
| sanity_check() { | |
| if ! command -v tmux &>/dev/null; then | |
| echo "tmux is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| if ! command -v fzf &>/dev/null; then | |
| echo "fzf is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| } | |
| switch_to() { | |
| if [[ -z $TMUX ]]; then | |
| log "attaching to session $1" | |
| tmux attach-session -t "$1" | |
| else | |
| log "switching to session $1" | |
| tmux switch-client -t "$1" | |
| fi | |
| } | |
| has_session() { | |
| tmux list-sessions | grep -q "^$1:" | |
| } | |
| hydrate() { | |
| if [[ ! -z $session_cmd ]]; then | |
| log "skipping hydrate for $1 -- using \"$session_cmd\" instead" | |
| return | |
| elif [ -f "$2/.tmux-sessionizer" ]; then | |
| log "sourcing(local) $2/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $2/.tmux-sessionizer" c-M | |
| elif [ -f "$HOME/.tmux-sessionizer" ]; then | |
| log "sourcing(global) $HOME/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $HOME/.tmux-sessionizer" c-M | |
| fi | |
| } | |
| is_tmux_running() { | |
| tmux_running=$(pgrep tmux) | |
| if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| init_pane_cache() { | |
| mkdir -p "$PANE_CACHE_DIR" | |
| touch "$PANE_CACHE_FILE" | |
| } | |
| get_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| init_pane_cache | |
| grep "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" | cut -d: -f3 | |
| } | |
| set_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| local pane_id="$3" | |
| init_pane_cache | |
| # Remove existing entry if it exists | |
| grep -v "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" > "${PANE_CACHE_FILE}.tmp" 2>/dev/null || true | |
| mv "${PANE_CACHE_FILE}.tmp" "$PANE_CACHE_FILE" | |
| # Add new entry | |
| echo "${session_idx}:${split_type}:${pane_id}" >> "$PANE_CACHE_FILE" | |
| } | |
| cleanup_dead_panes() { | |
| init_pane_cache | |
| local temp_file="${PANE_CACHE_FILE}.tmp" | |
| while IFS=: read -r idx split pane_id; do | |
| if tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${pane_id}$"; then | |
| echo "${idx}:${split}:${pane_id}" >> "$temp_file" | |
| fi | |
| done < "$PANE_CACHE_FILE" | |
| mv "$temp_file" "$PANE_CACHE_FILE" 2>/dev/null || touch "$PANE_CACHE_FILE" | |
| } | |
| sanity_check | |
| handle_session_cmd() { | |
| log "executing session command $session_cmd with index $session_idx split_type=$split_type" | |
| if ! is_tmux_running; then | |
| echo "Error: tmux is not running. Please start tmux first before using session commands." | |
| exit 1 | |
| fi | |
| current_session=$(tmux display-message -p '#S') | |
| if [[ -n "$split_type" ]]; then | |
| handle_split_session_cmd "$current_session" | |
| else | |
| handle_window_session_cmd "$current_session" | |
| fi | |
| exit 0 | |
| } | |
| handle_window_session_cmd() { | |
| local current_session="$1" | |
| start_index=$((69 + $session_idx)) | |
| target="$current_session:$start_index" | |
| log "target: $target command $session_cmd has-session=$(tmux has-session -t="$target" 2> /dev/null)" | |
| if tmux has-session -t="$target" 2> /dev/null; then | |
| switch_to "$target" | |
| else | |
| log "executing session command: tmux neww -dt $target $session_cmd" | |
| tmux neww -dt $target "$session_cmd" | |
| hydrate "$target" "$selected" | |
| tmux select-window -t $target | |
| fi | |
| } | |
| handle_split_session_cmd() { | |
| local current_session="$1" | |
| cleanup_dead_panes | |
| # Check if pane already exists | |
| local existing_pane_id=$(get_pane_id "$session_idx" "$split_type") | |
| if [[ -n "$existing_pane_id" ]] && tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${existing_pane_id}$"; then | |
| log "switching to existing pane $existing_pane_id" | |
| tmux select-pane -t "$existing_pane_id" | |
| if [[ -z $TMUX ]]; then | |
| tmux attach-session -t "$current_session" | |
| else | |
| tmux switch-client -t "$current_session" | |
| fi | |
| else | |
| # Create new split | |
| local split_flag="" | |
| if [[ "$split_type" == "vsplit" ]]; then | |
| split_flag="-h" # horizontal layout (vertical split) | |
| else | |
| split_flag="-v" # vertical layout (horizontal split) | |
| fi | |
| log "creating new split: tmux split-window $split_flag -c $(pwd) $session_cmd" | |
| local new_pane_id=$(tmux split-window $split_flag -c "$(pwd)" -P -F "#{pane_id}" "$session_cmd") | |
| if [[ -n "$new_pane_id" ]]; then | |
| set_pane_id "$session_idx" "$split_type" "$new_pane_id" | |
| log "created pane $new_pane_id for session_idx=$session_idx split_type=$split_type" | |
| fi | |
| fi | |
| } | |
| if [[ ! -z $session_cmd ]]; then | |
| handle_session_cmd | |
| elif [[ ! -z $user_selected ]]; then | |
| selected="$user_selected" | |
| else | |
| # selected=$(find_dirs | fzf) | |
| selected=$(find_dirs | fzf \ | |
| --bind 'ctrl-d:execute-silent( | |
| [[ {} == \[TMUX\]* ]] && tmux kill-session -t "$(echo {} | cut -d" " -f2-)" | |
| )+reload(tmux-sessionizer --find-dirs)' \ | |
| --header 'ENTER: select, CTRL-D: kill session') | |
| fi | |
| if [[ -z $selected ]]; then | |
| exit 0 | |
| fi | |
| if [[ "$selected" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| fi | |
| selected_name=$(basename "$selected" | tr . _) | |
| if ! has_session "$selected_name"; then | |
| if [[ -z $TMUX ]]; then | |
| # Outside tmux - create attached session to get proper terminal size | |
| tmux new-session -s "$selected_name" -c "$selected" \; \ | |
| new-window -c "$selected" \; \ | |
| new-window -c "$selected" \; \ | |
| send-keys -t "$selected_name:0" "nvim" C-m \; \ | |
| send-keys -t "$selected_name:1" "source ~/.zshrc && dev" C-m \; \ | |
| select-window -t "$selected_name:0" | |
| hydrate "$selected_name" "$selected" | |
| exit 0 | |
| else | |
| # Inside tmux - create detached then switch | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| tmux new-window -t "$selected_name" -c "$selected" | |
| tmux new-window -t "$selected_name" -c "$selected" | |
| tmux send-keys -t "$selected_name:0" "nvim" C-m | |
| tmux send-keys -t "$selected_name:1" "source ~/.zshrc && dev" C-m | |
| tmux select-window -t "$selected_name:0" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| fi | |
| switch_to "$selected_name" |
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
| #!/usr/bin/env bash | |
| CONFIG_FILE_NAME="tmux-sessionizer.conf" | |
| CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-sessionizer" | |
| CONFIG_FILE="$CONFIG_DIR/$CONFIG_FILE_NAME" | |
| PANE_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/tmux-sessionizer" | |
| PANE_CACHE_FILE="$PANE_CACHE_DIR/panes.cache" | |
| # config file example | |
| # ------------------------ | |
| # # file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf | |
| # # If set this override the default TS_SEARCH_PATHS (~/personal ~/projects) | |
| # TS_SEARCH_PATHS=(~/) | |
| # # If set this add additional search paths to the default TS_SEARCH_PATHS | |
| # # The number prefix is the depth for the Path [OPTIONAL] | |
| # TS_EXTRA_SEARCH_PATHS=(~/ghq:3 ~/Git:3 ~/.config:2) | |
| # # if set this override the TS_MAX_DEPTH (1) | |
| # TS_MAX_DEPTH=2 | |
| # This is not meant to override .tmux-sessionizer. At first i thought this | |
| # would be a good command, but i don't think its ackshually what i want. | |
| # | |
| # Instead, its a list of commands to run on windows who's index is way outside | |
| # of the first 10 windows. This allows you to create as many windows in your | |
| # session as you would like without having your workflow interrupted by these | |
| # programatic windows | |
| # | |
| # how to use: | |
| # tmux-sessionizer -s 0 will execute the first command in window -t 69. | |
| # use single quotes to wrap the command. | |
| # TS_SESSION_COMMANDS=(<cmd1> <cmd2>) | |
| # | |
| # TS_LOG=true # will write logs to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # TS_LOG_FILE=<file> # will write logs to <file> Defaults to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # ------------------------ | |
| if [[ -f "$CONFIG_FILE" ]]; then | |
| source "$CONFIG_FILE" | |
| fi | |
| if [[ -f "$CONFIG_FILE_NAME" ]]; then | |
| source "$CONFIG_FILE_NAME" | |
| fi | |
| if [[ $TS_LOG != "true" ]]; then | |
| if [[ -z $TS_LOG_FILE ]]; then | |
| TS_LOG_FILE="$HOME/.local/share/tmux-sessionizer/tmux-sessionizer.logs" | |
| fi | |
| mkdir -p "$(dirname "$TS_LOG_FILE")" | |
| fi | |
| log() { | |
| if [[ -z $TS_LOG ]]; then | |
| return | |
| elif [[ $TS_LOG == "echo" ]]; then | |
| echo "$*" | |
| elif [[ $TS_LOG == "file" ]]; then | |
| echo "$*" >> "$TS_LOG_FILE" | |
| fi | |
| } | |
| # if TS_SEARCH_PATHS is not set use default | |
| [[ -n "$TS_SEARCH_PATHS" ]] || TS_SEARCH_PATHS=(~/personal ~/projects) | |
| # Add any extra search paths to the TS_SEARCH_PATHS array | |
| # e.g : EXTRA_SEARCH_PATHS=("$HOME/extra1:4" "$HOME/extra2") | |
| # note : Path can be suffixed with :number to limit or extend the depth of the search for the Path | |
| if [[ ${#TS_EXTRA_SEARCH_PATHS[@]} -gt 0 ]]; then | |
| TS_SEARCH_PATHS+=("${TS_EXTRA_SEARCH_PATHS[@]}") | |
| fi | |
| # utility function to find directories | |
| find_dirs() { | |
| # list TMUX sessions | |
| if [[ -n "${TMUX}" ]]; then | |
| current_session=$(tmux display-message -p '#S') | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | grep -vFx "[TMUX] $current_session" | sort -Vr | |
| else | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | sort -Vr | |
| fi | |
| # note: TS_SEARCH_PATHS is an array of paths to search for directories | |
| # if the path ends with :number, it will search for directories with a max depth of number ;) | |
| # if there is no number, it will search for directories with a max depth defined by TS_MAX_DEPTH or 1 if not set | |
| for entry in "${TS_SEARCH_PATHS[@]}"; do | |
| # Check if entry as :number as suffix then adapt the maxdepth parameter | |
| if [[ "$entry" =~ ^([^:]+):([0-9]+)$ ]]; then | |
| path="${BASH_REMATCH[1]}" | |
| depth="${BASH_REMATCH[2]}" | |
| else | |
| path="$entry" | |
| fi | |
| [[ -d "$path" ]] && find "$path" -mindepth 1 -maxdepth "${depth:-${TS_MAX_DEPTH:-1}}" -path '*/.git' -prune -o -type d -print | |
| done | sort -Vr | |
| } | |
| get_jira_title() { | |
| local ticket="$1" | |
| local cache_file="$HOME/.cache/tmux-sessionizer-jira/$ticket" | |
| if [[ -f "$cache_file" && $(find "$cache_file" -mtime -7 2>/dev/null) ]]; then | |
| cat "$cache_file" | |
| else | |
| mkdir -p "$(dirname "$cache_file")" | |
| local title=$(acli jira workitem view "$ticket" --fields summary 2>/dev/null | tail -1 | sed 's/^[[:space:]]*Summary: //') | |
| echo "$title" > "$cache_file" | |
| echo "$title" | |
| fi | |
| } | |
| add_jira_info() { | |
| while IFS= read -r line; do | |
| if [[ "$line" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| session_name="${BASH_REMATCH[1]}" | |
| if [[ "$session_name" =~ (CONN-[0-9]+) ]]; then | |
| ticket="${BASH_REMATCH[1]}" | |
| title=$(get_jira_title "$ticket") | |
| if [[ -n "$title" ]]; then | |
| echo "$line [$ticket: $title]" | |
| else | |
| echo "$line [$ticket]" | |
| fi | |
| else | |
| echo "$line" | |
| fi | |
| else | |
| dir_name=$(basename "$line") | |
| if [[ "$dir_name" =~ ^(CONN-[0-9]+) ]]; then | |
| ticket="${BASH_REMATCH[1]}" | |
| title=$(get_jira_title "$ticket") | |
| if [[ -n "$title" ]]; then | |
| echo "$line [$ticket: $title]" | |
| else | |
| echo "$line [$ticket]" | |
| fi | |
| else | |
| echo "$line" | |
| fi | |
| fi | |
| done | |
| } | |
| session_idx="" | |
| session_cmd="" | |
| user_selected="" | |
| split_type="" | |
| VERSION="0.1.0" | |
| while [[ "$#" -gt 0 ]]; do | |
| case "$1" in | |
| -h | --help) | |
| echo "Usage: tmux-sessionizer [OPTIONS] [SEARCH_PATH]" | |
| echo "Options:" | |
| echo " -h, --help Display this help message" | |
| echo " -s, --session <name> session command index." | |
| echo " --vsplit Create vertical split (horizontal layout) for session command" | |
| echo " --hsplit Create horizontal split (vertical layout) for session command" | |
| exit 0 | |
| ;; | |
| -s | --session) | |
| session_idx="$2" | |
| if [[ -z $session_idx ]]; then | |
| echo "Session index cannot be empty" | |
| exit 1 | |
| fi | |
| if [[ -z $TS_SESSION_COMMANDS ]]; then | |
| echo "TS_SESSION_COMMANDS is not set. Must have a command set to run when switching to a session" | |
| exit 1 | |
| fi | |
| if [[ -z "$session_idx" || "$session_idx" -lt 0 || "$session_idx" -ge "${#TS_SESSION_COMMANDS[@]}" ]]; then | |
| echo "Error: Invalid index. Please provide an index between 0 and $((${#TS_SESSION_COMMANDS[@]} - 1))." | |
| exit 1 | |
| fi | |
| session_cmd="${TS_SESSION_COMMANDS[$session_idx]}" | |
| shift | |
| ;; | |
| --vsplit) | |
| split_type="vsplit" | |
| ;; | |
| --hsplit) | |
| split_type="hsplit" | |
| ;; | |
| -v | --version) | |
| echo "tmux-sessionizer version $VERSION" | |
| exit 0 | |
| ;; | |
| --find-dirs) | |
| find_dirs | |
| exit 0 | |
| ;; | |
| --find-dirs-jira) | |
| find_dirs | add_jira_info | |
| exit 0 | |
| ;; | |
| *) | |
| user_selected="$1" | |
| ;; | |
| esac | |
| shift | |
| done | |
| log "tmux-sessionizer($VERSION): idx=$session_idx cmd=$session_cmd user_selected=$user_selected split_type=$split_type log=$TS_LOG log_file=$TS_LOG_FILE" | |
| # Validate split options are only used with session commands | |
| if [[ -n "$split_type" && -z "$session_idx" ]]; then | |
| echo "Error: --vsplit and --hsplit can only be used with -s/--session option" | |
| exit 1 | |
| fi | |
| sanity_check() { | |
| if ! command -v tmux &>/dev/null; then | |
| echo "tmux is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| if ! command -v fzf &>/dev/null; then | |
| echo "fzf is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| } | |
| switch_to() { | |
| if [[ -z $TMUX ]]; then | |
| log "attaching to session $1" | |
| tmux attach-session -t "$1" | |
| else | |
| log "switching to session $1" | |
| tmux switch-client -t "$1" | |
| fi | |
| } | |
| has_session() { | |
| tmux list-sessions | grep -q "^$1:" | |
| } | |
| hydrate() { | |
| if [[ ! -z $session_cmd ]]; then | |
| log "skipping hydrate for $1 -- using \"$session_cmd\" instead" | |
| return | |
| elif [ -f "$2/.tmux-sessionizer" ]; then | |
| log "sourcing(local) $2/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $2/.tmux-sessionizer" c-M | |
| elif [ -f "$HOME/.tmux-sessionizer" ]; then | |
| log "sourcing(global) $HOME/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $HOME/.tmux-sessionizer" c-M | |
| fi | |
| } | |
| is_tmux_running() { | |
| tmux_running=$(pgrep tmux) | |
| if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| init_pane_cache() { | |
| mkdir -p "$PANE_CACHE_DIR" | |
| touch "$PANE_CACHE_FILE" | |
| } | |
| get_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| init_pane_cache | |
| grep "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" | cut -d: -f3 | |
| } | |
| set_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| local pane_id="$3" | |
| init_pane_cache | |
| # Remove existing entry if it exists | |
| grep -v "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" > "${PANE_CACHE_FILE}.tmp" 2>/dev/null || true | |
| mv "${PANE_CACHE_FILE}.tmp" "$PANE_CACHE_FILE" | |
| # Add new entry | |
| echo "${session_idx}:${split_type}:${pane_id}" >> "$PANE_CACHE_FILE" | |
| } | |
| cleanup_dead_panes() { | |
| init_pane_cache | |
| local temp_file="${PANE_CACHE_FILE}.tmp" | |
| while IFS=: read -r idx split pane_id; do | |
| if tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${pane_id}$"; then | |
| echo "${idx}:${split}:${pane_id}" >> "$temp_file" | |
| fi | |
| done < "$PANE_CACHE_FILE" | |
| mv "$temp_file" "$PANE_CACHE_FILE" 2>/dev/null || touch "$PANE_CACHE_FILE" | |
| } | |
| sanity_check | |
| handle_session_cmd() { | |
| log "executing session command $session_cmd with index $session_idx split_type=$split_type" | |
| if ! is_tmux_running; then | |
| echo "Error: tmux is not running. Please start tmux first before using session commands." | |
| exit 1 | |
| fi | |
| current_session=$(tmux display-message -p '#S') | |
| if [[ -n "$split_type" ]]; then | |
| handle_split_session_cmd "$current_session" | |
| else | |
| handle_window_session_cmd "$current_session" | |
| fi | |
| exit 0 | |
| } | |
| handle_window_session_cmd() { | |
| local current_session="$1" | |
| start_index=$((69 + $session_idx)) | |
| target="$current_session:$start_index" | |
| log "target: $target command $session_cmd has-session=$(tmux has-session -t="$target" 2> /dev/null)" | |
| if tmux has-session -t="$target" 2> /dev/null; then | |
| switch_to "$target" | |
| else | |
| log "executing session command: tmux neww -dt $target $session_cmd" | |
| tmux neww -dt $target "$session_cmd" | |
| hydrate "$target" "$selected" | |
| tmux select-window -t $target | |
| fi | |
| } | |
| handle_split_session_cmd() { | |
| local current_session="$1" | |
| cleanup_dead_panes | |
| # Check if pane already exists | |
| local existing_pane_id=$(get_pane_id "$session_idx" "$split_type") | |
| if [[ -n "$existing_pane_id" ]] && tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${existing_pane_id}$"; then | |
| log "switching to existing pane $existing_pane_id" | |
| tmux select-pane -t "$existing_pane_id" | |
| if [[ -z $TMUX ]]; then | |
| tmux attach-session -t "$current_session" | |
| else | |
| tmux switch-client -t "$current_session" | |
| fi | |
| else | |
| # Create new split | |
| local split_flag="" | |
| if [[ "$split_type" == "vsplit" ]]; then | |
| split_flag="-h" # horizontal layout (vertical split) | |
| else | |
| split_flag="-v" # vertical layout (horizontal split) | |
| fi | |
| log "creating new split: tmux split-window $split_flag -c $(pwd) $session_cmd" | |
| local new_pane_id=$(tmux split-window $split_flag -c "$(pwd)" -P -F "#{pane_id}" "$session_cmd") | |
| if [[ -n "$new_pane_id" ]]; then | |
| set_pane_id "$session_idx" "$split_type" "$new_pane_id" | |
| log "created pane $new_pane_id for session_idx=$session_idx split_type=$split_type" | |
| fi | |
| fi | |
| } | |
| if [[ ! -z $session_cmd ]]; then | |
| handle_session_cmd | |
| elif [[ ! -z $user_selected ]]; then | |
| selected="$user_selected" | |
| else | |
| selected=$(find_dirs | fzf \ | |
| --bind 'start:reload(tmux-sessionizer2 --find-dirs-jira)' \ | |
| --bind 'ctrl-d:execute-silent( | |
| session=$(echo {} | sed "s/^\\\[TMUX\\\] \\([^ ]*\\).*/\\1/") | |
| [[ {} == \\[TMUX\\]* ]] && tmux kill-session -t "$session" | |
| )+reload(tmux-sessionizer2 --find-dirs-jira)' \ | |
| --header 'ENTER: select, CTRL-D: kill session') | |
| fi | |
| if [[ -z $selected ]]; then | |
| exit 0 | |
| fi | |
| if [[ "$selected" =~ ^\[TMUX\]\ (.+)\ \[CONN-[0-9]+: ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| elif [[ "$selected" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| elif [[ "$selected" =~ ^(.+)\ \[CONN-[0-9]+: ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| fi | |
| selected_name=$(basename "$selected" | tr . _) | |
| if ! is_tmux_running; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| if ! has_session "$selected_name"; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| switch_to "$selected_name" |
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
| vim.keymap.set("n", "<C-f>", "<cmd>silent !tmux neww tmux-sessionizer<CR>") | |
| vim.keymap.set("n", "<M-j>", "<cmd>silent !tmux neww tmux-sessionizer -s 0<CR>") | |
| vim.keymap.set("n", "<M-k>", "<cmd>silent !tmux neww tmux-sessionizer -s 1<CR>") | |
| vim.keymap.set("n", "<M-l>", "<cmd>silent !tmux neww tmux-sessionizer -s 2<CR>") | |
| vim.keymap.set("n", "<M-;>", "<cmd>silent !tmux neww tmux-sessionizer -s 3<CR>") | |
| -- vim: ts=2 sts=2 sw=2 et |
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
| #!/usr/bin/env bash | |
| CONFIG_FILE_NAME="tmux-sessionizer.conf" | |
| CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-sessionizer" | |
| CONFIG_FILE="$CONFIG_DIR/$CONFIG_FILE_NAME" | |
| PANE_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/tmux-sessionizer" | |
| PANE_CACHE_FILE="$PANE_CACHE_DIR/panes.cache" | |
| # config file example | |
| # ------------------------ | |
| # # file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf | |
| # # If set this override the default TS_SEARCH_PATHS (~/personal ~/projects) | |
| # TS_SEARCH_PATHS=(~/) | |
| # # If set this add additional search paths to the default TS_SEARCH_PATHS | |
| # # The number prefix is the depth for the Path [OPTIONAL] | |
| # TS_EXTRA_SEARCH_PATHS=(~/ghq:3 ~/Git:3 ~/.config:2) | |
| # # if set this override the TS_MAX_DEPTH (1) | |
| # TS_MAX_DEPTH=2 | |
| # This is not meant to override .tmux-sessionizer. At first i thought this | |
| # would be a good command, but i don't think its ackshually what i want. | |
| # | |
| # Instead, its a list of commands to run on windows who's index is way outside | |
| # of the first 10 windows. This allows you to create as many windows in your | |
| # session as you would like without having your workflow interrupted by these | |
| # programatic windows | |
| # | |
| # how to use: | |
| # tmux-sessionizer -s 0 will execute the first command in window -t 69. | |
| # use single quotes to wrap the command. | |
| # TS_SESSION_COMMANDS=(<cmd1> <cmd2>) | |
| # | |
| # TS_LOG=true # will write logs to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # TS_LOG_FILE=<file> # will write logs to <file> Defaults to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # ------------------------ | |
| if [[ -f "$CONFIG_FILE" ]]; then | |
| source "$CONFIG_FILE" | |
| fi | |
| if [[ -f "$CONFIG_FILE_NAME" ]]; then | |
| source "$CONFIG_FILE_NAME" | |
| fi | |
| if [[ $TS_LOG != "true" ]]; then | |
| if [[ -z $TS_LOG_FILE ]]; then | |
| TS_LOG_FILE="$HOME/.local/share/tmux-sessionizer/tmux-sessionizer.logs" | |
| fi | |
| mkdir -p "$(dirname "$TS_LOG_FILE")" | |
| fi | |
| log() { | |
| if [[ -z $TS_LOG ]]; then | |
| return | |
| elif [[ $TS_LOG == "echo" ]]; then | |
| echo "$*" | |
| elif [[ $TS_LOG == "file" ]]; then | |
| echo "$*" >> "$TS_LOG_FILE" | |
| fi | |
| } | |
| # if TS_SEARCH_PATHS is not set use default | |
| [[ -n "$TS_SEARCH_PATHS" ]] || TS_SEARCH_PATHS=(~/personal ~/projects) | |
| # Add any extra search paths to the TS_SEARCH_PATHS array | |
| # e.g : EXTRA_SEARCH_PATHS=("$HOME/extra1:4" "$HOME/extra2") | |
| # note : Path can be suffixed with :number to limit or extend the depth of the search for the Path | |
| if [[ ${#TS_EXTRA_SEARCH_PATHS[@]} -gt 0 ]]; then | |
| TS_SEARCH_PATHS+=("${TS_EXTRA_SEARCH_PATHS[@]}") | |
| fi | |
| # utility function to find directories | |
| find_dirs() { | |
| # list TMUX sessions | |
| if [[ -n "${TMUX}" ]]; then | |
| current_session=$(tmux display-message -p '#S') | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | grep -vFx "[TMUX] $current_session" | sort -Vr | |
| else | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | sort -Vr | |
| fi | |
| # note: TS_SEARCH_PATHS is an array of paths to search for directories | |
| # if the path ends with :number, it will search for directories with a max depth of number ;) | |
| # if there is no number, it will search for directories with a max depth defined by TS_MAX_DEPTH or 1 if not set | |
| for entry in "${TS_SEARCH_PATHS[@]}"; do | |
| # Check if entry as :number as suffix then adapt the maxdepth parameter | |
| if [[ "$entry" =~ ^([^:]+):([0-9]+)$ ]]; then | |
| path="${BASH_REMATCH[1]}" | |
| depth="${BASH_REMATCH[2]}" | |
| else | |
| path="$entry" | |
| fi | |
| [[ -d "$path" ]] && find "$path" -mindepth 1 -maxdepth "${depth:-${TS_MAX_DEPTH:-1}}" -path '*/.git' -prune -o -type d -print | |
| done | sort -Vr | |
| } | |
| session_idx="" | |
| session_cmd="" | |
| user_selected="" | |
| split_type="" | |
| VERSION="0.1.0" | |
| while [[ "$#" -gt 0 ]]; do | |
| case "$1" in | |
| -h | --help) | |
| echo "Usage: tmux-sessionizer [OPTIONS] [SEARCH_PATH]" | |
| echo "" | |
| echo "A tmux session manager that creates and switches between project sessions." | |
| echo "" | |
| echo "Options:" | |
| echo " -h, --help Display this help message" | |
| echo " -v, --version Show version information" | |
| echo " -s, --session <index> Execute session command by index (requires TS_SESSION_COMMANDS)" | |
| echo " --vsplit Create vertical split for session command (use with -s)" | |
| echo " --hsplit Create horizontal split for session command (use with -s)" | |
| echo " --find-dirs List all available directories and tmux sessions" | |
| echo "" | |
| echo "Interactive Mode:" | |
| echo " When run without arguments, opens fzf to select from:" | |
| echo " - Existing tmux sessions (prefixed with [TMUX])" | |
| echo " - Project directories from configured search paths" | |
| echo "" | |
| echo " Keybindings in fzf:" | |
| echo " ENTER - Select and switch to session/directory" | |
| echo " CTRL-D - Kill selected tmux session" | |
| echo "" | |
| echo "Configuration:" | |
| echo " Config file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf" | |
| echo " See script comments for configuration options." | |
| echo "" | |
| echo "Examples:" | |
| echo " tmux-sessionizer # Interactive mode" | |
| echo " tmux-sessionizer ~/my-project # Direct path selection" | |
| echo " tmux-sessionizer -s 0 # Execute first session command" | |
| echo " tmux-sessionizer -s 1 --vsplit # Execute second command in vertical split" | |
| exit 0 | |
| ;; | |
| -s | --session) | |
| session_idx="$2" | |
| if [[ -z $session_idx ]]; then | |
| echo "Session index cannot be empty" | |
| exit 1 | |
| fi | |
| if [[ -z $TS_SESSION_COMMANDS ]]; then | |
| echo "TS_SESSION_COMMANDS is not set. Must have a command set to run when switching to a session" | |
| exit 1 | |
| fi | |
| if [[ -z "$session_idx" || "$session_idx" -lt 0 || "$session_idx" -ge "${#TS_SESSION_COMMANDS[@]}" ]]; then | |
| echo "Error: Invalid index. Please provide an index between 0 and $((${#TS_SESSION_COMMANDS[@]} - 1))." | |
| exit 1 | |
| fi | |
| session_cmd="${TS_SESSION_COMMANDS[$session_idx]}" | |
| shift | |
| ;; | |
| --vsplit) | |
| split_type="vsplit" | |
| ;; | |
| --hsplit) | |
| split_type="hsplit" | |
| ;; | |
| -v | --version) | |
| echo "tmux-sessionizer version $VERSION" | |
| exit 0 | |
| ;; | |
| --find-dirs) | |
| find_dirs | |
| exit 0 | |
| ;; | |
| *) | |
| user_selected="$1" | |
| ;; | |
| esac | |
| shift | |
| done | |
| log "tmux-sessionizer($VERSION): idx=$session_idx cmd=$session_cmd user_selected=$user_selected split_type=$split_type log=$TS_LOG log_file=$TS_LOG_FILE" | |
| # Validate split options are only used with session commands | |
| if [[ -n "$split_type" && -z "$session_idx" ]]; then | |
| echo "Error: --vsplit and --hsplit can only be used with -s/--session option" | |
| exit 1 | |
| fi | |
| sanity_check() { | |
| if ! command -v tmux &>/dev/null; then | |
| echo "tmux is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| if ! command -v fzf &>/dev/null; then | |
| echo "fzf is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| } | |
| switch_to() { | |
| if [[ -z $TMUX ]]; then | |
| log "attaching to session $1" | |
| tmux attach-session -t "$1" | |
| else | |
| log "switching to session $1" | |
| tmux switch-client -t "$1" | |
| fi | |
| } | |
| has_session() { | |
| tmux list-sessions | grep -q "^$1:" | |
| } | |
| hydrate() { | |
| if [[ ! -z $session_cmd ]]; then | |
| log "skipping hydrate for $1 -- using \"$session_cmd\" instead" | |
| return | |
| elif [ -f "$2/.tmux-sessionizer" ]; then | |
| log "sourcing(local) $2/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $2/.tmux-sessionizer" c-M | |
| elif [ -f "$HOME/.tmux-sessionizer" ]; then | |
| log "sourcing(global) $HOME/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $HOME/.tmux-sessionizer" c-M | |
| fi | |
| } | |
| is_tmux_running() { | |
| tmux_running=$(pgrep tmux) | |
| if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| init_pane_cache() { | |
| mkdir -p "$PANE_CACHE_DIR" | |
| touch "$PANE_CACHE_FILE" | |
| } | |
| get_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| init_pane_cache | |
| grep "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" | cut -d: -f3 | |
| } | |
| set_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| local pane_id="$3" | |
| init_pane_cache | |
| # Remove existing entry if it exists | |
| grep -v "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" > "${PANE_CACHE_FILE}.tmp" 2>/dev/null || true | |
| mv "${PANE_CACHE_FILE}.tmp" "$PANE_CACHE_FILE" | |
| # Add new entry | |
| echo "${session_idx}:${split_type}:${pane_id}" >> "$PANE_CACHE_FILE" | |
| } | |
| cleanup_dead_panes() { | |
| init_pane_cache | |
| local temp_file="${PANE_CACHE_FILE}.tmp" | |
| while IFS=: read -r idx split pane_id; do | |
| if tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${pane_id}$"; then | |
| echo "${idx}:${split}:${pane_id}" >> "$temp_file" | |
| fi | |
| done < "$PANE_CACHE_FILE" | |
| mv "$temp_file" "$PANE_CACHE_FILE" 2>/dev/null || touch "$PANE_CACHE_FILE" | |
| } | |
| sanity_check | |
| handle_session_cmd() { | |
| log "executing session command $session_cmd with index $session_idx split_type=$split_type" | |
| if ! is_tmux_running; then | |
| echo "Error: tmux is not running. Please start tmux first before using session commands." | |
| exit 1 | |
| fi | |
| current_session=$(tmux display-message -p '#S') | |
| if [[ -n "$split_type" ]]; then | |
| handle_split_session_cmd "$current_session" | |
| else | |
| handle_window_session_cmd "$current_session" | |
| fi | |
| exit 0 | |
| } | |
| handle_window_session_cmd() { | |
| local current_session="$1" | |
| start_index=$((69 + $session_idx)) | |
| target="$current_session:$start_index" | |
| log "target: $target command $session_cmd has-session=$(tmux has-session -t="$target" 2> /dev/null)" | |
| if tmux has-session -t="$target" 2> /dev/null; then | |
| switch_to "$target" | |
| else | |
| log "executing session command: tmux neww -dt $target $session_cmd" | |
| tmux neww -dt $target "$session_cmd" | |
| hydrate "$target" "$selected" | |
| tmux select-window -t $target | |
| fi | |
| } | |
| handle_split_session_cmd() { | |
| local current_session="$1" | |
| cleanup_dead_panes | |
| # Check if pane already exists | |
| local existing_pane_id=$(get_pane_id "$session_idx" "$split_type") | |
| if [[ -n "$existing_pane_id" ]] && tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${existing_pane_id}$"; then | |
| log "switching to existing pane $existing_pane_id" | |
| tmux select-pane -t "$existing_pane_id" | |
| if [[ -z $TMUX ]]; then | |
| tmux attach-session -t "$current_session" | |
| else | |
| tmux switch-client -t "$current_session" | |
| fi | |
| else | |
| # Create new split | |
| local split_flag="" | |
| if [[ "$split_type" == "vsplit" ]]; then | |
| split_flag="-h" # horizontal layout (vertical split) | |
| else | |
| split_flag="-v" # vertical layout (horizontal split) | |
| fi | |
| log "creating new split: tmux split-window $split_flag -c $(pwd) $session_cmd" | |
| local new_pane_id=$(tmux split-window $split_flag -c "$(pwd)" -P -F "#{pane_id}" "$session_cmd") | |
| if [[ -n "$new_pane_id" ]]; then | |
| set_pane_id "$session_idx" "$split_type" "$new_pane_id" | |
| log "created pane $new_pane_id for session_idx=$session_idx split_type=$split_type" | |
| fi | |
| fi | |
| } | |
| if [[ ! -z $session_cmd ]]; then | |
| handle_session_cmd | |
| elif [[ ! -z $user_selected ]]; then | |
| selected="$user_selected" | |
| else | |
| # selected=$(find_dirs | fzf) | |
| selected=$(find_dirs | fzf \ | |
| --bind 'ctrl-d:execute-silent( | |
| [[ {} == \[TMUX\]* ]] && tmux kill-session -t "$(echo {} | cut -d" " -f2-)" | |
| )+reload(tmux-sessionizer --find-dirs)' \ | |
| --header 'ENTER: select, CTRL-D: kill session') | |
| fi | |
| if [[ -z $selected ]]; then | |
| exit 0 | |
| fi | |
| if [[ "$selected" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| fi | |
| selected_name=$(basename "$selected" | tr . _) | |
| if ! is_tmux_running; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| if ! has_session "$selected_name"; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| # Create two additional windows (total of 3) | |
| tmux new-window -t "$selected_name" -c "$selected" # Window 1 | |
| tmux new-window -t "$selected_name" -c "$selected" # Window 2 | |
| # Execute commands in specific windows with proper shell loading | |
| tmux send-keys -t "$selected_name:0" "nvim" C-m # Window 0: nvim | |
| tmux send-keys -t "$selected_name:1" "source ~/.zshrc && dev" C-m # Window 1: dev with zshrc loaded | |
| # Window 2 remains empty with shell | |
| # Select the first window | |
| tmux select-window -t "$selected_name:0" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| switch_to "$selected_name" |
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
| #!/usr/bin/env bash | |
| CONFIG_FILE_NAME="tmux-sessionizer.conf" | |
| CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/tmux-sessionizer" | |
| CONFIG_FILE="$CONFIG_DIR/$CONFIG_FILE_NAME" | |
| PANE_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/tmux-sessionizer" | |
| PANE_CACHE_FILE="$PANE_CACHE_DIR/panes.cache" | |
| # config file example | |
| # ------------------------ | |
| # # file: ~/.config/tmux-sessionizer/tmux-sessionizer.conf | |
| # # If set this override the default TS_SEARCH_PATHS (~/personal ~/projects) | |
| # TS_SEARCH_PATHS=(~/) | |
| # # If set this add additional search paths to the default TS_SEARCH_PATHS | |
| # # The number prefix is the depth for the Path [OPTIONAL] | |
| # TS_EXTRA_SEARCH_PATHS=(~/ghq:3 ~/Git:3 ~/.config:2) | |
| # # if set this override the TS_MAX_DEPTH (1) | |
| # TS_MAX_DEPTH=2 | |
| # This is not meant to override .tmux-sessionizer. At first i thought this | |
| # would be a good command, but i don't think its ackshually what i want. | |
| # | |
| # Instead, its a list of commands to run on windows who's index is way outside | |
| # of the first 10 windows. This allows you to create as many windows in your | |
| # session as you would like without having your workflow interrupted by these | |
| # programatic windows | |
| # | |
| # how to use: | |
| # tmux-sessionizer -s 0 will execute the first command in window -t 69. | |
| # use single quotes to wrap the command. | |
| # TS_SESSION_COMMANDS=(<cmd1> <cmd2>) | |
| # | |
| # TS_LOG=true # will write logs to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # TS_LOG_FILE=<file> # will write logs to <file> Defaults to ~/.local/share/tmux-sessionizer/tmux-sessionizer.logs | |
| # ------------------------ | |
| if [[ -f "$CONFIG_FILE" ]]; then | |
| source "$CONFIG_FILE" | |
| fi | |
| if [[ -f "$CONFIG_FILE_NAME" ]]; then | |
| source "$CONFIG_FILE_NAME" | |
| fi | |
| if [[ $TS_LOG != "true" ]]; then | |
| if [[ -z $TS_LOG_FILE ]]; then | |
| TS_LOG_FILE="$HOME/.local/share/tmux-sessionizer/tmux-sessionizer.logs" | |
| fi | |
| mkdir -p "$(dirname "$TS_LOG_FILE")" | |
| fi | |
| log() { | |
| if [[ -z $TS_LOG ]]; then | |
| return | |
| elif [[ $TS_LOG == "echo" ]]; then | |
| echo "$*" | |
| elif [[ $TS_LOG == "file" ]]; then | |
| echo "$*" >> "$TS_LOG_FILE" | |
| fi | |
| } | |
| # if TS_SEARCH_PATHS is not set use default | |
| [[ -n "$TS_SEARCH_PATHS" ]] || TS_SEARCH_PATHS=(~/personal ~/projects) | |
| # Add any extra search paths to the TS_SEARCH_PATHS array | |
| # e.g : EXTRA_SEARCH_PATHS=("$HOME/extra1:4" "$HOME/extra2") | |
| # note : Path can be suffixed with :number to limit or extend the depth of the search for the Path | |
| if [[ ${#TS_EXTRA_SEARCH_PATHS[@]} -gt 0 ]]; then | |
| TS_SEARCH_PATHS+=("${TS_EXTRA_SEARCH_PATHS[@]}") | |
| fi | |
| # utility function to find directories | |
| find_dirs() { | |
| # list TMUX sessions | |
| if [[ -n "${TMUX}" ]]; then | |
| current_session=$(tmux display-message -p '#S') | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | grep -vFx "[TMUX] $current_session" | sort -Vr | |
| else | |
| tmux list-sessions -F "[TMUX] #{session_name}" 2>/dev/null | sort -Vr | |
| fi | |
| # note: TS_SEARCH_PATHS is an array of paths to search for directories | |
| # if the path ends with :number, it will search for directories with a max depth of number ;) | |
| # if there is no number, it will search for directories with a max depth defined by TS_MAX_DEPTH or 1 if not set | |
| for entry in "${TS_SEARCH_PATHS[@]}"; do | |
| # Check if entry as :number as suffix then adapt the maxdepth parameter | |
| if [[ "$entry" =~ ^([^:]+):([0-9]+)$ ]]; then | |
| path="${BASH_REMATCH[1]}" | |
| depth="${BASH_REMATCH[2]}" | |
| else | |
| path="$entry" | |
| fi | |
| [[ -d "$path" ]] && find "$path" -mindepth 1 -maxdepth "${depth:-${TS_MAX_DEPTH:-1}}" -path '*/.git' -prune -o -type d -print | |
| done | sort -Vr | |
| } | |
| get_jira_title() { | |
| local ticket="$1" | |
| local cache_file="$HOME/.cache/tmux-sessionizer-jira/$ticket" | |
| if [[ -f "$cache_file" && $(find "$cache_file" -mtime -7 2>/dev/null) ]]; then | |
| cat "$cache_file" | |
| else | |
| mkdir -p "$(dirname "$cache_file")" | |
| local title=$(acli jira workitem view "$ticket" --fields summary 2>/dev/null | tail -1 | sed 's/^[[:space:]]*Summary: //') | |
| echo "$title" > "$cache_file" | |
| echo "$title" | |
| fi | |
| } | |
| add_jira_info() { | |
| while IFS= read -r line; do | |
| if [[ "$line" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| session_name="${BASH_REMATCH[1]}" | |
| if [[ "$session_name" =~ (CONN-[0-9]+) ]]; then | |
| ticket="${BASH_REMATCH[1]}" | |
| title=$(get_jira_title "$ticket") | |
| if [[ -n "$title" ]]; then | |
| echo "$line [$ticket: $title]" | |
| else | |
| echo "$line [$ticket]" | |
| fi | |
| else | |
| echo "$line" | |
| fi | |
| else | |
| dir_name=$(basename "$line") | |
| if [[ "$dir_name" =~ ^(CONN-[0-9]+) ]]; then | |
| ticket="${BASH_REMATCH[1]}" | |
| title=$(get_jira_title "$ticket") | |
| if [[ -n "$title" ]]; then | |
| echo "$line [$ticket: $title]" | |
| else | |
| echo "$line [$ticket]" | |
| fi | |
| else | |
| echo "$line" | |
| fi | |
| fi | |
| done | |
| } | |
| session_idx="" | |
| session_cmd="" | |
| user_selected="" | |
| split_type="" | |
| VERSION="0.1.0" | |
| while [[ "$#" -gt 0 ]]; do | |
| case "$1" in | |
| -h | --help) | |
| echo "Usage: tmux-sessionizer [OPTIONS] [SEARCH_PATH]" | |
| echo "Options:" | |
| echo " -h, --help Display this help message" | |
| echo " -s, --session <name> session command index." | |
| echo " --vsplit Create vertical split (horizontal layout) for session command" | |
| echo " --hsplit Create horizontal split (vertical layout) for session command" | |
| exit 0 | |
| ;; | |
| -s | --session) | |
| session_idx="$2" | |
| if [[ -z $session_idx ]]; then | |
| echo "Session index cannot be empty" | |
| exit 1 | |
| fi | |
| if [[ -z $TS_SESSION_COMMANDS ]]; then | |
| echo "TS_SESSION_COMMANDS is not set. Must have a command set to run when switching to a session" | |
| exit 1 | |
| fi | |
| if [[ -z "$session_idx" || "$session_idx" -lt 0 || "$session_idx" -ge "${#TS_SESSION_COMMANDS[@]}" ]]; then | |
| echo "Error: Invalid index. Please provide an index between 0 and $((${#TS_SESSION_COMMANDS[@]} - 1))." | |
| exit 1 | |
| fi | |
| session_cmd="${TS_SESSION_COMMANDS[$session_idx]}" | |
| shift | |
| ;; | |
| --vsplit) | |
| split_type="vsplit" | |
| ;; | |
| --hsplit) | |
| split_type="hsplit" | |
| ;; | |
| -v | --version) | |
| echo "tmux-sessionizer version $VERSION" | |
| exit 0 | |
| ;; | |
| --find-dirs) | |
| find_dirs | |
| exit 0 | |
| ;; | |
| --find-dirs-jira) | |
| find_dirs | add_jira_info | |
| exit 0 | |
| ;; | |
| *) | |
| user_selected="$1" | |
| ;; | |
| esac | |
| shift | |
| done | |
| log "tmux-sessionizer($VERSION): idx=$session_idx cmd=$session_cmd user_selected=$user_selected split_type=$split_type log=$TS_LOG log_file=$TS_LOG_FILE" | |
| # Validate split options are only used with session commands | |
| if [[ -n "$split_type" && -z "$session_idx" ]]; then | |
| echo "Error: --vsplit and --hsplit can only be used with -s/--session option" | |
| exit 1 | |
| fi | |
| sanity_check() { | |
| if ! command -v tmux &>/dev/null; then | |
| echo "tmux is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| if ! command -v fzf &>/dev/null; then | |
| echo "fzf is not installed. Please install it first." | |
| exit 1 | |
| fi | |
| } | |
| switch_to() { | |
| if [[ -z $TMUX ]]; then | |
| log "attaching to session $1" | |
| tmux attach-session -t "$1" | |
| else | |
| log "switching to session $1" | |
| tmux switch-client -t "$1" | |
| fi | |
| } | |
| has_session() { | |
| tmux list-sessions | grep -q "^$1:" | |
| } | |
| hydrate() { | |
| if [[ ! -z $session_cmd ]]; then | |
| log "skipping hydrate for $1 -- using \"$session_cmd\" instead" | |
| return | |
| elif [ -f "$2/.tmux-sessionizer" ]; then | |
| log "sourcing(local) $2/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $2/.tmux-sessionizer" c-M | |
| elif [ -f "$HOME/.tmux-sessionizer" ]; then | |
| log "sourcing(global) $HOME/.tmux-sessionizer" | |
| tmux send-keys -t "$1" "source $HOME/.tmux-sessionizer" c-M | |
| fi | |
| } | |
| is_tmux_running() { | |
| tmux_running=$(pgrep tmux) | |
| if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| init_pane_cache() { | |
| mkdir -p "$PANE_CACHE_DIR" | |
| touch "$PANE_CACHE_FILE" | |
| } | |
| get_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| init_pane_cache | |
| grep "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" | cut -d: -f3 | |
| } | |
| set_pane_id() { | |
| local session_idx="$1" | |
| local split_type="$2" | |
| local pane_id="$3" | |
| init_pane_cache | |
| # Remove existing entry if it exists | |
| grep -v "^${session_idx}:${split_type}:" "$PANE_CACHE_FILE" > "${PANE_CACHE_FILE}.tmp" 2>/dev/null || true | |
| mv "${PANE_CACHE_FILE}.tmp" "$PANE_CACHE_FILE" | |
| # Add new entry | |
| echo "${session_idx}:${split_type}:${pane_id}" >> "$PANE_CACHE_FILE" | |
| } | |
| cleanup_dead_panes() { | |
| init_pane_cache | |
| local temp_file="${PANE_CACHE_FILE}.tmp" | |
| while IFS=: read -r idx split pane_id; do | |
| if tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${pane_id}$"; then | |
| echo "${idx}:${split}:${pane_id}" >> "$temp_file" | |
| fi | |
| done < "$PANE_CACHE_FILE" | |
| mv "$temp_file" "$PANE_CACHE_FILE" 2>/dev/null || touch "$PANE_CACHE_FILE" | |
| } | |
| sanity_check | |
| handle_session_cmd() { | |
| log "executing session command $session_cmd with index $session_idx split_type=$split_type" | |
| if ! is_tmux_running; then | |
| echo "Error: tmux is not running. Please start tmux first before using session commands." | |
| exit 1 | |
| fi | |
| current_session=$(tmux display-message -p '#S') | |
| if [[ -n "$split_type" ]]; then | |
| handle_split_session_cmd "$current_session" | |
| else | |
| handle_window_session_cmd "$current_session" | |
| fi | |
| exit 0 | |
| } | |
| handle_window_session_cmd() { | |
| local current_session="$1" | |
| start_index=$((69 + $session_idx)) | |
| target="$current_session:$start_index" | |
| log "target: $target command $session_cmd has-session=$(tmux has-session -t="$target" 2> /dev/null)" | |
| if tmux has-session -t="$target" 2> /dev/null; then | |
| switch_to "$target" | |
| else | |
| log "executing session command: tmux neww -dt $target $session_cmd" | |
| tmux neww -dt $target "$session_cmd" | |
| hydrate "$target" "$selected" | |
| tmux select-window -t $target | |
| fi | |
| } | |
| handle_split_session_cmd() { | |
| local current_session="$1" | |
| cleanup_dead_panes | |
| # Check if pane already exists | |
| local existing_pane_id=$(get_pane_id "$session_idx" "$split_type") | |
| if [[ -n "$existing_pane_id" ]] && tmux list-panes -a -F "#{pane_id}" 2>/dev/null | grep -q "^${existing_pane_id}$"; then | |
| log "switching to existing pane $existing_pane_id" | |
| tmux select-pane -t "$existing_pane_id" | |
| if [[ -z $TMUX ]]; then | |
| tmux attach-session -t "$current_session" | |
| else | |
| tmux switch-client -t "$current_session" | |
| fi | |
| else | |
| # Create new split | |
| local split_flag="" | |
| if [[ "$split_type" == "vsplit" ]]; then | |
| split_flag="-h" # horizontal layout (vertical split) | |
| else | |
| split_flag="-v" # vertical layout (horizontal split) | |
| fi | |
| log "creating new split: tmux split-window $split_flag -c $(pwd) $session_cmd" | |
| local new_pane_id=$(tmux split-window $split_flag -c "$(pwd)" -P -F "#{pane_id}" "$session_cmd") | |
| if [[ -n "$new_pane_id" ]]; then | |
| set_pane_id "$session_idx" "$split_type" "$new_pane_id" | |
| log "created pane $new_pane_id for session_idx=$session_idx split_type=$split_type" | |
| fi | |
| fi | |
| } | |
| if [[ ! -z $session_cmd ]]; then | |
| handle_session_cmd | |
| elif [[ ! -z $user_selected ]]; then | |
| selected="$user_selected" | |
| else | |
| selected=$(find_dirs | fzf \ | |
| --bind 'start:reload(tmux-sessionizer2 --find-dirs-jira)' \ | |
| --bind 'ctrl-d:execute-silent( | |
| session=$(echo {} | sed "s/^\\\[TMUX\\\] \\([^ ]*\\).*/\\1/") | |
| [[ {} == \\[TMUX\\]* ]] && tmux kill-session -t "$session" | |
| )+reload(tmux-sessionizer2 --find-dirs-jira)' \ | |
| --header 'ENTER: select, CTRL-D: kill session') | |
| fi | |
| if [[ -z $selected ]]; then | |
| exit 0 | |
| fi | |
| if [[ "$selected" =~ ^\[TMUX\]\ (.+)\ \[CONN-[0-9]+: ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| elif [[ "$selected" =~ ^\[TMUX\]\ (.+)$ ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| elif [[ "$selected" =~ ^(.+)\ \[CONN-[0-9]+: ]]; then | |
| selected="${BASH_REMATCH[1]}" | |
| fi | |
| selected_name=$(basename "$selected" | tr . _) | |
| if ! is_tmux_running; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| if ! has_session "$selected_name"; then | |
| tmux new-session -ds "$selected_name" -c "$selected" | |
| hydrate "$selected_name" "$selected" | |
| fi | |
| switch_to "$selected_name" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment