aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-04-04 16:07:34 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-04-04 16:07:34 +0200
commit2a9d37026a5b2599930c2d7338cdf04bf254812b (patch)
treea818c19634a05f500daaccf42e36205a28a52635 /pkgs/by-name
parentfix(pkgs/tskm): Remove typos (diff)
downloadnixos-config-2a9d37026a5b2599930c2d7338cdf04bf254812b.zip
feat(pkgs/tskm): Support listing the open tabs in a project
Diffstat (limited to 'pkgs/by-name')
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.lock27
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.toml3
-rw-r--r--pkgs/by-name/ts/tskm/src/cli.rs7
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/handle.rs43
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/mod.rs104
5 files changed, 183 insertions, 1 deletions
diff --git a/pkgs/by-name/ts/tskm/Cargo.lock b/pkgs/by-name/ts/tskm/Cargo.lock
index 879cbf57..4a064858 100644
--- a/pkgs/by-name/ts/tskm/Cargo.lock
+++ b/pkgs/by-name/ts/tskm/Cargo.lock
@@ -470,6 +470,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
+name = "lz4_flex"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
+dependencies = [
+ "twox-hash",
+]
+
+[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -603,6 +612,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
name = "stderrlog"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -701,6 +716,7 @@ dependencies = [
"clap_complete",
"dirs",
"log",
+ "lz4_flex",
"serde",
"serde_json",
"stderrlog",
@@ -709,6 +725,16 @@ dependencies = [
]
[[package]]
+name = "twox-hash"
+version = "1.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "static_assertions",
+]
+
+[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -723,6 +749,7 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
+ "serde",
]
[[package]]
diff --git a/pkgs/by-name/ts/tskm/Cargo.toml b/pkgs/by-name/ts/tskm/Cargo.toml
index 3344e378..d2990b0c 100644
--- a/pkgs/by-name/ts/tskm/Cargo.toml
+++ b/pkgs/by-name/ts/tskm/Cargo.toml
@@ -10,10 +10,11 @@ anyhow = "1.0.97"
clap = { version = "4.5.34", features = ["derive"] }
dirs = "6.0.0"
log = "0.4.27"
+lz4_flex = "0.11.3"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
stderrlog = "0.6.0"
-url = { version = "2.5.4" }
+url = { version = "2.5.4", features = ["serde"] }
walkdir = "2.5.0"
[profile.release]
diff --git a/pkgs/by-name/ts/tskm/src/cli.rs b/pkgs/by-name/ts/tskm/src/cli.rs
index 958033b3..bf0af7fb 100644
--- a/pkgs/by-name/ts/tskm/src/cli.rs
+++ b/pkgs/by-name/ts/tskm/src/cli.rs
@@ -88,6 +88,13 @@ pub enum OpenCommand {
/// This will use rofi's dmenu mode to select one project from the list of all registered
/// projects.
Select,
+
+ /// List all open tabs in the project.
+ ListTabs {
+ /// The project to open.
+ #[arg(value_parser = task::Project::from_project_string)]
+ project: Option<task::Project>,
+ }
}
#[derive(Subcommand, Debug)]
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 5738d232..08bd1de4 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
@@ -58,6 +58,49 @@ pub fn handle(command: OpenCommand) -> Result<()> {
open_in_browser(&selected_project).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!");
+ };
+
+ 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 {
+ " "
+ }
+ };
+ println!("{}{}", is_selected, entry.url);
+ }
+ }
}
Ok(())
}
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 a70793bc..2dc75957 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
@@ -1,2 +1,106 @@
+use std::{collections::HashMap, fs::File, io};
+
+use anyhow::{Context, Result};
+use lz4_flex::decompress_size_prepended;
+use serde::Deserialize;
+use serde_json::Value;
+use url::Url;
+
+use crate::task::Project;
+
pub mod handle;
pub use handle::handle;
+
+impl Project {
+ pub(super) fn get_sessionstore(&self) -> Result<SessionStore> {
+ let path = dirs::home_dir()
+ .expect("Will exist")
+ .join(".mozilla/firefox")
+ .join(self.to_project_display())
+ .join("sessionstore-backups/recovery.jsonlz4");
+ let file = decompress_mozlz4(
+ File::open(&path)
+ .with_context(|| format!("Failed to open path '{}'", path.display()))?,
+ )
+ .with_context(|| format!("Failed to decompress file as mozlzh '{}'", path.display()))?;
+
+ let contents: SessionStore = serde_json::from_str(&file).with_context(|| {
+ format!(
+ "Failed to deserialize file ('{}') as session store.",
+ path.display()
+ )
+ })?;
+ Ok(contents)
+ }
+}
+
+fn decompress_mozlz4<P: io::Read>(mut file: P) -> Result<String> {
+ const MOZLZ4_MAGIC_NUMBER: &[u8] = b"mozLz40\0";
+
+ let mut buf = [0u8; 8];
+ file.read_exact(&mut buf)
+ .context("Failed to read the mozlz40 header.")?;
+
+ assert_eq!(buf, MOZLZ4_MAGIC_NUMBER);
+
+ let mut buf = vec![];
+ file.read_to_end(&mut buf).context("Failed to read file")?;
+
+ let uncompressed = decompress_size_prepended(&buf).context("Failed to decompress file")?;
+
+ Ok(String::from_utf8(uncompressed).expect("This should be valid json and thus utf8"))
+}
+
+#[derive(Deserialize, Debug)]
+pub struct SessionStore {
+ pub windows: Vec<Window>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct Window {
+ pub tabs: Vec<Tab>,
+ pub selected: usize,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct Tab {
+ pub entries: Vec<TabEntry>,
+ #[serde(rename = "lastAccessed")]
+ pub last_accessed: u64,
+ pub hidden: bool,
+ #[serde(rename = "searchMode")]
+ pub search_mode: Option<Value>,
+ #[serde(rename = "userContextId")]
+ pub user_context_id: u32,
+ pub attributes: TabAttributes,
+ #[serde(rename = "extData")]
+ pub ext_data: Option<HashMap<String, Value>>,
+ pub index: usize,
+ #[serde(rename = "requestedIndex")]
+ pub requested_index: Option<u32>,
+ pub image: Option<Url>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct TabEntry {
+ pub url: Url,
+ pub title: String,
+ #[serde(rename = "cacheKey")]
+ pub cache_key: u32,
+ #[serde(rename = "ID")]
+ pub id: u32,
+ #[serde(rename = "docshellUUID")]
+ pub docshell_uuid: Value,
+ #[serde(rename = "resultPrincipalURI")]
+ pub result_principal_uri: Option<Url>,
+ #[serde(rename = "hasUserInteraction")]
+ pub has_user_interaction: bool,
+ #[serde(rename = "triggeringPrincipal_base64")]
+ pub triggering_principal_base64: Value,
+ #[serde(rename = "docIdentifier")]
+ pub doc_identifier: u32,
+ pub persist: bool,
+}
+
+#[derive(Deserialize, Debug, Clone, Copy)]
+pub struct TabAttributes {}