Compare commits

..

No commits in common. "3bea615b5292af4df766242471789c73de175faf" and "2812a556e12aa79e8598baad7d08e9403e0a60a9" have entirely different histories.

4 changed files with 40 additions and 105 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "open" name = "open"
version = "2.0.0" version = "1.0.0"
authors = ["Valerie Wolfe <sleeplessval@gmail.com>"] authors = ["Valerie Wolfe <sleeplessval@gmail.com>"]
edition = "2018" edition = "2018"

View file

@ -1,70 +0,0 @@
.Dd $Mdocdate$
.Dt OPEN 1
.Os
.Sh NAME
.Nm open
.Nd opens files with a user-defined program.
.Sh SYNOPSIS
.Nm open
.Op Ar file
.Nm open
.Op Fl hpv
.Sh DESCRIPTION
.Nm
is a replacement for
.Xr xdg-open 1
that is more easily configurable with a TOML file. Its options are as follows:
.Bl -tag -width Ds
.It Fl h\ |\ --help
Displays a brief help text.
.It Fl p\ |\ --path
Displays the path to the configuration file being used.
.It Fl v\ |\ --version
Displays version information.
.It Ar file
The file to open. If not provided, the current directory is used.
.El
.Sh FILES
.Bl -tag -width DS
.It $HOME/.config/open.toml
The global configuration file in TOML format.
.It .open
The local configuration file in TOML format.
.Nm open
will search upwards to try to find a local file. Local configuration items are prioritized.
.El
.Sh CONFIGURATION
Files can be matched on extension or exact name. Filenames are in the 'filename' array, and extensions are in the 'extension' array.
.Pp
.Dl [[extension]]
.Dl match = (string or array; matching value(s))
.Dl command = (string; the command to open with)
.Dl shell = (boolean; decides if the command is run in the terminal)
.Pp
.Pp
The "dir" section is used to set associations for directories:
.Pp
.Dl [dir]
.Dl command = (string; the command to open with)
.Dl shell = (boolean; decides if the command is run in the terminal)
.Pp
.Sh EXIT STATUS
.Bl -tag -width Ds
.It 1
No configuration file was found.
.It 4
The target file does not exist.
.It 5
No matching configuration section was found for the target file.
.El
.Sh SEE ALSO
.Xr xdg-open 1 ,
.Xr open 3p
.Sh AUTHORS
.An -nosplit
.An Valerie Wolfe Aq Mt sleeplessval@gmail.com
.Sh BUGS
.Nm
hides the
.Xr open 3p
builtin, breaking convention and possibly some older script files.

View file

@ -6,12 +6,10 @@ use std::{
}; };
use pico_args::Arguments; use pico_args::Arguments;
use toml::value::Value; use toml::value::{ Array, Value };
mod config; mod config;
mod error; mod error;
mod util;
use config::Config; use config::Config;
fn main() { fn main() {
@ -35,9 +33,17 @@ fn main() {
// path flag (-p / --path) // path flag (-p / --path)
if args.contains(["-p", "--path"]) { if args.contains(["-p", "--path"]) {
if let Some(local) = config.local_path { println!("{local}"); } let local = config.local_path;
else if let Some(global) = config.global_path { println!("{global}"); } let global = config.global_path;
else { error::no_configs(); } if local.is_some() {
println!("{}", local.unwrap());
return;
}
if global.is_some() {
println!("{}", global.unwrap());
return;
}
error::no_configs();
return; return;
} }
@ -48,17 +54,16 @@ fn main() {
if !target.exists() { error::not_found(&target); } if !target.exists() { error::not_found(&target); }
// get section // get section
// ordering: filename -> type (ext/dir) -> default // ordering: filename -> type (ext/dir)
let mut section = None; let mut section = None;
// by exact filename // by exact filename
if let Some(filename) = target.file_name() { let filename = target.file_name();
let array = config.get("filename"); if filename.is_some() {
let matches: Vec<Value>; let filename_section = config.get(filename.unwrap().to_str().unwrap());
if let Some(Value::Array(array)) = array { matches = util::matches(array, filename.to_string_lossy().into()); } if filename_section.is_some() {
else { matches = Vec::new(); } section = filename_section;
}
section = if matches.len() > 0 { matches.get(0).cloned() } else { None };
} }
// handle types; dir first // handle types; dir first
@ -71,13 +76,24 @@ fn main() {
// handle types; extensions second // handle types; extensions second
if section.is_none() { if section.is_none() {
if let Some(extension) = target.extension() { let extension = target.extension();
let array: Option<Value> = config.get("extension"); if extension.is_some() {
let matches: Vec<Value>; let extension = extension.unwrap().to_str();
if let Some(Value::Array(array)) = array { matches = util::matches(array, extension.to_string_lossy().into()); }
else { matches = Vec::new(); }
section = if matches.len() > 0 { matches.get(0).cloned() } else { None }; // pull extension array and filter matches
let i_macrosection: Option<Value> = config.get("extension");
let macrosection: Array = i_macrosection.unwrap().as_array().unwrap().to_owned();
let matches = macrosection.iter().filter(|value| {
let table = value.as_table().unwrap();
let i_target = table.get("match").unwrap();
let target = i_target.as_str();
target == extension
}).map(|value| value.to_owned() );
let sections: Vec<Value> = matches.collect();
if sections.len() > 0 {
section = sections.get(0).cloned();
}
} }
} }

View file

@ -1,16 +1,5 @@
use std::{
process::{ Command, Stdio }
};
use toml::{ value::Array, Value };
/// gets array entries with matching "match" values.
pub fn matches(macrosection: Array, to_match: String) -> Vec<Value> {
macrosection.iter().filter(|value| {
if let Some(table) = value.as_table() {
match table.get("match").unwrap() {
Value::String(target) => *target == to_match,
Value::Array(values) => values.contains(&Value::String(to_match.clone())),
_ => false
}
} else { false }
}).map(|value| value.to_owned()).collect()
}