// nixos-config - My current NixOS configuration // // Copyright (C) 2025 Benedikt Peetz // SPDX-License-Identifier: GPL-3.0-or-later // // This file is part of my nixos-config. // // You should have received a copy of the License along with this program. // If not, see . use anyhow::{bail, Context, Result}; use log::{error, info}; use url::Url; use crate::{browser::open_in_browser, cli::OpenCommand, rofi, state::State, task}; fn is_empty(project: &task::Project) -> Result { 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 { non_empty } => { for project in task::Project::all().context("Failed to get all project files")? { 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 qutebrowser", project.to_project_display() ) })?; if project.is_touched() { project.untouch().with_context(|| { format!( "Failed to untouch project ('{}')", project.to_project_display() ) })?; } } } } OpenCommand::Project { project, url } => { project.touch().context("Failed to touch project")?; open_in_browser(&project, state, url).with_context(|| { format!("Failed to open project: {}", project.to_project_display()) })?; } OpenCommand::Select { url } => { let selected_project: task::Project = task::Project::from_project_string( &rofi::select( task::Project::all() .context("Failed to get all registered projects")? .iter() .map(task::Project::to_project_display) .collect::>() .as_slice(), ) .context("Failed to get selected project")?, ) .expect("This should work, as we send only projects in"); selected_project .touch() .context("Failed to touch project")?; open_in_browser(&selected_project, state, url).context("Failed to open project")?; } 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"); } }; 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; } } } } if projects.len() > 1 { println!("/* {} */", project.to_project_display()); } 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() ) }); } }; for (active, url) in tabs { let is_selected = { if active { "🔻 " } else { " " } }; println!("{is_selected}{url}"); } } } } Ok(()) } fn get_tabs(project: &task::Project) -> Result> { let session_store = project.get_sessionstore()?; 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::>(); Ok(tabs .into_iter() .map(|(active, hist)| (active, hist.url.clone())) .collect()) }