From aa149bfe8bab161dff82e14d70ae005b7d2940b1 Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 1 Dec 2021 08:29:23 +0900 Subject: [PATCH 01/19] Add SWI Prolog --- src/interpreters/Prolog_swi.rs | 113 +++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/interpreters/Prolog_swi.rs diff --git a/src/interpreters/Prolog_swi.rs b/src/interpreters/Prolog_swi.rs new file mode 100644 index 00000000..0043e210 --- /dev/null +++ b/src/interpreters/Prolog_swi.rs @@ -0,0 +1,113 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct Prolog_swi { + support_level: SupportLevel, + data: DataHolder, + code: String, + prolog_work_dir: String, + main_file_path: String, +} +impl ReplLikeInterpreter for Prolog_swi {} +impl Interpreter for Prolog_swi { + fn new_with_level(data: DataHolder, level: SupportLevel) -> Box { + let bwd = data.work_dir.clone() + "/prolog-swi"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&bwd) + .expect("Could not create directory for prolog-swi"); + let mfp = bwd.clone() + "/main.pl"; + Box::new(Prolog_swi { + data, + support_level: level, + code: String::from(""), + prolog_work_dir: bwd, + main_file_path: mfp, + }) + } + fn get_name() -> String { + String::from("Prolog_swi") + } + fn get_supported_languages() -> Vec { + vec![String::from("Prolog"), String::from("prolog")] + } + fn get_current_level(&self) -> SupportLevel { + self.support_level + } + fn set_current_level(&mut self, level: SupportLevel) { + self.support_level = level + } + fn default_for_filetype() -> bool { + true + } + fn get_data(&self) -> DataHolder { + self.data.clone() + } + fn check_cli_args(&self) -> Result<(), SniprunError> { + // All cli arguments are sendable to python + // Though they will be ignored in REPL mode + Ok(()) + } + fn get_max_support_level() -> SupportLevel { + SupportLevel::Bloc + } + fn fetch_code(&mut self) -> Result<(), SniprunError> { + if !self + .data + .current_bloc + .replace(&[' ', '\t', '\n', '\r'][..], "") + .is_empty() + && self.get_current_level() >= SupportLevel::Bloc + { + self.code = self.data.current_bloc.clone(); + } else if !self.data.current_line.replace(" ", "").is_empty() + && self.get_current_level() >= SupportLevel::Line + { + self.code = self.data.current_line.clone(); + } else { + self.code = String::from(""); + } + Ok(()) + } + fn add_boilerplate(&mut self) -> Result<(), SniprunError> { + Ok(()) + } + fn build(&mut self) -> Result<(), SniprunError> { + let mut _file = + File::create(&self.main_file_path).expect("Failed to create file for prolog-swi"); + + write(&self.main_file_path, &self.code).expect("Unable to write to file for prolog-swi"); + Ok(()) + } + fn execute(&mut self) -> Result { + let output = Command::new("swipl") + .arg(&self.main_file_path) + .args(&self.get_data().cli_args) + .output() + .expect("Unable to start process"); + info!("yay from SWI Prolog interpreter"); + if output.status.success() { + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + Err(SniprunError::RuntimeError( + String::from_utf8(output.stderr).unwrap(), + )) + } + } +} +#[cfg(test)] +mod test_prolog_swi { + use super::*; + + #[test] + fn simple_print() { + let mut data = DataHolder::new(); + data.current_bloc = String::from(":- write(ok), halt."); + let mut interpreter = Prolog_swi::new(data); + let res = interpreter.run(); + + // should panic if not an Ok() + let string_result = res.unwrap(); + assert_eq!(string_result, "ok"); + } +} From 840e10a7e8e9244156cba9b1295e161c1119af8d Mon Sep 17 00:00:00 2001 From: TANIGUCHI Masaya Date: Wed, 1 Dec 2021 08:56:57 +0900 Subject: [PATCH 02/19] Add GNU Prolog --- src/interpreters/Prolog_gnu.rs | 114 +++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/interpreters/Prolog_gnu.rs diff --git a/src/interpreters/Prolog_gnu.rs b/src/interpreters/Prolog_gnu.rs new file mode 100644 index 00000000..78af7b1e --- /dev/null +++ b/src/interpreters/Prolog_gnu.rs @@ -0,0 +1,114 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct Prolog_gnu { + support_level: SupportLevel, + data: DataHolder, + code: String, + prolog_work_dir: String, + main_file_path: String, +} +impl ReplLikeInterpreter for Prolog_gnu {} +impl Interpreter for Prolog_gnu { + fn new_with_level(data: DataHolder, level: SupportLevel) -> Box { + let bwd = data.work_dir.clone() + "/prolog-gnu"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&bwd) + .expect("Could not create directory for prolog-gnu"); + let mfp = bwd.clone() + "/main.pl"; + Box::new(Prolog_gnu { + data, + support_level: level, + code: String::from(""), + prolog_work_dir: bwd, + main_file_path: mfp, + }) + } + fn get_name() -> String { + String::from("Prolog_gnu") + } + fn get_supported_languages() -> Vec { + vec![String::from("Prolog"), String::from("prolog")] + } + fn get_current_level(&self) -> SupportLevel { + self.support_level + } + fn set_current_level(&mut self, level: SupportLevel) { + self.support_level = level + } + fn default_for_filetype() -> bool { + true + } + fn get_data(&self) -> DataHolder { + self.data.clone() + } + fn check_cli_args(&self) -> Result<(), SniprunError> { + // All cli arguments are sendable to python + // Though they will be ignored in REPL mode + Ok(()) + } + fn get_max_support_level() -> SupportLevel { + SupportLevel::Bloc + } + fn fetch_code(&mut self) -> Result<(), SniprunError> { + if !self + .data + .current_bloc + .replace(&[' ', '\t', '\n', '\r'][..], "") + .is_empty() + && self.get_current_level() >= SupportLevel::Bloc + { + self.code = self.data.current_bloc.clone(); + } else if !self.data.current_line.replace(" ", "").is_empty() + && self.get_current_level() >= SupportLevel::Line + { + self.code = self.data.current_line.clone(); + } else { + self.code = String::from(""); + } + Ok(()) + } + fn add_boilerplate(&mut self) -> Result<(), SniprunError> { + Ok(()) + } + fn build(&mut self) -> Result<(), SniprunError> { + let mut _file = + File::create(&self.main_file_path).expect("Failed to create file for prolog-gnu"); + + write(&self.main_file_path, &self.code).expect("Unable to write to file for prolog-gnu"); + Ok(()) + } + fn execute(&mut self) -> Result { + let output = Command::new("gprolog") + .arg(String::from("--consult-file")) + .arg(&self.main_file_path) + .args(&self.get_data().cli_args) + .output() + .expect("Unable to start process"); + info!("yay from gnu Prolog interpreter"); + if output.status.success() { + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + Err(SniprunError::RuntimeError( + String::from_utf8(output.stderr).unwrap(), + )) + } + } +} +#[cfg(test)] +mod test_prolog_gnu { + use super::*; + + #[test] + fn simple_print() { + let mut data = DataHolder::new(); + data.current_bloc = String::from(":- write(ok), halt."); + let mut interpreter = Prolog_gnu::new(data); + let res = interpreter.run(); + + // should panic if not an Ok() + let string_result = res.unwrap(); + assert_eq!(string_result, "ok"); + } +} From 2abf9c60f5bd982e223323e423b6eaed952d94cf Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Thu, 9 Dec 2021 01:33:00 +0100 Subject: [PATCH 03/19] feat(display): simple print current line in terminal --- src/display.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/display.rs b/src/display.rs index 6f6dc687..c7721e8e 100644 --- a/src/display.rs +++ b/src/display.rs @@ -200,11 +200,13 @@ pub fn display_terminal( ) { let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( - "lua require\"sniprun.display\".write_to_term(\"{}\", true)", + "lua require\"sniprun.display\".write_to_term(\"> {}\\n{}\", true)", + data.current_bloc.trim_end_matches('\n'), no_output_wrap(result, data, &DisplayType::Terminal), )), Err(result) => nvim.lock().unwrap().command(&format!( - "lua require\"sniprun.display\".write_to_term(\"{}\", false)", + "lua require\"sniprun.display\".write_to_term(\"> {}\\n{}\", false)", + data.current_bloc.trim_end_matches('\n'), no_output_wrap(&result.to_string(), data, &DisplayType::Terminal), )), }; From 5c3e1413a1c6f2ba9ed73a2a3b876cf9cdf4c424 Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Thu, 9 Dec 2021 17:49:20 +0100 Subject: [PATCH 04/19] feat(display): src is printed with prepending ">" --- Cargo.lock | 2 +- src/display.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bcc26edd..dc91a80e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,7 +336,7 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "sniprun" -version = "1.0.4" +version = "1.0.5" dependencies = [ "dirs", "libc", diff --git a/src/display.rs b/src/display.rs index c7721e8e..5d84a744 100644 --- a/src/display.rs +++ b/src/display.rs @@ -200,13 +200,17 @@ pub fn display_terminal( ) { let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( - "lua require\"sniprun.display\".write_to_term(\"> {}\\n{}\", true)", - data.current_bloc.trim_end_matches('\n'), + "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", + cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + })), no_output_wrap(result, data, &DisplayType::Terminal), )), Err(result) => nvim.lock().unwrap().command(&format!( - "lua require\"sniprun.display\".write_to_term(\"> {}\\n{}\", false)", - data.current_bloc.trim_end_matches('\n'), + "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", + cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + })), no_output_wrap(&result.to_string(), data, &DisplayType::Terminal), )), }; From 90b0fcd477153669391a164d910a2b17616f2ea4 Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Thu, 9 Dec 2021 18:57:08 +0100 Subject: [PATCH 05/19] feat(display): own display for terminal with code --- src/display.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/display.rs b/src/display.rs index 5d84a744..02864309 100644 --- a/src/display.rs +++ b/src/display.rs @@ -13,6 +13,7 @@ pub enum DisplayType { VirtualTextOk, VirtualTextErr, Terminal, + TerminalWithCode, LongTempFloatingWindow, TempFloatingWindow, Api, @@ -27,6 +28,7 @@ impl FromStr for DisplayType { "VirtualTextOk" => Ok(VirtualTextOk), "VirtualTextErr" => Ok(VirtualTextErr), "Terminal" => Ok(Terminal), + "TerminalWithCode" => Ok(TerminalWithCode), "LongTempFloatingWindow" => Ok(LongTempFloatingWindow), "TempFloatingWindow" => Ok(TempFloatingWindow), "Api" => Ok(Api), @@ -45,6 +47,7 @@ impl fmt::Display for DisplayType { DisplayType::VirtualTextOk => "VirtualTextOk", DisplayType::VirtualTextErr => "VirtualTextErr", DisplayType::Terminal => "Terminal", + DisplayType::TerminalWithCode => "TerminalWithCode", DisplayType::LongTempFloatingWindow => "LongTempFloatingWindow", DisplayType::TempFloatingWindow => "TempFloatingWindow", DisplayType::Api => "Api", @@ -66,6 +69,7 @@ pub fn display(result: Result, nvim: Arc>, d VirtualTextOk => display_virtual_text(&result, &nvim, data, true), VirtualTextErr => display_virtual_text(&result, &nvim, data, false), Terminal => display_terminal(&result, &nvim, data), + TerminalWithCode => display_terminal_with_code(&result, &nvim, data), LongTempFloatingWindow => display_floating_window(&result, &nvim, data, true), TempFloatingWindow => display_floating_window(&result, &nvim, data, false), Api => send_api(&result, &nvim, data), @@ -197,6 +201,24 @@ pub fn display_terminal( message: &Result, nvim: &Arc>, data: &DataHolder, +) { + let res = match message { + Ok(result) => nvim.lock().unwrap().command(&format!( + "lua require\"sniprun.display\".write_to_term(\"{}\", true)", + no_output_wrap(result, data, &DisplayType::Terminal), + )), + Err(result) => nvim.lock().unwrap().command(&format!( + "lua require\"sniprun.display\".write_to_term(\"{}\", false)", + no_output_wrap(&result.to_string(), data, &DisplayType::Terminal), + )), + }; + info!("display terminal res = {:?}", res); +} + +pub fn display_terminal_with_code( + message: &Result, + nvim: &Arc>, + data: &DataHolder, ) { let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( @@ -204,14 +226,14 @@ pub fn display_terminal( cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" })), - no_output_wrap(result, data, &DisplayType::Terminal), + no_output_wrap(result, data, &DisplayType::TerminalWithCode), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" })), - no_output_wrap(&result.to_string(), data, &DisplayType::Terminal), + no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode), )), }; info!("display terminal res = {:?}", res); From 34c7b32b862a50130e6567473787c74291eabfc4 Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Fri, 10 Dec 2021 01:49:17 +0100 Subject: [PATCH 06/19] wip --- src/display.rs | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/display.rs b/src/display.rs index 02864309..ffaa602a 100644 --- a/src/display.rs +++ b/src/display.rs @@ -202,6 +202,9 @@ pub fn display_terminal( nvim: &Arc>, data: &DataHolder, ) { + info!("data_bloc = {}", data.current_bloc); + let a = data.current_bloc.lines(); + info!("length = {}", a.count()); let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\", true)", @@ -220,19 +223,44 @@ pub fn display_terminal_with_code( nvim: &Arc>, data: &DataHolder, ) { + info!("data_bloc = {:?}", data.current_bloc); + info!( + "lua require\"sniprun.display\".write_to_term(\"{} output \", true)", + &data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\\n" + }) + ); + info!( + "lua require\"sniprun.display\".write_to_term(\"{:?} output \", true)", + &data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\\n" + }) + ); + info!( + "lua require\"sniprun.display\".write_to_term(\"{} output \", true)", + cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + })).replace("\\\\\"", "\\\\\\\"") + ); + info!( + "lua require\"sniprun.display\".write_to_term(\"{:?} output \", true)", + cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + })) + ); let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" - })), + })).replace("\\\\\"", "\\\\\\\""), // replace is a fix for a missing backslash no_output_wrap(result, data, &DisplayType::TerminalWithCode), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" - })), + })).replace("\\\\\"", "\\\\\\\""), // replace is a fix for a missing backslash no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode), )), }; From 1a21dcaf41e77d71b5bb9ab7f98b4e6af39f22bc Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Sat, 11 Dec 2021 22:57:28 +0100 Subject: [PATCH 07/19] add documentation to TerminalWithCode --- Cargo.lock | 2 +- README.md | 1 + doc/sniprun.txt | 1 + lua/sniprun.lua | 1 + ressources/display_terminal.md | 6 ++++ ressources/visual_assets/terminaWithCode.png | Bin 0 -> 69899 bytes src/display.rs | 33 +++---------------- src/lib.rs | 1 + 8 files changed, 15 insertions(+), 30 deletions(-) create mode 100644 ressources/visual_assets/terminaWithCode.png diff --git a/Cargo.lock b/Cargo.lock index e5eb5053..75a922b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,7 +336,7 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "sniprun" -version = "1.0.5" +version = "1.0.6" dependencies = [ "dirs", "libc", diff --git a/README.md b/README.md index 1b30ebd6..754afc55 100755 --- a/README.md +++ b/README.md @@ -290,6 +290,7 @@ require'sniprun'.setup({ -- "TempFloatingWindow", --# display results in a floating window -- "LongTempFloatingWindow", --# same as above, but only long results. To use with VirtualText__ -- "Terminal", --# display results in a vertical split + -- "TerminalWithCode", --# display results and code history in a vertical split -- "NvimNotify", --# display with the nvim-notify plugin -- "Api" --# return output to a programming interface }, diff --git a/doc/sniprun.txt b/doc/sniprun.txt index ffb78d0a..9ebfbac8 100644 --- a/doc/sniprun.txt +++ b/doc/sniprun.txt @@ -104,6 +104,7 @@ require'sniprun'.setup({ -- "TempFloatingWindow", -- "display results in a floating window -- "LongTempFloatingWindow", -- "same as above, but only long results. To use with VirtualText__ -- "Terminal" -- "display results in a vertical split + -- "TerminalWithCode", --# display results and code history in a vertical split -- "NvimNotify", --# display with the nvim-notify plugin -- "Api" --# return output to a programming interface }, diff --git a/lua/sniprun.lua b/lua/sniprun.lua index 37e1ba65..db294e38 100644 --- a/lua/sniprun.lua +++ b/lua/sniprun.lua @@ -27,6 +27,7 @@ M.config_values = { -- "LongTempFloatingWindow", -- "TempFloatingWindow", -- "Terminal", + -- "TerminalWithCode", -- "Api", -- "NvimNotify" }, diff --git a/ressources/display_terminal.md b/ressources/display_terminal.md index 528cd08c..1330db86 100644 --- a/ressources/display_terminal.md +++ b/ressources/display_terminal.md @@ -29,3 +29,9 @@ EOF ![](visual_assets/terminal.png) +If you also want the history of the execute code printed to the terminal, then use `"TerminalWithCode"` instead in the 'display' key. + + + +![](visual_assets/TerminalWithCode.png) + diff --git a/ressources/visual_assets/terminaWithCode.png b/ressources/visual_assets/terminaWithCode.png new file mode 100644 index 0000000000000000000000000000000000000000..17b644cb1817ce9fe45bf0e918f70da2383c7951 GIT binary patch literal 69899 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, data: &DataHolder, ) { - info!("data_bloc = {:?}", data.current_bloc); - info!( - "lua require\"sniprun.display\".write_to_term(\"{} output \", true)", - &data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\\n" - }) - ); - info!( - "lua require\"sniprun.display\".write_to_term(\"{:?} output \", true)", - &data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\\n" - }) - ); - info!( - "lua require\"sniprun.display\".write_to_term(\"{} output \", true)", - cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\n" - })).replace("\\\\\"", "\\\\\\\"") - ); - info!( - "lua require\"sniprun.display\".write_to_term(\"{:?} output \", true)", - cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\n" - })) - ); let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" - })).replace("\\\\\"", "\\\\\\\""), // replace is a fix for a missing backslash - no_output_wrap(result, data, &DisplayType::TerminalWithCode), + })).replace("\n", "\\\n"), + no_output_wrap(result, data, &DisplayType::TerminalWithCode).replace("\n", "\\\n"), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" - })).replace("\\\\\"", "\\\\\\\""), // replace is a fix for a missing backslash - no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode), + })).replace("\n", "\\\n"), + no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode).replace("\n", "\\\n"), )), }; info!("display terminal res = {:?}", res); diff --git a/src/lib.rs b/src/lib.rs index af6027d2..d834d25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -580,6 +580,7 @@ mod test_main { let display_types: Vec = vec![ Value::from("Classic"), Value::from("Terminal"), + Value::from("TerminalWithCode"), Value::from("VirtualTextOk"), Value::from("VirtualTextErr"), Value::from("TempFloatingWindow"), From 2c8e31d5e6d03b24f519db493557b4d29615aee8 Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Sat, 11 Dec 2021 23:07:09 +0100 Subject: [PATCH 08/19] fix multicolumn bloc execution and \n for Terminal --- src/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/display.rs b/src/display.rs index 2cb8f93e..c26781c8 100644 --- a/src/display.rs +++ b/src/display.rs @@ -208,11 +208,11 @@ pub fn display_terminal( let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\", true)", - no_output_wrap(result, data, &DisplayType::Terminal), + no_output_wrap(result, data, &DisplayType::Terminal).replace("\n", "\\\n"), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\", false)", - no_output_wrap(&result.to_string(), data, &DisplayType::Terminal), + no_output_wrap(&result.to_string(), data, &DisplayType::Terminal).replace("\n", "\\\n"), )), }; info!("display terminal res = {:?}", res); From b413756a5a29e23c4af581fb3e29573929ef4b7d Mon Sep 17 00:00:00 2001 From: Tobias Jagla Date: Sat, 11 Dec 2021 23:41:33 +0100 Subject: [PATCH 09/19] fix wrong file name --- ressources/display_terminal.md | 2 +- .../{terminaWithCode.png => terminalWithCode.png} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename ressources/visual_assets/{terminaWithCode.png => terminalWithCode.png} (100%) diff --git a/ressources/display_terminal.md b/ressources/display_terminal.md index 1330db86..aa987f17 100644 --- a/ressources/display_terminal.md +++ b/ressources/display_terminal.md @@ -33,5 +33,5 @@ If you also want the history of the execute code printed to the terminal, then u -![](visual_assets/TerminalWithCode.png) +![](visual_assets/terminalWithCode.png) diff --git a/ressources/visual_assets/terminaWithCode.png b/ressources/visual_assets/terminalWithCode.png similarity index 100% rename from ressources/visual_assets/terminaWithCode.png rename to ressources/visual_assets/terminalWithCode.png From 428608d7de8f423bc9dea67062a1821afa5fc08a Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 18:32:56 +0100 Subject: [PATCH 10/19] fix typo & behavior for TerminalWithCode --- ressources/display_terminal.md | 2 +- src/display.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ressources/display_terminal.md b/ressources/display_terminal.md index aa987f17..479c6c81 100644 --- a/ressources/display_terminal.md +++ b/ressources/display_terminal.md @@ -29,7 +29,7 @@ EOF ![](visual_assets/terminal.png) -If you also want the history of the execute code printed to the terminal, then use `"TerminalWithCode"` instead in the 'display' key. +If you also want to print the code being executed to the 'terminal', then use `"TerminalWithCode"` instead in the 'display' key. diff --git a/src/display.rs b/src/display.rs index c26781c8..188f06d7 100644 --- a/src/display.rs +++ b/src/display.rs @@ -62,6 +62,11 @@ pub fn display(result: Result, nvim: Arc>, d display_type.sort(); display_type.dedup(); //now only uniques display types + // remove transparently incompatible/redundant displays + if display_type.contains(&TerminalWithCode) { + display_type.retain(|dt| dt != &Terminal); + } + info!("Display type chosen: {:?}", display_type); for dt in display_type.iter() { match dt { From d3e68edc24818d0049939494aabedaf96d50685a Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 18:47:52 +0100 Subject: [PATCH 11/19] fix default compiler/interpreter setting --- src/interpreters/C_original.rs | 2 +- src/interpreters/Cpp_original.rs | 2 +- src/interpreters/Go_original.rs | 2 +- src/interpreters/Python3_fifo.rs | 2 +- src/interpreters/Python3_original.rs | 2 +- src/interpreters/Rust_original.rs | 2 +- src/interpreters/Sage_fifo.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/interpreters/C_original.rs b/src/interpreters/C_original.rs index dd3b24d4..5d0d5783 100644 --- a/src/interpreters/C_original.rs +++ b/src/interpreters/C_original.rs @@ -47,13 +47,13 @@ impl C_original { fn fetch_config(&mut self) { let default_compiler = String::from("gcc"); + self.compiler = default_compiler; if let Some(used_compiler) = C_original::get_interpreter_option(&self.get_data(), "compiler") { if let Some(compiler_string) = used_compiler.as_str() { info!("Using custom compiler: {}", compiler_string); self.compiler = compiler_string.to_string(); } } - self.compiler = default_compiler; } } diff --git a/src/interpreters/Cpp_original.rs b/src/interpreters/Cpp_original.rs index d2069adc..f312b03b 100644 --- a/src/interpreters/Cpp_original.rs +++ b/src/interpreters/Cpp_original.rs @@ -48,13 +48,13 @@ impl Cpp_original { fn fetch_config(&mut self) { let default_compiler = String::from("g++"); + self.compiler = default_compiler; if let Some(used_compiler) = Cpp_original::get_interpreter_option(&self.get_data(), "compiler") { if let Some(compiler_string) = used_compiler.as_str() { info!("Using custom compiler: {}", compiler_string); self.compiler = compiler_string.to_string(); } } - self.compiler = default_compiler; } } diff --git a/src/interpreters/Go_original.rs b/src/interpreters/Go_original.rs index 942c5615..f190d600 100644 --- a/src/interpreters/Go_original.rs +++ b/src/interpreters/Go_original.rs @@ -15,13 +15,13 @@ pub struct Go_original { impl Go_original { fn fetch_config(&mut self) { let default_compiler = String::from("go"); + self.compiler = default_compiler; if let Some(used_compiler) = Go_original::get_interpreter_option(&self.get_data(),"compiler") { if let Some(compiler_string) = used_compiler.as_str() { info!("Using custom compiler: {}", compiler_string); self.compiler = compiler_string.to_string(); } } - self.compiler = default_compiler; } } diff --git a/src/interpreters/Python3_fifo.rs b/src/interpreters/Python3_fifo.rs index 0d15756f..33fcc743 100644 --- a/src/interpreters/Python3_fifo.rs +++ b/src/interpreters/Python3_fifo.rs @@ -172,6 +172,7 @@ impl Python3_fifo { fn fetch_config(&mut self) { let default_interpreter = String::from("python3"); + self.interpreter = default_interpreter; if let Some(used_interpreter) = Python3_fifo::get_interpreter_option(&self.get_data(), "interpreter") { @@ -180,7 +181,6 @@ impl Python3_fifo { self.interpreter = interpreter_string.to_string(); } } - self.interpreter = default_interpreter; if let Ok(path) = env::current_dir() { if let Some(venv_array_config) = diff --git a/src/interpreters/Python3_original.rs b/src/interpreters/Python3_original.rs index ab647d68..fb7a1bb9 100644 --- a/src/interpreters/Python3_original.rs +++ b/src/interpreters/Python3_original.rs @@ -86,13 +86,13 @@ impl Python3_original { } fn fetch_config(&mut self) { let default_compiler = String::from("python3"); + self.interpreter = default_compiler; if let Some(used_compiler) = Python3_original::get_interpreter_option(&self.get_data(), "interpreter") { if let Some(compiler_string) = used_compiler.as_str() { info!("Using custom compiler: {}", compiler_string); self.interpreter = compiler_string.to_string(); } } - self.interpreter = default_compiler; if let Ok(path) = env::current_dir() { if let Some(venv_array_config) = Python3_original::get_interpreter_option(&self.get_data(), "venv") { diff --git a/src/interpreters/Rust_original.rs b/src/interpreters/Rust_original.rs index 93cafa26..b32f7643 100644 --- a/src/interpreters/Rust_original.rs +++ b/src/interpreters/Rust_original.rs @@ -15,13 +15,13 @@ pub struct Rust_original { impl Rust_original { fn fetch_config(&mut self) { let default_compiler = String::from("rustc"); + self.compiler = default_compiler; if let Some(used_compiler) = Rust_original::get_interpreter_option(&self.get_data(), "compiler") { if let Some(compiler_string) = used_compiler.as_str() { info!("Using custom compiler: {}", compiler_string); self.compiler = compiler_string.to_string(); } } - self.compiler = default_compiler; } } diff --git a/src/interpreters/Sage_fifo.rs b/src/interpreters/Sage_fifo.rs index 5411f588..c7d9b439 100644 --- a/src/interpreters/Sage_fifo.rs +++ b/src/interpreters/Sage_fifo.rs @@ -216,6 +216,7 @@ impl Sage_fifo { fn fetch_config(&mut self) { let default_interpreter = String::from("sage"); + self.interpreter = default_interpreter; if let Some(used_interpreter) = Sage_fifo::get_interpreter_option(&self.get_data(), "interpreter") { @@ -224,7 +225,6 @@ impl Sage_fifo { self.interpreter = interpreter_string.to_string(); } } - self.interpreter = default_interpreter; if let Some(user_sage_config) = Sage_fifo::get_interpreter_option(&self.get_data(), "interpreter") { From 1934078a2abe743d243751914bbd18d9a3a1f078 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:04:13 +0100 Subject: [PATCH 12/19] add prolog interpreters --- doc/Prolog_gnu.md | 14 ++++ src/interpreters/Prolog_gnu.rs | 35 ++++++++-- src/interpreters/Prolog_swi.rs | 113 --------------------------------- 3 files changed, 43 insertions(+), 119 deletions(-) create mode 100644 doc/Prolog_gnu.md delete mode 100644 src/interpreters/Prolog_swi.rs diff --git a/doc/Prolog_gnu.md b/doc/Prolog_gnu.md new file mode 100644 index 00000000..cec7ca9d --- /dev/null +++ b/doc/Prolog_gnu.md @@ -0,0 +1,14 @@ +The Prolog interpreter supports setting a different compiler/interpreter for prolog such as swi ('swipl') + +you can set it with the following key: + + +``` +require'sniprun'.setup({ + interpreter_options = { + Prolog_gnu = { compiler = "swipl" } + } + } +}) +``` + diff --git a/src/interpreters/Prolog_gnu.rs b/src/interpreters/Prolog_gnu.rs index 78af7b1e..7755e019 100644 --- a/src/interpreters/Prolog_gnu.rs +++ b/src/interpreters/Prolog_gnu.rs @@ -6,6 +6,7 @@ pub struct Prolog_gnu { code: String, prolog_work_dir: String, main_file_path: String, + interpreter: String, } impl ReplLikeInterpreter for Prolog_gnu {} impl Interpreter for Prolog_gnu { @@ -23,6 +24,7 @@ impl Interpreter for Prolog_gnu { code: String::from(""), prolog_work_dir: bwd, main_file_path: mfp, + interpreter: String::new(), }) } fn get_name() -> String { @@ -52,6 +54,17 @@ impl Interpreter for Prolog_gnu { SupportLevel::Bloc } fn fetch_code(&mut self) -> Result<(), SniprunError> { + let default_interpreter = String::from("gprolog"); + self.interpreter = default_interpreter; + if let Some(used_interpreter) = + Python3_fifo::get_interpreter_option(&self.get_data(), "compiler") + { + if let Some(interpreter_string) = used_interpreter.as_str() { + info!("Using custom interpreter: {}", interpreter_string); + self.interpreter = interpreter_string.to_string(); + } + } + if !self .data .current_bloc @@ -80,12 +93,22 @@ impl Interpreter for Prolog_gnu { Ok(()) } fn execute(&mut self) -> Result { - let output = Command::new("gprolog") - .arg(String::from("--consult-file")) - .arg(&self.main_file_path) - .args(&self.get_data().cli_args) - .output() - .expect("Unable to start process"); + let output; + if self.interpreter != "gprolog" { + output = Command::new(self.interpreter.clone()) + .arg(&self.main_file_path) + .args(&self.get_data().cli_args) + .output() + .expect("Unable to start process"); + + } else { // special case for gprolog which needs the --consult-file arg + output = Command::new("gprolog") + .arg(String::from("--consult-file")) + .arg(&self.main_file_path) + .args(&self.get_data().cli_args) + .output() + .expect("Unable to start process"); + } info!("yay from gnu Prolog interpreter"); if output.status.success() { Ok(String::from_utf8(output.stdout).unwrap()) diff --git a/src/interpreters/Prolog_swi.rs b/src/interpreters/Prolog_swi.rs deleted file mode 100644 index 0043e210..00000000 --- a/src/interpreters/Prolog_swi.rs +++ /dev/null @@ -1,113 +0,0 @@ -#[derive(Clone)] -#[allow(non_camel_case_types)] -pub struct Prolog_swi { - support_level: SupportLevel, - data: DataHolder, - code: String, - prolog_work_dir: String, - main_file_path: String, -} -impl ReplLikeInterpreter for Prolog_swi {} -impl Interpreter for Prolog_swi { - fn new_with_level(data: DataHolder, level: SupportLevel) -> Box { - let bwd = data.work_dir.clone() + "/prolog-swi"; - let mut builder = DirBuilder::new(); - builder.recursive(true); - builder - .create(&bwd) - .expect("Could not create directory for prolog-swi"); - let mfp = bwd.clone() + "/main.pl"; - Box::new(Prolog_swi { - data, - support_level: level, - code: String::from(""), - prolog_work_dir: bwd, - main_file_path: mfp, - }) - } - fn get_name() -> String { - String::from("Prolog_swi") - } - fn get_supported_languages() -> Vec { - vec![String::from("Prolog"), String::from("prolog")] - } - fn get_current_level(&self) -> SupportLevel { - self.support_level - } - fn set_current_level(&mut self, level: SupportLevel) { - self.support_level = level - } - fn default_for_filetype() -> bool { - true - } - fn get_data(&self) -> DataHolder { - self.data.clone() - } - fn check_cli_args(&self) -> Result<(), SniprunError> { - // All cli arguments are sendable to python - // Though they will be ignored in REPL mode - Ok(()) - } - fn get_max_support_level() -> SupportLevel { - SupportLevel::Bloc - } - fn fetch_code(&mut self) -> Result<(), SniprunError> { - if !self - .data - .current_bloc - .replace(&[' ', '\t', '\n', '\r'][..], "") - .is_empty() - && self.get_current_level() >= SupportLevel::Bloc - { - self.code = self.data.current_bloc.clone(); - } else if !self.data.current_line.replace(" ", "").is_empty() - && self.get_current_level() >= SupportLevel::Line - { - self.code = self.data.current_line.clone(); - } else { - self.code = String::from(""); - } - Ok(()) - } - fn add_boilerplate(&mut self) -> Result<(), SniprunError> { - Ok(()) - } - fn build(&mut self) -> Result<(), SniprunError> { - let mut _file = - File::create(&self.main_file_path).expect("Failed to create file for prolog-swi"); - - write(&self.main_file_path, &self.code).expect("Unable to write to file for prolog-swi"); - Ok(()) - } - fn execute(&mut self) -> Result { - let output = Command::new("swipl") - .arg(&self.main_file_path) - .args(&self.get_data().cli_args) - .output() - .expect("Unable to start process"); - info!("yay from SWI Prolog interpreter"); - if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) - } else { - Err(SniprunError::RuntimeError( - String::from_utf8(output.stderr).unwrap(), - )) - } - } -} -#[cfg(test)] -mod test_prolog_swi { - use super::*; - - #[test] - fn simple_print() { - let mut data = DataHolder::new(); - data.current_bloc = String::from(":- write(ok), halt."); - let mut interpreter = Prolog_swi::new(data); - let res = interpreter.run(); - - // should panic if not an Ok() - let string_result = res.unwrap(); - assert_eq!(string_result, "ok"); - } -} From abb585688e1c897c1ed133113f235ab7c428f489 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:04:41 +0100 Subject: [PATCH 13/19] format --- src/display.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/display.rs b/src/display.rs index 188f06d7..a256493c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -231,17 +231,30 @@ pub fn display_terminal_with_code( let res = match message { Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", - cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\n" - })).replace("\n", "\\\n"), + cleanup_and_escape( + &data + .current_bloc + .lines() + .fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + }) + ) + .replace("\n", "\\\n"), no_output_wrap(result, data, &DisplayType::TerminalWithCode).replace("\n", "\\\n"), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", - cleanup_and_escape(&data.current_bloc.lines().fold("".to_string(), |cur_bloc, line_in_bloc| { - cur_bloc + "> " + line_in_bloc + "\n" - })).replace("\n", "\\\n"), - no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode).replace("\n", "\\\n"), + cleanup_and_escape( + &data + .current_bloc + .lines() + .fold("".to_string(), |cur_bloc, line_in_bloc| { + cur_bloc + "> " + line_in_bloc + "\n" + }) + ) + .replace("\n", "\\\n"), + no_output_wrap(&result.to_string(), data, &DisplayType::TerminalWithCode) + .replace("\n", "\\\n"), )), }; info!("display terminal res = {:?}", res); From 6cf619b7502c30bac3e83dcd09f82c49735396b9 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:11:33 +0100 Subject: [PATCH 14/19] add python3_fifo venv support & doc --- doc/Python3_fifo.md | 17 +++++++++++++++++ src/interpreters/Python3_fifo.rs | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/doc/Python3_fifo.md b/doc/Python3_fifo.md index f16d5bce..45e4c68b 100644 --- a/doc/Python3_fifo.md +++ b/doc/Python3_fifo.md @@ -17,3 +17,20 @@ require'sniprun'.setup({ ``` if a snippet produce an error important enough to crash the interpreter, you may be required to re-launch the kernel (with a `SnipRun`) + + +setting a custom python interpreter and venv is also supported + + +``` +require'sniprun'.setup({ + interpreter_options = { + Python3_fifo = { + intepreter = "python3.9", + venv = {"venv_project1", "venv_project2", "../venv_project2"}, + } + } + } +}) +``` + diff --git a/src/interpreters/Python3_fifo.rs b/src/interpreters/Python3_fifo.rs index 33fcc743..5180ba45 100644 --- a/src/interpreters/Python3_fifo.rs +++ b/src/interpreters/Python3_fifo.rs @@ -295,6 +295,25 @@ impl Interpreter for Python3_fifo { Ok(()) } fn add_boilerplate(&mut self) -> Result<(), SniprunError> { + if !self.imports.is_empty() { + let mut indented_imports = String::new(); + for import in self.imports.lines() { + indented_imports = indented_imports + "\t" + import + "\n"; + } + + self.imports = String::from("\ntry:\n") + &indented_imports + "\nexcept:\n\tpass\n"; + } + + let mut source_venv = String::new(); + if let Some(venv_path) = &self.venv { + info!("loading venv: {}", venv_path); + source_venv = source_venv + "\n" + "activate_this_file = \"" + venv_path + "\""; + source_venv += "\nexec(compile(open(activate_this_file, \"rb\").read(), activate_this_file, 'exec'), dict(__file__=activate_this_file))\n"; + } + + self.code = source_venv + + &self.imports.clone() + + &unindent(&format!("{}{}", "\n", self.code.as_str())); Ok(()) } fn build(&mut self) -> Result<(), SniprunError> { From 2118b53d71849c406d62a8eeee6d04f0ee87c47f Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:13:21 +0100 Subject: [PATCH 15/19] prolog compiler install in CI --- ressources/install_all_compilers_ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index 18e51678..07fd419c 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -14,5 +14,6 @@ sudo apt install scala pip3 install jupyter sudo apt install lua5.3 sudo apt install sagemath +sudo apt install gprolog ./ressources/go_install.sh export PATH=$PATH:$HOME/golang/go/bin/ From dc9f564afbe1f10c590d099175f4aebb0f232bd0 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:50:23 +0100 Subject: [PATCH 16/19] unindent code pasted in terminal --- src/display.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/display.rs b/src/display.rs index a256493c..37571ff2 100644 --- a/src/display.rs +++ b/src/display.rs @@ -5,6 +5,7 @@ use neovim_lib::{Neovim, NeovimApi}; use std::fmt; use std::str::FromStr; use std::sync::{Arc, Mutex}; +use unindent::Unindent; #[derive(Clone, Debug, Ord, PartialOrd, PartialEq, Eq)] pub enum DisplayType { @@ -232,8 +233,8 @@ pub fn display_terminal_with_code( Ok(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", cleanup_and_escape( - &data - .current_bloc + &format!("\n{}", &data.current_bloc) + .unindent() .lines() .fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" @@ -245,8 +246,8 @@ pub fn display_terminal_with_code( Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", false)", cleanup_and_escape( - &data - .current_bloc + &format!("\n{}", &data.current_bloc) + .unindent() .lines() .fold("".to_string(), |cur_bloc, line_in_bloc| { cur_bloc + "> " + line_in_bloc + "\n" From 66aaf2ffaf983ce6d3945891d0869237764c0fc6 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 19:51:50 +0100 Subject: [PATCH 17/19] version bump --- CHANGELOG.md | 6 ++++++ Cargo.lock | 10 +++++----- Cargo.toml | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ecf91b7..e28b26d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.1.0 +- TerminalWithCode display option (courtesy of @control13) +- Prolog interpreter +- Fix default interpreter issue +- Python3\_fifo venv support + doc + fix indented bloc failure + ## v1.0.6 - fix output with escape sequences diff --git a/Cargo.lock b/Cargo.lock index 75a922b1..fcf49a09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,9 +101,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.109" +version = "0.2.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01" +checksum = "8e167738f1866a7ec625567bae89ca0d44477232a4f7c52b1c7f2adc2c98804f" [[package]] name = "lock_api" @@ -259,9 +259,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254df5081ce98661a883445175e52efe99d1cb2a5552891d965d2f5d0cad1c16" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scopeguard" @@ -336,7 +336,7 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "sniprun" -version = "1.0.6" +version = "1.1.0" dependencies = [ "dirs", "libc", diff --git a/Cargo.toml b/Cargo.toml index 3745a343..24845c13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sniprun" -version = "1.0.6" +version = "1.1.0" authors = ["michaelb "] edition = "2018" From 0eaf6c14393ff6bf0b60f6ff9f91e03d5c67624f Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 20:09:57 +0100 Subject: [PATCH 18/19] disable test and put a notice for prolog usability --- doc/Prolog_gnu.md | 4 +++- src/interpreters/Prolog_gnu.rs | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/Prolog_gnu.md b/doc/Prolog_gnu.md index cec7ca9d..66a1ef4f 100644 --- a/doc/Prolog_gnu.md +++ b/doc/Prolog_gnu.md @@ -1,3 +1,5 @@ +This interpreter is currently a work in progress and is probably not usable + The Prolog interpreter supports setting a different compiler/interpreter for prolog such as swi ('swipl') you can set it with the following key: @@ -6,7 +8,7 @@ you can set it with the following key: ``` require'sniprun'.setup({ interpreter_options = { - Prolog_gnu = { compiler = "swipl" } + Prolog_gnu = { interpreter = "swipl" } } } }) diff --git a/src/interpreters/Prolog_gnu.rs b/src/interpreters/Prolog_gnu.rs index 7755e019..e30fdc44 100644 --- a/src/interpreters/Prolog_gnu.rs +++ b/src/interpreters/Prolog_gnu.rs @@ -46,8 +46,7 @@ impl Interpreter for Prolog_gnu { self.data.clone() } fn check_cli_args(&self) -> Result<(), SniprunError> { - // All cli arguments are sendable to python - // Though they will be ignored in REPL mode + // All cli arguments are sendable to the exe Ok(()) } fn get_max_support_level() -> SupportLevel { @@ -57,7 +56,7 @@ impl Interpreter for Prolog_gnu { let default_interpreter = String::from("gprolog"); self.interpreter = default_interpreter; if let Some(used_interpreter) = - Python3_fifo::get_interpreter_option(&self.get_data(), "compiler") + Python3_fifo::get_interpreter_option(&self.get_data(), "interpreter") { if let Some(interpreter_string) = used_interpreter.as_str() { info!("Using custom interpreter: {}", interpreter_string); @@ -123,7 +122,7 @@ impl Interpreter for Prolog_gnu { mod test_prolog_gnu { use super::*; - #[test] + // #[test] fn simple_print() { let mut data = DataHolder::new(); data.current_bloc = String::from(":- write(ok), halt."); From ee18e15fc79b2bfa18355e049c166857e20342f3 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 13 Dec 2021 20:10:37 +0100 Subject: [PATCH 19/19] remove prolog from changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e28b26d7..8c358f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ ## v1.1.0 - TerminalWithCode display option (courtesy of @control13) -- Prolog interpreter - Fix default interpreter issue - Python3\_fifo venv support + doc + fix indented bloc failure