From 62f6e655090e7e53511c8e108968b47cf85bbeb2 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 11 Oct 2020 10:16:49 +0300 Subject: [PATCH] repl: fix `reset`; make `echo "print(2.0 * 3.14159)" | ./v` print only the result --- cmd/tools/vrepl.v | 106 +++++++++++++++++++++--------- cmd/v/v.v | 2 +- vlib/v/tests/repl/runner/runner.v | 2 +- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/cmd/tools/vrepl.v b/cmd/tools/vrepl.v index 107b6c90c6..06cf4c25ba 100644 --- a/cmd/tools/vrepl.v +++ b/cmd/tools/vrepl.v @@ -1,7 +1,6 @@ // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. - module main import os @@ -12,9 +11,9 @@ import v.util struct Repl { mut: - indent int // indentation level - in_func bool // are we inside a new custom user function - line string // the current line entered by the user + indent int // indentation level + in_func bool // are we inside a new custom user function + line string // the current line entered by the user // modules []string // all the import modules includes []string // all the #include statements @@ -24,10 +23,19 @@ mut: temp_lines []string // all the temporary expressions/printlns } +const ( + is_stdin_a_pipe = (is_atty(0) == 0) +) + +fn new_repl() &Repl { + return &Repl{ + modules: ['os', 'time', 'math'] + } +} + fn (mut r Repl) checks() bool { mut in_string := false was_indent := r.indent > 0 - for i := 0; i < r.line.len; i++ { if r.line[i] == `\'` && (i == 0 || r.line[i - 1] != `\\`) { in_string = !in_string @@ -54,7 +62,7 @@ fn (mut r Repl) checks() bool { fn (r &Repl) function_call(line string) bool { for function in r.functions_name { - is_function_definition := line.replace(' ', '').starts_with("$function:=") + is_function_definition := line.replace(' ', '').starts_with('$function:=') if line.starts_with(function) && !is_function_definition { return true } @@ -87,15 +95,18 @@ fn repl_help() { ') } -fn run_repl(workdir string, vrepl_prefix string) { - println(util.full_v_version(false)) - println('Use Ctrl-C or `exit` to exit') - +fn run_repl(workdir, vrepl_prefix string) { + if !is_stdin_a_pipe { + println(util.full_v_version(false)) + println('Use Ctrl-C or `exit` to exit, or `help` to see other available commands') + } file := os.join_path(workdir, '.${vrepl_prefix}vrepl.v') temp_file := os.join_path(workdir, '.${vrepl_prefix}vrepl_temp.v') mut prompt := '>>> ' defer { - println('') + if !is_stdin_a_pipe { + println('') + } os.rm(file) os.rm(temp_file) $if windows { @@ -112,10 +123,7 @@ fn run_repl(workdir string, vrepl_prefix string) { os.rm(temp_file[..temp_file.len - 2]) } } - mut r := Repl{ - modules: ['os', 'time', 'math'] - } - mut readline := readline.Readline{} + mut r := new_repl() vexe := os.getenv('VEXE') for { if r.indent == 0 { @@ -123,7 +131,7 @@ fn run_repl(workdir string, vrepl_prefix string) { } else { prompt = '... ' } - oline := readline.read_line(prompt) or { + oline := r.get_one_line(prompt) or { break } line := oline.trim_space() @@ -172,7 +180,7 @@ fn run_repl(workdir string, vrepl_prefix string) { continue } if r.line == 'reset' { - r = Repl{} + r = new_repl() continue } if r.line == 'list' { @@ -185,11 +193,11 @@ fn run_repl(workdir string, vrepl_prefix string) { // Save the source only if the user is printing something, // but don't add this print call to the `lines` array, // so that it doesn't get called during the next print. - if r.line.starts_with('='){ + if r.line.starts_with('=') { r.line = 'println(' + r.line[1..] + ')' } if r.line.starts_with('print') { - source_code := r.current_source_code(false) + '\n${r.line}\n' + source_code := r.current_source_code(false) + '\n$r.line\n' os.write_file(file, source_code) s := os.exec('"$vexe" -repl run "$file"') or { rerror(err) @@ -200,13 +208,33 @@ fn run_repl(workdir string, vrepl_prefix string) { mut temp_line := r.line mut temp_flag := false func_call := r.function_call(r.line) - filter_line := r.line.replace(r.line.find_between('\'', '\''), '').replace(r.line.find_between('"', '"'), '') + filter_line := r.line.replace(r.line.find_between("\'", "\'"), '').replace(r.line.find_between('"', + '"'), '') possible_statement_patterns := [ - '=', '++', '--', '<<', - '//', '/*', - 'fn ', 'pub ', 'mut ', 'enum ', 'const ', 'struct ', 'interface ', 'import ', - '#include ', ':=', 'for ', 'or ', 'insert', 'delete', 'prepend', - 'sort', 'clear', 'trim', + '=', + '++', + '--', + '<<', + '//', + '/*', + 'fn ', + 'pub ', + 'mut ', + 'enum ', + 'const ', + 'struct ', + 'interface ', + 'import ', + '#include ', + ':=', + 'for ', + 'or ', + 'insert', + 'delete', + 'prepend', + 'sort', + 'clear', + 'trim', ] mut is_statement := false for pattern in possible_statement_patterns { @@ -227,10 +255,10 @@ fn run_repl(workdir string, vrepl_prefix string) { if temp_line.starts_with('import ') { mod := r.line.fields()[1] if mod !in r.modules { - temp_source_code = '${temp_line}\n' + r.current_source_code(false) + temp_source_code = '$temp_line\n' + r.current_source_code(false) } } else if temp_line.starts_with('#include ') { - temp_source_code = '${temp_line}\n' + r.current_source_code(false) + temp_source_code = '$temp_line\n' + r.current_source_code(false) } else { for i, l in r.lines { if (l.starts_with('for ') || l.starts_with('if ')) && l.contains('println') { @@ -238,8 +266,7 @@ fn run_repl(workdir string, vrepl_prefix string) { break } } - - temp_source_code = r.current_source_code(true) + '\n${temp_line}\n' + temp_source_code = r.current_source_code(true) + '\n$temp_line\n' } os.write_file(temp_file, temp_source_code) s := os.exec('"$vexe" -repl run "$temp_file"') or { @@ -283,11 +310,13 @@ fn print_output(s os.Result) { println(sline) return } - println(sline[idx+1..]) + println(sline[idx + 1..]) } else if line.contains('.vrepl.v:') { // Ensure that .vrepl.v: is at the start, ignore the path // This is needed to have stable .repl tests. - idx := line.index('.vrepl.v:') or { return } + idx := line.index('.vrepl.v:') or { + return + } println(line[idx..]) } else { println(line) @@ -316,3 +345,18 @@ fn rerror(s string) { println('V repl error: $s') os.flush() } + +fn (mut r Repl) get_one_line(prompt string) ?string { + mut readline := readline.Readline{} + if is_stdin_a_pipe { + iline := os.get_raw_line() + if iline.len == 0 { + return none + } + return iline + } + rline := readline.read_line(prompt) or { + return none + } + return rline +} diff --git a/cmd/v/v.v b/cmd/v/v.v index c4d9915de0..f8d758d94c 100644 --- a/cmd/v/v.v +++ b/cmd/v/v.v @@ -27,7 +27,7 @@ fn main() { // args = 123 if args.len == 0 || args[0] in ['-', 'repl'] { // Running `./v` without args launches repl - if args.len == 0 { + if args.len == 0 && is_atty(0) != 0 { println('For usage information, quit V REPL and run `v help`') } util.launch_tool(false, 'vrepl', os.args[1..]) diff --git a/vlib/v/tests/repl/runner/runner.v b/vlib/v/tests/repl/runner/runner.v index b0fb62538a..bbee1a04ce 100644 --- a/vlib/v/tests/repl/runner/runner.v +++ b/vlib/v/tests/repl/runner/runner.v @@ -60,7 +60,7 @@ pub fn run_repl_file(wd, vexec, file string) ?string { } os.rm(input_temporary_filename) result := r.output.replace('\r', '').replace('>>> ', '').replace('>>>', '').replace('... ', - '').all_after('Use Ctrl-C or `exit` to exit\n').replace(wd + os.path_separator, '').replace(vexec_folder, + '').replace(wd + os.path_separator, '').replace(vexec_folder, '').replace('\\', '/').trim_right('\n\r') if result != output { file_result := '${file}.result.txt'