about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-07-20 18:41:16 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-07-20 18:41:16 +0200
commit24d7d3e14ff14d6e43670023bd0862e82f9408e7 (patch)
tree79d0da401fac0dbc451f8c0ac63e2306d4c4ac16
parentmodules/legacy/conf/iamb: Move to `by-name` and modernize (diff)
downloadnixos-config-24d7d3e14ff14d6e43670023bd0862e82f9408e7.zip
pkgs/tskm: Support raw paths in place of URLs
Otherwise, using `tskm` as an URL opener might fail (e.g., as `xdg-open
/some/path`, would still invoke it).
-rw-r--r--pkgs/by-name/ts/tskm/src/browser/mod.rs16
-rw-r--r--pkgs/by-name/ts/tskm/src/cli.rs6
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/handle.rs2
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/mod.rs30
4 files changed, 44 insertions, 10 deletions
diff --git a/pkgs/by-name/ts/tskm/src/browser/mod.rs b/pkgs/by-name/ts/tskm/src/browser/mod.rs
index d83bcbc4..2129982f 100644
--- a/pkgs/by-name/ts/tskm/src/browser/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/browser/mod.rs
@@ -14,11 +14,14 @@ use url::Url;
 use crate::{state::State, task};
 
 #[allow(clippy::too_many_lines)]
-pub fn open_in_browser(
+pub fn open_in_browser<U>(
     selected_project: &task::Project,
     state: &mut State,
-    urls: Option<Vec<Url>>,
-) -> Result<()> {
+    urls: Option<Vec<U>>,
+) -> Result<()>
+where
+    U: Into<Url>,
+{
     let old_project: Option<task::Project> =
         task::Project::get_current().context("Failed to get currently active project")?;
     let old_task: Option<task::Task> =
@@ -129,7 +132,7 @@ pub fn open_in_browser(
 
         if let Some(mut stream) = socket {
             let real_url = if let Some(urls) = urls {
-                urls.into_iter().map(|url| url.to_string()).collect()
+                urls.into_iter().map(|url| url.into().to_string()).collect()
             } else {
                 // Always add a new tab, so that qutebrowser is marked as “urgent”.
                 vec!["qute://start".to_owned()]
@@ -153,7 +156,10 @@ pub fn open_in_browser(
             ExitStatus::default()
         } else {
             let args = if let Some(urls) = urls {
-                urls.iter().map(ToString::to_string).collect()
+                urls.into_iter()
+                    .map(Into::<Url>::into)
+                    .map(|u| u.to_string())
+                    .collect()
             } else {
                 vec![]
             };
diff --git a/pkgs/by-name/ts/tskm/src/cli.rs b/pkgs/by-name/ts/tskm/src/cli.rs
index 23d9545f..359c1050 100644
--- a/pkgs/by-name/ts/tskm/src/cli.rs
+++ b/pkgs/by-name/ts/tskm/src/cli.rs
@@ -13,11 +13,11 @@ use std::{ffi::OsStr, path::PathBuf};
 use anyhow::{bail, Result};
 use clap::{builder::StyledStr, ArgAction, Parser, Subcommand, ValueEnum};
 use clap_complete::{ArgValueCompleter, CompletionCandidate};
-use url::Url;
 
 use crate::{
     interface::{
         input::{Input, Tag},
+        open::UrlLike,
         project::ProjectName,
     },
     state, task,
@@ -127,7 +127,7 @@ pub enum OpenCommand {
         project: task::Project,
 
         /// The URLs to open.
-        urls: Option<Vec<Url>>,
+        urls: Option<Vec<UrlLike>>,
     },
 
     /// Open a selected project in it's Qutebrowser profile.
@@ -136,7 +136,7 @@ pub enum OpenCommand {
     /// projects.
     Select {
         /// The URLs to open.
-        urls: Option<Vec<Url>>,
+        urls: Option<Vec<UrlLike>>,
     },
 
     /// List all open tabs in the project.
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 0cf60b41..3897a63b 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
@@ -43,7 +43,7 @@ pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
                         project.to_project_display(),
                         if is_empty { "is empty" } else { "is not empty" }
                     );
-                    open_in_browser(project, state, None).with_context(|| {
+                    open_in_browser(project, state, None::<Vec<Url>>).with_context(|| {
                         format!(
                             "Failed to open project ('{}') in qutebrowser",
                             project.to_project_display()
diff --git a/pkgs/by-name/ts/tskm/src/interface/open/mod.rs b/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
index e302c7d1..e403b4a8 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
@@ -8,7 +8,11 @@
 // 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::File, io::Read, str::FromStr};
+use std::{
+    fs::{self, File},
+    io::Read,
+    str::FromStr,
+};
 
 use anyhow::{anyhow, Context, Result};
 use taskchampion::chrono::NaiveDateTime;
@@ -20,6 +24,30 @@ use crate::task::Project;
 pub mod handle;
 pub use handle::handle;
 
+/// An Url that also accepts file paths
+#[derive(Debug, Clone)]
+pub struct UrlLike(Url);
+
+impl FromStr for UrlLike {
+    type Err = url::ParseError;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        if let Ok(u) = fs::canonicalize(s) {
+            Ok(Self(Url::from_file_path(u).expect(
+                "The path could be canonicalized, as such it is valid for this",
+            )))
+        } else {
+            Url::from_str(s).map(Self)
+        }
+    }
+}
+
+impl From<UrlLike> for Url {
+    fn from(value: UrlLike) -> Self {
+        value.0
+    }
+}
+
 impl Project {
     pub(super) fn get_sessionstore(&self) -> Result<SessionStore> {
         let path = dirs::data_local_dir()