libimagnotesfrontend/
lib.rs1#![forbid(unsafe_code)]
21
22#![deny(
23 non_camel_case_types,
24 non_snake_case,
25 path_statements,
26 trivial_numeric_casts,
27 unstable_features,
28 unused_allocation,
29 unused_import_braces,
30 unused_imports,
31 unused_must_use,
32 unused_mut,
33 unused_qualifications,
34 while_true,
35)]
36
37extern crate clap;
38#[macro_use] extern crate log;
39extern crate itertools;
40#[macro_use] extern crate failure;
41extern crate resiter;
42
43extern crate libimagnotes;
44extern crate libimagrt;
45extern crate libimagentryedit;
46extern crate libimagerror;
47extern crate libimagutil;
48extern crate libimagstore;
49
50use std::io::Write;
51
52use itertools::Itertools;
53use clap::App;
54use failure::Error;
55use failure::err_msg;
56use failure::Fallible as Result;
57use resiter::IterInnerOkOrElse;
58
59use libimagentryedit::edit::Edit;
60use libimagrt::runtime::Runtime;
61use libimagrt::application::ImagApplication;
62use libimagstore::iter::get::StoreIdGetIteratorExtension;
63use libimagnotes::note::Note;
64use libimagnotes::notestore::*;
65use libimagutil::warn_result::WarnResult;
66
67
68mod ui;
69
70pub enum ImagNotes {}
75impl ImagApplication for ImagNotes {
76 fn run(rt: Runtime) -> Result<()> {
77 match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
78 "create" => create(&rt),
79 "delete" => delete(&rt),
80 "edit" => edit(&rt),
81 "list" => list(&rt),
82 other => {
83 debug!("Unknown command");
84 if rt.handle_unknown_subcommand("imag-notes", other, rt.cli())?.success() {
85 Ok(())
86 } else {
87 Err(err_msg("Failed to handle unknown subcommand"))
88 }
89 },
90 }
91 }
92
93 fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
94 ui::build_ui(app)
95 }
96
97 fn name() -> &'static str {
98 env!("CARGO_PKG_NAME")
99 }
100
101 fn description() -> &'static str {
102 "Note taking helper"
103 }
104
105 fn version() -> &'static str {
106 env!("CARGO_PKG_VERSION")
107 }
108}
109
110fn name_from_cli(rt: &Runtime, subcmd: &str) -> String {
111 rt.cli().subcommand_matches(subcmd).unwrap().value_of("name").map(String::from).unwrap()
112}
113
114fn create(rt: &Runtime) -> Result<()> {
115 let name = name_from_cli(rt, "create");
116 let mut note = rt.store().new_note(name, String::new())?;
117
118 if rt.cli().subcommand_matches("create").unwrap().is_present("edit") {
119 note.edit_content(rt)?
120 }
121
122 rt.report_touched(note.get_location()).map_err(Error::from)
123}
124
125fn delete(rt: &Runtime) -> Result<()> {
126 rt.store().delete_note(name_from_cli(rt, "delete")).map(|_| ())
127}
128
129fn edit(rt: &Runtime) -> Result<()> {
130 let name = name_from_cli(rt, "edit");
131 rt
132 .store()
133 .get_note(name.clone())?
134 .ok_or_else(|| format_err!("Name '{}' not found", name))
135 .and_then(|mut note| {
136 note.edit_content(rt).map_warn_err_str("Editing failed")?;
137 rt.report_touched(note.get_location()).map_err(Error::from)
138 })
139}
140
141fn list(rt: &Runtime) -> Result<()> {
142 use std::cmp::Ordering;
143
144 rt
145 .store()
146 .all_notes()?
147 .into_get_iter(rt.store())
148 .map_inner_ok_or_else(|| err_msg("Did not find one entry"))
149 .collect::<Result<Vec<_>>>()?
150 .into_iter()
151 .sorted_by(|a, b| match (a.get_name(), b.get_name()) {
152 (Ok(a), Ok(b)) => a.cmp(&b),
153 _ => Ordering::Greater,
154 })
155 .map(|note| {
156 let name = note.get_name().map_err(Error::from)?;
157 writeln!(rt.stdout(), "{}", name)?;
158 rt.report_touched(note.get_location()).map_err(Error::from)
159 })
160 .collect::<Result<Vec<_>>>()
161 .map(|_| ())
162}
163