From 9fcc0339dc1fe34383fb9ad4db8f1b207f24d117 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Sat, 5 Feb 2022 18:14:35 +0100 Subject: [PATCH 01/16] F# bloc level support --- Cargo.lock | 2 +- Cargo.toml | 2 +- doc/FSharp_Original.md | 1 + src/interpreters/FSharp_fifo.rs | 390 ++++++++++++++++++++++++++++++++ 4 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 doc/FSharp_Original.md create mode 100644 src/interpreters/FSharp_fifo.rs diff --git a/Cargo.lock b/Cargo.lock index e22ec2cc..43165a68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,7 +336,7 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "sniprun" -version = "1.1.2" +version = "1.2.0" dependencies = [ "dirs", "libc", diff --git a/Cargo.toml b/Cargo.toml index 35cf7aab..f69bcd0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sniprun" -version = "1.2" +version = "1.2.0" authors = ["michaelb "] edition = "2018" diff --git a/doc/FSharp_Original.md b/doc/FSharp_Original.md new file mode 100644 index 00000000..4bdc7d06 --- /dev/null +++ b/doc/FSharp_Original.md @@ -0,0 +1 @@ +# This interpreter relies on dotnet fsi being available and on your path diff --git a/src/interpreters/FSharp_fifo.rs b/src/interpreters/FSharp_fifo.rs new file mode 100644 index 00000000..4f6e24ee --- /dev/null +++ b/src/interpreters/FSharp_fifo.rs @@ -0,0 +1,390 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct FSharp_fifo { + support_level: SupportLevel, + data: DataHolder, + code: String, + main_file_path: String, + plugin_root: String, + cache_dir: String, + + interpreter: String, + current_output_id: u32, +} + +impl FSharp_fifo { + fn wait_out_file( + &self, + out_path: String, + err_path: String, + id: u32, + ) -> Result { + let end_mark = String::from("sniprun_finished_id=") + &id.to_string() + "\n"; + let start_mark = String::from("sniprun_started_id=") + &id.to_string(); + + info!( + "searching for things between {:?} and {:?}", + start_mark, end_mark + ); + + let mut out_contents = String::new(); + let mut err_contents = String::new(); + + let mut pause = std::time::Duration::from_millis(50); + let start = std::time::Instant::now(); + loop { + std::thread::sleep(pause); + pause = pause.saturating_add(std::time::Duration::from_millis(50)); + + // timeout after 30s if no result found + if start.elapsed().as_secs() > 30 { + return Err(SniprunError::InterpreterLimitationError(String::from( + "reached the 30s timeout", + ))); + } + + // FSharp_fifo-specific things to workaround nonblocking plot issues + if start.elapsed().as_millis() > 150 { + let sync_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/sync_repl.sh"; + let res = Command::new(sync_repl_cmd) + .arg(self.cache_dir.clone()) + .output(); + info!( + "had to sync the repl because of timeout on awaiting result:\ + happens when a blocking command (plot, infinite loop) is run: {:?}", + res + ); + } + + //check for stderr first + if let Ok(mut file) = std::fs::File::open(&err_path) { + info!("errfile exists"); + out_contents.clear(); + let res = file.read_to_string(&mut err_contents); + if res.is_ok() { + info!("errfile could be read : {:?}", err_contents); + // info!("file : {:?}", contents); + if err_contents.contains(&end_mark) { + if let Some(index) = err_contents.rfind(&start_mark) { + let mut err_to_display = err_contents + [index + start_mark.len()..err_contents.len() - end_mark.len() - 1] + .to_owned(); + info!("err to display : {:?}", err_to_display); + if !err_to_display.trim().is_empty() { + info!("err found"); + if err_to_display.lines().count() > 2 { + let mut err_to_display_vec = + err_to_display.lines().skip(2).collect::>(); + err_to_display_vec.dedup(); + err_to_display = err_to_display_vec.join("\n"); + } + + return Err(SniprunError::RuntimeError(err_to_display)); + } + } + } + } + } + + //check for stdout + if let Ok(mut file) = std::fs::File::open(&out_path) { + info!("file exists"); + out_contents.clear(); + let res = file.read_to_string(&mut out_contents); + if res.is_ok() { + info!("file could be read : {:?}", out_contents); + // info!("file : {:?}", contents); + if out_contents.contains(&end_mark) { + info!("out found"); + let index = out_contents.rfind(&start_mark).unwrap(); + return Ok(out_contents + [index + start_mark.len()..out_contents.len() - end_mark.len() - 1] + .to_owned()); + } + } + } + + info!("not found yet"); + } + } + + fn get_nvim_pid(data: &DataHolder) -> String { + data.nvim_pid.to_string() + } + + fn fetch_config(&mut self) { + let default_interpreter = String::from("dotnet fsi --nologo"); + self.interpreter = default_interpreter; + if let Some(used_interpreter) = + FSharp_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(); + } + } + } +} + +impl Interpreter for FSharp_fifo { + fn new_with_level(data: DataHolder, level: SupportLevel) -> Box { + //create a subfolder in the cache folder + let rwd = data.work_dir.clone() + "/fsharp_fifo"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&rwd) + .expect("Could not create directory for fsharp-fifo"); + + //pre-create string pointing to main file's and binary's path + let mfp = rwd.clone() + "/main.fsx"; + + let pgr = data.sniprun_root_dir.clone(); + Box::new(FSharp_fifo { + cache_dir: rwd + "/" + &FSharp_fifo::get_nvim_pid(&data), + data, + support_level: level, + code: String::from(""), + main_file_path: mfp, + plugin_root: pgr, + current_output_id: 0, + interpreter: String::new(), + }) + } + + fn get_name() -> String { + String::from("FSharp_fifo") + } + + fn default_for_filetype() -> bool { + false + } + + fn behave_repl_like_default() -> bool { + false + } + + fn has_repl_capability() -> bool { + false + } + + fn get_supported_languages() -> Vec { + vec![String::from("F#"), String::from("fsx"), String::from("fs")] + } + + fn get_current_level(&self) -> SupportLevel { + self.support_level + } + fn set_current_level(&mut self, level: SupportLevel) { + self.support_level = level; + } + + fn get_data(&self) -> DataHolder { + self.data.clone() + } + + fn get_max_support_level() -> SupportLevel { + SupportLevel::Bloc + } + + fn fetch_code(&mut self) -> Result<(), SniprunError> { + self.fetch_config(); + 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> { + write(&self.main_file_path, &self.code).expect("Unable to write to file for fsharp_fifo"); + Ok(()) + } + fn execute(&mut self) -> Result { + let output = Command::new(self.interpreter.split_whitespace().next().unwrap()) + .args(self.interpreter.split_whitespace().skip(1)) + .arg(&self.interpreter) + .arg(&self.main_file_path) + .args(&self.get_data().cli_args) + .output() + .expect("Unable to start process"); + if output.status.success() { + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + return Err(SniprunError::RuntimeError( + String::from_utf8(output.stderr.clone()) + .unwrap() + .lines() + .last() + .unwrap_or(&String::from_utf8(output.stderr).unwrap()) + .to_owned(), + )); + } + } +} + +impl ReplLikeInterpreter for FSharp_fifo { + fn fetch_code_repl(&mut self) -> Result<(), SniprunError> { + if !self.read_previous_code().is_empty() { + // nothing to do, kernel already running + info!("fsi kernel already running"); + + if let Some(id) = self.get_pid() { + // there is a race condition here but honestly you'd have to + // trigger it on purpose + self.current_output_id = id + 1; + self.set_pid(self.current_output_id); + } else { + info!("Could not retrieve a previous id even if the kernel is running"); + info!("This was in saved code: {}", self.read_previous_code()); + return Err(SniprunError::CustomError( + "Sniprun failed to connect to the running kernel, please SnipReset".to_string(), + )); + } + + self.fetch_code()?; + Ok(()) + } else { + self.fetch_config(); + // launch everything + self.set_pid(0); + + let init_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/init_repl.sh"; + info!( + "launching kernel : {:?} on {:?}", + init_repl_cmd, &self.cache_dir + ); + + match daemon() { + Ok(Fork::Child) => { + let _res = Command::new("bash") + .args(&[ + init_repl_cmd, + self.cache_dir.clone(), + self.interpreter.clone() + " --nologo ", + ]) + .output() + .unwrap(); + let pause = std::time::Duration::from_millis(36_000_000); + std::thread::sleep(pause); + + return Err(SniprunError::CustomError( + "Timeout expired for dotnet fsi REPL".to_owned(), + )); + } + Ok(Fork::Parent(_)) => {} + Err(_) => info!( + "FSharp_fifo could not fork itself to the background to launch the kernel" + ), + }; + + self.save_code("kernel_launched\n".to_owned()); + + let pause = std::time::Duration::from_millis(2000); // prevent an user from re-running the snippet + // before dotnet launches (2-3 secs) + std::thread::sleep(pause); + Err(SniprunError::CustomError( + "F# interactive kernel launched, re-run your snippet".to_owned(), + )) + } + } + + fn add_boilerplate_repl(&mut self) -> Result<(), SniprunError> { + self.add_boilerplate()?; + let start_mark = String::from("\nprint(\"sniprun_started_id=") + + &self.current_output_id.to_string() + + "\")\n"; + let end_mark = String::from("\nprint(\"sniprun_finished_id=") + + &self.current_output_id.to_string() + + "\")\n"; + let start_mark_err = String::from("\nprint(\"sniprun_started_id=") + + &self.current_output_id.to_string() + + "\", file=sys.stderr)\n"; + let end_mark_err = String::from("\nprint(\"sniprun_finished_id=") + + &self.current_output_id.to_string() + + "\", file=sys.stderr)\n"; + + // remove empty lines interpreted as 'enter' by the repl + self.code = self + .code + .lines() + .filter(|l| !l.trim().is_empty()) + .collect::>() + .join("\n") + .replace("#\n#", "\n"); + + let all_code = String::from("\n") + &self.code + "\n\n"; + self.code = start_mark + &start_mark_err + &all_code + &end_mark + &end_mark_err; + Ok(()) + } + + fn build_repl(&mut self) -> Result<(), SniprunError> { + self.build() + } + + fn execute_repl(&mut self) -> Result { + let send_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/launcher_repl.sh"; + info!("running launcher {}", send_repl_cmd); + let res = Command::new(send_repl_cmd) + .arg(self.main_file_path.clone()) + .arg(self.cache_dir.clone() + "/fifo_repl/pipe_in") + .spawn(); + info!("cmd status: {:?}", res); + res.expect("could not run launcher"); + // info!("launcher launched : {:?}", res); + + let outfile = self.cache_dir.clone() + "/fifo_repl/out_file"; + let errfile = self.cache_dir.clone() + "/fifo_repl/err_file"; + info!("outfile : {:?}", outfile); + self.wait_out_file(outfile, errfile, self.current_output_id) + } +} + +#[cfg(test)] +mod test_fsharp_fifo { + use super::*; + + use serial_test::serial; + + #[test] + #[serial(pythonfifo)] + fn simple_print() { + let mut data = DataHolder::new(); + data.current_bloc = String::from("print(\"lol\",1);"); + let mut interpreter = FSharp_fifo::new(data); + let res = interpreter.run_at_level_repl(SupportLevel::Bloc); + assert!(res.is_err()); + } + + #[test] + #[serial(pythonfifo)] + fn print_quote() { + let mut data = DataHolder::new(); + data.current_bloc = String::from("print(\"->\\\"\",1);"); + let mut interpreter = FSharp_fifo::new(data); + let res = interpreter.run_at_level_repl(SupportLevel::Bloc); + assert!(res.is_err()); + } + + #[test] + fn module_usage() { + let data = DataHolder::new(); + let interpreter = FSharp_fifo::new(data); + assert!(interpreter.module_used("import numpy as np", "print(np.array([1,2,3]))")); + assert!(!interpreter.module_used("import numpy", "print(np.array([1,2,3]))")); + } +} From 192980752700972edd8164c3398c5c2cccea26cb Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Sat, 5 Feb 2022 19:05:03 +0100 Subject: [PATCH 02/16] F# repl not working yet... --- src/interpreters/FSharp_fifo.rs | 64 ++++++++------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/src/interpreters/FSharp_fifo.rs b/src/interpreters/FSharp_fifo.rs index 4f6e24ee..a637a5b4 100644 --- a/src/interpreters/FSharp_fifo.rs +++ b/src/interpreters/FSharp_fifo.rs @@ -43,19 +43,6 @@ impl FSharp_fifo { ))); } - // FSharp_fifo-specific things to workaround nonblocking plot issues - if start.elapsed().as_millis() > 150 { - let sync_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/sync_repl.sh"; - let res = Command::new(sync_repl_cmd) - .arg(self.cache_dir.clone()) - .output(); - info!( - "had to sync the repl because of timeout on awaiting result:\ - happens when a blocking command (plot, infinite loop) is run: {:?}", - res - ); - } - //check for stderr first if let Ok(mut file) = std::fs::File::open(&err_path) { info!("errfile exists"); @@ -165,7 +152,7 @@ impl Interpreter for FSharp_fifo { } fn has_repl_capability() -> bool { - false + true } fn get_supported_languages() -> Vec { @@ -275,7 +262,7 @@ impl ReplLikeInterpreter for FSharp_fifo { .args(&[ init_repl_cmd, self.cache_dir.clone(), - self.interpreter.clone() + " --nologo ", + self.interpreter.clone(), ]) .output() .unwrap(); @@ -305,18 +292,18 @@ impl ReplLikeInterpreter for FSharp_fifo { fn add_boilerplate_repl(&mut self) -> Result<(), SniprunError> { self.add_boilerplate()?; - let start_mark = String::from("\nprint(\"sniprun_started_id=") + let start_mark = String::from("\nprintfn \"sniprun_started_id=") + &self.current_output_id.to_string() - + "\")\n"; - let end_mark = String::from("\nprint(\"sniprun_finished_id=") + + "\"\n"; + let end_mark = String::from("\nprintfn \"sniprun_finished_id=") + &self.current_output_id.to_string() - + "\")\n"; - let start_mark_err = String::from("\nprint(\"sniprun_started_id=") + + "\"\n"; + let start_mark_err = String::from("\neprintfn \"sniprun_started_id=") + &self.current_output_id.to_string() - + "\", file=sys.stderr)\n"; - let end_mark_err = String::from("\nprint(\"sniprun_finished_id=") + + "\" \n"; + let end_mark_err = String::from("\neprintfn \"sniprun_finished_id=") + &self.current_output_id.to_string() - + "\", file=sys.stderr)\n"; + + "\"\n"; // remove empty lines interpreted as 'enter' by the repl self.code = self @@ -324,8 +311,7 @@ impl ReplLikeInterpreter for FSharp_fifo { .lines() .filter(|l| !l.trim().is_empty()) .collect::>() - .join("\n") - .replace("#\n#", "\n"); + .join("\n"); let all_code = String::from("\n") + &self.code + "\n\n"; self.code = start_mark + &start_mark_err + &all_code + &end_mark + &end_mark_err; @@ -337,6 +323,7 @@ impl ReplLikeInterpreter for FSharp_fifo { } fn execute_repl(&mut self) -> Result { + let send_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/launcher_repl.sh"; info!("running launcher {}", send_repl_cmd); let res = Command::new(send_repl_cmd) @@ -358,33 +345,12 @@ impl ReplLikeInterpreter for FSharp_fifo { mod test_fsharp_fifo { use super::*; - use serial_test::serial; - #[test] - #[serial(pythonfifo)] fn simple_print() { let mut data = DataHolder::new(); - data.current_bloc = String::from("print(\"lol\",1);"); - let mut interpreter = FSharp_fifo::new(data); - let res = interpreter.run_at_level_repl(SupportLevel::Bloc); - assert!(res.is_err()); - } - - #[test] - #[serial(pythonfifo)] - fn print_quote() { - let mut data = DataHolder::new(); - data.current_bloc = String::from("print(\"->\\\"\",1);"); + data.current_bloc = String::from("printfn \"lol\""); let mut interpreter = FSharp_fifo::new(data); - let res = interpreter.run_at_level_repl(SupportLevel::Bloc); - assert!(res.is_err()); - } - - #[test] - fn module_usage() { - let data = DataHolder::new(); - let interpreter = FSharp_fifo::new(data); - assert!(interpreter.module_used("import numpy as np", "print(np.array([1,2,3]))")); - assert!(!interpreter.module_used("import numpy", "print(np.array([1,2,3]))")); + let res = interpreter.run_at_level(SupportLevel::Bloc); + assert!(res.is_ok()); } } From ad835e095a806c0504dd1ca53611f08c21687876 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Sun, 6 Feb 2022 16:16:43 +0100 Subject: [PATCH 03/16] F# support --- CHANGELOG.md | 3 +++ README.md | 1 + doc/FSharp_Original.md | 60 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1f29fa6..99d00b05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v1.2.1 +- F# support + ## v1.2 - Live mode (a @ChristianChiarulli idea and partial realisation) - Lower ressources usage for REPL interpreters diff --git a/README.md b/README.md index 3028da05..ce1a8eb7 100755 --- a/README.md +++ b/README.md @@ -431,6 +431,7 @@ println!("-> {}", alphabet); | C++ | Import | No | | Coffeescript | Bloc | No | | D | Bloc | No | +| F# | Bloc | No, but _could_ \*\* | | Go | Bloc | No | | Haskell | Line | No | | Java | Bloc | No | diff --git a/doc/FSharp_Original.md b/doc/FSharp_Original.md index 4bdc7d06..37592088 100644 --- a/doc/FSharp_Original.md +++ b/doc/FSharp_Original.md @@ -1 +1,61 @@ # This interpreter relies on dotnet fsi being available and on your path + + +The default interpreter command is `dotnet fsi --nologo` but it can be changed via the configuration key + + +``` +require'sniprun'.setup({ + interpreter_options = { + FSharp_fifo = { + interpreter = "...." + } + } + } +}) +``` + + +### REPL (would solve slowness issues) + +For now, REPL is broken due to dotnet fsi being capricious about its stdin. + +I'll explain rapidly how sniprun implement a REPL interpreter around named pipes (FIFOs). + +The first time a fifo-based interpreter receive a run command, it forks to the background and executes `ressources/init_repl.sh`. +There is a lot of thing in that script but to replicate, you just have to: + + + +- `mkfifo pipe_in` + +- create a launcher script: + +```bash +#!/bin/bash +/bin/cat pipe_in | dotnet fsi + +# or replace 'dotnet fsi' by whatever you cant to try +``` + +- launch it in the background: `bash ./launcher.sh &`, (or `bash ./launcher.sh > out.txt & ` to redirect stdout to out.txt like sniprun does) + +- ensure the pipe will stay open: `sleep 3600 > pipe_in &` (cat, exec 3> variations will also work) + +- `echo "printfn \" hey \" " > pipe_in` or `cat hello_world.fsx > pipe_in` + +- normally, the result should be printed in the terminal that ran the launcher, or in the out file. + + + + +#### The issue: + +right now, dotnet fsi looks like it's blocked by the first sleep > pipe_in... but something **has** to keep the pipe open or when it closes, the fsi REPL reading from that will exit. + +I suspect the thing has something to do with interactive mode. + +For example, `python` has a similar problem, but `python -i ` (forced interactive mode, even if no terminal is detected because it runs in the background / its stdin was hijacked) works fine in the above example. + +If you find something to replace dotnet fsi with, that exhibits the same correct behavior as `python -i`, sniprun REPL mode _should_ work. + From 39a4f445bd20d71b9d92a56a63376531ed327624 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Sun, 6 Feb 2022 16:20:02 +0100 Subject: [PATCH 04/16] add test for fsharp interpreter --- src/interpreters/FSharp_fifo.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/interpreters/FSharp_fifo.rs b/src/interpreters/FSharp_fifo.rs index a637a5b4..135c0a82 100644 --- a/src/interpreters/FSharp_fifo.rs +++ b/src/interpreters/FSharp_fifo.rs @@ -351,6 +351,8 @@ mod test_fsharp_fifo { data.current_bloc = String::from("printfn \"lol\""); let mut interpreter = FSharp_fifo::new(data); let res = interpreter.run_at_level(SupportLevel::Bloc); - assert!(res.is_ok()); + // should panic if not an Ok() + let string_result = res.unwrap(); + assert_eq!(string_result, "lol\n"); } } From 6802eb3a5465eb320d8ecc2e7fae502c77500522 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Sun, 6 Feb 2022 16:21:15 +0100 Subject: [PATCH 05/16] add installer for dotnet 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 07fd419c..789db8b0 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -15,5 +15,6 @@ pip3 install jupyter sudo apt install lua5.3 sudo apt install sagemath sudo apt install gprolog +sudo apt install dotnet ./ressources/go_install.sh export PATH=$PATH:$HOME/golang/go/bin/ From 6ab45c16c8e951ee609e069cc4435c91c9515e8e Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Tue, 8 Feb 2022 22:04:00 +0100 Subject: [PATCH 06/16] fix multiline output in floating windows --- CHANGELOG.md | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- src/display.rs | 6 +++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d00b05..8971d640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## v1.2.1 - F# support +- Fix multiline display in floating windows ## v1.2 - Live mode (a @ChristianChiarulli idea and partial realisation) diff --git a/Cargo.lock b/Cargo.lock index 43165a68..8e66862c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,7 +336,7 @@ checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "sniprun" -version = "1.2.0" +version = "1.2.1" dependencies = [ "dirs", "libc", diff --git a/Cargo.toml b/Cargo.toml index f69bcd0a..5bbe397b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sniprun" -version = "1.2.0" +version = "1.2.1" authors = ["michaelb "] edition = "2018" diff --git a/src/display.rs b/src/display.rs index edd1dd91..fc77efbd 100644 --- a/src/display.rs +++ b/src/display.rs @@ -307,16 +307,16 @@ pub fn display_floating_window( "lua require\"sniprun.display\".fw_open({},{},\"{}\", true)", row - 1, col, - no_output_wrap(result, data, &DisplayType::TempFloatingWindow), + no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow).replace("\n", "\\\n"), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".fw_open({},{},\"{}\", false)", row - 1, col, - no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow), + no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow).replace("\n", "\\\n"), )), }; - info!("disaply floating window res = {:?}", res); + info!("display floating window res = {:?}", res); } pub fn return_message_classic( From 12a1d02071c09c301ca758e143581077f38f1cff Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Tue, 8 Feb 2022 22:26:28 +0100 Subject: [PATCH 07/16] bloc-level support for deno --- src/interpreters/JS_TS_deno.rs | 157 ++++++++++++++++++++++++ src/interpreters/TypeScript_original.rs | 1 - 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/interpreters/JS_TS_deno.rs diff --git a/src/interpreters/JS_TS_deno.rs b/src/interpreters/JS_TS_deno.rs new file mode 100644 index 00000000..8d1224ae --- /dev/null +++ b/src/interpreters/JS_TS_deno.rs @@ -0,0 +1,157 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct JS_TS_deno { + support_level: SupportLevel, + data: DataHolder, + code: String, + + language_work_dir: String, + main_file_path: String, +} + +impl ReplLikeInterpreter for JS_TS_deno {} + +impl Interpreter for JS_TS_deno { + fn new_with_level(data: DataHolder, support_level: SupportLevel) -> Box { + //create a subfolder in the cache folder + let lwd = data.work_dir.clone() + "/js-ts_deno"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&lwd) + .expect("Could not create directory for example"); + + //pre-create string pointing to main file's and binary's path + let mfp = lwd.clone() + "/main.ts"; + Box::new(JS_TS_deno { + data, + support_level, + code: String::new(), + language_work_dir: lwd, + main_file_path: mfp, + }) + } + + fn get_supported_languages() -> Vec { + vec![ + String::from("TS/JS via Deno"), // in 1st position of vector, used for info only + //':set ft?' in nvim to get the filetype of opened file + String::from("typescript"), + String::from("typescriptreact"), + String::from("ts"), //should not be necessary, but just in case + String::from("js"), + String::from("javascript"), + ] + } + + fn get_name() -> String { + // get your interpreter name + String::from("JS_TS_deno") + } + + 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 { + false + } + fn get_data(&self) -> DataHolder { + self.data.clone() + } + + fn get_max_support_level() -> SupportLevel { + //define the max level support of the interpreter (see readme for definitions) + SupportLevel::Bloc + } + + + fn fetch_code(&mut self) -> Result<(), SniprunError> { + //note: you probably don't have to modify, or even understand this function + + //here if you detect conditions that make higher support level impossible, + //or unecessary, you should set the current level down. Then you will be able to + //ignore maybe-heavy code that won't be needed anyway + + //add code from data to self.code + if !self + .data + .current_bloc + .replace(&[' ', '\t', '\n', '\r'][..], "") + .is_empty() + && self.support_level >= SupportLevel::Bloc + { + self.code = self.data.current_bloc.clone(); + } else if !self.data.current_line.replace(" ", "").is_empty() + && self.support_level >= SupportLevel::Line + { + self.code = self.data.current_line.clone(); + } else { + // no code was retrieved + self.code = String::from(""); + } + + // now self.code contains the line or bloc of code wanted :-) + info!("Typescript self.code) = {}", self.code); + Ok(()) + } + + fn add_boilerplate(&mut self) -> Result<(), SniprunError> { + Ok(()) + } + + fn build(&mut self) -> Result<(), SniprunError> { + //write code to file + let mut _file = File::create(&self.main_file_path).expect("failed to create file for typescript_original"); + // io errors can be ignored, or handled into a proper sniprunerror + // if you panic, it should not be too dangerous for anyone + write(&self.main_file_path, &self.code) + .expect("unable to write to file for typescript_original"); + + Ok(()) + } + + fn execute(&mut self) -> Result { + //run th binary and get the std output (or stderr) + let output = Command::new("deno") + .arg("run") + .arg("-A") + .arg("--unstable") + .arg(&self.main_file_path) + .output() + .expect("Unable to start process"); + + if output.status.success() { + //return stdout + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + // return stderr + Err(SniprunError::RuntimeError( + String::from_utf8(output.stderr).unwrap(), + )) + } + } +} + +#[cfg(test)] +mod test_ts_js_deno_original { + use super::*; + #[test] + fn simple_print() { + let mut data = DataHolder::new(); + + //inspired from Rust syntax + data.current_bloc = String::from("let message: string = 'Hi';\nconsole.log(message);"); + let mut interpreter = JS_TS_deno::new(data); + let res = interpreter.run(); + + // -> should panic if not an Ok() + let string_result = res.unwrap(); + + // -> compare result with predicted + assert_eq!(string_result, "Hi\n"); + } +} diff --git a/src/interpreters/TypeScript_original.rs b/src/interpreters/TypeScript_original.rs index 754a3076..955b19e6 100644 --- a/src/interpreters/TypeScript_original.rs +++ b/src/interpreters/TypeScript_original.rs @@ -137,7 +137,6 @@ impl Interpreter for TypeScript_original { mod test_typescript_original { use super::*; #[test] - #[cfg_attr(feature = "ignore_in_ci", ignore)] fn simple_print() { let mut data = DataHolder::new(); From 8a95cdf045b30a0dde1444a01f51a05afb026d20 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Tue, 8 Feb 2022 23:28:56 +0100 Subject: [PATCH 08/16] deno REPL mode --- CHANGELOG.md | 1 + README.md | 5 +- ressources/install_all_compilers_ci.sh | 3 + src/interpreters/JS_TS_deno.rs | 241 ++++++++++++++++++++++++- 4 files changed, 240 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8971d640..daac6a5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## v1.2.1 - F# support - Fix multiline display in floating windows +- Deno brings REPL support for Javascript and TypeScript ## v1.2 - Live mode (a @ChristianChiarulli idea and partial realisation) diff --git a/README.md b/README.md index ce1a8eb7..6e25141f 100755 --- a/README.md +++ b/README.md @@ -435,7 +435,7 @@ println!("-> {}", alphabet); | Go | Bloc | No | | Haskell | Line | No | | Java | Bloc | No | -| JavaScript | Bloc | No | +| JavaScript | Bloc | Yes\*\* (Deno)| | Julia | Bloc | Yes\*\* | | Lua | Bloc | No | | Lua-nvim | Bloc | Yes\*\* | @@ -449,8 +449,7 @@ println!("-> {}", alphabet); | Rust | Bloc | No | | SageMath | Import | Yes\*\* | | Scala | Bloc | No | -| TypeScript | Bloc | No | - +| TypeScript | Bloc | Yes\*\* (Deno)| Want support for your language? Submit an [issue](https://github.com/michaelb/sniprun/issues/new?assignees=&labels=new-langage-support&template=support-for--language-.md&title=), or even better, [contribute](CONTRIBUTING.md), it's easy! diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index 789db8b0..c4e80641 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -18,3 +18,6 @@ sudo apt install gprolog sudo apt install dotnet ./ressources/go_install.sh export PATH=$PATH:$HOME/golang/go/bin/ + +# deno for typescript and javascript +curl -fsSL https://deno.land/x/install/install.sh | sh diff --git a/src/interpreters/JS_TS_deno.rs b/src/interpreters/JS_TS_deno.rs index 8d1224ae..22c1668a 100644 --- a/src/interpreters/JS_TS_deno.rs +++ b/src/interpreters/JS_TS_deno.rs @@ -4,12 +4,102 @@ pub struct JS_TS_deno { support_level: SupportLevel, data: DataHolder, code: String, + cache_dir: String, + current_output_id: u32, language_work_dir: String, main_file_path: String, } -impl ReplLikeInterpreter for JS_TS_deno {} +impl JS_TS_deno { + fn wait_out_file( + &self, + out_path: String, + err_path: String, + id: u32, + ) -> Result { + let end_mark = String::from("sniprun_finished_id=") + &id.to_string(); + let start_mark = String::from("sniprun_started_id=") + &id.to_string(); + + info!( + "searching for things between {:?} and {:?}", + start_mark, end_mark + ); + + let mut out_contents = String::new(); + let mut err_contents = String::new(); + + let mut pause = std::time::Duration::from_millis(50); + let start = std::time::Instant::now(); + loop { + std::thread::sleep(pause); + pause = pause.saturating_add(std::time::Duration::from_millis(50)); + + // timeout after 30s if no result found + if start.elapsed().as_secs() > 30 { + return Err(SniprunError::InterpreterLimitationError(String::from( + "reached the 30s timeout", + ))); + } + + //check for stderr first + if let Ok(mut file) = std::fs::File::open(&err_path) { + info!("errfile exists"); + out_contents.clear(); + let res = file.read_to_string(&mut err_contents); + if res.is_ok() { + // info!("errfile could be read : {:?}", err_contents); + if err_contents.contains(&end_mark) { + if let Some(index) = err_contents.rfind(&start_mark) { + let mut err_to_display = err_contents + [index + start_mark.len()..err_contents.len() - end_mark.len() - 1] + .to_owned(); + info!("err to display : {:?}", err_to_display); + if !err_to_display.trim().is_empty() { + info!("err found"); + if err_to_display.lines().count() > 2 { + let mut err_to_display_vec = + err_to_display.lines().skip(2).collect::>(); + err_to_display_vec.dedup(); + err_to_display = err_to_display_vec.join("\n"); + } + + return Err(SniprunError::RuntimeError(err_to_display)); + } + } + } + } + } + + //check for stdout + if let Ok(mut file) = std::fs::File::open(&out_path) { + info!("file exists"); + out_contents.clear(); + let res = file.read_to_string(&mut out_contents); + if res.is_ok() { + // info!("out {}", out_contents); + let relevant_content: String = out_contents + .lines() + .filter(|l| !l.contains("undefined")) + .collect::>() + .join("\n"); + info!("relevant {}", relevant_content); + info!("file could be read : {:?}", relevant_content); + // info!("file : {:?}", contents); + if relevant_content.contains(&end_mark) { + info!("out found"); + let index = relevant_content.rfind(&start_mark).unwrap(); + return Ok(relevant_content[index + start_mark.len() + ..relevant_content.len() - end_mark.len() - 1] + .to_owned()); + } + } + } + + info!("not found yet"); + } + } +} impl Interpreter for JS_TS_deno { fn new_with_level(data: DataHolder, support_level: SupportLevel) -> Box { @@ -24,11 +114,13 @@ impl Interpreter for JS_TS_deno { //pre-create string pointing to main file's and binary's path let mfp = lwd.clone() + "/main.ts"; Box::new(JS_TS_deno { + cache_dir: lwd.clone() + "/" + &Python3_fifo::get_nvim_pid(&data), data, support_level, code: String::new(), language_work_dir: lwd, main_file_path: mfp, + current_output_id: 0, }) } @@ -68,6 +160,13 @@ impl Interpreter for JS_TS_deno { SupportLevel::Bloc } + fn behave_repl_like_default() -> bool { + true + } + + fn has_repl_capability() -> bool { + true + } fn fetch_code(&mut self) -> Result<(), SniprunError> { //note: you probably don't have to modify, or even understand this function @@ -95,7 +194,7 @@ impl Interpreter for JS_TS_deno { } // now self.code contains the line or bloc of code wanted :-) - info!("Typescript self.code) = {}", self.code); + info!("javascript/typescript self.code) = {}", self.code); Ok(()) } @@ -105,11 +204,11 @@ impl Interpreter for JS_TS_deno { fn build(&mut self) -> Result<(), SniprunError> { //write code to file - let mut _file = File::create(&self.main_file_path).expect("failed to create file for typescript_original"); + let mut _file = + File::create(&self.main_file_path).expect("failed to create file for js_ts_deno"); // io errors can be ignored, or handled into a proper sniprunerror // if you panic, it should not be too dangerous for anyone - write(&self.main_file_path, &self.code) - .expect("unable to write to file for typescript_original"); + write(&self.main_file_path, &self.code).expect("unable to write to file for js_ts_deno"); Ok(()) } @@ -136,17 +235,136 @@ impl Interpreter for JS_TS_deno { } } +impl ReplLikeInterpreter for JS_TS_deno { + fn fetch_code_repl(&mut self) -> Result<(), SniprunError> { + if !self.read_previous_code().is_empty() { + // nothing to do, kernel already running + info!("Deno kernel already running"); + + if let Some(id) = self.get_pid() { + // there is a race condition here but honestly you'd have to + // trigger it on purpose + self.current_output_id = id + 1; + self.set_pid(self.current_output_id); + } else { + info!("Could not retrieve a previous id even if the kernel is running"); + info!("This was in saved code: {}", self.read_previous_code()); + return Err(SniprunError::CustomError( + "Sniprun failed to connect to the running kernel, please SnipReset".to_string(), + )); + } + + self.fetch_code()?; + Ok(()) + } else { + // launch everything + self.set_pid(0); + + let init_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/init_repl.sh"; + info!( + "launching kernel : {:?} on {:?}", + init_repl_cmd, &self.cache_dir + ); + + match daemon() { + Ok(Fork::Child) => { + let _res = Command::new("bash") + .args(&[ + init_repl_cmd, + self.cache_dir.clone(), + String::from("deno"), + String::from("repl"), + String::from("-q"), + ]) + .output() + .unwrap(); + let pause = std::time::Duration::from_millis(36_000_000); + std::thread::sleep(pause); + + return Err(SniprunError::CustomError( + "Timeout expired for python3 REPL".to_owned(), + )); + } + Ok(Fork::Parent(_)) => {} + Err(_) => { + info!("JS_TS_deno could not fork itself to the background to launch the kernel") + } + }; + + let pause = std::time::Duration::from_millis(100); + std::thread::sleep(pause); + self.save_code("kernel_launched\n".to_owned()); + + Err(SniprunError::CustomError( + "Deno kernel launched, re-run your snippet".to_owned(), + )) + } + } + + fn add_boilerplate_repl(&mut self) -> Result<(), SniprunError> { + self.add_boilerplate()?; + let start_mark = String::from("\nconsole.log(\"sniprun_started_id=") + + &self.current_output_id.to_string() + + "\")\n"; + let end_mark = String::from("\nconsole.log(\"sniprun_finished_id=") + + &self.current_output_id.to_string() + + "\")\n"; + let start_mark_err = String::from("\nconsole.error(\"sniprun_started_id=") + + &self.current_output_id.to_string() + + "\")\n"; + let end_mark_err = String::from("\nconsole.error(\"sniprun_finished_id=") + + &self.current_output_id.to_string() + + "\")\n"; + + // Removing empty lines + // self.code = self + // .code + // .lines() + // .filter(|l| !l.trim().is_empty()) + // .collect::>() + // .join("\n"); + + let all_code = String::from("\n") + &self.code + "\n\n"; + self.code = start_mark + &start_mark_err + &all_code + &end_mark + &end_mark_err; + Ok(()) + } + + fn build_repl(&mut self) -> Result<(), SniprunError> { + self.build() + } + + fn execute_repl(&mut self) -> Result { + let send_repl_cmd = self.data.sniprun_root_dir.clone() + "/ressources/launcher_repl.sh"; + info!("running launcher {}", send_repl_cmd); + let res = Command::new(send_repl_cmd) + .arg(self.main_file_path.clone()) + .arg(self.cache_dir.clone() + "/fifo_repl/pipe_in") + .spawn(); + info!("cmd status: {:?}", res); + res.expect("could not run launcher"); + // info!("launcher launched : {:?}", res); + + let outfile = self.cache_dir.clone() + "/fifo_repl/out_file"; + let errfile = self.cache_dir.clone() + "/fifo_repl/err_file"; + info!("outfile : {:?}", outfile); + self.wait_out_file(outfile, errfile, self.current_output_id) + } +} + #[cfg(test)] mod test_ts_js_deno_original { use super::*; + use serial_test::serial; + #[test] - fn simple_print() { + #[serial(deno)] + fn simple_print() { let mut data = DataHolder::new(); //inspired from Rust syntax data.current_bloc = String::from("let message: string = 'Hi';\nconsole.log(message);"); let mut interpreter = JS_TS_deno::new(data); - let res = interpreter.run(); + let res = interpreter.run_at_level(SupportLevel::Bloc); // -> should panic if not an Ok() let string_result = res.unwrap(); @@ -154,4 +372,13 @@ mod test_ts_js_deno_original { // -> compare result with predicted assert_eq!(string_result, "Hi\n"); } + #[test] + #[serial(deno)] + fn print_quote() { + let mut data = DataHolder::new(); + data.current_bloc = String::from("let message: string = 'Hi';\nconsole.log(message);"); + let mut interpreter = Python3_fifo::new(data); + let res = interpreter.run_at_level_repl(SupportLevel::Bloc); + assert!(res.is_err()); + } } From 13d6763a3c49c934e6b964005b1a58495a1a024f Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Tue, 8 Feb 2022 23:32:49 +0100 Subject: [PATCH 09/16] test name --- src/interpreters/JS_TS_deno.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreters/JS_TS_deno.rs b/src/interpreters/JS_TS_deno.rs index 22c1668a..50aca9ff 100644 --- a/src/interpreters/JS_TS_deno.rs +++ b/src/interpreters/JS_TS_deno.rs @@ -374,7 +374,7 @@ mod test_ts_js_deno_original { } #[test] #[serial(deno)] - fn print_quote() { + fn print_repl() { let mut data = DataHolder::new(); data.current_bloc = String::from("let message: string = 'Hi';\nconsole.log(message);"); let mut interpreter = Python3_fifo::new(data); From 8a9a5ff34514753e5e84a0d2bc9c1eb090c5f916 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Tue, 8 Feb 2022 23:56:00 +0100 Subject: [PATCH 10/16] installing ts-node and deno --- ressources/install_all_compilers_ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index c4e80641..6cf54abe 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -6,6 +6,7 @@ sudo apt install haskell-platform -y sudo apt install -y nodejs npm sudo npm install -g coffee-script sudo npm install -g typescript +sudo npm install -g ts-node sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/' sudo apt install r-base @@ -21,3 +22,5 @@ export PATH=$PATH:$HOME/golang/go/bin/ # deno for typescript and javascript curl -fsSL https://deno.land/x/install/install.sh | sh +export DENO_INSTALL=$HOME"/.deno" +export PATH="$DENO_INSTALL/bin:$PATH" From 334c33dbb8423e180e3a4f2f40968a5302b92f83 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 00:01:51 +0100 Subject: [PATCH 11/16] wider separator for snipinfo --- src/launcher.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/launcher.rs b/src/launcher.rs index 5789d88d..621b53ad 100644 --- a/src/launcher.rs +++ b/src/launcher.rs @@ -135,14 +135,14 @@ impl Launcher { v.push("\nAvailable interpreters and languages".to_owned()); - let separator = "|--------------------------|--------------|---------------|-------------|------------|--------------|".to_string(); + let separator = "|--------------------------|---------------|---------------|-------------|------------|--------------|".to_string(); v.push(separator.clone()); - v.push("| Interpreter | Language | Support Level | Default for | REPL | REPL enabled |".to_string()); - v.push("| | | | filetype | capability | by default |".to_string()); + v.push("| Interpreter | Language | Support Level | Default for | REPL | REPL enabled |".to_string()); + v.push("| | | | filetype | capability | by default |".to_string()); let mut temp_vec = vec![]; iter_types! { - let line = format!("| {:<25}| {:<13}| {:<14}|{:^13}|{:^12}|{:^14}|", + let line = format!("| {:<25}| {:<14}| {:<14}|{:^13}|{:^12}|{:^14}|", Current::get_name(), Current::get_supported_languages().get(0).unwrap_or(&"".to_string()), Current::get_max_support_level().to_string(), From d637a79be352ae43a2e5033d6dc13077870b5738 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 00:10:14 +0100 Subject: [PATCH 12/16] correct test --- ressources/install_all_compilers_ci.sh | 2 +- src/interpreters/JS_TS_deno.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index 6cf54abe..942c3663 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -22,5 +22,5 @@ export PATH=$PATH:$HOME/golang/go/bin/ # deno for typescript and javascript curl -fsSL https://deno.land/x/install/install.sh | sh -export DENO_INSTALL=$HOME"/.deno" +export DENO_INSTALL="/home/runner/.deno" export PATH="$DENO_INSTALL/bin:$PATH" diff --git a/src/interpreters/JS_TS_deno.rs b/src/interpreters/JS_TS_deno.rs index 50aca9ff..601dd15a 100644 --- a/src/interpreters/JS_TS_deno.rs +++ b/src/interpreters/JS_TS_deno.rs @@ -377,7 +377,7 @@ mod test_ts_js_deno_original { fn print_repl() { let mut data = DataHolder::new(); data.current_bloc = String::from("let message: string = 'Hi';\nconsole.log(message);"); - let mut interpreter = Python3_fifo::new(data); + let mut interpreter = JS_TS_deno::new(data); let res = interpreter.run_at_level_repl(SupportLevel::Bloc); assert!(res.is_err()); } From 951d5f57ad2e864398690543576c530bc08b1743 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 00:31:07 +0100 Subject: [PATCH 13/16] install deno from cargo --- ressources/install_all_compilers_ci.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index 942c3663..a5a5bde5 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -21,6 +21,4 @@ sudo apt install dotnet export PATH=$PATH:$HOME/golang/go/bin/ # deno for typescript and javascript -curl -fsSL https://deno.land/x/install/install.sh | sh -export DENO_INSTALL="/home/runner/.deno" -export PATH="$DENO_INSTALL/bin:$PATH" +cargo install deno --locked From 8752851ca4ca6181c550b3ad0884ca2a31da61aa Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 19:30:01 +0100 Subject: [PATCH 14/16] faster deno isntall in CI --- ressources/install_all_compilers_ci.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ressources/install_all_compilers_ci.sh b/ressources/install_all_compilers_ci.sh index a5a5bde5..9c080052 100755 --- a/ressources/install_all_compilers_ci.sh +++ b/ressources/install_all_compilers_ci.sh @@ -21,4 +21,6 @@ sudo apt install dotnet export PATH=$PATH:$HOME/golang/go/bin/ # deno for typescript and javascript -cargo install deno --locked +# cargo install deno --locked # too long, takes 20 min! +curl -fsSL https://deno.land/x/install/install.sh | sh +cp $HOME/.deno/bin/* $HOME/.cargo/bin From 9ce5a29e1037f35a253e4c2d92f3f673a9f01b4d Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 19:32:04 +0100 Subject: [PATCH 15/16] updating & formatting --- Cargo.lock | 4 ++-- src/display.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e66862c..b27ebae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bitflags" diff --git a/src/display.rs b/src/display.rs index fc77efbd..1be21209 100644 --- a/src/display.rs +++ b/src/display.rs @@ -307,13 +307,15 @@ pub fn display_floating_window( "lua require\"sniprun.display\".fw_open({},{},\"{}\", true)", row - 1, col, - no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow).replace("\n", "\\\n"), + no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow) + .replace("\n", "\\\n"), )), Err(result) => nvim.lock().unwrap().command(&format!( "lua require\"sniprun.display\".fw_open({},{},\"{}\", false)", row - 1, col, - no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow).replace("\n", "\\\n"), + no_output_wrap(&result.to_string(), data, &DisplayType::TempFloatingWindow) + .replace("\n", "\\\n"), )), }; info!("display floating window res = {:?}", res); From 1dd56298d341f463e3ff6d8366738190c56c7835 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Wed, 9 Feb 2022 19:43:46 +0100 Subject: [PATCH 16/16] looser code coverage targets for 'success' --- .codecov.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 47f6f748..38d8d949 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -3,11 +3,11 @@ coverage: patch: default: target: 1% - threshold: 1% + threshold: 90% path: "src" project: default: - target: 50% - threshold: 50% + target: 1% + threshold: 90% path: "src"