mirror of
https://github.com/chmln/handlr.git
synced 2024-11-23 17:51:46 +01:00
Polish
This commit is contained in:
parent
5ce3e839e3
commit
6da612bee1
7 changed files with 941 additions and 14 deletions
815
Cargo.lock
generated
815
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -19,3 +19,4 @@ json = "0.12.4"
|
|||
shlex = "0.1.1"
|
||||
thiserror = "1.0.14"
|
||||
ascii_table = "3.0.0"
|
||||
mime-db = "0.1.5"
|
||||
|
|
31
completions/handlr.fish
Normal file
31
completions/handlr.fish
Normal file
|
@ -0,0 +1,31 @@
|
|||
function __handlr_autocomplete
|
||||
function subcommands
|
||||
set -l handlr_commands 'get help launch list open set unset'
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "get" -d "Show handler for mime"
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "launch" -d "Launch given handler with path/args"
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "list" -d "Show handlers (default applications)"
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "open" -d "Open path/URL with default handler (like xdg-open)"
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "set" -d "Set handler for extension (e.g. pdf) or mime type"
|
||||
complete -f -c handlr -n "not __fish_seen_subcommand_from $handlr_commands" -a "unset" -d "Unset handler"
|
||||
end
|
||||
|
||||
function _set
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set' -s "em"
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set; __fish_prev_arg_in set' -a '-e -m'
|
||||
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set; __fish_prev_arg_in "-e"' -a "(handlr autocomplete -e)"
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set; __fish_prev_arg_in "-m"' -a '(handlr autocomplete -m)'
|
||||
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set; set -l last (commandline -pco)[-2]; [ "$last" = "-e" ]' -a '(handlr autocomplete -d)' -d "desc1 desc2"
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from set; set -l last (commandline -pco)[-2]; [ "$last" = "-m" ]' -a '(handlr autocomplete -d)'
|
||||
end
|
||||
|
||||
subcommands
|
||||
_set
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from get' -l 'json' -a '(handlr autocomplete -m)'
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from unset' -a '(handlr autocomplete -m)'
|
||||
complete -f -c handlr -n '__fish_seen_subcommand_from launch; __fish_prev_arg_in launch' -a '(handlr autocomplete -m)'
|
||||
|
||||
end
|
||||
|
||||
__handlr_autocomplete
|
26
src/autocomplete.rs
Normal file
26
src/autocomplete.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use crate::Result;
|
||||
pub fn extensions() -> Result<()> {
|
||||
use std::io::Write;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
mime_db::EXTENSIONS.iter().for_each(|(ext, _)| {
|
||||
stdout.write_all(ext.as_bytes()).unwrap();
|
||||
stdout.write_all(b"\n").unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mimes() -> Result<()> {
|
||||
use std::io::Write;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
mime_db::TYPES.iter().for_each(|(mime, _, _)| {
|
||||
stdout.write_all(mime.as_bytes()).unwrap();
|
||||
stdout.write_all(b"\n").unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
10
src/error.rs
10
src/error.rs
|
@ -4,14 +4,16 @@ pub enum Error {
|
|||
Parse(#[from] pest::error::Error<crate::common::Rule>),
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
#[error("handler not found")]
|
||||
#[error("no handler defined for this mime/extension")]
|
||||
NotFound,
|
||||
#[error("Invalid desktop entry")]
|
||||
#[error("badly-formatted desktop entry")]
|
||||
BadCmd,
|
||||
#[error("Could not find config dir")]
|
||||
#[error("could not locate config dir")]
|
||||
NoConfigDir,
|
||||
#[error("could not guess mime type")]
|
||||
#[error("could not figure out the mime from extension. please provide the mime type directly")]
|
||||
Ambiguous,
|
||||
#[error("either mime (via -m) or extension (via -e) must be provided")]
|
||||
MissingMimeOrExt,
|
||||
}
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
|
46
src/main.rs
46
src/main.rs
|
@ -1,6 +1,7 @@
|
|||
use error::{Error, Result};
|
||||
use structopt::StructOpt;
|
||||
|
||||
mod autocomplete;
|
||||
mod common;
|
||||
mod error;
|
||||
mod mimeapps;
|
||||
|
@ -23,19 +24,40 @@ enum Cmd {
|
|||
args: Vec<String>,
|
||||
},
|
||||
Set {
|
||||
mime: Mime,
|
||||
#[structopt(long, short)]
|
||||
mime: Option<Mime>,
|
||||
#[structopt(long, short)]
|
||||
ext: Option<String>,
|
||||
handler: Handler,
|
||||
},
|
||||
Unset {
|
||||
mime: Mime,
|
||||
},
|
||||
#[structopt(setting = structopt::clap::AppSettings::Hidden)]
|
||||
Autocomplete {
|
||||
#[structopt(short)]
|
||||
desktop_files: bool,
|
||||
#[structopt(short)]
|
||||
mimes: bool,
|
||||
#[structopt(short)]
|
||||
extensions: bool,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut apps = mimeapps::MimeApps::read()?;
|
||||
|
||||
match Cmd::from_args() {
|
||||
Cmd::Set { mime, handler } => {
|
||||
Cmd::Set { mime, ext, handler } => {
|
||||
let mime = match ext {
|
||||
Some(extension) => mime_guess::from_ext(&extension)
|
||||
.first_raw()
|
||||
.map(ToOwned::to_owned)
|
||||
.map(Mime)
|
||||
.ok_or(Error::Ambiguous)?,
|
||||
None => mime.ok_or(Error::MissingMimeOrExt)?,
|
||||
};
|
||||
|
||||
apps.set_handler(mime, handler)?;
|
||||
}
|
||||
Cmd::Launch { mime, args } => {
|
||||
|
@ -47,13 +69,14 @@ fn main() -> Result<()> {
|
|||
Cmd::Open { path } => match url::Url::parse(&path) {
|
||||
Ok(url) => {
|
||||
let mime = Mime(format!("x-scheme-handler/{}", url.scheme()));
|
||||
|
||||
apps.get_handler(&mime)?.open(path)?;
|
||||
}
|
||||
Err(_) => {
|
||||
let guess = mime_guess::from_path(&path)
|
||||
.first_raw()
|
||||
.ok_or(Error::Ambiguous)?;
|
||||
apps.get_handler(&Mime(guess.to_owned()))?.open(path)?;
|
||||
.first_or_text_plain()
|
||||
.to_string();
|
||||
apps.get_handler(&Mime(guess))?.open(path)?;
|
||||
}
|
||||
},
|
||||
Cmd::List => {
|
||||
|
@ -62,6 +85,19 @@ fn main() -> Result<()> {
|
|||
Cmd::Unset { mime } => {
|
||||
apps.remove_handler(&mime)?;
|
||||
}
|
||||
Cmd::Autocomplete {
|
||||
desktop_files,
|
||||
mimes,
|
||||
extensions,
|
||||
} => {
|
||||
if desktop_files {
|
||||
apps.list_handlers()?;
|
||||
} else if mimes {
|
||||
autocomplete::mimes()?;
|
||||
} else if extensions {
|
||||
autocomplete::extensions()?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -158,6 +158,32 @@ impl MimeApps {
|
|||
|
||||
ascii_table::AsciiTable::default().print(rows);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn list_handlers(&self) -> Result<()> {
|
||||
// use rayon::iter::ParallelBridge;
|
||||
// use rayon::prelude::ParallelIterator;
|
||||
use std::convert::TryFrom;
|
||||
use std::io::Write;
|
||||
|
||||
let stdout = std::io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
|
||||
std::fs::read_dir("/usr/share/applications")?
|
||||
.chain(std::fs::read_dir({
|
||||
let mut dir = dirs::data_dir().ok_or(Error::NoConfigDir)?;
|
||||
dir.push("applications");
|
||||
dir
|
||||
})?)
|
||||
.filter_map(Result::ok)
|
||||
.filter_map(|p| DesktopEntry::try_from(p.path()).ok())
|
||||
.for_each(|e| {
|
||||
stdout.write_all(e.file_name.as_bytes()).unwrap();
|
||||
stdout.write_all(b"\t").unwrap();
|
||||
stdout.write_all(e.name.as_bytes()).unwrap();
|
||||
stdout.write_all(b"\n").unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue