diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ecf91b7..8c358f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v1.1.0 +- TerminalWithCode display option (courtesy of @control13) +- 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 e5eb5053..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.5" +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" 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/Prolog_gnu.md b/doc/Prolog_gnu.md new file mode 100644 index 00000000..66a1ef4f --- /dev/null +++ b/doc/Prolog_gnu.md @@ -0,0 +1,16 @@ +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: + + +``` +require'sniprun'.setup({ + interpreter_options = { + Prolog_gnu = { interpreter = "swipl" } + } + } +}) +``` + 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/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..479c6c81 100644 --- a/ressources/display_terminal.md +++ b/ressources/display_terminal.md @@ -29,3 +29,9 @@ EOF ![](visual_assets/terminal.png) +If you also want to print the code being executed to the 'terminal', then use `"TerminalWithCode"` instead in the 'display' key. + + + +![](visual_assets/terminalWithCode.png) + 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/ diff --git a/ressources/visual_assets/terminalWithCode.png b/ressources/visual_assets/terminalWithCode.png new file mode 100644 index 00000000..17b644cb Binary files /dev/null and b/ressources/visual_assets/terminalWithCode.png differ diff --git a/src/display.rs b/src/display.rs index cd0f3d31..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 { @@ -13,6 +14,7 @@ pub enum DisplayType { VirtualTextOk, VirtualTextErr, Terminal, + TerminalWithCode, LongTempFloatingWindow, TempFloatingWindow, Api, @@ -27,6 +29,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 +48,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", @@ -59,6 +63,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 { @@ -66,6 +75,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), @@ -198,14 +208,54 @@ 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)", - 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); +} + +pub fn display_terminal_with_code( + message: &Result, + nvim: &Arc>, + data: &DataHolder, +) { + let res = match message { + Ok(result) => nvim.lock().unwrap().command(&format!( + "lua require\"sniprun.display\".write_to_term(\"{}\\n{}\", true)", + cleanup_and_escape( + &format!("\n{}", &data.current_bloc) + .unindent() + .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( + &format!("\n{}", &data.current_bloc) + .unindent() + .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); 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/Prolog_gnu.rs b/src/interpreters/Prolog_gnu.rs new file mode 100644 index 00000000..e30fdc44 --- /dev/null +++ b/src/interpreters/Prolog_gnu.rs @@ -0,0 +1,136 @@ +#[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, + interpreter: 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, + interpreter: String::new(), + }) + } + 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 the exe + Ok(()) + } + fn get_max_support_level() -> SupportLevel { + 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(), "interpreter") + { + 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 + .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; + 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()) + } 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"); + } +} diff --git a/src/interpreters/Python3_fifo.rs b/src/interpreters/Python3_fifo.rs index 0d15756f..5180ba45 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) = @@ -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> { 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") { 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"),