diff --git a/README.md b/README.md index 4fa1bab5..652e7b98 100644 --- a/README.md +++ b/README.md @@ -168,8 +168,8 @@ predicates it defines. For example, with the program shown above: ; What = pure_world. ``` -Press `SPACE` to show further answers, if any exist. Press `.` to -abort the search and return to the toplevel prompt. +Press `SPACE` to show further answers, if any exist. Press `RETURN` or + `.` to abort the search and return to the toplevel prompt. Press `h` to show a help message. To quit Scryer Prolog, use the standard predicate `halt/0`: diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 7100855e..660de341 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -178,6 +178,7 @@ pub enum SystemClauseType { FetchGlobalVar, FetchGlobalVarWithOffset, GetChar, + GetSingleChar, ResetAttrVarState, TruncateIfNoLiftedHeapGrowthDiff, TruncateIfNoLiftedHeapGrowth, @@ -241,7 +242,6 @@ pub enum SystemClauseType { InstallNewBlock, Maybe, QuotedToken, - RawInputReadChar, ReadTermFromChars, ResetBlock, ReturnFromVerifyAttr, @@ -309,6 +309,7 @@ impl SystemClauseType { clause_name!("$fetch_global_var_with_offset") } &SystemClauseType::GetChar => clause_name!("$get_char"), + &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { clause_name!("$truncate_if_no_lh_growth") @@ -364,7 +365,6 @@ impl SystemClauseType { &SystemClauseType::QuotedToken => { clause_name!("$quoted_token") } - &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), &SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), @@ -455,6 +455,7 @@ impl SystemClauseType { ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_char", 1) => Some(SystemClauseType::GetChar), + ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar), ("$points_to_cont_reset_marker", 1) => { Some(SystemClauseType::PointsToContinuationResetMarker) } @@ -506,7 +507,6 @@ impl SystemClauseType { ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$quoted_token", 1) => Some(SystemClauseType::QuotedToken), - ("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar), ("$nextEP", 3) => Some(SystemClauseType::NextEP), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm), diff --git a/src/prolog/lib/charsio.pl b/src/prolog/lib/charsio.pl index 9cf5f325..4e3a4a22 100644 --- a/src/prolog/lib/charsio.pl +++ b/src/prolog/lib/charsio.pl @@ -1,4 +1,5 @@ -:- module(charsio, [read_term_from_chars/2, +:- module(charsio, [get_single_char/1, + read_term_from_chars/2, write_term_to_chars/3]). :- use_module(library(iso_ext)). @@ -56,6 +57,13 @@ extend_var_list_([V|Vs], N, VarList, NewVarList, VarType) :- ). +get_single_char(C) :- + ( var(C) -> '$get_single_char'(C) + ; atom_length(C, 1) -> '$get_single_char'(C) + ; throw(error(domain_error(in_character, C), get_single_char/1)) + ). + + read_term_from_chars(Chars, Term) :- ( var(Chars) -> throw(error(instantiation_error, read_term_from_chars/2)) diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index cd9cc86f..e2cad96a 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -31,40 +31,30 @@ use std::rc::Rc; use crate::crossterm::event::{read, Event, KeyCode, KeyEvent}; use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode}; -pub enum ContinueResult { - ContinueQuery, - Conclude, - Help, - PrintWithoutMaxDepth, - PrintWithMaxDepth -} - -pub fn next_keypress() -> ContinueResult { +pub fn get_single_char() -> char { + let c; + enable_raw_mode().expect("failed to enable raw mode"); loop { - match read() { - Ok(Event::Key(KeyEvent { code, .. })) => { - match code { - KeyCode::Char('w') => { - return ContinueResult::PrintWithoutMaxDepth; - } - KeyCode::Char('p') => { - return ContinueResult::PrintWithMaxDepth; - } - KeyCode::Char(' ') | KeyCode::Char(';') | KeyCode::Char('n') => { - return ContinueResult::ContinueQuery; - } - KeyCode::Char('.') => { - return ContinueResult::Conclude; - } - KeyCode::Char('h') => { - return ContinueResult::Help; - } - _ => {} - } + if let Ok(Event::Key(KeyEvent { code, .. })) = read() { + match code { + KeyCode::Char(ch) => { + c = ch; + break; + }, + KeyCode::Enter => { + c = '\n'; + break; + }, + KeyCode::Tab => { + c = '\t'; + break; + }, + _ => () } - _ => {} } } + disable_raw_mode().expect("failed to disable raw mode"); + c } struct BrentAlgState { @@ -1463,6 +1453,13 @@ impl MachineState { } } } + &SystemClauseType::GetSingleChar => { + let c = get_single_char(); + + let a1 = self[temp_v!(1)]; + + self.unify(Addr::Char(c), a1); + } &SystemClauseType::GetModuleClause => { let module = self[temp_v!(3)]; let head = self[temp_v!(1)]; @@ -2880,26 +2877,6 @@ impl MachineState { &SystemClauseType::InstallNewBlock => { self.install_new_block(temp_v!(1)); } - &SystemClauseType::RawInputReadChar => { - let keypress = { - enable_raw_mode().expect("failed to transition into raw mode"); - let result = next_keypress(); - disable_raw_mode().expect("failed to transition out of raw mode"); - - result - }; - - let c = match keypress { - ContinueResult::ContinueQuery => ';', - ContinueResult::Conclude => '.', - ContinueResult::Help => 'h', - ContinueResult::PrintWithoutMaxDepth => 'w', - ContinueResult::PrintWithMaxDepth => 'p', - }; - - let target = self[temp_v!(1)]; - self.unify(Addr::Char(c), target); - } &SystemClauseType::NextEP => { let first_arg = self.store(self.deref(self[temp_v!(1)])); diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 27bf71f5..aad24573 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -145,30 +145,31 @@ ). '$read_input'(ThreadedGoals, NewVarList) :- - '$raw_input_read_char'(C), - ( C == w -> + get_single_char(C), + ( C = w -> nl, write(' '), '$write_eq'(ThreadedGoals, NewVarList, 0), '$read_input'(ThreadedGoals, NewVarList) - ; C == p -> + ; C = p -> nl, write(' '), '$write_eq'(ThreadedGoals, NewVarList, 20), '$read_input'(ThreadedGoals, NewVarList) - ; C == (';') -> + ; member(C, [';', ' ', n]) -> nl, write('; '), false - ; C == h -> + ; C = h -> '$help_message', '$read_input'(ThreadedGoals, NewVarList) - ; C == '.', + ; member(C, ['\n', .]) -> nl, write('; ...'), nl + ; '$read_input'(ThreadedGoals, NewVarList) ). '$help_message' :- nl, nl, write('SPACE, "n" or ";": next solution, if any\n'), - write('".": stop enumeration\n'), + write('RETURN or ".": stop enumeration\n'), write('"h": display this help message\n'), write('"w": write terms without depth limit\n'), write('"p": print terms with depth limit\n\n').