diff options
Diffstat (limited to 'pkgs/by-name/ts/tskm/src/interface')
-rw-r--r-- | pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs | 51 | ||||
-rw-r--r-- | pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs | 9 | ||||
-rw-r--r-- | pkgs/by-name/ts/tskm/src/interface/open/handle.rs | 115 |
3 files changed, 117 insertions, 58 deletions
diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs index a9a46ee7..d904b12e 100644 --- a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs +++ b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs @@ -1,33 +1,46 @@ use std::{ env, - fs::{self, read_to_string, OpenOptions}, + fs::{self, read_to_string, File, OpenOptions}, io::Write, process::Command, }; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; -use crate::cli::NeorgCommand; +use crate::{cli::NeorgCommand, state::State}; -pub fn handle(command: NeorgCommand) -> Result<()> { +pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> { match command { NeorgCommand::Task { id } => { - let project = id.project()?; - let path = dirs::data_local_dir() + let project = id.project(state)?; + let base = dirs::data_local_dir() .expect("This should exists") - .join("notes") - .join(project.get_neorg_path()?); + .join("tskm/notes"); + let path = base.join(project.get_neorg_path()?); fs::create_dir_all(path.parent().expect("This should exist"))?; { - let contents = read_to_string(&path)?; - if contents.contains(format!("% {}", id.to_uuid()?).as_str()) { + let contents = if path.exists() { + read_to_string(&path) + .with_context(|| format!("Failed to read file: '{}'", path.display()))? + } else { + File::create(&path) + .with_context(|| format!("Failed to create file: '{}'", path.display()))?; + String::new() + }; + + if !contents.contains(format!("% {}", id.uuid()).as_str()) { let mut options = OpenOptions::new(); - options.append(true).create(true); + options.append(true).create(false); let mut file = options.open(&path)?; - file.write_all(format!("* TITLE (% {})", id.to_uuid()?).as_bytes())?; + file.write_all(format!("* TITLE (% {})", id.uuid()).as_bytes()) + .with_context(|| { + format!("Failed to write task uuid to file: '{}'", path.display()) + })?; + file.flush() + .with_context(|| format!("Failed to flush file: '{}'", path.display()))?; } } @@ -36,7 +49,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> { .args([ path.to_str().expect("Should be a utf-8 str"), "-c", - format!("/% {}", id.to_uuid()?).as_str(), + format!("/% {}", id.uuid()).as_str(), ]) .status()?; if !status.success() { @@ -46,7 +59,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> { { let status = Command::new("git") .args(["add", "."]) - .current_dir(&path) + .current_dir(path.parent().expect("Will exist")) .status()?; if !status.success() { bail!("Git add . failed!"); @@ -56,14 +69,10 @@ pub fn handle(command: NeorgCommand) -> Result<()> { .args([ "commit", "--message", - format!( - "chore({}): Update", - path.parent().expect("Should have a parent").display() - ) - .as_str(), + format!("chore({}): Update", project.get_neorg_path()?.display()).as_str(), "--no-gpg-sign", ]) - .current_dir(&path) + .current_dir(path.parent().expect("Will exist")) .status()?; if !status.success() { bail!("Git commit failed!"); @@ -71,7 +80,7 @@ pub fn handle(command: NeorgCommand) -> Result<()> { } { - id.annotate("[neorg data]")?; + id.mark_neorg_data(state)?; } } } diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs index dc5cdf19..51d58ab3 100644 --- a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs +++ b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs @@ -8,11 +8,18 @@ pub mod handle; pub use handle::handle; impl Project { + /// Return the stored neorg path of this project. + /// The returned path will never start with a slash (/). pub(super) fn get_neorg_path(&self) -> Result<PathBuf> { let project_path = run_task(&[ "_get", format!("rc.context.{}.rc.neorg_path", self.to_context_display()).as_str(), ])?; - Ok(PathBuf::from(project_path.as_str())) + + let final_path = project_path + .strip_prefix('/') + .unwrap_or(project_path.as_str()); + + Ok(PathBuf::from(final_path)) } } diff --git a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs index dc0d165d..4d7341b2 100644 --- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs +++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs @@ -1,17 +1,23 @@ -use std::process; +use std::{ + fs, + net::{IpAddr, Ipv4Addr}, + path::PathBuf, + process, +}; use anyhow::{bail, Context, Result}; -use log::{error, info}; +use log::{error, info, warn}; +use url::Url; -use crate::{cli::OpenCommand, rofi, task}; +use crate::{cli::OpenCommand, rofi, state::State, task}; -pub fn handle(command: OpenCommand) -> Result<()> { +pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> { match command { OpenCommand::Review => { for project in task::Project::all().context("Failed to get all project files")? { if project.is_touched() { info!("Reviewing project: '{}'", project.to_project_display()); - open_in_browser(project).with_context(|| { + open_in_browser(project, state, None).with_context(|| { format!( "Failed to open project ('{}') in Firefox", project.to_project_display() @@ -26,23 +32,13 @@ pub fn handle(command: OpenCommand) -> Result<()> { } } } - OpenCommand::Project { project } => { - let project = if let Some(p) = project { - p - } else if let Some(p) = - task::Project::get_current().context("Failed to get currently focused project")? - { - p - } else { - bail!("You need to either supply a project or have a project active!"); - }; - + OpenCommand::Project { project, url } => { project.touch().context("Failed to touch project")?; - open_in_browser(&project).with_context(|| { + open_in_browser(&project, state, url).with_context(|| { format!("Failed to open project: {}", project.to_project_display()) })?; } - OpenCommand::Select => { + OpenCommand::Select { url } => { let selected_project: task::Project = task::Project::from_project_string( &rofi::select( task::Project::all() @@ -60,7 +56,7 @@ pub fn handle(command: OpenCommand) -> Result<()> { .touch() .context("Failed to touch project")?; - open_in_browser(&selected_project).context("Failed to open project")?; + open_in_browser(&selected_project, state, url).context("Failed to open project")?; } OpenCommand::ListTabs { project } => { let project = if let Some(p) = project { @@ -109,12 +105,15 @@ pub fn handle(command: OpenCommand) -> Result<()> { Ok(()) } -fn open_in_browser(selected_project: &task::Project) -> Result<()> { +fn open_in_browser( + selected_project: &task::Project, + state: &mut State, + url: Option<Url>, +) -> Result<()> { let old_project: Option<task::Project> = task::Project::get_current().context("Failed to get currently active project")?; - // We have ensured that only one task may be active - let old_task: Option<task::Id> = - task::Id::get_current().context("Failed to get currently active task")?; + let old_task: Option<task::Task> = + task::Task::get_current(state).context("Failed to get currently active task")?; selected_project.activate().with_context(|| { format!( @@ -124,7 +123,7 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> { })?; let tracking_task = { - let all_tasks = selected_project.get_tasks().with_context(|| { + let all_tasks = selected_project.get_tasks(state).with_context(|| { format!( "Failed to get assoctiated tasks for project: '{}'", selected_project.to_project_display() @@ -132,7 +131,7 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> { })?; let tracking_task = all_tasks.into_iter().find(|t| { - let maybe_desc = t.description(); + let maybe_desc = t.description(state); if let Ok(desc) = maybe_desc { desc == "tracking" } else { @@ -149,31 +148,75 @@ fn open_in_browser(selected_project: &task::Project) -> Result<()> { "Starting task {} -> tracking", selected_project.to_project_display() ); - task.start() + task.start(state) .with_context(|| format!("Failed to start task {task}"))?; } tracking_task }; - let status = process::Command::new("firefox") - .args([ - "-P", - selected_project.to_project_display().as_str(), - "about:newtab", - ]) - .status() - .context("Failed to start firefox")?; + let status = { + let mut args = vec!["-P".to_owned(), selected_project.to_project_display()]; + if let Some(url) = url { + args.push(url.to_string()); + } else { + let lock_file = dirs::home_dir() + .expect("Exists") + .join(".mozilla/firefox") + .join(selected_project.to_project_display()) + .join("lock"); + + if lock_file.exists() { + let (ip, pid): (IpAddr, u32) = { + let link = fs::read_link(&lock_file).with_context(|| { + format!("Failed to readlink lock at '{}'", lock_file.display()) + })?; + + let (ip, pid) = link + .to_str() + .expect("Should work") + .split_once(':') + .expect("The split works"); + + ( + ip.parse().expect("Should be a valid ip address"), + pid.parse().expect("Should be a valid pid"), + ) + }; + + if ip != Ipv4Addr::new(127, 0, 0, 2) { + warn!("Your ip is weird.."); + } + + if PathBuf::from("/proc").join(pid.to_string()).exists() { + // Another Firefox instance has already been started for this project + // Add a buffer URL to force Firefox to open it in the already open instance + args.push("about:newtab".to_owned()); + } else { + // This project does not yet have another Firefox instance + // We do not need to add anything to the arguments, Firefox will open a new + // instance. + } + } else { + // There is no lock file and thus no instance already open. + } + }; + + process::Command::new("firefox") + .args(args) + .status() + .context("Failed to start firefox")? + }; if !status.success() { error!("Firefox run exited with error."); } if let Some(task) = tracking_task { - task.stop() + task.stop(state) .with_context(|| format!("Failed to stop task {task}"))?; } if let Some(task) = old_task { - task.start() + task.start(state) .with_context(|| format!("Failed to start task {task}"))?; } |