232 lines
5.7 KiB
Rust
232 lines
5.7 KiB
Rust
use skim::prelude::*;
|
|
use std::{
|
|
collections::BTreeMap,
|
|
fs::File,
|
|
io::{BufRead, BufReader, Cursor, Result, Write},
|
|
path::PathBuf,
|
|
};
|
|
use tmux_interface::{
|
|
commands::tmux::StdIO, AttachSession, HasSession, KillSession, ListClients, NewSession,
|
|
SwitchClient, Tmux,
|
|
};
|
|
|
|
fn separate(line: Result<String>) -> Option<(String, String)> {
|
|
let line_ = line.unwrap();
|
|
let (s1, s2) = line_.split_once(" ")?;
|
|
Some((s1.to_owned(), s2.to_owned()))
|
|
}
|
|
|
|
fn set_projects(path: &PathBuf, projects: &BTreeMap<String, String>) {
|
|
let mut project_lines = projects
|
|
.iter()
|
|
.map(|(project_name, project_path)| {
|
|
let mut project_line: String = project_name.to_owned();
|
|
project_line.push_str(" ");
|
|
project_line.push_str(project_path);
|
|
return project_line;
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.join("\n");
|
|
|
|
project_lines.push('\n');
|
|
|
|
let mut file = File::create(path).expect("Projects list could not be created.");
|
|
file
|
|
.write(project_lines.as_bytes())
|
|
.expect("Projects list could not be written to.");
|
|
}
|
|
|
|
fn get_projects(path: &PathBuf) -> BTreeMap<String, String> {
|
|
let reader = BufReader::new(File::open(path).expect("Projects list could not be opened."));
|
|
|
|
reader.lines().filter_map(separate).collect()
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum Mode {
|
|
Find,
|
|
Add,
|
|
Delete,
|
|
Base,
|
|
}
|
|
|
|
fn add_project(
|
|
projects: &mut BTreeMap<String, String>,
|
|
project_name: Option<&String>,
|
|
) -> Option<String> {
|
|
let project_path = std::env::current_dir().expect("Current directory is not available.");
|
|
|
|
let project_path_string = project_path
|
|
.clone()
|
|
.into_os_string()
|
|
.into_string()
|
|
.expect("Current directory is not UTF-8 encoded.");
|
|
|
|
let project_name_string: String = match project_name {
|
|
Some(name) => name.to_string(),
|
|
None => match project_path.file_name() {
|
|
Some(name) => name
|
|
.to_str()
|
|
.expect("Current directory name cannot be stringified.")
|
|
.to_string(),
|
|
None => "unnamed".to_string(),
|
|
},
|
|
};
|
|
|
|
projects.insert(project_name_string.clone(), project_path_string);
|
|
|
|
Some(project_name_string)
|
|
}
|
|
|
|
fn delete_project(projects: &mut BTreeMap<String, String>, project_path: &String) {
|
|
dbg!(&project_path);
|
|
dbg!(&projects);
|
|
let project_name = projects
|
|
.iter()
|
|
.filter(|(_k, v)| v == &project_path)
|
|
.last()
|
|
.map(|(k, _v)| k.clone())
|
|
.unwrap_or("".to_string());
|
|
dbg!(&project_name);
|
|
projects.remove(&project_name);
|
|
}
|
|
|
|
fn find_projects(
|
|
projects: &BTreeMap<String, String>,
|
|
project_name: Option<&String>,
|
|
) -> Option<String> {
|
|
let project_names = projects.clone().into_keys().collect::<Vec<_>>().join("\n");
|
|
|
|
let options = SkimOptionsBuilder::default()
|
|
.height(Some("100%"))
|
|
.multi(false)
|
|
.query(project_name.map(|string| string.as_str()))
|
|
.select1(true)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let items = SkimItemReader::default().of_bufread(Cursor::new(project_names));
|
|
|
|
let result = Skim::run_with(&options, Some(items)).expect("No skim result.");
|
|
|
|
match result.is_abort {
|
|
true => None,
|
|
false => Some(result.selected_items.first()?.output().to_string()),
|
|
}
|
|
}
|
|
|
|
fn focus_project(projects: &BTreeMap<String, String>, project_name: Option<String>) {
|
|
let session_name = match project_name {
|
|
Some(name) => name,
|
|
None => "base".to_string(),
|
|
};
|
|
|
|
let has_session = Tmux::with_command(HasSession::new().target_session(&session_name))
|
|
.status()
|
|
.unwrap()
|
|
.success();
|
|
|
|
match has_session {
|
|
false => Tmux::with_command(
|
|
NewSession::new()
|
|
.session_name(&session_name)
|
|
.start_directory(&projects[&session_name])
|
|
.detached(),
|
|
)
|
|
.status()
|
|
.unwrap()
|
|
.success(),
|
|
true => true,
|
|
};
|
|
|
|
match std::env::var("TMUX") {
|
|
Ok(_) => Tmux::with_command(SwitchClient::new().target_session(&session_name))
|
|
.status()
|
|
.unwrap()
|
|
.success(),
|
|
Err(_) => Tmux::with_command(AttachSession::new().target_session(&session_name))
|
|
.status()
|
|
.unwrap()
|
|
.success(),
|
|
};
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
|
|
let mode: Mode = match args.get(1) {
|
|
Some(flag) => match flag.as_str() {
|
|
"-a" => Mode::Add,
|
|
"-d" => Mode::Delete,
|
|
"-b" => Mode::Base,
|
|
_ => Mode::Find,
|
|
},
|
|
_ => Mode::Find,
|
|
};
|
|
|
|
let project_file_path = PathBuf::from("/home/lukew/Documents/projects");
|
|
let mut projects = get_projects(&project_file_path);
|
|
|
|
let old_session_name = String::from_utf8(
|
|
Tmux::with_command(
|
|
ListClients::new()
|
|
.target_session(std::env::var("TMUX_PANE").unwrap_or("".to_string()))
|
|
.format("#S"),
|
|
)
|
|
.output()
|
|
.unwrap()
|
|
.stdout(),
|
|
)
|
|
.unwrap()
|
|
.strip_suffix("\n")
|
|
.unwrap()
|
|
.to_string();
|
|
|
|
let old_session_path = String::from_utf8(
|
|
Tmux::with_command(
|
|
ListClients::new()
|
|
.target_session(std::env::var("TMUX_PANE").unwrap_or("".to_string()))
|
|
.format("#{pane_start_path}"),
|
|
)
|
|
.output()
|
|
.unwrap()
|
|
.stdout(),
|
|
)
|
|
.unwrap()
|
|
.strip_suffix("\n")
|
|
.unwrap()
|
|
.to_string();
|
|
|
|
let project_name = match mode {
|
|
Mode::Add => add_project(&mut projects, args.get(2)),
|
|
Mode::Delete => {
|
|
delete_project(&mut projects, &old_session_path);
|
|
None
|
|
}
|
|
Mode::Base => None,
|
|
Mode::Find => find_projects(&projects, args.get(1)),
|
|
};
|
|
|
|
focus_project(&projects, project_name);
|
|
|
|
set_projects(&project_file_path, &projects);
|
|
|
|
match mode {
|
|
Mode::Delete => Tmux::with_command(KillSession::new().target_session(old_session_name))
|
|
.stderr(Some(StdIO::Null))
|
|
.status()
|
|
.unwrap()
|
|
.success(),
|
|
_ => true,
|
|
};
|
|
|
|
match true {
|
|
true => Tmux::with_command(KillSession::new().target_session("PROJECTS"))
|
|
.stderr(Some(StdIO::Null))
|
|
.status()
|
|
.unwrap()
|
|
.success(),
|
|
false => false,
|
|
};
|
|
}
|