forked from cinco/tmuxido
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36aaa65945 | ||
|
|
10a38a1f85 | ||
|
|
42bdc1d409 | ||
|
|
a592c99375 |
+10
@@ -76,6 +76,16 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- apk add --no-cache curl jq
|
- apk add --no-cache curl jq
|
||||||
- |
|
- |
|
||||||
|
# Delete existing release for this tag if present (handles retag scenarios)
|
||||||
|
EXISTING_ID=$(curl -fsSL \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"https://git.cincoeuzebio.com/api/v1/repos/cinco/Tmuxido/releases/tags/$DRONE_TAG" \
|
||||||
|
| jq -r '.id // empty')
|
||||||
|
if [ -n "$EXISTING_ID" ]; then
|
||||||
|
curl -fsSL -X DELETE \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
"https://git.cincoeuzebio.com/api/v1/repos/cinco/Tmuxido/releases/$EXISTING_ID"
|
||||||
|
fi
|
||||||
# Read DRONE_TAG via ENVIRON inside awk to avoid Drone's ${VAR} substitution
|
# Read DRONE_TAG via ENVIRON inside awk to avoid Drone's ${VAR} substitution
|
||||||
# which would replace ${TAG} with an empty string before the shell runs.
|
# which would replace ${TAG} with an empty string before the shell runs.
|
||||||
BODY=$(awk '
|
BODY=$(awk '
|
||||||
|
|||||||
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [0.5.1] - 2026-03-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Tmux window creation now targets windows by name instead of numeric index, eliminating
|
||||||
|
"index in use" and "can't find window" errors when `base-index` is not 0
|
||||||
|
- Self-update asset name corrected from `x86_64-linux` to `tmuxido-x86_64-linux` to match
|
||||||
|
what CI actually uploads, fixing 404 on `--update`
|
||||||
|
- CI release pipeline now deletes any existing release for the tag before recreating,
|
||||||
|
preventing 409 Conflict errors on retagged releases
|
||||||
|
|
||||||
## [0.5.0] - 2026-03-01
|
## [0.5.0] - 2026-03-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
Generated
+1
-1
@@ -864,7 +864,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tmuxido"
|
name = "tmuxido"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tmuxido"
|
name = "tmuxido"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
+2
-2
@@ -20,8 +20,8 @@ pub fn current_version() -> &'static str {
|
|||||||
fn detect_arch() -> Result<&'static str> {
|
fn detect_arch() -> Result<&'static str> {
|
||||||
let arch = std::env::consts::ARCH;
|
let arch = std::env::consts::ARCH;
|
||||||
match arch {
|
match arch {
|
||||||
"x86_64" => Ok("x86_64-linux"),
|
"x86_64" => Ok("tmuxido-x86_64-linux"),
|
||||||
"aarch64" => Ok("aarch64-linux"),
|
"aarch64" => Ok("tmuxido-aarch64-linux"),
|
||||||
_ => Err(anyhow::anyhow!("Unsupported architecture: {}", arch)),
|
_ => Err(anyhow::anyhow!("Unsupported architecture: {}", arch)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-56
@@ -41,7 +41,6 @@ impl SessionConfig {
|
|||||||
pub struct TmuxSession {
|
pub struct TmuxSession {
|
||||||
pub(crate) session_name: String,
|
pub(crate) session_name: String,
|
||||||
project_path: String,
|
project_path: String,
|
||||||
base_index: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TmuxSession {
|
impl TmuxSession {
|
||||||
@@ -53,34 +52,12 @@ impl TmuxSession {
|
|||||||
.replace('.', "_")
|
.replace('.', "_")
|
||||||
.replace(' ', "-");
|
.replace(' ', "-");
|
||||||
|
|
||||||
let base_index = Self::get_base_index();
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
session_name,
|
session_name,
|
||||||
project_path: project_path.display().to_string(),
|
project_path: project_path.display().to_string(),
|
||||||
base_index,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_base_index() -> usize {
|
|
||||||
// Try to get base-index from tmux
|
|
||||||
let output = Command::new("tmux")
|
|
||||||
.args(["show-options", "-gv", "base-index"])
|
|
||||||
.output();
|
|
||||||
|
|
||||||
if let Ok(output) = output
|
|
||||||
&& output.status.success()
|
|
||||||
{
|
|
||||||
let index_str = String::from_utf8_lossy(&output.stdout);
|
|
||||||
if let Ok(index) = index_str.trim().parse::<usize>() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to 0 if we can't determine
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create(&self, config: &SessionConfig) -> Result<()> {
|
pub fn create(&self, config: &SessionConfig) -> Result<()> {
|
||||||
// Check if we're already inside a tmux session
|
// Check if we're already inside a tmux session
|
||||||
let inside_tmux = std::env::var("TMUX").is_ok();
|
let inside_tmux = std::env::var("TMUX").is_ok();
|
||||||
@@ -167,25 +144,23 @@ impl TmuxSession {
|
|||||||
.status()
|
.status()
|
||||||
.context("Failed to create tmux session")?;
|
.context("Failed to create tmux session")?;
|
||||||
|
|
||||||
// Create panes for first window if specified
|
let first_target = format!("{}:{}", self.session_name, first_window.name);
|
||||||
|
|
||||||
if !first_window.panes.is_empty() {
|
if !first_window.panes.is_empty() {
|
||||||
self.create_panes(self.base_index, &first_window.panes)?;
|
self.create_panes(&first_target, &first_window.panes)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply layout for first window if specified
|
|
||||||
if let Some(layout) = &first_window.layout {
|
if let Some(layout) = &first_window.layout {
|
||||||
self.apply_layout(self.base_index, layout)?;
|
self.apply_layout(&first_target, layout)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create additional windows
|
// Create additional windows, targeting by session name so tmux auto-assigns the index
|
||||||
for (index, window) in config.windows.iter().skip(1).enumerate() {
|
for window in config.windows.iter().skip(1) {
|
||||||
let window_index = self.base_index + index + 1;
|
|
||||||
|
|
||||||
Command::new("tmux")
|
Command::new("tmux")
|
||||||
.args([
|
.args([
|
||||||
"new-window",
|
"new-window",
|
||||||
"-t",
|
"-t",
|
||||||
&format!("{}:{}", self.session_name, window_index),
|
&self.session_name,
|
||||||
"-n",
|
"-n",
|
||||||
&window.name,
|
&window.name,
|
||||||
"-c",
|
"-c",
|
||||||
@@ -194,46 +169,44 @@ impl TmuxSession {
|
|||||||
.status()
|
.status()
|
||||||
.with_context(|| format!("Failed to create window: {}", window.name))?;
|
.with_context(|| format!("Failed to create window: {}", window.name))?;
|
||||||
|
|
||||||
// Create panes if specified
|
let target = format!("{}:{}", self.session_name, window.name);
|
||||||
|
|
||||||
if !window.panes.is_empty() {
|
if !window.panes.is_empty() {
|
||||||
self.create_panes(window_index, &window.panes)?;
|
self.create_panes(&target, &window.panes)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply layout if specified
|
|
||||||
if let Some(layout) = &window.layout {
|
if let Some(layout) = &window.layout {
|
||||||
self.apply_layout(window_index, layout)?;
|
self.apply_layout(&target, layout)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the first window
|
// Select the first window by name
|
||||||
Command::new("tmux")
|
Command::new("tmux")
|
||||||
.args([
|
.args(["select-window", "-t", &first_target])
|
||||||
"select-window",
|
|
||||||
"-t",
|
|
||||||
&format!("{}:{}", self.session_name, self.base_index),
|
|
||||||
])
|
|
||||||
.status()
|
.status()
|
||||||
.context("Failed to select first window")?;
|
.context("Failed to select first window")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_panes(&self, window_index: usize, panes: &[String]) -> Result<()> {
|
fn create_panes(&self, window_target: &str, panes: &[String]) -> Result<()> {
|
||||||
for (pane_index, command) in panes.iter().enumerate() {
|
for (pane_index, command) in panes.iter().enumerate() {
|
||||||
let target = format!("{}:{}", self.session_name, window_index);
|
|
||||||
|
|
||||||
// First pane already exists (created with the window), skip split
|
// First pane already exists (created with the window), skip split
|
||||||
if pane_index > 0 {
|
if pane_index > 0 {
|
||||||
// Create new pane by splitting
|
|
||||||
Command::new("tmux")
|
Command::new("tmux")
|
||||||
.args(["split-window", "-t", &target, "-c", &self.project_path])
|
.args([
|
||||||
|
"split-window",
|
||||||
|
"-t",
|
||||||
|
window_target,
|
||||||
|
"-c",
|
||||||
|
&self.project_path,
|
||||||
|
])
|
||||||
.status()
|
.status()
|
||||||
.context("Failed to split pane")?;
|
.context("Failed to split pane")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the command to the pane if it's not empty
|
|
||||||
if !command.is_empty() {
|
if !command.is_empty() {
|
||||||
let pane_target = format!("{}:{}.{}", self.session_name, window_index, pane_index);
|
let pane_target = format!("{}.{}", window_target, pane_index);
|
||||||
Command::new("tmux")
|
Command::new("tmux")
|
||||||
.args(["send-keys", "-t", &pane_target, command, "Enter"])
|
.args(["send-keys", "-t", &pane_target, command, "Enter"])
|
||||||
.status()
|
.status()
|
||||||
@@ -244,14 +217,9 @@ impl TmuxSession {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_layout(&self, window_index: usize, layout: &str) -> Result<()> {
|
fn apply_layout(&self, window_target: &str, layout: &str) -> Result<()> {
|
||||||
Command::new("tmux")
|
Command::new("tmux")
|
||||||
.args([
|
.args(["select-layout", "-t", window_target, layout])
|
||||||
"select-layout",
|
|
||||||
"-t",
|
|
||||||
&format!("{}:{}", self.session_name, window_index),
|
|
||||||
layout,
|
|
||||||
])
|
|
||||||
.status()
|
.status()
|
||||||
.with_context(|| format!("Failed to apply layout: {}", layout))?;
|
.with_context(|| format!("Failed to apply layout: {}", layout))?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user