Skip to content

Commit

Permalink
feat(Interact): Add interactive mode
Browse files Browse the repository at this point in the history
  • Loading branch information
nokome committed Apr 5, 2021
1 parent 62f8eb4 commit 8122ba0
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 15 deletions.
77 changes: 77 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ edition = "2018"

cli = ["template-handlebars", "exitcode", "structopt", "termimad"]

open = ["serve", "serve-http", "serve-ws", "webbrowser"]
interact = ["rustyline"]

convert = []
open = ["serve", "serve-http", "serve-ws", "webbrowser"]

serve = []
serve-stdio = []
Expand Down Expand Up @@ -53,8 +53,8 @@ watch = ["notify"]

default = [
"cli",
"interact",
"open",
"convert",
"serve",
"serve-stdio",
"serve-http",
Expand Down Expand Up @@ -96,6 +96,7 @@ once_cell = "1.7.2"
rand = "0.8.3"
regex = "1.4.5"
reqwest = { version = "0.11.2", optional = true, features = ["json"] }
rustyline = { version = "8.0.0", optional = true }
self_update = { version = "0.26.0", optional = true, features = [
"archive-tar",
"archive-zip",
Expand Down
4 changes: 2 additions & 2 deletions rust/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ pub async fn cli(args: Vec<String>) -> Result<i32> {
plugins::read_plugins()?;

let result = if command.is_none() {
interact::run()
interact::run(&config).await
} else {
match command.unwrap() {
Command::Open(args) => open::cli::run(args).await,
Command::Convert(args) => convert::cli::run(args),
Command::Serve(args) => serve::cli::run(args, &config.serve).await,
Command::Plugins(args) => plugins::cli::run(args, &config.plugins).await,
Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
Command::Config(args) => config::cli::run(args, &config),
Command::Config(args) => config::cli::run(args, &config).map(|_| ()),
}
};

Expand Down
17 changes: 10 additions & 7 deletions rust/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,30 +242,33 @@ pub mod cli {
pub property: String,
}

pub fn run(args: Args, config: &Config) -> Result<()> {
pub fn run(args: Args, config: &Config) -> Result<Config> {
let Args { action } = args;
match action {
Action::Get(action) => {
let Get { pointer } = action;
println!("{}", super::display(config, pointer)?)
println!("{}", super::display(config, pointer)?);
Ok(config.clone())
}
Action::Set(action) => {
let Set { pointer, value } = action;
let config = super::set(config, &pointer, &value)?;
write(&config)?;
Ok(config)
}
Action::Reset(action) => {
let Reset { property } = action;
let config = super::reset(config, &property)?;
write(&config)?;
Ok(config)
}
Action::Dirs => {
let config = util::dirs::config(false)?.display().to_string();
let plugins = util::dirs::plugins(false)?.display().to_string();
println!("config: {}\nplugins: {}", config, plugins);
let config_dir = util::dirs::config(false)?.display().to_string();
let plugins_dir = util::dirs::plugins(false)?.display().to_string();
println!("config: {}\nplugins: {}", config_dir, plugins_dir);
Ok(config.clone())
}
};
Ok(())
}
}
}

Expand Down
111 changes: 111 additions & 0 deletions rust/src/interact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::{config, convert, open, plugins, serve, upgrade, util::dirs};
use anyhow::{bail, Result};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(
about = "Stencila command line tool",
setting = structopt::clap::AppSettings::NoBinaryName,
setting = structopt::clap::AppSettings::ColoredHelp,
setting = structopt::clap::AppSettings::VersionlessSubcommands
)]
pub struct Line {
#[structopt(subcommand)]
pub command: Command,
}

#[derive(Debug, StructOpt)]
#[structopt(
setting = structopt::clap::AppSettings::DeriveDisplayOrder
)]
pub enum Command {
Open(open::cli::Args),
Convert(convert::cli::Args),
Serve(serve::cli::Args),
Plugins(plugins::cli::Args),
Config(config::cli::Args),
Upgrade(upgrade::cli::Args),
}

/// Run the interactive REPL
#[cfg(feature = "interact")]
#[tracing::instrument]
pub async fn run(config: &config::Config) -> Result<()> {
use rustyline::{error::ReadlineError, Editor};

let history_file = dirs::config(true)?.join("history.txt");

let mut rl = Editor::<()>::new();
if rl.load_history(&history_file).is_err() {
tracing::debug!("No previous history found")
}

let mut config = config.clone();

loop {
let readline = rl.readline("> ");
match readline {
Ok(line) => {
rl.add_history_entry(line.as_str());
let clap = Line::clap();
let line = line.split_whitespace().collect::<Vec<&str>>();
match clap.get_matches_from_safe(line) {
Ok(matches) => {
let Line { command } = Line::from_clap(&matches);
if let Err(error) = match command {
Command::Open(args) => open::cli::run(args).await,
Command::Convert(args) => convert::cli::run(args),
Command::Serve(args) => serve::cli::run(args, &config.serve).await,
Command::Plugins(args) => {
plugins::cli::run(args, &config.plugins).await
}
Command::Upgrade(args) => upgrade::cli::run(args, &config.upgrade),
Command::Config(args) => match config::cli::run(args, &config) {
Ok(config_changed) => {
// Update the configuration (may have been changed by `set` and `reset`)
config = config_changed;
Ok(())
}
Err(err) => Err(err),
},
} {
eprintln!("{}", error)
}
}
Err(error) => {
if error.kind == structopt::clap::ErrorKind::VersionDisplayed {
print!("{}", error)
} else if error.kind == structopt::clap::ErrorKind::HelpDisplayed
|| error.kind == structopt::clap::ErrorKind::MissingArgumentOrSubcommand
{
// Remove the unnecessary command / version line at the start
let lines = error
.to_string()
.lines()
.skip(1)
.map(str::to_string)
.collect::<Vec<String>>()
.join("\n");
print!("{}", lines)
} else {
tracing::debug!("{:?}", error.kind);
eprintln!("{}", error)
}
}
}
}
Err(ReadlineError::Interrupted) => {
tracing::info!("Ctrl-C pressed, interrupting current command");
// TODO
}
Err(ReadlineError::Eof) => {
tracing::info!("Ctrl-D pressed, ending session");
break;
}
Err(error) => bail!(error),
}
}
rl.save_history(&history_file)?;

Ok(())
}
8 changes: 5 additions & 3 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
#[cfg(feature = "cli")]
pub mod cli;

#[cfg(feature = "interact")]
pub mod interact;

#[cfg(feature = "open")]
pub mod open;

#[cfg(feature = "convert")]
pub mod convert;

#[cfg(feature = "plugins")]
pub mod plugins;

Expand Down Expand Up @@ -48,6 +48,8 @@ pub mod encode;
pub mod export;
pub mod import;

pub mod convert;

pub mod validate;

pub mod execute;
Expand Down

0 comments on commit 8122ba0

Please sign in to comment.