From 1da2553b9286194fa4a68db3bb054064bc9e6931 Mon Sep 17 00:00:00 2001 From: SW Date: Mon, 15 Jun 2026 12:47:51 +0200 Subject: [PATCH] Ghostty: run commands directly via base64 to avoid Gatekeeper prompts; translate README; anonymize examples --- Cargo.lock | 1 + Cargo.toml | 1 + README.md | 82 ++++++++++++++++++------------------ examples/Scripts/update.md | 6 +-- examples/Servers/web.md | 5 +++ examples/Synology/dsmview.md | 5 --- src/commands.rs | 53 +++++++++++------------ tests/load_examples.rs | 2 +- 8 files changed, 79 insertions(+), 76 deletions(-) create mode 100644 examples/Servers/web.md delete mode 100644 examples/Synology/dsmview.md diff --git a/Cargo.lock b/Cargo.lock index 4619fdb..a943594 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,6 +759,7 @@ dependencies = [ name = "lines" version = "0.1.0" dependencies = [ + "base64", "clap", "crossterm", "directories", diff --git a/Cargo.toml b/Cargo.toml index 9ea8788..8331bf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +base64 = "0.22.1" clap = { version = "4.6.1", features = ["derive"] } crossterm = "0.29.0" directories = "6.0.0" diff --git a/README.md b/README.md index 22906f3..c891568 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,79 @@ # lines -TUI aplikace pro rychlé spouštění často používaných příkazů — ideální pro SSH skripty, aktualizace a cokoliv, co pouštíš pravidelně z terminálu. +A TUI app for quickly running frequently used commands — ideal for SSH scripts, updates, and anything you run regularly from the terminal. -## Instalace +## Installation ```bash brew install janvete/tools/lines ``` -## Použití +## Usage ```bash -lines # otevře TUI -lines --dir /cesta/k/datům # použije jinou datovou složku +lines # opens the TUI +lines --dir /path # use a different data directory ``` -## Struktura dat +## Data structure -Data jsou běžné `.md` soubory ve složce `~/.lines`. Skupiny = podsložky. +Data is stored as plain `.md` files in `~/.lines`. Groups are subdirectories. ``` ~/.lines -├── Synology -│ └── dsmview.md +├── Servers +│ └── web.md └── Scripts └── update.md ``` -### Konfigurace +### `.md` format -Vytvoř soubor `~/.lines/config.toml`: - -```toml -terminal = "Ghostty" # možnosti: Terminal, Ghostty, iTerm -``` - -Výchozí terminál je `Terminal` (macOS Terminál.app). - -## Formát `.md` - -Každá sekce začíná nadpisem `# Název příkazu`. Pod ním následují řádky příkazů. +Each section starts with `# Command name`. Command lines follow the heading. ```markdown -# Sysel DSM -dsmview ssh root@192.168.40.15 +# Web server +ssh admin@web.example.com -# Johy DSM -dsmview ssh root@192.168.51.3 +# Database +ssh admin@db.example.com ``` -Sekce bez příkazů znamená "spustit všechny příkazy v tomto souboru". +A section without command lines means "run all commands in this file". ```markdown -# Spustí vše +# Run all # Docker update -ssh root@192.168.53.3 /opt/mealie/update.sh -ssh root@192.168.53.5 /opt/yamtrack/update.sh +ssh admin@host1.example.com /opt/app/update.sh +ssh admin@host2.example.com /opt/app/update.sh ``` -## Ovládání +## Configuration -| Klávesa | Akce | -|---------|------| -| `↑/↓` nebo `j/k` | pohyb v seznamu | -| `←/→` nebo `h/l` | přepínání panelů | -| `Enter` | spustí vybraný příkaz / všechny příkazy | -| `e` | otevře aktuální `.md` soubor v `$EDITOR` | -| `r` | znovu načte data ze složky | -| `q` nebo `Esc` | ukončí aplikaci | +Create `~/.lines/config.toml`: -## Zálohování +```toml +terminal = "Ghostty" # options: Terminal, Ghostty, iTerm +``` -Celá datová složka `~/.lines` je obyčejný text — stačí ji zkopírovat na disk, do Gitu nebo iCloudu. Na novém Macu ji přeneseš a `lines` ji rovnou načte. +The default terminal is `Terminal` (macOS Terminal.app). -## Licence +## Controls + +| Key | Action | +|-----|--------| +| `↑/↓` or `j/k` | move | +| `←/→` or `h/l` | switch panel | +| `Enter` | run selected command / all commands | +| `e` | open current `.md` file in `$EDITOR` | +| `r` | reload data | +| `q` / `Esc` | quit | + +## Backup + +The entire `~/.lines` folder is plain text. Copy it to a disk, Git repo, or iCloud. On a new Mac, move it to the same location and `lines` works immediately. + +## License MIT diff --git a/examples/Scripts/update.md b/examples/Scripts/update.md index 4f43d85..39a9cbf 100644 --- a/examples/Scripts/update.md +++ b/examples/Scripts/update.md @@ -1,5 +1,5 @@ -# Spustí vše +# Run all # Docker update -ssh root@192.168.53.3 /opt/mealie/update.sh -ssh root@192.168.53.5 /opt/yamtrack/update.sh +ssh admin@host1.example.com /opt/app/update.sh +ssh admin@host2.example.com /opt/app/update.sh diff --git a/examples/Servers/web.md b/examples/Servers/web.md new file mode 100644 index 0000000..47d0725 --- /dev/null +++ b/examples/Servers/web.md @@ -0,0 +1,5 @@ +# Main server +ssh admin@web.example.com + +# Backup server +ssh admin@backup.example.com diff --git a/examples/Synology/dsmview.md b/examples/Synology/dsmview.md deleted file mode 100644 index bc205e4..0000000 --- a/examples/Synology/dsmview.md +++ /dev/null @@ -1,5 +0,0 @@ -# Sysel DSM -dsmview ssh root@192.168.40.15 - -# Johy DSM -dsmview ssh root@192.168.51.3 diff --git a/src/commands.rs b/src/commands.rs index 168cd71..b367548 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,9 +1,11 @@ use std::fs; use std::io::Write; use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::process::Command; +use base64::{engine::general_purpose::STANDARD, Engine}; + use crate::config::Terminal; use crate::parser::{CommandFile, Section}; @@ -22,20 +24,15 @@ pub fn run_section(section: &Section, file: &CommandFile, terminal: &Terminal, d return; } - let script = build_script(&commands); - execute_in_terminal(&script, terminal, data_dir); + match terminal { + Terminal::Ghostty => run_in_ghostty(&commands), + _ => run_via_script(&commands, terminal, data_dir), + } } -fn build_script(commands: &[String]) -> String { - commands.join("\n") -} - -fn script_dir(data_dir: &Path) -> PathBuf { - data_dir.join(".run") -} - -fn execute_in_terminal(script: &str, terminal: &Terminal, data_dir: &Path) { - let run_dir = script_dir(data_dir); +fn run_via_script(commands: &[String], terminal: &Terminal, data_dir: &Path) { + let script = commands.join("\n"); + let run_dir = data_dir.join(".run"); if fs::create_dir_all(&run_dir).is_err() { return; } @@ -60,12 +57,28 @@ fn execute_in_terminal(script: &str, terminal: &Terminal, data_dir: &Path) { let _ = fs::set_permissions(&script_path, fs::Permissions::from_mode(0o755)); match terminal { - Terminal::Ghostty => run_in_ghostty(&script_path), Terminal::Iterm => run_in_iterm(&script_path), Terminal::Builtin => run_in_terminal_app(&script_path), + Terminal::Ghostty => unreachable!(), } } +fn run_in_ghostty(commands: &[String]) { + let script = commands.join("\n"); + let encoded = STANDARD.encode(script); + let shell_command = format!("echo {} | base64 -D | bash", encoded); + + let _ = Command::new("open") + .arg("-na") + .arg("Ghostty") + .arg("--args") + .arg("-e") + .arg("bash") + .arg("-c") + .arg(shell_command) + .spawn(); +} + fn run_in_terminal_app(script_path: &Path) { let path_str = script_path.to_string_lossy(); let applescript = format!( @@ -82,18 +95,6 @@ end tell"#, .spawn(); } -fn run_in_ghostty(script_path: &Path) { - let path_str = script_path.to_string_lossy(); - let _ = Command::new("open") - .arg("-na") - .arg("Ghostty") - .arg("--args") - .arg("-e") - .arg("bash") - .arg(path_str.as_ref()) - .spawn(); -} - fn run_in_iterm(script_path: &Path) { let path_str = script_path.to_string_lossy(); let applescript = format!( diff --git a/tests/load_examples.rs b/tests/load_examples.rs index 36c9cf0..d540fce 100644 --- a/tests/load_examples.rs +++ b/tests/load_examples.rs @@ -3,6 +3,6 @@ use std::path::PathBuf; #[test] fn test_example_files_exist() { let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"); - assert!(examples.join("Synology/dsmview.md").exists()); + assert!(examples.join("Servers/web.md").exists()); assert!(examples.join("Scripts/update.md").exists()); }