Merge branch 'repl' into repl-warnings

Signed-off-by: Richard Feldman <oss@rtfeldman.com>
This commit is contained in:
Richard Feldman 2022-11-03 20:05:18 -07:00 committed by GitHub
commit 0657c38bb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 115 deletions

View file

@ -23,7 +23,6 @@ rustyline = {git = "https://github.com/roc-lang/rustyline", rev = "e74333c"}
rustyline-derive = {git = "https://github.com/roc-lang/rustyline", rev = "e74333c"}
target-lexicon = "0.12.2"
unicode-segmentation = "1.10.0"
termsize = "0.1.6"
roc_build = {path = "../compiler/build"}
roc_builtins = {path = "../compiler/builtins"}

View file

@ -22,7 +22,7 @@ pub const WELCOME_MESSAGE: &str = concatcp!(
// For when nothing is entered in the repl
// TODO add link to repl tutorial(does not yet exist).
pub const SHORT_INSTRUCTIONS: &str = "Enter an expression, or :help, or :q to quit.\n";
pub const SHORT_INSTRUCTIONS: &str = "Enter an expression, or :help, or :q to quit.\n\n";
pub fn main() -> i32 {
use rustyline::error::ReadlineError;
@ -42,9 +42,10 @@ pub fn main() -> i32 {
Ok(line) => {
editor.add_history_entry(line.trim());
let dimensions = editor.dimensions();
let repl_helper = editor.helper_mut().expect("Editor helper was not set");
match repl_helper.step(&line) {
match repl_helper.step(&line, dimensions) {
Ok(output) => {
// If there was no output, don't print a blank line!
// (This happens for something like a type annotation.)

View file

@ -17,9 +17,8 @@ use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
use rustyline_derive::{Completer, Helper, Hinter};
use std::borrow::Cow;
use target_lexicon::Triple;
use termsize::Size;
pub const PROMPT: &str = concatcp!("\n", BLUE, "»", END_COL, " ");
pub const PROMPT: &str = concatcp!(BLUE, "»", END_COL, " ");
pub const CONT_PROMPT: &str = concatcp!(BLUE, "", END_COL, " ");
/// The prefix we use for the automatic variable names we assign to each expr,
@ -92,7 +91,7 @@ impl ReplState {
}
}
pub fn step(&mut self, line: &str) -> Result<String, i32> {
pub fn step(&mut self, line: &str, dimensions: Option<(usize, usize)>) -> Result<String, i32> {
let arena = Bump::new();
match parse_src(&arena, line) {
@ -103,7 +102,7 @@ impl ReplState {
// After two blank lines in a row, give up and try parsing it
// even though it's going to fail. This way you don't get stuck
// in a perpetual Incomplete state due to a syntax error.
Ok(self.eval_and_format(line))
Ok(self.eval_and_format(line, dimensions))
} else {
// The previous line wasn't blank, but the line isn't empty either.
// This could mean that, for example, you're writing a multiline `when`
@ -119,7 +118,7 @@ impl ReplState {
| ParseOutcome::ValueDef(_)
| ParseOutcome::TypeDef(_)
| ParseOutcome::SyntaxErr
| ParseOutcome::Incomplete => Ok(self.eval_and_format(line)),
| ParseOutcome::Incomplete => Ok(self.eval_and_format(line, dimensions)),
ParseOutcome::Help => {
// TODO add link to repl tutorial(does not yet exist).
Ok(TIPS.to_string())
@ -128,7 +127,7 @@ impl ReplState {
}
}
pub fn eval_and_format(&mut self, src: &str) -> String {
pub fn eval_and_format(&mut self, src: &str, dimensions: Option<(usize, usize)>) -> String {
let arena = Bump::new();
let pending_past_def;
let mut opt_var_name;
@ -281,7 +280,7 @@ impl ReplState {
self.add_past_def(ident, src);
}
format_output(output, problems, opt_var_name)
format_output(output, problems, opt_var_name, dimensions)
}
fn next_auto_ident(&mut self) -> u64 {
@ -550,6 +549,7 @@ fn format_output(
opt_output: Option<ReplOutput>,
problems: Problems,
opt_var_name: Option<String>,
dimensions: Option<(usize, usize)>,
) -> String {
let mut buf = String::new();
@ -587,10 +587,10 @@ fn format_output(
use unicode_segmentation::UnicodeSegmentation;
const VAR_NAME_PREFIX: &str = " # "; // e.g. in " # val1"
const VAR_NAME_COLUMN_MAX: u16 = 80; // Right-align the var_name at this column
const VAR_NAME_COLUMN_MAX: usize = 32; // Right-align the var_name at this column
let var_name_column = match termsize::get() {
Some(Size { cols, rows: _ }) => cols.min(VAR_NAME_COLUMN_MAX) as usize,
let term_width = match dimensions {
Some((width, _)) => width.min(VAR_NAME_COLUMN_MAX),
None => VAR_NAME_COLUMN_MAX as usize,
};
@ -605,11 +605,11 @@ fn format_output(
.count();
let var_name_len =
var_name.graphemes(true).count() + VAR_NAME_PREFIX.graphemes(true).count();
let spaces_needed = if last_line_len + var_name_len > var_name_column {
let spaces_needed = if last_line_len + var_name_len > term_width {
buf.push('\n');
var_name_column - var_name_len
term_width - var_name_len
} else {
var_name_column - last_line_len - var_name_len
term_width - last_line_len - var_name_len
};
for _ in 0..spaces_needed {
@ -620,6 +620,7 @@ fn format_output(
buf.push_str(VAR_NAME_PREFIX);
buf.push_str(&var_name);
buf.push_str(END_COL);
buf.push('\n');
}
}
}

View file

@ -88,7 +88,7 @@ fn exhaustiveness_problem() {
#[test]
fn tips() {
assert!(!is_incomplete(""));
assert_eq!(ReplState::new().step(""), Ok(TIPS.to_string()));
assert_eq!(ReplState::new().step("", None), Ok(TIPS.to_string()));
}
#[test]
@ -98,7 +98,7 @@ fn standalone_annotation() {
incomplete(&mut input);
assert!(!is_incomplete(&input));
assert_eq!(state.step(&input), Ok(String::new()));
assert_eq!(state.step(&input, None), Ok(String::new()));
}
/// validate and step the given input, then check the Result vs the output
@ -106,7 +106,7 @@ fn standalone_annotation() {
fn complete(input: &str, state: &mut ReplState, expected_step_result: Result<(&str, &str), i32>) {
assert!(!is_incomplete(input));
match state.step(input) {
match state.step(input, None) {
Ok(string) => {
let escaped =
std::string::String::from_utf8(strip_ansi_escapes::strip(string.trim()).unwrap())
@ -144,7 +144,7 @@ fn incomplete(input: &mut String) {
fn error(input: &str, state: &mut ReplState, expected_step_result: String) {
assert!(!is_incomplete(input));
let escaped = state.step(input).map(|string| {
let escaped = state.step(input, None).map(|string| {
std::string::String::from_utf8(strip_ansi_escapes::strip(string.trim()).unwrap()).unwrap()
});