Skip to content

Commit 27f1dcc

Browse files
committed
Add back-up degraded REPL mode if terminal lacks features.
1 parent aebd8d2 commit 27f1dcc

File tree

2 files changed

+80
-34
lines changed

2 files changed

+80
-34
lines changed

cli-repl/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# GameLisp command line REPL
22
A command line [Read-Eval-Print-Loop](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop)
33
for [GameLisp](https://gamelisp.rs).
4+
Runs on Linux, MacOS X, and Windows both in PowerShell and CMD.EXE
5+
but [Mintty](https://mintty.github.io/) ([Cygwin](https://www.cygwin.com/), [MSYS2](https://www.msys2.org/))
6+
is [not supported](https://github.com/murarth/linefeed/issues/68) and works
7+
only in [dumb terminal](https://books.google.com/books?id=jT2fQqJplN8C&lpg=PT3&pg=PT3) mode.
48

59
It can be used for running GameLisp programs from shell scripts by
610
passing their file names as arguments.

cli-repl/src/main.rs

+76-34
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use glsp::prelude::*;
1212

1313
use gong::{ ItemClass, Item };
14-
use linefeed::{ Interface, ReadResult };
14+
use linefeed::{ Interface, ReadResult, terminal::DefaultTerminal };
1515

1616
static OPTS: gong::options::OptionSet = gong::gong_option_set_fixed!(
1717
[
@@ -49,7 +49,6 @@ fn usage() {
4949
fn main() {
5050
debug_assert!(OPTS.is_valid());
5151

52-
let cwd = std::env::current_dir().unwrap();
5352
let args: Vec<String> = std::env::args().skip(1).collect();
5453
let mut files = Vec::new();
5554
let mut run_repl = true;
@@ -117,24 +116,41 @@ fn main() {
117116
;; for “name” in a web browser.
118117
;; E.g.: rust, lisp, std, special-forms, abbreviations, if, ', @, #n, #t, #f
119118
;; Without argument, shows the reference manual.
120-
;;; (www "url") loads “url” in a web browser, unless using --sandboxed.
121-
;;; CTRL+D to exit, command input history stored in "./{history}"."#,
119+
;;; (www "url") loads “url” in a web browser, unless using --sandboxed."#,
122120
name = env!("CARGO_PKG_NAME"),
123121
version = env!("CARGO_PKG_VERSION"),
124122
homepage = env!("CARGO_PKG_HOMEPAGE"),
123+
);
124+
125+
match Interface::new(env!("CARGO_PKG_NAME")) {
126+
Ok(cli) => {
127+
repl(runtime, sandboxed, cli);
128+
},
129+
Err(err) => {
130+
eprintln!(";;; Terminal is not fully functional: {}", err);
131+
degraded_repl(runtime, sandboxed);
132+
}
133+
};
134+
}
135+
136+
fn repl(runtime: Runtime, sandboxed: bool, cli: Interface<DefaultTerminal>) {
137+
let cwd = std::env::current_dir().unwrap();
138+
139+
eprintln!(
140+
r#";;; CTRL+D to exit, command input history stored in "./{history}"."#,
125141
history = HISTORY_FILE,
126142
);
127-
let cli = Interface::new(env!("CARGO_PKG_NAME")).unwrap();
143+
128144
if let Err(e) = cli.load_history(HISTORY_FILE) {
129145
if e.kind() != std::io::ErrorKind::NotFound {
130146
eprintln!("ERROR: failed to load REPL history from {} at {}, {:?}",
131147
HISTORY_FILE, cwd.display(), e);
132148
}
133149
}
134150

135-
{
136-
let mut reader = cli.lock_reader();
137-
reader.set_blink_matching_paren(true);
151+
if std::env::var("TERM").map_or(false, |s| { s != "dumb" }) {
152+
// These options need features not available in dumb terminals.
153+
cli.lock_reader().set_blink_matching_paren(true);
138154
}
139155

140156
loop {
@@ -143,24 +159,11 @@ fn main() {
143159
match cli.read_line() {
144160
Ok(line) => {
145161
match line {
146-
ReadResult::Input(mut line) => {
147-
line = line.trim_end().to_string();
162+
ReadResult::Input(line) => {
148163
runtime.run(|| {
149-
if line == "help" || line.starts_with("help ") {
150-
let url = help(Some(line[4..].trim_start()));
151-
if sandboxed {
152-
prn!("{}", url);
153-
} else {
154-
match www(Some(&url)) {
155-
Ok(_url) => { prn!("{}", url); },
156-
Err(err) => { return Err(err); }
157-
}
158-
}
159-
} else {
160-
match eval_line(&line) {
161-
Ok(result) => { prn!("{}", result); },
162-
Err(err) => { eprn!("{}", err.val()); }
163-
}
164+
match eval_line(&line, sandboxed) {
165+
Ok(result) => { prn!("{}", result); },
166+
Err(err) => { eprn!("{}", err.val()); }
164167
}
165168
Ok(())
166169
});
@@ -175,6 +178,8 @@ fn main() {
175178
},
176179
Err(err) => {
177180
eprintln!("Error: failed to read command line: {:?}", err);
181+
eprintln!("Switching to degraded mode.");
182+
degraded_repl(runtime, sandboxed);
178183
break;
179184
}
180185
}
@@ -186,16 +191,53 @@ fn main() {
186191
}
187192
}
188193

189-
fn eval_line(line: &str) -> GResult<Val> {
190-
match glsp::parse_all(&line, None) {
191-
Ok(values) => {
192-
match glsp::eval_multi(&values, Some(EnvMode::Copied)) {
193-
Ok(result) => Ok(result),
194-
Err(err) => Err(error!("Evaluation error: {}", err.val()))
194+
use std::io::{BufRead};
195+
fn degraded_repl(runtime: Runtime, sandboxed: bool) {
196+
eprint!("> ");
197+
for line in std::io::stdin().lock().lines() {
198+
match line {
199+
Ok(line) => {
200+
runtime.run(|| {
201+
match eval_line(&line, sandboxed) {
202+
Ok(result) => { prn!("{}", result); },
203+
Err(err) => { eprn!("{}", err.val()); }
204+
}
205+
Ok(())
206+
});
207+
},
208+
Err(err) => {
209+
eprintln!("Error: failed to read command line: {:?}", err);
210+
break;
211+
}
212+
}
213+
eprint!("> ");
214+
}
215+
}
216+
217+
fn eval_line(mut line: &str, sandboxed: bool) -> GResult<Val> {
218+
line = line.trim_start().trim_end();
219+
if line == "help" || line.starts_with("help ") {
220+
let url = help(Some(line[4..].trim_start()));
221+
if sandboxed {
222+
prn!("{}", url);
223+
url.to_string().to_val()
224+
} else {
225+
match www(Some(&url)) {
226+
Ok(url) => url.to_string().to_val(),
227+
Err(err) => Err(err)
228+
}
229+
}
230+
} else {
231+
match glsp::parse_all(line, None) {
232+
Ok(values) => {
233+
match glsp::eval_multi(&values, Some(EnvMode::Copied)) {
234+
Ok(result) => Ok(result),
235+
Err(err) => Err(error!("Evaluation error: {}", err.val()))
236+
}
237+
},
238+
Err(err) => {
239+
Err(error!("Syntax error: {}", err.val()))
195240
}
196-
},
197-
Err(err) => {
198-
Err(error!("Syntax error: {}", err.val()))
199241
}
200242
}
201243
}

0 commit comments

Comments
 (0)