Auto merge of #31 - matthiasbeyer:ui-external, r=matthiasbeyer

Ui external

Tracking branch for implementation to call external editor and edit file contents with it.
This commit is contained in:
Homu 2015-12-30 17:49:57 +09:00
commit 2568c37a25
7 changed files with 122 additions and 0 deletions

View file

@ -22,6 +22,18 @@ args:
required: false required: false
takes_value: true takes_value: true
- editor:
short: e
long: editor
help: Set editor, if not set $EDITOR of the system will be asked, else vim
required: false
takes_value: true
- editor_opts:
long: editor-opts
help: Set editor options
required: false
takes_value: true
- storename: - storename:
short: s short: s

View file

@ -47,6 +47,17 @@ impl<'a> CliConfig<'a> {
.and_then(|s| Some(rtp + s)) .and_then(|s| Some(rtp + s))
}) })
} }
pub fn editor(&self) -> Option<String> {
self.cli_matches.value_of("editor").and_then(|s| Some(String::from(s)))
}
pub fn editor_opts(&self) -> String {
self.cli_matches
.value_of("editor_opts")
.map(|s| String::from(s))
.unwrap_or(String::from(""))
}
} }
impl<'a> Debug for CliConfig<'a> { impl<'a> Debug for CliConfig<'a> {

View file

@ -10,6 +10,8 @@ pub struct Configuration {
pub store_sub : String, pub store_sub : String,
pub verbose : bool, pub verbose : bool,
pub debugging : bool, pub debugging : bool,
pub editor : Option<String>,
pub editor_opts : String,
} }
impl Configuration { impl Configuration {
@ -20,6 +22,8 @@ impl Configuration {
let mut verbose = false; let mut verbose = false;
let mut debugging = false; let mut debugging = false;
let mut store_sub = String::from("/store"); let mut store_sub = String::from("/store");
let mut editor = None;
let mut editor_opts = String::from("");
if let Some(cfg) = fetch_config(rtp.clone()) { if let Some(cfg) = fetch_config(rtp.clone()) {
if let Some(v) = cfg.lookup_boolean("verbose") { if let Some(v) = cfg.lookup_boolean("verbose") {
@ -31,6 +35,12 @@ impl Configuration {
if let Some(s) = cfg.lookup_str("store") { if let Some(s) = cfg.lookup_str("store") {
store_sub = String::from(s); store_sub = String::from(s);
} }
if let Some(s) = cfg.lookup_str("editor") {
editor = Some(String::from(s));
}
if let Some(s) = cfg.lookup_str("editor-opts") {
editor_opts = String::from(s);
}
} }
let runtimepath = rtp.unwrap_or(String::from("/tmp/")); let runtimepath = rtp.unwrap_or(String::from("/tmp/"));
@ -40,12 +50,16 @@ impl Configuration {
debug!(" - debugging : {}", debugging); debug!(" - debugging : {}", debugging);
debug!(" - store sub : {}", store_sub); debug!(" - store sub : {}", store_sub);
debug!(" - runtimepath: {}", runtimepath); debug!(" - runtimepath: {}", runtimepath);
debug!(" - editor : {:?}", editor);
debug!(" - editor-opts: {}", editor_opts);
Configuration { Configuration {
verbose: verbose, verbose: verbose,
debugging: debugging, debugging: debugging,
store_sub: store_sub, store_sub: store_sub,
rtp: runtimepath, rtp: runtimepath,
editor: editor,
editor_opts: editor_opts,
} }
} }
@ -65,6 +79,14 @@ impl Configuration {
self.rtp.clone() self.rtp.clone()
} }
pub fn editor(&self) -> Option<String> {
self.editor.clone()
}
pub fn editor_opts(&self) -> &String {
&self.editor_opts
}
} }
fn rtp_path(config: &CliConfig) -> Option<String> { fn rtp_path(config: &CliConfig) -> Option<String> {

View file

@ -92,6 +92,20 @@ impl<'a> Runtime<'a> {
} }
} }
pub fn editor(&self) -> String {
use std::env::var;
if let Some(editor) = self.config.editor() {
editor + &self.config.editor_opts()[..]
} else if let Some(editor) = self.configuration.editor() {
editor + &self.configuration.editor_opts()[..]
} else if let Ok(editor) = var("EDITOR") {
editor
} else {
String::from("vim")
}
}
} }
impl<'a> Debug for Runtime<'a> { impl<'a> Debug for Runtime<'a> {

61
src/ui/external/editor.rs vendored Normal file
View file

@ -0,0 +1,61 @@
use std::ops::Drop;
use std::path::PathBuf;
use std::fs::File;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use runtime::Runtime;
/**
* A function which lets the user provide content by editing a temp files which gets removed after
* the function got the content from it.
*/
pub fn let_user_provide_content(rt: &Runtime) -> Option<String> {
use std::io::Read;
use std::fs::File;
use std::process::Command;
use std::process::Child;
let filepath = "/tmp/imag-tmp.md";
let file_created = File::create(filepath)
.map(|_| true)
.unwrap_or(false);
if !file_created {
warn!("Could not create temporary file for user input!");
return None;
}
let output = {
let mut cmd = Command::new(rt.editor());
cmd.arg(filepath);
debug!("cmd = {:?}", cmd);
cmd.spawn()
.and_then(|child| {
child.wait_with_output()
})
};
let process_out = output.map_err(|e| {
error!("Editor call failed");
debug!("Editor call failed: {:?}", e);
return None as Option<String>;
}).unwrap();
if !process_out.status.success() {
error!("Editor call failed");
debug!("status = {:?}", process_out.status);
debug!("stdout = {:?}", String::from_utf8(process_out.stdout));
debug!("stderr = {:?}", String::from_utf8(process_out.stderr));
return None;
}
let mut contents = String::new();
File::open(filepath).map(|mut file| {
file.read_to_string(&mut contents);
Some(contents)
}).unwrap_or(None)
}

1
src/ui/external/mod.rs vendored Normal file
View file

@ -0,0 +1 @@
pub mod editor;

View file

@ -1 +1,2 @@
pub mod file; pub mod file;
pub mod external;