Last active
September 29, 2024 21:04
-
-
Save alloc33/3c6a45b5af6cceb0fa309450422140e9 to your computer and use it in GitHub Desktop.
Simple rust script to print out obsidian hotkeys in a readable format. Path to the <VAULT>/.obsidian/hotkeys.json should be provided as argument
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env rust-script | |
| //! ```cargo | |
| //! [dependencies] | |
| //! serde = { version = "1.0", features = ["derive"] } | |
| //! serde_json = "1.0" | |
| //! colored = "2.0" | |
| //! cli-tables = "0.1.0" | |
| //! ``` | |
| use cli_tables::Table; | |
| use colored::*; | |
| use serde::Deserialize; | |
| use std::env; | |
| use std::fs::File; | |
| use std::io::BufReader; | |
| #[derive(Debug, Deserialize)] | |
| struct KeyBinding { | |
| modifiers: Option<Vec<String>>, | |
| key: Option<String>, | |
| } | |
| fn format_modifiers(mut modifiers: Vec<String>) -> Vec<String> { | |
| // Ensure "Mod" (or "Cmd" in macOS) is first | |
| if let Some(pos) = modifiers.iter().position(|x| x == "Mod") { | |
| let mod_item = modifiers.remove(pos); | |
| modifiers.insert(0, mod_item); | |
| } | |
| // If the OS is macOS, replace "Mod" with "Cmd" and "Alt" with "Opt" | |
| if cfg!(target_os = "macos") { | |
| for modifier in &mut modifiers { | |
| if modifier == "Mod" { | |
| *modifier = "Cmd".to_string(); | |
| } else if modifier == "Alt" { | |
| *modifier = "Opt".to_string(); | |
| } | |
| } | |
| } | |
| modifiers | |
| } | |
| fn print_action(action: &str, bindings: &Vec<KeyBinding>) { | |
| println!("\n{}:", action.bold().magenta()); | |
| for binding in bindings { | |
| let modifiers = binding.modifiers.clone().unwrap_or_else(Vec::new); | |
| let formatted_modifiers = format_modifiers(modifiers).join(" + ").bold().yellow(); | |
| let key = binding.key.as_deref().unwrap_or("None").bold().cyan(); | |
| println!(" {} + {}", formatted_modifiers, key); | |
| } | |
| } | |
| fn parse_and_print_json( | |
| file_path: &str, | |
| use_table: bool, | |
| ) -> Result<(), Box<dyn std::error::Error>> { | |
| // Open and parse the file | |
| let file = File::open(file_path)?; | |
| let reader = BufReader::new(file); | |
| let json_data: serde_json::Value = serde_json::from_reader(reader)?; | |
| let mut no_bindings_list = Vec::new(); | |
| let mut table_data: Vec<Vec<String>> = vec![vec![ | |
| "Action".to_string(), | |
| "Modifiers".to_string(), | |
| "Key".to_string(), | |
| ]]; | |
| // Iterate and process JSON data | |
| if let serde_json::Value::Object(map) = json_data { | |
| for (action, bindings) in map { | |
| if let serde_json::Value::Array(bindings_array) = bindings { | |
| if bindings_array.is_empty() { | |
| no_bindings_list.push(action); | |
| } else { | |
| let parsed_bindings: Vec<KeyBinding> = bindings_array | |
| .into_iter() | |
| .filter_map(|b| serde_json::from_value(b).ok()) | |
| .collect(); | |
| if use_table { | |
| for binding in parsed_bindings { | |
| let modifiers = | |
| format_modifiers(binding.modifiers.unwrap_or_else(Vec::new)) | |
| .join(" + "); | |
| let key = binding.key.unwrap_or("None".to_string()); | |
| table_data.push(vec![action.clone(), modifiers, key]); | |
| } | |
| } else { | |
| if !parsed_bindings.is_empty() { | |
| print_action(&action, &parsed_bindings); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Print actions with no bindings at the end in table or regular format | |
| if !no_bindings_list.is_empty() { | |
| if use_table { | |
| for action in no_bindings_list { | |
| table_data.push(vec![action, "None".to_string(), "None".to_string()]); | |
| } | |
| } else { | |
| println!( | |
| "\n{}", | |
| "Default actions with no bindings:".bold().bright_black() | |
| ); | |
| for action in no_bindings_list { | |
| println!(" {}", action.bright_black()); | |
| } | |
| } | |
| } | |
| } | |
| // If the table flag is used, print the table | |
| if use_table { | |
| let mut table = Table::new(&table_data); | |
| println!("{}", table.to_string()); | |
| } | |
| Ok(()) | |
| } | |
| fn main() { | |
| // Get the command line arguments | |
| let args: Vec<String> = env::args().collect(); | |
| if args.len() < 2 { | |
| eprintln!("Usage: {} <path to json file> [-t]", args[0]); | |
| std::process::exit(1); | |
| } | |
| let file_path = &args[1]; | |
| let use_table = args.len() > 2 && args[2] == "-t"; | |
| // Parse and print the JSON file | |
| if let Err(e) = parse_and_print_json(file_path, use_table) { | |
| eprintln!("Error: {}", e); | |
| std::process::exit(1); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment