enable an option to disable readline

This commit is contained in:
Mark Thom
2019-03-21 19:46:42 -06:00
parent 4b2fb8b1c7
commit 33b581effc
4 changed files with 165 additions and 98 deletions

View File

@@ -1,17 +1,21 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.11" version = "0.8.12"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
repository = "https://github.com/mthom/scryer-prolog" repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
license = "BSD-3-Clause" license = "BSD-3-Clause"
[features]
default = ["readline_rs_compat"]
[dependencies] [dependencies]
cfg-if = "0.1.7"
downcast = "0.9.1" downcast = "0.9.1"
num = "0.2" num = "0.2"
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = "0.8.1" prolog_parser = "0.8.1"
readline_rs_compat = "0.1.5" readline_rs_compat = { version = "0.1.5", optional = true }
[dependencies.termion] [dependencies.termion]
version = "1.4.0" version = "1.4.0"

View File

@@ -114,6 +114,13 @@ readline:
/opt/local/lib /opt/local/lib
``` ```
If you'd like to disable readline (and the need for linking to it),
install with the line
```
cargo install scryer-prolog --no-default-features
```
You can find the `scryer-prolog` executable in `~/.cargo/bin`. You can find the `scryer-prolog` executable in `~/.cargo/bin`.
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X, Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,

View File

@@ -1,7 +1,13 @@
#[macro_use] extern crate cfg_if;
#[macro_use] extern crate downcast; #[macro_use] extern crate downcast;
#[macro_use] extern crate prolog_parser; #[macro_use] extern crate prolog_parser;
extern crate readline_rs_compat; cfg_if! {
if #[cfg(feature = "readline_rs_compat")] {
extern crate readline_rs_compat;
}
}
extern crate termion; extern crate termion;
mod prolog; mod prolog;
@@ -20,7 +26,8 @@ fn prolog_repl() {
let mut wam = Machine::new(); let mut wam = Machine::new();
loop { loop {
set_line_mode(LineMode::Single); #[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Single);
match toplevel_read_line() { match toplevel_read_line() {
Ok(Input::TermString(buffer)) => { Ok(Input::TermString(buffer)) => {
@@ -32,17 +39,18 @@ fn prolog_repl() {
print(&mut wam, result) print(&mut wam, result)
}, },
Ok(Input::Batch) => { Ok(Input::Batch) => {
set_line_mode(LineMode::Multi); #[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Multi);
let src = match read_batch("") { let src = match readline::read_batch("") {
Ok(src) => src, Ok(src) => src,
Err(e) => { Err(e) => {
println!("{}", e); println!("{}", e);
continue; continue;
} }
}; };
let result = compile_user_module(&mut wam, src.as_bytes()); let result = compile_user_module(&mut wam, &src[0 ..]);
print(&mut wam, result); print(&mut wam, result);
}, },
Ok(Input::Clear) => { Ok(Input::Clear) => {
@@ -57,6 +65,7 @@ fn prolog_repl() {
} }
fn main() { fn main() {
readline_initialize(); #[cfg(feature = "readline_rs_compat")]
readline::readline_initialize();
prolog_repl(); prolog_repl();
} }

View File

@@ -11,8 +11,6 @@ use prolog::machine::machine_state::MachineState;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::Read; use std::io::Read;
use readline_rs_compat::readline::*;
type SubtermDeque = VecDeque<(usize, usize)>; type SubtermDeque = VecDeque<(usize, usize)>;
impl<'a> TermRef<'a> { impl<'a> TermRef<'a> {
@@ -29,112 +27,161 @@ impl<'a> TermRef<'a> {
pub enum Input { pub enum Input {
Clear, Clear,
Batch, Batch,
TermString(&'static str) TermString(String)
} }
#[derive(Clone, Copy)] #[cfg(feature = "readline_rs_compat")]
pub enum LineMode { pub mod readline
Single, {
Multi use readline_rs_compat::readline::*;
}
static mut LINE_MODE: LineMode = LineMode::Single; #[derive(Clone, Copy)]
static mut END_OF_LINE: bool = false; pub enum LineMode {
Single,
Multi
}
static mut LINE_MODE: LineMode = LineMode::Single;
static mut END_OF_LINE: bool = false;
pub fn set_line_mode(mode: LineMode) { pub fn set_line_mode(mode: LineMode) {
unsafe { unsafe {
LINE_MODE = mode; LINE_MODE = mode;
END_OF_LINE = false; END_OF_LINE = false;
rl_done = 0; rl_done = 0;
}
}
fn is_directive(buf: &str) -> bool {
match buf {
"?- [user]." | "?- [clear]." => true,
_ => false
}
}
unsafe extern "C" fn bind_end_chord(_: i32, _: i32) -> i32 {
if let LineMode::Multi = LINE_MODE {
rl_done = 1;
}
0
}
unsafe extern "C" fn bind_end_key(_: i32, _: i32) -> i32 {
insert_text_rl(".");
if let LineMode::Single = LINE_MODE {
END_OF_LINE = true;
}
0
}
unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 {
if END_OF_LINE {
if let Some(buf) = rl_line_buffer_as_str() {
if is_directive(buf) {
println!("");
rl_done = 1;
return 0;
}
}
println!("");
rl_done = 1;
} else {
insert_text_rl("\n");
}
0
}
pub fn readline_initialize() {
let rc = initialize_rl(); // initialize editline.
if rc != 0 {
panic!("initialize_rl() failed with return code {}", rc);
}
unsafe {
rl_startup_hook = insert_query_prompt;
}
bind_key_rl('.' as i32, bind_end_key);
bind_key_rl('\n' as i32, bind_cr);
bind_key_rl('\r' as i32, bind_cr);
bind_keyseq_rl("\\C-d", bind_end_chord);
}
unsafe extern "C" fn insert_query_prompt() -> i32 {
if let LineMode::Single = LINE_MODE {
insert_text_rl("?- ");
}
0
}
pub fn read_batch(prompt: &str) -> Result<Vec<u8>, ::SessionError> {
match readline_rl(prompt) {
Some(input) => Ok(Vec::from(input.as_bytes())),
None => Err(::SessionError::UserPrompt)
}
}
pub fn read_line(prompt: &str) -> Result<String, ::SessionError> {
match readline_rl(prompt) {
Some(input) => Ok(String::from(input)),
None => Err(::SessionError::UserPrompt)
}
} }
} }
fn is_directive(buf: &str) -> bool { #[cfg(not(feature = "readline_rs_compat"))]
match buf { pub mod readline
"?- [user]." | "?- [clear]." => true, {
_ => false use std::io::{BufRead, Read, stdin, stdout, Write};
}
} pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> {
let mut buf = vec![];
unsafe extern "C" fn bind_end_chord(_: i32, _: i32) -> i32 { let stdin = stdin();
if let LineMode::Multi = LINE_MODE { let mut stdin = stdin.lock();
rl_done = 1;
match stdin.read_to_end(&mut buf) {
Ok(_) => Ok(buf),
_ => Err(::SessionError::UserPrompt)
}
} }
0 pub fn read_line(_: &str) -> Result<String, ::SessionError> {
} print!("?- ");
stdout().flush().unwrap();
unsafe extern "C" fn bind_end_key(_: i32, _: i32) -> i32 { let stdin = stdin();
insert_text_rl("."); let stdin = stdin.lock();
if let LineMode::Single = LINE_MODE { let mut buf = "?- ".to_string();
END_OF_LINE = true;
} for line in stdin.lines() {
match line {
0 Ok(line) => {
} buf += &line;
unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 { if line.trim().ends_with(".") {
if END_OF_LINE { break;
if let Some(buf) = rl_line_buffer_as_str() { }
if is_directive(buf) { },
println!(""); _ => return Err(::SessionError::UserPrompt)
rl_done = 1;
return 0;
} }
} }
println!(""); Ok(buf)
rl_done = 1;
} else {
insert_text_rl("\n");
} }
0
}
pub fn readline_initialize() {
let rc = initialize_rl(); // initialize editline.
if rc != 0 {
panic!("initialize_rl() failed with return code {}", rc);
}
bind_key_rl('.' as i32, bind_end_key);
bind_key_rl('\n' as i32, bind_cr);
bind_key_rl('\r' as i32, bind_cr);
bind_keyseq_rl("\\C-d", bind_end_chord);
}
pub fn read_batch(prompt: &str) -> Result<&'static str, SessionError> {
match readline_rl(prompt) {
Some(input) => Ok(input),
None => Err(SessionError::UserPrompt)
}
}
fn read_line(prompt: &str) -> Result<&'static str, SessionError> {
match readline_rl(prompt) {
Some(input) => Ok(input),
None => Err(SessionError::UserPrompt)
}
}
unsafe extern "C" fn insert_query_prompt() -> i32 {
if let LineMode::Single = LINE_MODE {
insert_text_rl("?- ");
}
0
} }
pub fn toplevel_read_line() -> Result<Input, SessionError> pub fn toplevel_read_line() -> Result<Input, SessionError>
{ {
unsafe { let buffer = readline::read_line("")?;
rl_startup_hook = insert_query_prompt;
}
let buffer = read_line("")?;
Ok(match &*buffer.trim() { Ok(match &*buffer.trim() {
"?- [clear]." => Input::Clear, "?- [clear]." => Input::Clear,