diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/build_nix.yml b/.github/workflows/build_nix.yml new file mode 100644 index 0000000..2462e02 --- /dev/null +++ b/.github/workflows/build_nix.yml @@ -0,0 +1,13 @@ +name: "Build legacy Nix package on Ubuntu" + +on: + push: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: cachix/install-nix-action@v26 + - name: Building package + run: nix build diff --git a/.gitignore b/.gitignore index 2e80806..fbe0330 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ /target /result + +.direnv diff --git a/Cargo.lock b/Cargo.lock index 6804f07..82e7aef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,113 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -17,6 +118,18 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "idna" version = "0.5.0" @@ -27,6 +140,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "is-docker" version = "0.2.0" @@ -46,6 +169,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itoa" version = "1.0.11" @@ -58,6 +187,12 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "memchr" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + [[package]] name = "once_cell" version = "1.19.0" @@ -107,12 +242,14 @@ dependencies = [ [[package]] name = "rofi-obsidian" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", + "clap", "open", "serde", "serde_json", + "toml", "url", ] @@ -153,6 +290,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.58" @@ -179,6 +331,40 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "toml" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -210,3 +396,91 @@ dependencies = [ "idna", "percent-encoding", ] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 7e171de..8eade66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rofi-obsidian" description = "Launch your Obsidian vaults from the comfort of rofi" -version = "0.1.1" +version = "0.1.2" edition = "2021" license = "Unlicense" readme = "README.md" @@ -17,7 +17,9 @@ strip = true # Strip symbols from binary* [dependencies] anyhow = "1.0.82" +clap = { version = "4.5.4", features = ["derive"] } open = "5.1.2" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" +toml = "0.8.13" url = "2.5.0" diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..39bacff --- /dev/null +++ b/default.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).defaultNix diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..77db547 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/99f1c2157fba4bfe6211a321fd0ee43199025dbf.tar.gz"; + sha256 = "0x2jn3vrawwv9xp15674wjz9pixwjyj3j771izayl962zziivbx2"; } +) { + src = ./.; +}).shellNix diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..77a4be4 --- /dev/null +++ b/src/args.rs @@ -0,0 +1,18 @@ +use clap::{Parser, Subcommand}; + +#[derive(Debug, Clone, Subcommand)] +pub enum SubCommand { + /// Initiate the configuration at the default location + InitConfig, + /// Edit the configuration + Config, + /// Run rofi-obsidian, default behaviour + Run, +} + +#[derive(Parser, Debug)] +#[command(author, version, about)] +pub struct Args { + #[command(subcommand)] + pub sub: Option, +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..78fba0b --- /dev/null +++ b/src/config.rs @@ -0,0 +1,59 @@ +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use std::{ + fs::{self, create_dir_all, write}, + path::PathBuf, +}; + +#[derive(Serialize, Deserialize, Default, Debug)] +#[serde(rename_all = "snake_case")] +pub enum DisplayName { + #[default] + VaultName, + Path, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub struct Config { + pub display_name: DisplayName, + pub source: Source, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Source { + pub flatpak: bool, + pub native: bool, + pub additional_sources: Vec, +} + +impl Config { + fn get_path() -> PathBuf { + let conf_home = std::env::var("XDG_CONFIG_HOME").unwrap_or("~/.config".into()); + PathBuf::from(conf_home).join("rofi-obsidian/config.toml") + } + + pub fn parse() -> Self { + let path = Self::get_path(); + + let conf = fs::read_to_string(path).unwrap_or_default(); + + toml::from_str(&conf).unwrap_or_default() + } + + pub fn write(&self) -> Result { + let path = Self::get_path(); + create_dir_all(path.parent().unwrap())?; + write(path.clone(), toml::to_string(self)?)?; + Ok(path) + } +} + +impl Default for Source { + fn default() -> Self { + Self { + flatpak: true, + native: true, + additional_sources: vec![], + } + } +} diff --git a/src/main.rs b/src/main.rs index 267ddee..781bbe3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,16 @@ +use crate::config::DisplayName; use anyhow::Result; -use std::collections::HashMap; +use args::{Args, SubCommand}; +use clap::Parser; +use config::Config; +use std::collections::{HashMap, HashSet}; use std::path::Path; use std::{env, fs}; use url::form_urlencoded::Serializer; +mod args; +mod config; + #[derive(serde::Serialize, serde::Deserialize, Debug)] struct VaultDB { vaults: HashMap, @@ -28,18 +35,8 @@ fn get_vaults(path: String) -> Result> { Ok(vault_paths) } -// Merge and deduplicate both the flatpak and native configuration files. -fn merge(v1: Vec, mut v2: Vec) -> Vec { - v1.iter().for_each(|i| { - if !v2.contains(i) { - v2.push(i.to_string()); - }; - }); - - v2 -} - -fn get_known_vaults() -> Vec { +fn build_sources(conf: &Config) -> Vec { + let mut sources: Vec = vec![]; let home = env::var("HOME").unwrap_or_default(); let xdg_conf = env::var("XDG_CONFIG_HOME").unwrap_or_else(|_| { if !home.is_empty() { @@ -53,31 +50,51 @@ fn get_known_vaults() -> Vec { return vec![]; } - let flatpak_conf: String = - format!("{home}/.var/app/md.obsidian.Obsidian/config/obsidian/obsidian.json"); - let native_conf: String = format!("{xdg_conf}/obsidian/obsidian.json"); + if conf.source.flatpak { + sources.push(format!( + "{home}/.var/app/md.obsidian.Obsidian/config/obsidian/obsidian.json" + )); + }; + + if conf.source.native { + sources.push(format!("{xdg_conf}/obsidian/obsidian.json")); + }; - let mut vault_paths = merge( - get_vaults(native_conf).unwrap_or_default(), - get_vaults(flatpak_conf).unwrap_or_default(), - ); + sources.append(&mut conf.source.additional_sources.clone()); - vault_paths.sort(); - vault_paths + sources } -fn main() -> Result<()> { - let rofi_state: u8 = env::var("ROFI_RETV")?.parse()?; +fn get_known_vaults(conf: &Config) -> Vec { + let sources = build_sources(conf); + + let mut vaults = sources + .iter() + .flat_map(|path| get_vaults(path.to_string()).unwrap_or_default()) + .collect::>() + .into_iter() + .map(|s| s.to_owned()) + .collect::>(); + + vaults.sort(); + vaults +} + +fn rofi_main(state: u8, conf: Config, _args: Args) -> Result<()> { let rofi_info: String = env::var("ROFI_INFO").unwrap_or_default(); - match rofi_state { + match state { // Prompting which vault to open 0 => { - get_known_vaults().iter().for_each(|vault| { - let name = Path::new(vault) - .file_stem() - .and_then(|s| s.to_str()) - .unwrap_or_else(|| vault); + get_known_vaults(&conf).iter().for_each(|vault| { + let name = match conf.display_name { + DisplayName::VaultName => Path::new(vault) + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or_else(|| vault), + DisplayName::Path => vault, + }; + println!("{name}\0info\x1f{vault}"); }); } @@ -85,8 +102,8 @@ fn main() -> Result<()> { 1 => { let path: String = Serializer::new(String::default()) .append_pair("path", &rofi_info) - .finish(); - let path = path.replace('+', "%20"); + .finish() + .replace('+', "%20"); #[cfg(debug_assertions)] eprintln!("{path}"); @@ -101,26 +118,37 @@ fn main() -> Result<()> { Ok(()) } -#[cfg(test)] -mod tests { - use crate::{get_vaults, merge}; - - #[test] - fn test_merge() { - let elem_test: String = "TEST".into(); - let elem_foo: String = "FOO".into(); - let elem_bar: String = "BAR".into(); +fn main() -> Result<()> { + let conf = config::Config::parse(); + let args = Args::parse(); - let v1 = vec![elem_test.clone(), elem_foo.clone()]; - let v2 = vec![elem_test.clone(), elem_bar.clone()]; + match args.sub { + Some(SubCommand::InitConfig) => { + let location = conf.write()?; + println!("Config written to: {:?}", location); + } + Some(SubCommand::Config) => { + unimplemented!() + } + Some(SubCommand::Run) | None => { + if let Ok(state) = env::var("ROFI_RETV") { + let state = state.parse()?; + rofi_main(state, conf, args)?; + } else { + println!( + "Error: {} cannot be run outside of rofi.", + env!("CARGO_BIN_NAME") + ); + } + } + } - let v3 = merge(v1, v2); + Ok(()) +} - assert_eq!(v3.len(), 3); - assert!(v3.contains(&elem_test)); - assert!(v3.contains(&elem_foo)); - assert!(v3.contains(&elem_bar)); - } +#[cfg(test)] +mod tests { + use crate::get_vaults; #[test] fn test_base_json() {