about summary refs log tree commit diff stats
path: root/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ts/tskm/src/interface/open/handle.rs')
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/handle.rs294
1 files changed, 116 insertions, 178 deletions
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 82f468b3..ca54b422 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
@@ -8,37 +8,46 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use std::{
-    fs,
-    net::{IpAddr, Ipv4Addr},
-    path::PathBuf,
-    process,
-};
-
-use anyhow::{Context, Result, bail};
-use log::{error, info, warn};
+use anyhow::{bail, Context, Result};
+use log::{error, info};
 use url::Url;
 
-use crate::{cli::OpenCommand, rofi, state::State, task};
+use crate::{browser::open_in_browser, cli::OpenCommand, rofi, state::State, task};
 
+fn is_empty(project: &task::Project) -> Result<bool> {
+    let tabs = get_tabs(project)?;
+
+    Ok(tabs.is_empty())
+}
+
+#[allow(clippy::too_many_lines)]
 pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
     match command {
-        OpenCommand::Review => {
+        OpenCommand::Review { non_empty } => {
             for project in task::Project::all().context("Failed to get all project files")? {
-                if project.is_touched() {
-                    info!("Reviewing project: '{}'", project.to_project_display());
+                let is_empty = is_empty(project)?;
+
+                if project.is_touched() || (non_empty && !is_empty) {
+                    info!(
+                        "Reviewing project: '{}' ({})",
+                        project.to_project_display(),
+                        if is_empty { "is empty" } else { "is not empty" }
+                    );
                     open_in_browser(project, state, None).with_context(|| {
                         format!(
-                            "Failed to open project ('{}') in Firefox",
-                            project.to_project_display()
-                        )
-                    })?;
-                    project.untouch().with_context(|| {
-                        format!(
-                            "Failed to untouch project ('{}')",
+                            "Failed to open project ('{}') in qutebrowser",
                             project.to_project_display()
                         )
                     })?;
+
+                    if project.is_touched() {
+                        project.untouch().with_context(|| {
+                            format!(
+                                "Failed to untouch project ('{}')",
+                                project.to_project_display()
+                            )
+                        })?;
+                    }
                 }
             }
         }
@@ -68,175 +77,104 @@ pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
 
             open_in_browser(&selected_project, state, url).context("Failed to open project")?;
         }
-        OpenCommand::ListTabs { 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::ListTabs { projects, mode } => {
+            let projects = {
+                if let Some(p) = projects {
+                    p
+                } else if mode.is_some() {
+                    task::Project::all()
+                        .context("Failed to get all projects")?
+                        .to_owned()
+                } else if let Some(p) = task::Project::get_current()
+                    .context("Failed to get currently focused project")?
+                {
+                    vec![p]
+                } else {
+                    bail!("You need to either select projects or pass --mode");
+                }
             };
 
-            let session_store = project.get_sessionstore().with_context(|| {
-                format!(
-                    "Failed to get session store for project: '{}'",
-                    project.to_project_display()
-                )
-            })?;
-
-            let selected = session_store
-                .windows
-                .iter()
-                .map(|w| w.selected)
-                .collect::<Vec<_>>();
-
-            let tabs = session_store
-                .windows
-                .iter()
-                .flat_map(|window| window.tabs.iter())
-                .map(|tab| tab.entries.get(tab.index - 1).expect("This should be Some"))
-                .collect::<Vec<_>>();
-
-            for (index, entry) in tabs.iter().enumerate() {
-                let index = index + 1;
-                let is_selected = {
-                    if selected.contains(&index) {
-                        "🔻 "
-                    } else {
-                        "   "
+            for project in &projects {
+                if let Some(mode) = mode {
+                    match mode {
+                        crate::cli::ListMode::Empty => {
+                            if !is_empty(project)? {
+                                continue;
+                            }
+
+                            // We do not need to print, tabs they are always empty.
+                            if projects.len() > 1 {
+                                println!("/* {} */", project.to_project_display());
+                            }
+                            continue;
+                        }
+                        crate::cli::ListMode::NonEmpty => {
+                            if is_empty(project)? {
+                                continue;
+                            }
+                        }
                     }
-                };
-                println!("{}{}", is_selected, entry.url);
-            }
-        }
-    }
-    Ok(())
-}
-
-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")?;
-    let old_task: Option<task::Task> =
-        task::Task::get_current(state).context("Failed to get currently active task")?;
-
-    selected_project.activate().with_context(|| {
-        format!(
-            "Failed to active project: '{}'",
-            selected_project.to_project_display()
-        )
-    })?;
-
-    let tracking_task = {
-        let all_tasks = selected_project.get_tasks(state).with_context(|| {
-            format!(
-                "Failed to get assoctiated tasks for project: '{}'",
-                selected_project.to_project_display()
-            )
-        })?;
-
-        let tracking_task = all_tasks.into_iter().find(|t| {
-            let maybe_desc = t.description(state);
-            if let Ok(desc) = maybe_desc {
-                desc == "tracking"
-            } else {
-                error!(
-                    "Getting task description returned error: {}",
-                    maybe_desc.expect_err("We already check for Ok")
-                );
-                false
-            }
-        });
-
-        if let Some(task) = tracking_task {
-            info!(
-                "Starting task {} -> tracking",
-                selected_project.to_project_display()
-            );
-            task.start(state)
-                .with_context(|| format!("Failed to start task {task}"))?;
-        }
-        tracking_task
-    };
-
-    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");
+                if projects.len() > 1 {
+                    println!("/* {} */", project.to_project_display());
+                }
 
-                    (
-                        ip.parse().expect("Should be a valid ip address"),
-                        pid.parse().expect("Should be a valid pid"),
-                    )
+                let tabs = match get_tabs(project) {
+                    Ok(ok) => ok,
+                    Err(err) => {
+                        if projects.len() > 1 {
+                            error!(
+                                "While trying to get the sessionstore for {}: {:?}",
+                                project.to_project_display(),
+                                err
+                            );
+                            continue;
+                        }
+
+                        return Err(err).with_context(|| {
+                            format!(
+                                "While trying to get the sessionstore for {}",
+                                project.to_project_display()
+                            )
+                        });
+                    }
                 };
 
-                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.
+                for (active, url) in tabs {
+                    let is_selected = {
+                        if active {
+                            "🔻 "
+                        } else {
+                            "   "
+                        }
+                    };
+                    println!("{is_selected}{url}");
                 }
-            } 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(state)
-            .with_context(|| format!("Failed to stop task {task}"))?;
-    }
-    if let Some(task) = old_task {
-        task.start(state)
-            .with_context(|| format!("Failed to start task {task}"))?;
-    }
+    Ok(())
+}
 
-    if let Some(project) = old_project {
-        project.activate().with_context(|| {
-            format!("Failed to active project {}", project.to_project_display())
-        })?;
-    } else {
-        task::Project::clear().context("Failed to clear currently focused project")?;
-    }
+fn get_tabs(project: &task::Project) -> Result<Vec<(bool, Url)>> {
+    let session_store = project.get_sessionstore()?;
 
-    Ok(())
+    let tabs = session_store
+        .windows
+        .iter()
+        .flat_map(|window| window.tabs.iter())
+        .filter_map(|tab| {
+            tab.history
+                .iter()
+                .find(|hist| hist.active)
+                .map(|hist| (tab.active, hist))
+        })
+        .collect::<Vec<_>>();
+
+    Ok(tabs
+        .into_iter()
+        .map(|(active, hist)| (active, hist.url.clone()))
+        .collect())
 }