Compare commits

...
7 Commits
Author SHA1 Message Date
Legrems d3e84d1257 feat: add firefox groups 2025-07-24 12:07:59 +02:00
Legrems 36bd56bcc4 Update tmux-pane-selection scripts to be more clear 2024-09-02 19:45:42 +02:00
Legrems 78ce7dac48 Update 15.08.2024 2024-08-15 16:10:44 +02:00
Legrems 6b1d53f65d Update tmux pane selection 2024-06-13 22:31:42 +02:00
Legrems c2b6eaa87a Add tmux pane selection 2024-06-10 16:46:58 +02:00
Legrems 953b9a791c Add tmux session select, update other scripts 2024-06-09 03:14:24 +02:00
Legrems d6e0fd4025 Update tmux-ssh-groups 2024-05-29 15:27:19 +02:00
6 changed files with 373 additions and 74 deletions
+65
View File
@@ -0,0 +1,65 @@
import argparse
import configparser
import os
import subprocess
import sys
from pathlib import Path
from pyfzf.pyfzf import FzfPrompt
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-open",
action="store_true",
help="Do not open firefox window. Mostly for debugging",
)
parser_args = parser.parse_args()
BASE_PATH = Path("~/.firefox/").expanduser()
configs = {}
sections = {}
for subconffile in os.listdir(BASE_PATH):
if not subconffile.endswith(".ini"):
continue
prefix = subconffile.replace(".ini", "").capitalize()
config = configparser.ConfigParser()
config.read(BASE_PATH / subconffile)
configs[subconffile] = config
for section in config.sections():
section_name = f"[{prefix}] {section}"
sections[section_name] = {
"section": section,
"config": subconffile,
}
fzf = FzfPrompt()
selections = fzf.prompt(
["Select one or more group to open"] + list(sections.keys()),
"--cycle --multi --header-lines 1",
)
if not selections:
sys.exit(0)
for selected_group in selections:
info = sections[selected_group]
config = configs[info["config"]]
prefix = config[info["section"]].get("prefix", "")
suffix = config[info["section"]].get("suffix", "")
endpoints = [
f"{prefix}{e}{suffix}" for e in config[info["section"]]["endpoints"].split("\n")
]
data = ["firefox"]
for endpoint in endpoints:
data.extend(["--new-tab", endpoint])
subprocess.Popen(data)
+35 -11
View File
@@ -1,18 +1,29 @@
import argparse
import configparser import configparser
import sys import sys
import time import time
import libtmux
from pathlib import Path from pathlib import Path
import libtmux
from pyfzf.pyfzf import FzfPrompt from pyfzf.pyfzf import FzfPrompt
parser = argparse.ArgumentParser()
parser.add_argument("--servers-file", "-f", help="Servers file to connect to")
parser_args = parser.parse_args()
if parser_args.servers_file:
with open(parser_args.servers_file, "r") as file:
data = file.read()
servers = []
for line in data.strip().split("\n"):
servers.append(line.strip())
config = configparser.ConfigParser() config = configparser.ConfigParser()
config_path = Path("~/.ssh-tmux-multi.ini").expanduser() config_path = Path("~/.ssh-tmux-multi.ini").expanduser()
config.read(config_path) config.read(config_path)
fav_key = "Favourite servers" fav_key = "Favourite servers"
fzf = FzfPrompt() fzf = FzfPrompt()
@@ -27,7 +38,9 @@ def get_all_known_ssh_hosts():
servers.add(line.split(" ")[0]) servers.add(line.split(" ")[0])
# Check previous ssh command on histfile # Check previous ssh command on histfile
with open(Path("~/.histfile").expanduser(), "r", encoding="utf-8", errors="ignore") as file: with open(
Path("~/.histfile").expanduser(), "r", encoding="utf-8", errors="ignore"
) as file:
lines = file.read().strip().split("\n") lines = file.read().strip().split("\n")
for line in lines: for line in lines:
@@ -47,14 +60,16 @@ def get_favourite_servers_first():
order = {} order = {}
for server in servers: for server in servers:
order[server] = '0' order[server] = "0"
for server, uses in config[fav_key].items(): for server, uses in config[fav_key].items():
if server in order: if server in order:
order[server] = uses order[server] = uses
# Return the most used servers first # Return the most used servers first
return [x[0] for x in sorted(order.items(), key=lambda x: int(x[1]), reverse=True)] for count, value in order.items():
print(count, value)
return [x[0] for x in sorted(order.items(), key=lambda x: x[1], reverse=True)]
def write_choosen_servers(servers): def write_choosen_servers(servers):
@@ -68,12 +83,17 @@ def write_choosen_servers(servers):
config[fav_key][server] = str(int(config[fav_key][server]) + 1) config[fav_key][server] = str(int(config[fav_key][server]) + 1)
else: else:
config[fav_key][server] = '1' config[fav_key][server] = "1"
with open(config_path, "w") as file: with open(config_path, "w") as file:
config.write(file) config.write(file)
servers = fzf.prompt(get_favourite_servers_first(), "--cycle --multi --print-query")
if not parser_args.servers_file:
servers = fzf.prompt(
["Select server to connect to"] + get_favourite_servers_first(),
"--cycle --multi --print-query --header-lines 1 --tmux center",
)
# Strip from query if found else, use the query # Strip from query if found else, use the query
if len(servers) > 1: if len(servers) > 1:
@@ -85,8 +105,10 @@ if not servers:
write_choosen_servers(servers) write_choosen_servers(servers)
srv = libtmux.Server() srv = libtmux.Server()
active_session = srv.sessions.filter(session_attached='1')[0] active_session = srv.sessions.filter(session_attached="1")[0]
window = active_session.new_window(f"ssh-multis {','.join(servers)}", window_shell=f"ssh {servers[0]}") window = active_session.new_window(
f"ssh-multis {','.join(servers)}", window_shell=f"ssh {servers[0]}"
)
for server in servers[1:]: for server in servers[1:]:
window.select_layout("tiled") window.select_layout("tiled")
@@ -96,7 +118,9 @@ for server in servers[1:]:
time.sleep(0.1) time.sleep(0.1)
# Confirm connection on asking panes # Confirm connection on asking panes
confirmation_needed_text = "Are you sure you want to continue connecting (yes/no/[fingerprint])?" confirmation_needed_text = (
"Are you sure you want to continue connecting (yes/no/[fingerprint])?"
)
for pane in window.panes: for pane in window.panes:
pane_content = pane.capture_pane() pane_content = pane.capture_pane()
if pane_content and confirmation_needed_text == pane_content[-1]: if pane_content and confirmation_needed_text == pane_content[-1]:
+99
View File
@@ -0,0 +1,99 @@
import argparse
import sys
from collections import defaultdict
from pprint import pprint
import libtmux
import sh
from pyfzf.pyfzf import FzfPrompt
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-open",
action="store_true",
help="Do not open tmux window. Mostly for debugging",
)
parser_args = parser.parse_args()
# Get active tmux sessions
srv = libtmux.Server()
fzf = FzfPrompt()
commands = defaultdict(list)
all_tty = [p.pane_tty for p in srv.panes]
cmd = f"-t {' -t '.join(all_tty)} -o pid:10 -o tty:10 -o command -ww" # -f
sh_commands = sh.ps(cmd.split(" ")).stdout.decode().strip().split("\n")
# Ignore first lines (i.e: table headers)
for cmd in sh_commands[1:]:
pid = cmd[:10].strip()
tty = cmd[10:20].strip()
command = cmd[20:].strip()
tty_number = int(tty.replace("pts/", ""))
if command in ["-zsh", "/bin/zsh"]:
continue
commands[tty_number].append(
{
"pid": int(pid),
"command": command,
}
)
def format_pane(pane):
global commands
tty_number = int(pane.pane_tty.replace("/dev/pts/", ""))
running_commands = sorted(commands[tty_number], key=lambda c: c["pid"])
if len(running_commands) >= 1:
cmd = running_commands[0]
else:
cmd = {"pid": "-", "command": "*command not found*"}
path = pane.pane_current_path.replace("/home/legrems/Documents/Arcanite", "~/D/A")
path = path.replace("/home/legrems/Documents", "~/D")
path = path.replace("/home/legrems", "~")
return [
f"{pane.pane_tty}: [{pane.session_name}: {pane.window_name}, {path}]: {cmd['command']}"
]
panes = []
for pane in srv.panes:
panes.extend(format_pane(pane))
selections = fzf.prompt(
["Select one pane you want to switch to"] + panes,
"--cycle --header-lines 1 --tmux center",
)
if not selections:
sys.exit(0)
pane_name = selections[0]
tty = pane_name.split(":")[0]
selected_pane = srv.panes.get(pane_tty=tty)
if parser_args.no_open:
print(selected_pane)
print(tty)
tty_number = int(tty.replace("/dev/pts/", ""))
pprint(commands[tty_number])
else:
# Go to this session
selected_pane.session.switch_client()
# Select the correct window
selected_pane.window.select()
# And switch to this pane
selected_pane.window.select_pane(selected_pane.pane_id)
+31
View File
@@ -0,0 +1,31 @@
import sys
import libtmux
from pyfzf.pyfzf import FzfPrompt
# Get active tmux sessions
srv = libtmux.Server()
fzf = FzfPrompt()
mapping = {}
lm = max(len(s.name) for s in srv.sessions if s.name)
for session in srv.sessions:
string = f"({session.name: <{lm}}) {session.session_path}"
mapping[string] = session
selections = fzf.prompt(
["Select one session you want to switch to"] + list(mapping.keys()),
"--cycle --header-lines 1 --tmux center",
)
if not selections:
sys.exit(0)
sess_str = selections[0]
session = mapping[sess_str]
session.switch_client()
session.active_window.active_pane.display_message(
f"Switched to session: {session.name}"
)
+16 -6
View File
@@ -1,9 +1,8 @@
import sys
from pathlib import Path
import libtmux import libtmux
import sh import sh
import sys
from pathlib import Path
from pyfzf.pyfzf import FzfPrompt from pyfzf.pyfzf import FzfPrompt
fzf = FzfPrompt() fzf = FzfPrompt()
@@ -12,10 +11,21 @@ folders = [
"~/Documents/PolyLAN/", "~/Documents/PolyLAN/",
"~/Documents/Python/", "~/Documents/Python/",
"~/Documents/", "~/Documents/",
"~/Documents/Games/Minecraft/modded/",
] ]
available_folders = sh.find(*[Path(f).expanduser() for f in folders] + "-mindepth 1 -maxdepth 1 -type d".split(" ")).strip().split("\n") available_folders = (
selected = fzf.prompt(available_folders, "--cycle") sh.find(
*[Path(f).expanduser() for f in folders]
+ "-mindepth 1 -maxdepth 1 -type d".split(" ")
)
.strip()
.split("\n")
)
selected = fzf.prompt(
["Select a folder to create or switch session to"] + available_folders,
"--cycle --header-lines 1 --tmux center",
)
if not selected: if not selected:
sys.exit(1) sys.exit(1)
+97 -27
View File
@@ -1,13 +1,32 @@
import libtmux import argparse
import configparser import configparser
import time
import sys
import os import os
import sys
import time
from pathlib import Path from pathlib import Path
import libtmux
from pyfzf.pyfzf import FzfPrompt from pyfzf.pyfzf import FzfPrompt
parser = argparse.ArgumentParser()
parser.add_argument(
"--no-open",
action="store_true",
help="Do not open tmux window. Mostly for debugging",
)
parser.add_argument(
"--separate-sessions",
"-s",
action="store_true",
help="Use a separate sessions for all of the groups",
)
parser_args = parser.parse_args()
def get_window_name(session_name):
name = session_name.replace("-", "").replace(" ", " ").replace(" ", "_")
return f"{'' if parser_args.separate_sessions else 'ssh-multig '}{name}"
BASE_PATH = Path("~/.ssh-tmux/").expanduser() BASE_PATH = Path("~/.ssh-tmux/").expanduser()
@@ -16,37 +35,58 @@ sections = {}
for subconffile in os.listdir(BASE_PATH): for subconffile in os.listdir(BASE_PATH):
if not subconffile.endswith(".ini"): if not subconffile.endswith(".ini"):
continue continue
prefix = subconffile.replace(".ini", "").capitalize()
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read(BASE_PATH / subconffile) config.read(BASE_PATH / subconffile)
configs[subconffile] = config configs[subconffile] = config
for section in config.sections(): for section in config.sections():
sections[section] = subconffile section_name = f"[{prefix}] {section}"
sections[section_name] = {
"section": section,
"config": subconffile,
}
fzf = FzfPrompt() fzf = FzfPrompt()
selections = fzf.prompt(sections.keys(), "--cycle") selections = fzf.prompt(
["Select one or more servers group to open"] + list(sections.keys()),
"--cycle --multi --header-lines 1 --tmux center",
)
if not selections: if not selections:
sys.exit(0) sys.exit(0)
selected_group = selections[0] # Get active tmux sessions
config = configs[sections[selected_group]]
servers = config[selected_group]["servers"].split("\n")
extra_commands = []
if "commands" in config[selected_group].keys():
extra_commands = config[selected_group]["commands"].split("\n")
if not servers:
sys.exit(1)
srv = libtmux.Server() srv = libtmux.Server()
active_sessions = srv.sessions.filter(session_attached='1') active_sessions = srv.attached_sessions
if active_sessions: if parser_args.separate_sessions:
sessions = srv.sessions.filter(name="SSH-MultiG")
if sessions:
active_session = sessions[0]
else:
active_session = srv.new_session(session_name="SSH-MultiG")
else:
if len(active_sessions) > 1:
session_choice = fzf.prompt(
[
"You have multiple active tmux sessions open. Choose one to create the window on"
]
+ [sess.name for sess in active_sessions],
"--cycle --header-lines 1",
)
if not session_choice:
sys.exit(0)
active_session = srv.sessions.filter(name=session_choice[0])[0]
elif len(active_sessions) == 1:
active_session = active_sessions[0] active_session = active_sessions[0]
else: else:
@@ -57,10 +97,36 @@ else:
else: else:
active_session = srv.sessions[0] active_session = srv.sessions[0]
window_name = f"ssh-multig {selected_group.replace(' ', '_')}" for selected_group in selections:
info = sections[selected_group]
config = configs[info["config"]]
servers = config[info["section"]]["servers"].split("\n")
extra_commands = []
if "commands" in config[info["section"]].keys():
extra_commands = config[info["section"]]["commands"].split("\n")
if parser_args.no_open:
print(selected_group)
print(f" - Servers ({len(servers)}):")
for server in servers:
print(f" * {server}")
if extra_commands:
print(f" - Extra commands ({len(extra_commands)}):")
for command in extra_commands:
print(f" * {command}")
continue
if not servers:
continue
window_name = get_window_name(selected_group)
if windows := active_session.windows.filter(name=window_name): if windows := active_session.windows.filter(name=window_name):
windows[0].select() windows[0].select()
sys.exit(0) continue
window = active_session.new_window(window_name, window_shell=f"ssh {servers[0]}") window = active_session.new_window(window_name, window_shell=f"ssh {servers[0]}")
@@ -70,10 +136,12 @@ for server in servers[1:]:
window.select_layout("tiled") window.select_layout("tiled")
# Wait until tmux finished working # Wait until tmux finished working
time.sleep(0.1) time.sleep(0.05)
# Confirm connection on asking panes # Confirm connection on asking panes
confirmation_needed_text = "Are you sure you want to continue connecting (yes/no/[fingerprint])?" confirmation_needed_text = (
"Are you sure you want to continue connecting (yes/no/[fingerprint])?"
)
for pane in window.panes: for pane in window.panes:
pane_content = pane.capture_pane() pane_content = pane.capture_pane()
if pane_content and confirmation_needed_text == pane_content[-1]: if pane_content and confirmation_needed_text == pane_content[-1]:
@@ -89,3 +157,5 @@ for command in extra_commands:
window.set_window_option("synchronize-panes", "off") window.set_window_option("synchronize-panes", "off")
window.select() window.select()
window.select_layout("tiled") window.select_layout("tiled")
active_session.switch_client()