Run cargo fmt on schala-repl code
This commit is contained in:
parent
77bf42be6c
commit
c9a4c83fce
@ -1,80 +1,76 @@
|
|||||||
use std::time;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::time;
|
||||||
|
|
||||||
pub trait ProgrammingLanguageInterface {
|
pub trait ProgrammingLanguageInterface {
|
||||||
fn get_language_name(&self) -> String;
|
fn get_language_name(&self) -> String;
|
||||||
fn get_source_file_suffix(&self) -> String;
|
fn get_source_file_suffix(&self) -> String;
|
||||||
|
|
||||||
fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse {
|
fn run_computation(&mut self, _request: ComputationRequest) -> ComputationResponse {
|
||||||
ComputationResponse {
|
ComputationResponse {
|
||||||
main_output: Err(format!("Computation pipeline not implemented")),
|
main_output: Err(format!("Computation pipeline not implemented")),
|
||||||
global_output_stats: GlobalOutputStats::default(),
|
global_output_stats: GlobalOutputStats::default(),
|
||||||
debug_responses: vec![],
|
debug_responses: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn request_meta(&mut self, _request: LangMetaRequest) -> LangMetaResponse {
|
fn request_meta(&mut self, _request: LangMetaRequest) -> LangMetaResponse {
|
||||||
LangMetaResponse::Custom { kind: format!("not-implemented"), value: format!("") }
|
LangMetaResponse::Custom {
|
||||||
}
|
kind: format!("not-implemented"),
|
||||||
|
value: format!(""),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ComputationRequest<'a> {
|
pub struct ComputationRequest<'a> {
|
||||||
pub source: &'a str,
|
pub source: &'a str,
|
||||||
pub debug_requests: HashSet<DebugAsk>,
|
pub debug_requests: HashSet<DebugAsk>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ComputationResponse {
|
pub struct ComputationResponse {
|
||||||
pub main_output: Result<String, String>,
|
pub main_output: Result<String, String>,
|
||||||
pub global_output_stats: GlobalOutputStats,
|
pub global_output_stats: GlobalOutputStats,
|
||||||
pub debug_responses: Vec<DebugResponse>,
|
pub debug_responses: Vec<DebugResponse>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct GlobalOutputStats {
|
pub struct GlobalOutputStats {
|
||||||
pub total_duration: time::Duration,
|
pub total_duration: time::Duration,
|
||||||
pub stage_durations: Vec<(String, time::Duration)>
|
pub stage_durations: Vec<(String, time::Duration)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
pub enum DebugAsk {
|
pub enum DebugAsk {
|
||||||
Timing,
|
Timing,
|
||||||
ByStage { stage_name: String, token: Option<String> },
|
ByStage {
|
||||||
|
stage_name: String,
|
||||||
|
token: Option<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugAsk {
|
impl DebugAsk {
|
||||||
pub fn is_for_stage(&self, name: &str) -> bool {
|
pub fn is_for_stage(&self, name: &str) -> bool {
|
||||||
match self {
|
match self {
|
||||||
DebugAsk::ByStage { stage_name, .. } if stage_name == name => true,
|
DebugAsk::ByStage { stage_name, .. } if stage_name == name => true,
|
||||||
_ => false
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DebugResponse {
|
pub struct DebugResponse {
|
||||||
pub ask: DebugAsk,
|
pub ask: DebugAsk,
|
||||||
pub value: String
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LangMetaRequest {
|
pub enum LangMetaRequest {
|
||||||
StageNames,
|
StageNames,
|
||||||
Docs {
|
Docs { source: String },
|
||||||
source: String,
|
Custom { kind: String, value: String },
|
||||||
},
|
ImmediateDebug(DebugAsk),
|
||||||
Custom {
|
|
||||||
kind: String,
|
|
||||||
value: String
|
|
||||||
},
|
|
||||||
ImmediateDebug(DebugAsk),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LangMetaResponse {
|
pub enum LangMetaResponse {
|
||||||
StageNames(Vec<String>),
|
StageNames(Vec<String>),
|
||||||
Docs {
|
Docs { doc_string: String },
|
||||||
doc_string: String,
|
Custom { kind: String, value: String },
|
||||||
},
|
ImmediateDebug(DebugResponse),
|
||||||
Custom {
|
|
||||||
kind: String,
|
|
||||||
value: String
|
|
||||||
},
|
|
||||||
ImmediateDebug(DebugResponse),
|
|
||||||
}
|
}
|
||||||
|
@ -1,91 +1,95 @@
|
|||||||
#![feature(box_patterns, box_syntax, proc_macro_hygiene, decl_macro)]
|
#![feature(box_patterns, box_syntax, proc_macro_hygiene, decl_macro)]
|
||||||
#![feature(plugin)]
|
#![feature(plugin)]
|
||||||
extern crate getopts;
|
|
||||||
extern crate linefeed;
|
|
||||||
extern crate itertools;
|
|
||||||
extern crate colored;
|
extern crate colored;
|
||||||
|
extern crate getopts;
|
||||||
|
extern crate itertools;
|
||||||
|
extern crate linefeed;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate serde_json;
|
|
||||||
extern crate includedir;
|
extern crate includedir;
|
||||||
extern crate phf;
|
extern crate phf;
|
||||||
|
extern crate serde_json;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::Path;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::path::Path;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
mod repl;
|
|
||||||
mod language;
|
mod language;
|
||||||
|
mod repl;
|
||||||
|
|
||||||
pub use language::{ProgrammingLanguageInterface,
|
pub use language::{
|
||||||
ComputationRequest, ComputationResponse,
|
ComputationRequest, ComputationResponse, DebugAsk, DebugResponse, GlobalOutputStats,
|
||||||
LangMetaRequest, LangMetaResponse,
|
LangMetaRequest, LangMetaResponse, ProgrammingLanguageInterface,
|
||||||
DebugResponse, DebugAsk, GlobalOutputStats};
|
};
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/static.rs"));
|
include!(concat!(env!("OUT_DIR"), "/static.rs"));
|
||||||
const VERSION_STRING: &'static str = "0.1.0";
|
const VERSION_STRING: &'static str = "0.1.0";
|
||||||
|
|
||||||
pub fn start_repl(langs: Vec<Box<dyn ProgrammingLanguageInterface>>) {
|
pub fn start_repl(langs: Vec<Box<dyn ProgrammingLanguageInterface>>) {
|
||||||
let options = command_line_options().parse(std::env::args()).unwrap_or_else(|e| {
|
let options = command_line_options()
|
||||||
println!("{:?}", e);
|
.parse(std::env::args())
|
||||||
exit(1);
|
.unwrap_or_else(|e| {
|
||||||
});
|
println!("{:?}", e);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
if options.opt_present("help") {
|
if options.opt_present("help") {
|
||||||
println!("{}", command_line_options().usage("Schala metainterpreter"));
|
println!("{}", command_line_options().usage("Schala metainterpreter"));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
match options.free[..] {
|
match options.free[..] {
|
||||||
[] | [_] => {
|
[] | [_] => {
|
||||||
let mut repl = repl::Repl::new(langs);
|
let mut repl = repl::Repl::new(langs);
|
||||||
repl.run_repl();
|
repl.run_repl();
|
||||||
}
|
}
|
||||||
[_, ref filename, ..] => {
|
[_, ref filename, ..] => {
|
||||||
run_noninteractive(filename, langs);
|
run_noninteractive(filename, langs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_noninteractive(filename: &str, languages: Vec<Box<dyn ProgrammingLanguageInterface>>) {
|
fn run_noninteractive(filename: &str, languages: Vec<Box<dyn ProgrammingLanguageInterface>>) {
|
||||||
let path = Path::new(filename);
|
let path = Path::new(filename);
|
||||||
let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_else(|| {
|
let ext = path
|
||||||
println!("Source file lacks extension");
|
.extension()
|
||||||
exit(1);
|
.and_then(|e| e.to_str())
|
||||||
});
|
.unwrap_or_else(|| {
|
||||||
let mut language = Box::new(languages.into_iter().find(|lang| lang.get_source_file_suffix() == ext)
|
println!("Source file lacks extension");
|
||||||
.unwrap_or_else(|| {
|
exit(1);
|
||||||
println!("Extension .{} not recognized", ext);
|
});
|
||||||
exit(1);
|
let mut language = Box::new(
|
||||||
}));
|
languages
|
||||||
|
.into_iter()
|
||||||
|
.find(|lang| lang.get_source_file_suffix() == ext)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
println!("Extension .{} not recognized", ext);
|
||||||
|
exit(1);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
let mut source_file = File::open(path).unwrap();
|
let mut source_file = File::open(path).unwrap();
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
source_file.read_to_string(&mut buffer).unwrap();
|
source_file.read_to_string(&mut buffer).unwrap();
|
||||||
|
|
||||||
let request = ComputationRequest {
|
let request = ComputationRequest {
|
||||||
source: &buffer,
|
source: &buffer,
|
||||||
debug_requests: HashSet::new(),
|
debug_requests: HashSet::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = language.run_computation(request);
|
let response = language.run_computation(request);
|
||||||
match response.main_output {
|
match response.main_output {
|
||||||
Ok(s) => println!("{}", s),
|
Ok(s) => println!("{}", s),
|
||||||
Err(s) => println!("{}", s)
|
Err(s) => println!("{}", s),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn command_line_options() -> getopts::Options {
|
fn command_line_options() -> getopts::Options {
|
||||||
let mut options = getopts::Options::new();
|
let mut options = getopts::Options::new();
|
||||||
options.optflag("h",
|
options.optflag("h", "help", "Show help text");
|
||||||
"help",
|
options.optflag("w", "webapp", "Start up web interpreter");
|
||||||
"Show help text");
|
options
|
||||||
options.optflag("w",
|
|
||||||
"webapp",
|
|
||||||
"Start up web interpreter");
|
|
||||||
options
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{Repl, InterpreterDirectiveOutput};
|
use super::{InterpreterDirectiveOutput, Repl};
|
||||||
use crate::repl::directive_actions::DirectiveAction;
|
use crate::repl::directive_actions::DirectiveAction;
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
@ -7,93 +7,116 @@ use colored::*;
|
|||||||
/// and then execute it with any remaining arguments
|
/// and then execute it with any remaining arguments
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum CommandTree {
|
pub enum CommandTree {
|
||||||
Terminal {
|
Terminal {
|
||||||
name: String,
|
name: String,
|
||||||
children: Vec<CommandTree>,
|
children: Vec<CommandTree>,
|
||||||
help_msg: Option<String>,
|
help_msg: Option<String>,
|
||||||
action: DirectiveAction,
|
action: DirectiveAction,
|
||||||
},
|
},
|
||||||
NonTerminal {
|
NonTerminal {
|
||||||
name: String,
|
name: String,
|
||||||
children: Vec<CommandTree>,
|
children: Vec<CommandTree>,
|
||||||
help_msg: Option<String>,
|
help_msg: Option<String>,
|
||||||
action: DirectiveAction,
|
action: DirectiveAction,
|
||||||
},
|
},
|
||||||
Top(Vec<CommandTree>),
|
Top(Vec<CommandTree>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandTree {
|
impl CommandTree {
|
||||||
pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> CommandTree {
|
pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> CommandTree {
|
||||||
CommandTree::NonTerminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children: vec![], action: DirectiveAction::Null }
|
CommandTree::NonTerminal {
|
||||||
}
|
name: s.to_string(),
|
||||||
|
help_msg: help.map(|x| x.to_string()),
|
||||||
pub fn terminal(s: &str, help: Option<&str>, children: Vec<CommandTree>, action: DirectiveAction) -> CommandTree {
|
children: vec![],
|
||||||
CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children, action}
|
action: DirectiveAction::Null,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nonterm(s: &str, help: Option<&str>, children: Vec<CommandTree>) -> CommandTree {
|
|
||||||
CommandTree::NonTerminal {
|
|
||||||
name: s.to_string(),
|
|
||||||
help_msg: help.map(|x| x.to_string()),
|
|
||||||
children,
|
|
||||||
action: DirectiveAction::Null
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_cmd(&self) -> &str {
|
pub fn terminal(
|
||||||
match self {
|
s: &str,
|
||||||
CommandTree::Terminal { name, .. } => name.as_str(),
|
help: Option<&str>,
|
||||||
CommandTree::NonTerminal {name, ..} => name.as_str(),
|
children: Vec<CommandTree>,
|
||||||
CommandTree::Top(_) => "",
|
action: DirectiveAction,
|
||||||
|
) -> CommandTree {
|
||||||
|
CommandTree::Terminal {
|
||||||
|
name: s.to_string(),
|
||||||
|
help_msg: help.map(|x| x.to_string()),
|
||||||
|
children,
|
||||||
|
action,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pub fn get_help(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
CommandTree::Terminal { help_msg, ..} => help_msg.as_ref().map(|s| s.as_str()).unwrap_or("<no help text provided>"),
|
|
||||||
CommandTree::NonTerminal { help_msg, .. } => help_msg.as_ref().map(|s| s.as_str()).unwrap_or("<no help text provided>"),
|
|
||||||
CommandTree::Top(_) => ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn get_children(&self) -> &Vec<CommandTree> {
|
|
||||||
use CommandTree::*;
|
|
||||||
match self {
|
|
||||||
Terminal { children, .. } |
|
|
||||||
NonTerminal { children, .. } |
|
|
||||||
Top(children) => children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn get_subcommands(&self) -> Vec<&str> {
|
|
||||||
self.get_children().iter().map(|x| x.get_cmd()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn perform(&self, repl: &mut Repl, arguments: &Vec<&str>) -> InterpreterDirectiveOutput {
|
pub fn nonterm(s: &str, help: Option<&str>, children: Vec<CommandTree>) -> CommandTree {
|
||||||
let mut dir_pointer: &CommandTree = self;
|
CommandTree::NonTerminal {
|
||||||
let mut idx = 0;
|
name: s.to_string(),
|
||||||
|
help_msg: help.map(|x| x.to_string()),
|
||||||
let res: Result<(DirectiveAction, usize), String> = loop {
|
children,
|
||||||
match dir_pointer {
|
action: DirectiveAction::Null,
|
||||||
CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => {
|
}
|
||||||
let next_command = match arguments.get(idx) {
|
}
|
||||||
Some(cmd) => cmd,
|
|
||||||
None => break Err(format!("Command requires arguments"))
|
pub fn get_cmd(&self) -> &str {
|
||||||
};
|
match self {
|
||||||
idx += 1;
|
CommandTree::Terminal { name, .. } => name.as_str(),
|
||||||
match subcommands.iter().find(|sc| sc.get_cmd() == *next_command) {
|
CommandTree::NonTerminal { name, .. } => name.as_str(),
|
||||||
Some(command_tree) => {
|
CommandTree::Top(_) => "",
|
||||||
dir_pointer = command_tree;
|
}
|
||||||
},
|
}
|
||||||
None => break Err(format!("Command {} not found", next_command))
|
pub fn get_help(&self) -> &str {
|
||||||
};
|
match self {
|
||||||
},
|
CommandTree::Terminal { help_msg, .. } => help_msg
|
||||||
CommandTree::Terminal { action, .. } => {
|
.as_ref()
|
||||||
break Ok((action.clone(), idx));
|
.map(|s| s.as_str())
|
||||||
},
|
.unwrap_or("<no help text provided>"),
|
||||||
}
|
CommandTree::NonTerminal { help_msg, .. } => help_msg
|
||||||
};
|
.as_ref()
|
||||||
|
.map(|s| s.as_str())
|
||||||
match res {
|
.unwrap_or("<no help text provided>"),
|
||||||
Ok((action, idx)) => action.perform(repl, &arguments[idx..]),
|
CommandTree::Top(_) => "",
|
||||||
Err(err) => Some(err.red().to_string())
|
}
|
||||||
|
}
|
||||||
|
pub fn get_children(&self) -> &Vec<CommandTree> {
|
||||||
|
use CommandTree::*;
|
||||||
|
match self {
|
||||||
|
Terminal { children, .. } | NonTerminal { children, .. } | Top(children) => children,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_subcommands(&self) -> Vec<&str> {
|
||||||
|
self.get_children().iter().map(|x| x.get_cmd()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn perform(&self, repl: &mut Repl, arguments: &Vec<&str>) -> InterpreterDirectiveOutput {
|
||||||
|
let mut dir_pointer: &CommandTree = self;
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
let res: Result<(DirectiveAction, usize), String> = loop {
|
||||||
|
match dir_pointer {
|
||||||
|
CommandTree::Top(subcommands)
|
||||||
|
| CommandTree::NonTerminal {
|
||||||
|
children: subcommands,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let next_command = match arguments.get(idx) {
|
||||||
|
Some(cmd) => cmd,
|
||||||
|
None => break Err(format!("Command requires arguments")),
|
||||||
|
};
|
||||||
|
idx += 1;
|
||||||
|
match subcommands.iter().find(|sc| sc.get_cmd() == *next_command) {
|
||||||
|
Some(command_tree) => {
|
||||||
|
dir_pointer = command_tree;
|
||||||
|
}
|
||||||
|
None => break Err(format!("Command {} not found", next_command)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
CommandTree::Terminal { action, .. } => {
|
||||||
|
break Ok((action.clone(), idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok((action, idx)) => action.perform(repl, &arguments[idx..]),
|
||||||
|
Err(err) => Some(err.red().to_string()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,132 +1,145 @@
|
|||||||
use super::{Repl, InterpreterDirectiveOutput};
|
use super::{InterpreterDirectiveOutput, Repl};
|
||||||
|
use crate::language::{DebugAsk, DebugResponse, LangMetaRequest, LangMetaResponse};
|
||||||
use crate::repl::help::help;
|
use crate::repl::help::help;
|
||||||
use crate::language::{LangMetaRequest, LangMetaResponse, DebugAsk, DebugResponse};
|
|
||||||
use std::fmt::Write as FmtWrite;
|
use std::fmt::Write as FmtWrite;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum DirectiveAction {
|
pub enum DirectiveAction {
|
||||||
Null,
|
Null,
|
||||||
Help,
|
Help,
|
||||||
QuitProgram,
|
QuitProgram,
|
||||||
ListPasses,
|
ListPasses,
|
||||||
ShowImmediate,
|
ShowImmediate,
|
||||||
Show,
|
Show,
|
||||||
Hide,
|
Hide,
|
||||||
TotalTimeOff,
|
TotalTimeOff,
|
||||||
TotalTimeOn,
|
TotalTimeOn,
|
||||||
StageTimeOff,
|
StageTimeOff,
|
||||||
StageTimeOn,
|
StageTimeOn,
|
||||||
Doc,
|
Doc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectiveAction {
|
impl DirectiveAction {
|
||||||
pub fn perform(&self, repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
pub fn perform(&self, repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
use DirectiveAction::*;
|
use DirectiveAction::*;
|
||||||
match self {
|
match self {
|
||||||
Null => None,
|
Null => None,
|
||||||
Help => help(repl, arguments),
|
Help => help(repl, arguments),
|
||||||
QuitProgram => {
|
QuitProgram => {
|
||||||
repl.save_before_exit();
|
repl.save_before_exit();
|
||||||
::std::process::exit(0)
|
::std::process::exit(0)
|
||||||
},
|
}
|
||||||
ListPasses => {
|
ListPasses => {
|
||||||
let language_state = repl.get_cur_language_state();
|
let language_state = repl.get_cur_language_state();
|
||||||
let pass_names = match language_state.request_meta(LangMetaRequest::StageNames) {
|
let pass_names = match language_state.request_meta(LangMetaRequest::StageNames) {
|
||||||
LangMetaResponse::StageNames(names) => names,
|
LangMetaResponse::StageNames(names) => names,
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
for pass in pass_names.iter().map(|name| Some(name)).intersperse(None) {
|
for pass in pass_names.iter().map(|name| Some(name)).intersperse(None) {
|
||||||
match pass {
|
match pass {
|
||||||
Some(pass) => write!(buf, "{}", pass).unwrap(),
|
Some(pass) => write!(buf, "{}", pass).unwrap(),
|
||||||
None => write!(buf, " -> ").unwrap(),
|
None => write!(buf, " -> ").unwrap(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Some(buf)
|
||||||
|
}
|
||||||
|
ShowImmediate => {
|
||||||
|
let cur_state = repl.get_cur_language_state();
|
||||||
|
let stage_name = match arguments.get(0) {
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
None => return Some(format!("Must specify a thing to debug")),
|
||||||
|
};
|
||||||
|
let meta = LangMetaRequest::ImmediateDebug(DebugAsk::ByStage {
|
||||||
|
stage_name: stage_name.clone(),
|
||||||
|
token: None,
|
||||||
|
});
|
||||||
|
let meta_response = cur_state.request_meta(meta);
|
||||||
|
|
||||||
|
let response = match meta_response {
|
||||||
|
LangMetaResponse::ImmediateDebug(DebugResponse { ask, value }) => match ask {
|
||||||
|
DebugAsk::ByStage {
|
||||||
|
stage_name: ref this_stage_name,
|
||||||
|
..
|
||||||
|
} if *this_stage_name == stage_name => value,
|
||||||
|
_ => return Some(format!("Wrong debug stage")),
|
||||||
|
},
|
||||||
|
_ => return Some(format!("Invalid language meta response")),
|
||||||
|
};
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
Show => {
|
||||||
|
let this_stage_name = match arguments.get(0) {
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
None => return Some(format!("Must specify a stage to show")),
|
||||||
|
};
|
||||||
|
let token = arguments.get(1).map(|s| s.to_string());
|
||||||
|
repl.options.debug_asks.retain(|ask| match ask {
|
||||||
|
DebugAsk::ByStage { stage_name, .. } if *stage_name == this_stage_name => false,
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let ask = DebugAsk::ByStage {
|
||||||
|
stage_name: this_stage_name,
|
||||||
|
token,
|
||||||
|
};
|
||||||
|
repl.options.debug_asks.insert(ask);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Hide => {
|
||||||
|
let stage_name_to_remove = match arguments.get(0) {
|
||||||
|
Some(s) => s.to_string(),
|
||||||
|
None => return Some(format!("Must specify a stage to hide")),
|
||||||
|
};
|
||||||
|
repl.options.debug_asks.retain(|ask| match ask {
|
||||||
|
DebugAsk::ByStage { stage_name, .. } if *stage_name == stage_name_to_remove => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
None
|
||||||
|
}
|
||||||
|
TotalTimeOff => total_time_off(repl, arguments),
|
||||||
|
TotalTimeOn => total_time_on(repl, arguments),
|
||||||
|
StageTimeOff => stage_time_off(repl, arguments),
|
||||||
|
StageTimeOn => stage_time_on(repl, arguments),
|
||||||
|
Doc => doc(repl, arguments),
|
||||||
}
|
}
|
||||||
Some(buf)
|
|
||||||
},
|
|
||||||
ShowImmediate => {
|
|
||||||
let cur_state = repl.get_cur_language_state();
|
|
||||||
let stage_name = match arguments.get(0) {
|
|
||||||
Some(s) => s.to_string(),
|
|
||||||
None => return Some(format!("Must specify a thing to debug")),
|
|
||||||
};
|
|
||||||
let meta = LangMetaRequest::ImmediateDebug(DebugAsk::ByStage { stage_name: stage_name.clone(), token: None });
|
|
||||||
let meta_response = cur_state.request_meta(meta);
|
|
||||||
|
|
||||||
let response = match meta_response {
|
|
||||||
LangMetaResponse::ImmediateDebug(DebugResponse { ask, value }) => match ask {
|
|
||||||
DebugAsk::ByStage { stage_name: ref this_stage_name, ..} if *this_stage_name == stage_name => value,
|
|
||||||
_ => return Some(format!("Wrong debug stage"))
|
|
||||||
},
|
|
||||||
_ => return Some(format!("Invalid language meta response")),
|
|
||||||
};
|
|
||||||
Some(response)
|
|
||||||
},
|
|
||||||
Show => {
|
|
||||||
let this_stage_name = match arguments.get(0) {
|
|
||||||
Some(s) => s.to_string(),
|
|
||||||
None => return Some(format!("Must specify a stage to show")),
|
|
||||||
};
|
|
||||||
let token = arguments.get(1).map(|s| s.to_string());
|
|
||||||
repl.options.debug_asks.retain(|ask| match ask {
|
|
||||||
DebugAsk::ByStage { stage_name, .. } if *stage_name == this_stage_name => false,
|
|
||||||
_ => true
|
|
||||||
});
|
|
||||||
|
|
||||||
let ask = DebugAsk::ByStage { stage_name: this_stage_name, token };
|
|
||||||
repl.options.debug_asks.insert(ask);
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Hide => {
|
|
||||||
let stage_name_to_remove = match arguments.get(0) {
|
|
||||||
Some(s) => s.to_string(),
|
|
||||||
None => return Some(format!("Must specify a stage to hide")),
|
|
||||||
};
|
|
||||||
repl.options.debug_asks.retain(|ask| match ask {
|
|
||||||
DebugAsk::ByStage { stage_name, .. } if *stage_name == stage_name_to_remove => false,
|
|
||||||
_ => true
|
|
||||||
});
|
|
||||||
None
|
|
||||||
},
|
|
||||||
TotalTimeOff => total_time_off(repl, arguments),
|
|
||||||
TotalTimeOn => total_time_on(repl, arguments),
|
|
||||||
StageTimeOff => stage_time_off(repl, arguments),
|
|
||||||
StageTimeOn => stage_time_on(repl, arguments),
|
|
||||||
Doc => doc(repl, arguments),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_time_on(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
fn total_time_on(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
repl.options.show_total_time = true;
|
repl.options.show_total_time = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_time_off(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
fn total_time_off(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
repl.options.show_total_time = false;
|
repl.options.show_total_time = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_time_on(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
fn stage_time_on(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
repl.options.show_stage_times = true;
|
repl.options.show_stage_times = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stage_time_off(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
fn stage_time_off(repl: &mut Repl, _: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
repl.options.show_stage_times = false;
|
repl.options.show_stage_times = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn doc(repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
fn doc(repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
arguments.get(0).map(|cmd| {
|
arguments
|
||||||
let source = cmd.to_string();
|
.get(0)
|
||||||
let meta = LangMetaRequest::Docs { source };
|
.map(|cmd| {
|
||||||
let cur_state = repl.get_cur_language_state();
|
let source = cmd.to_string();
|
||||||
match cur_state.request_meta(meta) {
|
let meta = LangMetaRequest::Docs { source };
|
||||||
LangMetaResponse::Docs { doc_string } => Some(doc_string),
|
let cur_state = repl.get_cur_language_state();
|
||||||
_ => Some(format!("Invalid doc response"))
|
match cur_state.request_meta(meta) {
|
||||||
}
|
LangMetaResponse::Docs { doc_string } => Some(doc_string),
|
||||||
}).unwrap_or(Some(format!(":docs needs an argument")))
|
_ => Some(format!("Invalid doc response")),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(Some(format!(":docs needs an argument")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,54 +2,103 @@ use crate::repl::command_tree::CommandTree;
|
|||||||
use crate::repl::directive_actions::DirectiveAction;
|
use crate::repl::directive_actions::DirectiveAction;
|
||||||
|
|
||||||
pub fn directives_from_pass_names(pass_names: &Vec<String>) -> CommandTree {
|
pub fn directives_from_pass_names(pass_names: &Vec<String>) -> CommandTree {
|
||||||
let passes_directives: Vec<CommandTree> = pass_names.iter()
|
let passes_directives: Vec<CommandTree> = pass_names
|
||||||
.map(|pass_name| {
|
.iter()
|
||||||
if pass_name == "parsing" {
|
.map(|pass_name| {
|
||||||
CommandTree::nonterm(pass_name, None, vec![
|
if pass_name == "parsing" {
|
||||||
CommandTree::nonterm_no_further_tab_completions("compact", None),
|
CommandTree::nonterm(
|
||||||
CommandTree::nonterm_no_further_tab_completions("expanded", None),
|
pass_name,
|
||||||
CommandTree::nonterm_no_further_tab_completions("trace", None),
|
None,
|
||||||
])
|
vec![
|
||||||
} else {
|
CommandTree::nonterm_no_further_tab_completions("compact", None),
|
||||||
CommandTree::nonterm_no_further_tab_completions(pass_name, None)
|
CommandTree::nonterm_no_further_tab_completions("expanded", None),
|
||||||
}
|
CommandTree::nonterm_no_further_tab_completions("trace", None),
|
||||||
})
|
],
|
||||||
.collect();
|
)
|
||||||
CommandTree::Top(get_list(&passes_directives, true))
|
} else {
|
||||||
|
CommandTree::nonterm_no_further_tab_completions(pass_name, None)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
CommandTree::Top(get_list(&passes_directives, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_list(passes_directives: &Vec<CommandTree>, include_help: bool) -> Vec<CommandTree> {
|
fn get_list(passes_directives: &Vec<CommandTree>, include_help: bool) -> Vec<CommandTree> {
|
||||||
use DirectiveAction::*;
|
use DirectiveAction::*;
|
||||||
|
|
||||||
vec![
|
vec![
|
||||||
CommandTree::terminal("exit", Some("exit the REPL"), vec![], QuitProgram),
|
CommandTree::terminal("exit", Some("exit the REPL"), vec![], QuitProgram),
|
||||||
CommandTree::terminal("quit", Some("exit the REPL"), vec![], QuitProgram),
|
CommandTree::terminal("quit", Some("exit the REPL"), vec![], QuitProgram),
|
||||||
CommandTree::terminal("help", Some("Print this help message"), if include_help { get_list(passes_directives, false) } else { vec![] }, Help),
|
CommandTree::terminal(
|
||||||
CommandTree::nonterm("debug",
|
"help",
|
||||||
Some("Configure debug information"),
|
Some("Print this help message"),
|
||||||
vec![
|
if include_help {
|
||||||
CommandTree::terminal("list-passes", Some("List all registered compiler passes"), vec![], ListPasses),
|
get_list(passes_directives, false)
|
||||||
CommandTree::terminal("show-immediate", None, passes_directives.clone(), ShowImmediate),
|
} else {
|
||||||
CommandTree::terminal("show", Some("Show debug output for a specific pass"), passes_directives.clone(), Show),
|
vec![]
|
||||||
CommandTree::terminal("hide", Some("Hide debug output for a specific pass"), passes_directives.clone(), Hide),
|
},
|
||||||
CommandTree::nonterm("total-time", None, vec![
|
Help,
|
||||||
CommandTree::terminal("on", None, vec![], TotalTimeOn),
|
),
|
||||||
CommandTree::terminal("off", None, vec![], TotalTimeOff),
|
CommandTree::nonterm(
|
||||||
]),
|
"debug",
|
||||||
CommandTree::nonterm("stage-times", Some("Computation time per-stage"), vec![
|
Some("Configure debug information"),
|
||||||
CommandTree::terminal("on", None, vec![], StageTimeOn),
|
vec![
|
||||||
CommandTree::terminal("off", None, vec![], StageTimeOff),
|
CommandTree::terminal(
|
||||||
])
|
"list-passes",
|
||||||
]
|
Some("List all registered compiler passes"),
|
||||||
),
|
vec![],
|
||||||
CommandTree::nonterm("lang",
|
ListPasses,
|
||||||
Some("switch between languages, or go directly to a langauge by name"),
|
),
|
||||||
vec![
|
CommandTree::terminal(
|
||||||
CommandTree::nonterm_no_further_tab_completions("next", None),
|
"show-immediate",
|
||||||
CommandTree::nonterm_no_further_tab_completions("prev", None),
|
None,
|
||||||
CommandTree::nonterm("go", None, vec![]),
|
passes_directives.clone(),
|
||||||
]
|
ShowImmediate,
|
||||||
),
|
),
|
||||||
CommandTree::terminal("doc", Some("Get language-specific help for an item"), vec![], Doc),
|
CommandTree::terminal(
|
||||||
]
|
"show",
|
||||||
|
Some("Show debug output for a specific pass"),
|
||||||
|
passes_directives.clone(),
|
||||||
|
Show,
|
||||||
|
),
|
||||||
|
CommandTree::terminal(
|
||||||
|
"hide",
|
||||||
|
Some("Hide debug output for a specific pass"),
|
||||||
|
passes_directives.clone(),
|
||||||
|
Hide,
|
||||||
|
),
|
||||||
|
CommandTree::nonterm(
|
||||||
|
"total-time",
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
|
CommandTree::terminal("on", None, vec![], TotalTimeOn),
|
||||||
|
CommandTree::terminal("off", None, vec![], TotalTimeOff),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
CommandTree::nonterm(
|
||||||
|
"stage-times",
|
||||||
|
Some("Computation time per-stage"),
|
||||||
|
vec![
|
||||||
|
CommandTree::terminal("on", None, vec![], StageTimeOn),
|
||||||
|
CommandTree::terminal("off", None, vec![], StageTimeOff),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
CommandTree::nonterm(
|
||||||
|
"lang",
|
||||||
|
Some("switch between languages, or go directly to a langauge by name"),
|
||||||
|
vec![
|
||||||
|
CommandTree::nonterm_no_further_tab_completions("next", None),
|
||||||
|
CommandTree::nonterm_no_further_tab_completions("prev", None),
|
||||||
|
CommandTree::nonterm("go", None, vec![]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
CommandTree::terminal(
|
||||||
|
"doc",
|
||||||
|
Some("Get language-specific help for an item"),
|
||||||
|
vec![],
|
||||||
|
Doc,
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,59 +1,83 @@
|
|||||||
use std::fmt::Write as FmtWrite;
|
use std::fmt::Write as FmtWrite;
|
||||||
|
|
||||||
use colored::*;
|
|
||||||
use super::command_tree::CommandTree;
|
use super::command_tree::CommandTree;
|
||||||
use super::{Repl, InterpreterDirectiveOutput};
|
use super::{InterpreterDirectiveOutput, Repl};
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
pub fn help(repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
pub fn help(repl: &mut Repl, arguments: &[&str]) -> InterpreterDirectiveOutput {
|
||||||
match arguments {
|
match arguments {
|
||||||
[] => return global_help(repl),
|
[] => return global_help(repl),
|
||||||
commands => {
|
commands => {
|
||||||
let dirs = repl.get_directives();
|
let dirs = repl.get_directives();
|
||||||
Some(match get_directive_from_commands(commands, &dirs) {
|
Some(match get_directive_from_commands(commands, &dirs) {
|
||||||
None => format!("Directive `{}` not found", commands.last().unwrap()),
|
None => format!("Directive `{}` not found", commands.last().unwrap()),
|
||||||
Some(dir) => {
|
Some(dir) => {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let cmd = dir.get_cmd();
|
let cmd = dir.get_cmd();
|
||||||
let children = dir.get_children();
|
let children = dir.get_children();
|
||||||
writeln!(buf, "`{}` - {}", cmd, dir.get_help()).unwrap();
|
writeln!(buf, "`{}` - {}", cmd, dir.get_help()).unwrap();
|
||||||
for sub in children.iter() {
|
for sub in children.iter() {
|
||||||
writeln!(buf, "\t`{} {}` - {}", cmd, sub.get_cmd(), sub.get_help()).unwrap();
|
writeln!(buf, "\t`{} {}` - {}", cmd, sub.get_cmd(), sub.get_help())
|
||||||
}
|
.unwrap();
|
||||||
buf
|
}
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_directive_from_commands<'a>(commands: &[&str], dirs: &'a CommandTree) -> Option<&'a CommandTree> {
|
fn get_directive_from_commands<'a>(
|
||||||
let mut directive_list = dirs.get_children();
|
commands: &[&str],
|
||||||
let mut matched_directive = None;
|
dirs: &'a CommandTree,
|
||||||
for cmd in commands {
|
) -> Option<&'a CommandTree> {
|
||||||
let found = directive_list.iter().find(|directive| directive.get_cmd() == *cmd);
|
let mut directive_list = dirs.get_children();
|
||||||
if let Some(dir) = found {
|
let mut matched_directive = None;
|
||||||
directive_list = dir.get_children();
|
for cmd in commands {
|
||||||
}
|
let found = directive_list
|
||||||
|
.iter()
|
||||||
|
.find(|directive| directive.get_cmd() == *cmd);
|
||||||
|
if let Some(dir) = found {
|
||||||
|
directive_list = dir.get_children();
|
||||||
|
}
|
||||||
|
|
||||||
matched_directive = found;
|
matched_directive = found;
|
||||||
}
|
}
|
||||||
matched_directive
|
matched_directive
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_help(repl: &mut Repl) -> InterpreterDirectiveOutput {
|
fn global_help(repl: &mut Repl) -> InterpreterDirectiveOutput {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let sigil = repl.interpreter_directive_sigil;
|
let sigil = repl.interpreter_directive_sigil;
|
||||||
|
|
||||||
writeln!(buf, "{} version {}", "Schala REPL".bright_red().bold(), crate::VERSION_STRING).unwrap();
|
writeln!(
|
||||||
writeln!(buf, "-----------------------").unwrap();
|
buf,
|
||||||
|
"{} version {}",
|
||||||
|
"Schala REPL".bright_red().bold(),
|
||||||
|
crate::VERSION_STRING
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writeln!(buf, "-----------------------").unwrap();
|
||||||
|
|
||||||
for directive in repl.get_directives().get_children() {
|
for directive in repl.get_directives().get_children() {
|
||||||
writeln!(buf, "{}{} - {}", sigil, directive.get_cmd(), directive.get_help()).unwrap();
|
writeln!(
|
||||||
}
|
buf,
|
||||||
|
"{}{} - {}",
|
||||||
|
sigil,
|
||||||
|
directive.get_cmd(),
|
||||||
|
directive.get_help()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let ref lang = repl.get_cur_language_state();
|
let ref lang = repl.get_cur_language_state();
|
||||||
writeln!(buf, "").unwrap();
|
writeln!(buf, "").unwrap();
|
||||||
writeln!(buf, "Language-specific help for {}", lang.get_language_name()).unwrap();
|
writeln!(
|
||||||
writeln!(buf, "-----------------------").unwrap();
|
buf,
|
||||||
Some(buf)
|
"Language-specific help for {}",
|
||||||
|
lang.get_language_name()
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
writeln!(buf, "-----------------------").unwrap();
|
||||||
|
Some(buf)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::language::{ProgrammingLanguageInterface,
|
use crate::language::{
|
||||||
ComputationRequest, LangMetaResponse, LangMetaRequest};
|
ComputationRequest, LangMetaRequest, LangMetaResponse, ProgrammingLanguageInterface,
|
||||||
|
};
|
||||||
|
|
||||||
mod command_tree;
|
mod command_tree;
|
||||||
use self::command_tree::CommandTree;
|
use self::command_tree::CommandTree;
|
||||||
@ -21,231 +22,253 @@ const OPTIONS_SAVE_FILE: &'static str = ".schala_repl";
|
|||||||
type InterpreterDirectiveOutput = Option<String>;
|
type InterpreterDirectiveOutput = Option<String>;
|
||||||
|
|
||||||
pub struct Repl {
|
pub struct Repl {
|
||||||
pub interpreter_directive_sigil: char,
|
pub interpreter_directive_sigil: char,
|
||||||
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
|
line_reader: ::linefeed::interface::Interface<::linefeed::terminal::DefaultTerminal>,
|
||||||
language_states: Vec<Box<dyn ProgrammingLanguageInterface>>,
|
language_states: Vec<Box<dyn ProgrammingLanguageInterface>>,
|
||||||
options: ReplOptions,
|
options: ReplOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum PromptStyle {
|
enum PromptStyle {
|
||||||
Normal,
|
Normal,
|
||||||
Multiline
|
Multiline,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Repl {
|
impl Repl {
|
||||||
pub fn new(initial_states: Vec<Box<dyn ProgrammingLanguageInterface>>) -> Repl {
|
pub fn new(initial_states: Vec<Box<dyn ProgrammingLanguageInterface>>) -> Repl {
|
||||||
use linefeed::Interface;
|
use linefeed::Interface;
|
||||||
let line_reader = Interface::new("schala-repl").unwrap();
|
let line_reader = Interface::new("schala-repl").unwrap();
|
||||||
let interpreter_directive_sigil = ':';
|
let interpreter_directive_sigil = ':';
|
||||||
|
|
||||||
Repl {
|
Repl {
|
||||||
interpreter_directive_sigil,
|
interpreter_directive_sigil,
|
||||||
line_reader,
|
line_reader,
|
||||||
language_states: initial_states,
|
language_states: initial_states,
|
||||||
options: ReplOptions::new(),
|
options: ReplOptions::new(),
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_repl(&mut self) {
|
|
||||||
println!("Schala MetaInterpreter version {}", crate::VERSION_STRING);
|
|
||||||
println!("Type {}help for help with the REPL", self.interpreter_directive_sigil);
|
|
||||||
self.load_options();
|
|
||||||
self.handle_repl_loop();
|
|
||||||
self.save_before_exit();
|
|
||||||
println!("Exiting...");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_options(&mut self) {
|
|
||||||
self.line_reader.load_history(HISTORY_SAVE_FILE).unwrap_or(());
|
|
||||||
match ReplOptions::load_from_file(OPTIONS_SAVE_FILE) {
|
|
||||||
Ok(options) => {
|
|
||||||
self.options = options;
|
|
||||||
},
|
|
||||||
Err(()) => ()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_repl_loop(&mut self) {
|
|
||||||
use linefeed::ReadResult::*;
|
|
||||||
let sigil = self.interpreter_directive_sigil;
|
|
||||||
|
|
||||||
'main: loop {
|
|
||||||
macro_rules! match_or_break {
|
|
||||||
($line:expr) => {
|
|
||||||
match $line {
|
|
||||||
Err(e) => {
|
|
||||||
println!("readline IO Error: {}", e);
|
|
||||||
break 'main;
|
|
||||||
},
|
|
||||||
Ok(Eof) | Ok(Signal(_)) => break 'main,
|
|
||||||
Ok(Input(ref input)) => input,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_line_reader();
|
|
||||||
let line = self.line_reader.read_line();
|
|
||||||
let input: &str = match_or_break!(line);
|
|
||||||
|
|
||||||
self.line_reader.add_history_unique(input.to_string());
|
pub fn run_repl(&mut self) {
|
||||||
let mut chars = input.chars().peekable();
|
println!("Schala MetaInterpreter version {}", crate::VERSION_STRING);
|
||||||
let repl_responses = match chars.nth(0) {
|
println!(
|
||||||
Some(ch) if ch == sigil => {
|
"Type {}help for help with the REPL",
|
||||||
if chars.peek() == Some(&'{') {
|
self.interpreter_directive_sigil
|
||||||
let mut buf = String::new();
|
);
|
||||||
buf.push_str(input.get(2..).unwrap());
|
self.load_options();
|
||||||
'multiline: loop {
|
self.handle_repl_loop();
|
||||||
self.set_prompt(PromptStyle::Multiline);
|
self.save_before_exit();
|
||||||
let new_line = self.line_reader.read_line();
|
println!("Exiting...");
|
||||||
let new_input = match_or_break!(new_line);
|
}
|
||||||
if new_input.starts_with(":}") {
|
|
||||||
break 'multiline;
|
fn load_options(&mut self) {
|
||||||
} else {
|
self.line_reader
|
||||||
buf.push_str(new_input);
|
.load_history(HISTORY_SAVE_FILE)
|
||||||
buf.push_str("\n");
|
.unwrap_or(());
|
||||||
}
|
match ReplOptions::load_from_file(OPTIONS_SAVE_FILE) {
|
||||||
|
Ok(options) => {
|
||||||
|
self.options = options;
|
||||||
}
|
}
|
||||||
self.handle_input(&buf)
|
Err(()) => (),
|
||||||
} else {
|
};
|
||||||
match self.handle_interpreter_directive(input) {
|
}
|
||||||
Some(directive_output) => println!("<> {}", directive_output),
|
|
||||||
None => (),
|
fn handle_repl_loop(&mut self) {
|
||||||
|
use linefeed::ReadResult::*;
|
||||||
|
let sigil = self.interpreter_directive_sigil;
|
||||||
|
|
||||||
|
'main: loop {
|
||||||
|
macro_rules! match_or_break {
|
||||||
|
($line:expr) => {
|
||||||
|
match $line {
|
||||||
|
Err(e) => {
|
||||||
|
println!("readline IO Error: {}", e);
|
||||||
|
break 'main;
|
||||||
|
}
|
||||||
|
Ok(Eof) | Ok(Signal(_)) => break 'main,
|
||||||
|
Ok(Input(ref input)) => input,
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
continue
|
self.update_line_reader();
|
||||||
}
|
let line = self.line_reader.read_line();
|
||||||
},
|
let input: &str = match_or_break!(line);
|
||||||
_ => self.handle_input(input)
|
|
||||||
};
|
|
||||||
|
|
||||||
for repl_response in repl_responses.iter() {
|
self.line_reader.add_history_unique(input.to_string());
|
||||||
println!("{}", repl_response);
|
let mut chars = input.chars().peekable();
|
||||||
}
|
let repl_responses = match chars.nth(0) {
|
||||||
}
|
Some(ch) if ch == sigil => {
|
||||||
}
|
if chars.peek() == Some(&'{') {
|
||||||
|
let mut buf = String::new();
|
||||||
|
buf.push_str(input.get(2..).unwrap());
|
||||||
|
'multiline: loop {
|
||||||
|
self.set_prompt(PromptStyle::Multiline);
|
||||||
|
let new_line = self.line_reader.read_line();
|
||||||
|
let new_input = match_or_break!(new_line);
|
||||||
|
if new_input.starts_with(":}") {
|
||||||
|
break 'multiline;
|
||||||
|
} else {
|
||||||
|
buf.push_str(new_input);
|
||||||
|
buf.push_str("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.handle_input(&buf)
|
||||||
|
} else {
|
||||||
|
match self.handle_interpreter_directive(input) {
|
||||||
|
Some(directive_output) => println!("<> {}", directive_output),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.handle_input(input),
|
||||||
|
};
|
||||||
|
|
||||||
fn update_line_reader(&mut self) {
|
for repl_response in repl_responses.iter() {
|
||||||
let tab_complete_handler = TabCompleteHandler::new(self.interpreter_directive_sigil, self.get_directives());
|
println!("{}", repl_response);
|
||||||
self.line_reader.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
}
|
||||||
self.set_prompt(PromptStyle::Normal);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn set_prompt(&mut self, prompt_style: PromptStyle) {
|
|
||||||
let prompt_str = match prompt_style {
|
|
||||||
PromptStyle::Normal => ">> ".to_string(),
|
|
||||||
PromptStyle::Multiline => ">| ".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.line_reader.set_prompt(&prompt_str).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_before_exit(&self) {
|
|
||||||
self.line_reader.save_history(HISTORY_SAVE_FILE).unwrap_or(());
|
|
||||||
self.options.save_to_file(OPTIONS_SAVE_FILE);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput {
|
|
||||||
let mut iter = input.chars();
|
|
||||||
iter.next();
|
|
||||||
let arguments: Vec<&str> = iter
|
|
||||||
.as_str()
|
|
||||||
.split_whitespace()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if arguments.len() < 1 {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let directives = self.get_directives();
|
fn update_line_reader(&mut self) {
|
||||||
directives.perform(self, &arguments)
|
let tab_complete_handler =
|
||||||
}
|
TabCompleteHandler::new(self.interpreter_directive_sigil, self.get_directives());
|
||||||
|
self.line_reader
|
||||||
fn get_cur_language_state(&mut self) -> &mut Box<dyn ProgrammingLanguageInterface> {
|
.set_completer(Arc::new(tab_complete_handler)); //TODO fix this here
|
||||||
//TODO this is obviously not complete
|
self.set_prompt(PromptStyle::Normal);
|
||||||
&mut self.language_states[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_input(&mut self, input: &str) -> Vec<ReplResponse> {
|
|
||||||
let mut debug_requests = HashSet::new();
|
|
||||||
for ask in self.options.debug_asks.iter() {
|
|
||||||
debug_requests.insert(ask.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = ComputationRequest { source: input, debug_requests };
|
fn set_prompt(&mut self, prompt_style: PromptStyle) {
|
||||||
let ref mut language_state = self.get_cur_language_state();
|
let prompt_str = match prompt_style {
|
||||||
let response = language_state.run_computation(request);
|
PromptStyle::Normal => ">> ".to_string(),
|
||||||
response::handle_computation_response(response, &self.options)
|
PromptStyle::Multiline => ">| ".to_string(),
|
||||||
}
|
};
|
||||||
|
|
||||||
fn get_directives(&mut self) -> CommandTree {
|
self.line_reader.set_prompt(&prompt_str).unwrap();
|
||||||
let language_state = self.get_cur_language_state();
|
}
|
||||||
let pass_names = match language_state.request_meta(LangMetaRequest::StageNames) {
|
|
||||||
LangMetaResponse::StageNames(names) => names,
|
|
||||||
_ => vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
directives_from_pass_names(&pass_names)
|
fn save_before_exit(&self) {
|
||||||
}
|
self.line_reader
|
||||||
|
.save_history(HISTORY_SAVE_FILE)
|
||||||
|
.unwrap_or(());
|
||||||
|
self.options.save_to_file(OPTIONS_SAVE_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_interpreter_directive(&mut self, input: &str) -> InterpreterDirectiveOutput {
|
||||||
|
let mut iter = input.chars();
|
||||||
|
iter.next();
|
||||||
|
let arguments: Vec<&str> = iter.as_str().split_whitespace().collect();
|
||||||
|
|
||||||
|
if arguments.len() < 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let directives = self.get_directives();
|
||||||
|
directives.perform(self, &arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cur_language_state(&mut self) -> &mut Box<dyn ProgrammingLanguageInterface> {
|
||||||
|
//TODO this is obviously not complete
|
||||||
|
&mut self.language_states[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_input(&mut self, input: &str) -> Vec<ReplResponse> {
|
||||||
|
let mut debug_requests = HashSet::new();
|
||||||
|
for ask in self.options.debug_asks.iter() {
|
||||||
|
debug_requests.insert(ask.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = ComputationRequest {
|
||||||
|
source: input,
|
||||||
|
debug_requests,
|
||||||
|
};
|
||||||
|
let ref mut language_state = self.get_cur_language_state();
|
||||||
|
let response = language_state.run_computation(request);
|
||||||
|
response::handle_computation_response(response, &self.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_directives(&mut self) -> CommandTree {
|
||||||
|
let language_state = self.get_cur_language_state();
|
||||||
|
let pass_names = match language_state.request_meta(LangMetaRequest::StageNames) {
|
||||||
|
LangMetaResponse::StageNames(names) => names,
|
||||||
|
_ => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
directives_from_pass_names(&pass_names)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct TabCompleteHandler {
|
struct TabCompleteHandler {
|
||||||
sigil: char,
|
sigil: char,
|
||||||
top_level_commands: CommandTree,
|
top_level_commands: CommandTree,
|
||||||
}
|
}
|
||||||
|
|
||||||
use linefeed::complete::{Completion, Completer};
|
use linefeed::complete::{Completer, Completion};
|
||||||
use linefeed::terminal::Terminal;
|
use linefeed::terminal::Terminal;
|
||||||
|
|
||||||
impl TabCompleteHandler {
|
impl TabCompleteHandler {
|
||||||
fn new(sigil: char, top_level_commands: CommandTree) -> TabCompleteHandler {
|
fn new(sigil: char, top_level_commands: CommandTree) -> TabCompleteHandler {
|
||||||
TabCompleteHandler {
|
TabCompleteHandler {
|
||||||
top_level_commands,
|
top_level_commands,
|
||||||
sigil,
|
sigil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Terminal> Completer<T> for TabCompleteHandler {
|
impl<T: Terminal> Completer<T> for TabCompleteHandler {
|
||||||
fn complete(&self, word: &str, prompter: &::linefeed::prompter::Prompter<T>, start: usize, _end: usize) -> Option<Vec<Completion>> {
|
fn complete(
|
||||||
let line = prompter.buffer();
|
&self,
|
||||||
|
word: &str,
|
||||||
|
prompter: &::linefeed::prompter::Prompter<T>,
|
||||||
|
start: usize,
|
||||||
|
_end: usize,
|
||||||
|
) -> Option<Vec<Completion>> {
|
||||||
|
let line = prompter.buffer();
|
||||||
|
|
||||||
if !line.starts_with(self.sigil) {
|
if !line.starts_with(self.sigil) {
|
||||||
return None;
|
return None;
|
||||||
}
|
|
||||||
|
|
||||||
let mut words = line[1..(if start == 0 { 1 } else { start })].split_whitespace();
|
|
||||||
let mut completions = Vec::new();
|
|
||||||
let mut command_tree: Option<&CommandTree> = Some(&self.top_level_commands);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match words.next() {
|
|
||||||
None => {
|
|
||||||
let top = match command_tree {
|
|
||||||
Some(CommandTree::Top(_)) => true,
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
let word = if top { word.get(1..).unwrap() } else { word };
|
|
||||||
for cmd in command_tree.map(|x| x.get_subcommands()).unwrap_or(vec![]).into_iter() {
|
|
||||||
if cmd.starts_with(word) {
|
|
||||||
completions.push(Completion {
|
|
||||||
completion: format!("{}{}", if top { ":" } else { "" }, cmd),
|
|
||||||
display: Some(cmd.to_string()),
|
|
||||||
suffix: ::linefeed::complete::Suffix::Some(' ')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Some(s) => {
|
|
||||||
let new_ptr: Option<&CommandTree> = command_tree.and_then(|cm| match cm {
|
|
||||||
CommandTree::Top(children) => children.iter().find(|c| c.get_cmd() == s),
|
|
||||||
CommandTree::NonTerminal { children, .. } => children.iter().find(|c| c.get_cmd() == s),
|
|
||||||
CommandTree::Terminal { children, .. } => children.iter().find(|c| c.get_cmd() == s),
|
|
||||||
});
|
|
||||||
command_tree = new_ptr;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let mut words = line[1..(if start == 0 { 1 } else { start })].split_whitespace();
|
||||||
|
let mut completions = Vec::new();
|
||||||
|
let mut command_tree: Option<&CommandTree> = Some(&self.top_level_commands);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match words.next() {
|
||||||
|
None => {
|
||||||
|
let top = match command_tree {
|
||||||
|
Some(CommandTree::Top(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
let word = if top { word.get(1..).unwrap() } else { word };
|
||||||
|
for cmd in command_tree
|
||||||
|
.map(|x| x.get_subcommands())
|
||||||
|
.unwrap_or(vec![])
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
|
if cmd.starts_with(word) {
|
||||||
|
completions.push(Completion {
|
||||||
|
completion: format!("{}{}", if top { ":" } else { "" }, cmd),
|
||||||
|
display: Some(cmd.to_string()),
|
||||||
|
suffix: ::linefeed::complete::Suffix::Some(' '),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Some(s) => {
|
||||||
|
let new_ptr: Option<&CommandTree> = command_tree.and_then(|cm| match cm {
|
||||||
|
CommandTree::Top(children) => children.iter().find(|c| c.get_cmd() == s),
|
||||||
|
CommandTree::NonTerminal { children, .. } => {
|
||||||
|
children.iter().find(|c| c.get_cmd() == s)
|
||||||
|
}
|
||||||
|
CommandTree::Terminal { children, .. } => {
|
||||||
|
children.iter().find(|c| c.get_cmd() == s)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
command_tree = new_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(completions)
|
||||||
}
|
}
|
||||||
Some(completions)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,46 @@
|
|||||||
use crate::language::DebugAsk;
|
use crate::language::DebugAsk;
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ReplOptions {
|
pub struct ReplOptions {
|
||||||
pub debug_asks: HashSet<DebugAsk>,
|
pub debug_asks: HashSet<DebugAsk>,
|
||||||
pub show_total_time: bool,
|
pub show_total_time: bool,
|
||||||
pub show_stage_times: bool,
|
pub show_stage_times: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReplOptions {
|
impl ReplOptions {
|
||||||
pub fn new() -> ReplOptions {
|
pub fn new() -> ReplOptions {
|
||||||
ReplOptions {
|
ReplOptions {
|
||||||
debug_asks: HashSet::new(),
|
debug_asks: HashSet::new(),
|
||||||
show_total_time: true,
|
show_total_time: true,
|
||||||
show_stage_times: false,
|
show_stage_times: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_to_file(&self, filename: &str) {
|
pub fn save_to_file(&self, filename: &str) {
|
||||||
let res = File::create(filename)
|
let res = File::create(filename).and_then(|mut file| {
|
||||||
.and_then(|mut file| {
|
let buf = crate::serde_json::to_string(self).unwrap();
|
||||||
let buf = crate::serde_json::to_string(self).unwrap();
|
file.write_all(buf.as_bytes())
|
||||||
file.write_all(buf.as_bytes())
|
});
|
||||||
});
|
if let Err(err) = res {
|
||||||
if let Err(err) = res {
|
println!("Error saving {} file {}", filename, err);
|
||||||
println!("Error saving {} file {}", filename, err);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_from_file(filename: &str) -> Result<ReplOptions, ()> {
|
pub fn load_from_file(filename: &str) -> Result<ReplOptions, ()> {
|
||||||
File::open(filename)
|
File::open(filename)
|
||||||
.and_then(|mut file| {
|
.and_then(|mut file| {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
file.read_to_string(&mut contents)?;
|
file.read_to_string(&mut contents)?;
|
||||||
Ok(contents)
|
Ok(contents)
|
||||||
})
|
})
|
||||||
.and_then(|contents| {
|
.and_then(|contents| {
|
||||||
let output: ReplOptions = crate::serde_json::from_str(&contents)?;
|
let output: ReplOptions = crate::serde_json::from_str(&contents)?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
})
|
})
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,65 +3,78 @@ use std::fmt;
|
|||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use super::ReplOptions;
|
use super::ReplOptions;
|
||||||
use crate::language::{ DebugAsk, ComputationResponse};
|
use crate::language::{ComputationResponse, DebugAsk};
|
||||||
|
|
||||||
pub struct ReplResponse {
|
pub struct ReplResponse {
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
text: String,
|
text: String,
|
||||||
color: Option<Color>
|
color: Option<Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ReplResponse {
|
impl fmt::Display for ReplResponse {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
if let Some(ref label) = self.label {
|
if let Some(ref label) = self.label {
|
||||||
write!(buf, "({})", label).unwrap();
|
write!(buf, "({})", label).unwrap();
|
||||||
|
}
|
||||||
|
write!(buf, "=> {}", self.text).unwrap();
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self.color {
|
||||||
|
Some(c) => buf.color(c),
|
||||||
|
None => buf.normal(),
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
write!(buf, "=> {}", self.text).unwrap();
|
|
||||||
write!(f, "{}", match self.color {
|
|
||||||
Some(c) => buf.color(c),
|
|
||||||
None => buf.normal()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_computation_response(
|
||||||
|
response: ComputationResponse,
|
||||||
|
options: &ReplOptions,
|
||||||
|
) -> Vec<ReplResponse> {
|
||||||
|
let mut responses = vec![];
|
||||||
|
|
||||||
pub fn handle_computation_response(response: ComputationResponse, options: &ReplOptions) -> Vec<ReplResponse> {
|
if options.show_total_time {
|
||||||
let mut responses = vec![];
|
responses.push(ReplResponse {
|
||||||
|
label: Some("Total time".to_string()),
|
||||||
|
text: format!("{:?}", response.global_output_stats.total_duration),
|
||||||
|
color: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if options.show_total_time {
|
if options.show_stage_times {
|
||||||
responses.push(ReplResponse {
|
responses.push(ReplResponse {
|
||||||
label: Some("Total time".to_string()),
|
label: Some("Stage times".to_string()),
|
||||||
text: format!("{:?}", response.global_output_stats.total_duration),
|
text: format!("{:?}", response.global_output_stats.stage_durations),
|
||||||
color: None,
|
color: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for debug_resp in response.debug_responses {
|
||||||
|
let stage_name = match debug_resp.ask {
|
||||||
|
DebugAsk::ByStage { stage_name, .. } => stage_name,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
responses.push(ReplResponse {
|
||||||
|
label: Some(stage_name.to_string()),
|
||||||
|
text: debug_resp.value,
|
||||||
|
color: Some(Color::Red),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
responses.push(match response.main_output {
|
||||||
|
Ok(s) => ReplResponse {
|
||||||
|
label: None,
|
||||||
|
text: s,
|
||||||
|
color: None,
|
||||||
|
},
|
||||||
|
Err(e) => ReplResponse {
|
||||||
|
label: Some("Error".to_string()),
|
||||||
|
text: e,
|
||||||
|
color: Some(Color::Red),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if options.show_stage_times {
|
responses
|
||||||
responses.push(ReplResponse {
|
|
||||||
label: Some("Stage times".to_string()),
|
|
||||||
text: format!("{:?}", response.global_output_stats.stage_durations),
|
|
||||||
color: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for debug_resp in response.debug_responses {
|
|
||||||
let stage_name = match debug_resp.ask {
|
|
||||||
DebugAsk::ByStage { stage_name, .. } => stage_name,
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
responses.push(ReplResponse {
|
|
||||||
label: Some(stage_name.to_string()),
|
|
||||||
text: debug_resp.value,
|
|
||||||
color: Some(Color::Red),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
responses.push(match response.main_output {
|
|
||||||
Ok(s) => ReplResponse { label: None, text: s, color: None },
|
|
||||||
Err(e) => ReplResponse { label: Some("Error".to_string()), text: e, color: Some(Color::Red) },
|
|
||||||
});
|
|
||||||
|
|
||||||
responses
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user