From 81cb53db2eaaf5b8b8d9d74f175f911b8aa0cfd2 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Fri, 14 May 2021 12:00:06 +0200 Subject: [PATCH 1/4] better default colors for floating windows --- README.md | 7 +++---- lua/sniprun.lua | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1ddf1c21..f713bda9 100755 --- a/README.md +++ b/README.md @@ -280,14 +280,13 @@ require'sniprun'.setup({ }, -- customize highlight groups (setting this overrides colorscheme) - snipruncolors = { + snipruncolors = { SniprunVirtualTextOk = {bg="#66eeff",fg="#000000",ctermbg="Cyan",cterfg="Black"}, - SniprunFloatingWinOk = {bg="#66eeff",fg="#000000",ctermbg="Cyan",cterfg="Black"}, + SniprunFloatingWinOk = {fg="#66eeff",ctermfg="Cyan"}, SniprunVirtualTextErr = {bg="#881515",fg="#000000",ctermbg="DarkRed",cterfg="Black"}, - SniprunFloatingWinErr = {bg="#881515",fg="#000000",ctermbg="DarkRed",cterfg="Black"}, + SniprunFloatingWinErr = {fg="#881515",ctermfg="DarkRed"}, } - }) EOF ``` diff --git a/lua/sniprun.lua b/lua/sniprun.lua index 92d29bdc..fbdf173c 100644 --- a/lua/sniprun.lua +++ b/lua/sniprun.lua @@ -37,9 +37,9 @@ M.config_values = { -- default highlight stuff goes here snipruncolors = { SniprunVirtualTextOk = {bg="#66eeff",fg="#000000",ctermbg="Cyan",cterfg="Black"}, - SniprunFloatingWinOk = {bg="#66eeff",fg="#000000",ctermbg="Cyan",cterfg="Black"}, + SniprunFloatingWinOk = {fg="#66eeff",ctermfg="Cyan"}, SniprunVirtualTextErr = {bg="#881515",fg="#000000",ctermbg="DarkRed",cterfg="Black"}, - SniprunFloatingWinErr = {bg="#881515",fg="#000000",ctermbg="DarkRed",cterfg="Black"}, + SniprunFloatingWinErr = {fg="#881515",ctermfg="DarkRed"}, } } From 1c146e145095789e61fa07a2ac052abcfb5c291d Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Mon, 17 May 2021 20:19:05 +0200 Subject: [PATCH 2/4] configurable border style --- CONTRIBUTING.md | 2 +- README.md | 13 ++++++++----- lua/sniprun.lua | 16 ++++++++++------ lua/sniprun/display.lua | 3 ++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21d479da..58253ec3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ Yeah cool but what _code_ goes inside? --- I just finished some changes, how do I test my code quickly? --> compile `cargo build --release` and run `nvim --cmd "set rtp+=. -u NORC ` from the sniprun project root. +-> compile `cargo build --release` and run `nvim --cmd "set rtp+=. -u NONE ` from the sniprun project root. --- diff --git a/README.md b/README.md index f713bda9..6fedf84d 100755 --- a/README.md +++ b/README.md @@ -126,8 +126,6 @@ Sniprun will then: - [optionnal] **cargo and the rust toolchain** version >= 1.43.0 (you can find those [here](https://www.rust-lang.org/tools/install)). -- [optionnal] recent GLIBC (at least 2.33) if you want to use the precompiled binary, otherwise you'll have to compile sniprun yourself. - - **Compiler / interpreter** for the languages you work with must be installed & on your \$PATH. In case specific build tools or softwares are required, those are documented in the [doc](https://github.com/michaelb/sniprun/tree/master/doc) folder, for each interpreter, which I urge you to get a look at before getting started as it also contains the potential limitations of each interpreter; this information can also be accessed through `:SnipInfo ` (tab autocompletion supported). @@ -266,8 +264,7 @@ require'sniprun'.setup({ repl_enable = {}, --" enable REPL-like behavior for the given interpreters repl_disable = {}, --" disable REPL-like behavior for the given interpreters - inline_messages = 0, --" inline_message (0/1) is a one-line way to display messages - --" to workaround sniprun not being able to display anything + interpreter_options = {}, --" intepreter-specific options, consult docs / :SnipInfo -- " you can combo different display modes as desired display = { @@ -285,8 +282,14 @@ require'sniprun'.setup({ SniprunFloatingWinOk = {fg="#66eeff",ctermfg="Cyan"}, SniprunVirtualTextErr = {bg="#881515",fg="#000000",ctermbg="DarkRed",cterfg="Black"}, SniprunFloatingWinErr = {fg="#881515",ctermfg="DarkRed"}, - } + }, + + -- miscellaneous compatibility/adjustement settings + inline_messages = 0, --" inline_message (0/1) is a one-line way to display messages + --" to workaround sniprun not being able to display anything + borders = 'single' --" display borders around floating windows + --" possible values are 'none', 'single', 'double', or 'shadow' }) EOF ``` diff --git a/lua/sniprun.lua b/lua/sniprun.lua index fbdf173c..83f948d1 100644 --- a/lua/sniprun.lua +++ b/lua/sniprun.lua @@ -17,11 +17,7 @@ M.config_values = { repl_enable = {}, repl_disable = {}, - interpreter_options = { - example_original = { - example_option = "--optimize-with-debug-info", - } - }, + interpreter_options = {}, display = { "Classic", @@ -33,6 +29,7 @@ M.config_values = { }, inline_messages = 0, + borders = 'single', -- default highlight stuff goes here snipruncolors = { @@ -70,7 +67,7 @@ function M.setup(opts) if next(opts) == nil then return end for key,value in pairs(opts) do if M.config_values[key] == nil then - error(string.format('[Sniprun] Key %s not exist in config values',key)) + error(string.format('[Sniprun] Key %s does not exist in config values',key)) return end if key == 'snipruncolors' then @@ -81,6 +78,7 @@ function M.setup(opts) M.configure_keymaps() M.setup_highlights() M.setup_autocommands() + M.setup_display() M.config_up = 1 end @@ -100,6 +98,12 @@ local highlight = function(group, styles) end +function M.setup_display() + local D = require'sniprun.display' + D.borders = M.config_values.borders +end + + function M.setup_highlights() local colors_table = M.config_values["snipruncolors"] if M.custom_highlight then diff --git a/lua/sniprun/display.lua b/lua/sniprun/display.lua index 1deab90b..1b5774db 100644 --- a/lua/sniprun/display.lua +++ b/lua/sniprun/display.lua @@ -6,6 +6,7 @@ M.term.buffer = -1 M.term.window_handle = 0 M.term.current_line = -1 M.term.chan = -1 +M.borders = 'single' local NAMESPACE = 'sniprun' @@ -29,7 +30,7 @@ function M.fw_open(row, column, message, ok, temp) vim.api.nvim_buf_set_lines(bufnr,h,h+1,false,{line}) vim.api.nvim_buf_add_highlight(bufnr, namespace_id, hl, h,0,-1) -- highlight lines in floating window end - M.fw_handle = vim.api.nvim_open_win(bufnr, false, {relative='win', width=w+1, height=h, bufpos=bp, focusable=false, style='minimal',border='single'}) + M.fw_handle = vim.api.nvim_open_win(bufnr, false, {relative='win', width=w+1, height=h, bufpos=bp, focusable=false, style='minimal',border=M.borders}) end function M.term_open() From 18be53eec5c1b56f8a454165bdb0a11f17754dc6 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Fri, 21 May 2021 18:49:21 +0200 Subject: [PATCH 3/4] temp --- README.md | 2 +- src/interpreters/Julia_jupyter.rs | 258 ++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 src/interpreters/Julia_jupyter.rs diff --git a/README.md b/README.md index 6fedf84d..e77f065e 100755 --- a/README.md +++ b/README.md @@ -425,7 +425,7 @@ Due to its nature, Sniprun may have trouble with programs that : ## Troubleshooting -begin by updating the plugin and running `:checkhealth sniprun` +begin by updating the plugin and running `:SnipReset` and then `:checkhealth sniprun` - **Silent fail**: the sniprun binary may be incompatible with your distro/OS/arch. Use `bash ./install.sh 1` as post-install to compile locally. - Terminal and Floating Window display mode do not work: Linked to [this](https://github.com/michaelb/sniprun/issues/70) issue, no fix found yet. diff --git a/src/interpreters/Julia_jupyter.rs b/src/interpreters/Julia_jupyter.rs new file mode 100644 index 00000000..892e0636 --- /dev/null +++ b/src/interpreters/Julia_jupyter.rs @@ -0,0 +1,258 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct Julia_jupyter { + support_level: SupportLevel, + data: DataHolder, + code: String, + kernel_file: String, + main_file_path: String, + launcher_path: String, + plugin_root: String, + cache_dir: String, +} + +impl Interpreter for Julia_jupyter { + fn new_with_level(data: DataHolder, level: SupportLevel) -> Box { + //create a subfolder in the cache folder + let pwd = data.work_dir.clone() + "/julia_jupyter"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&pwd) + .expect("Could not create directory for julia-jupyter"); + + //pre-create string pointing to main file's and binary's path + let mfp = pwd.clone() + "/main.jl"; + let lp = pwd.clone() + "/main.sh"; + + let pgr = data.sniprun_root_dir.clone(); + + let kp = pwd.clone() + "/kernel_sniprun.json"; + Box::new(Julia_jupyter { + data, + support_level: level, + code: String::new(), + kernel_file: kp, + main_file_path: mfp, + launcher_path: lp, + plugin_root: pgr, + cache_dir: pwd, + }) + } + + fn get_name() -> String { + String::from("Julia_jupyter") + } + + fn behave_repl_like_default() -> bool { + true + } + + fn has_repl_capability() -> bool { + true + } + + fn get_supported_languages() -> Vec { + vec![String::from("Julia"), String::from("julia")] + } + + 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> { + 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> { + self.code = String::from("\nprintln(\"\")\n") + + &unindent(&format!("{}{}", "\n", self.code.as_str())); + //add a print newline because the jupyter prompt interferers with fetching the result + Ok(()) + } + fn build(&mut self) -> Result<(), SniprunError> { + // info!("python code:\n {}", self.code); + write(&self.main_file_path, &self.code).expect("Unable to write to file for julia_jupyter"); + Ok(()) + } + fn execute(&mut self) -> Result { + let output = Command::new("julia") + .arg(&self.main_file_path) + .output() + .expect("Unable to start process"); + if output.status.success() { + return 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 Julia_jupyter { + fn fetch_code_repl(&mut self) -> Result<(), SniprunError> { + self.fetch_code()?; + let saved_code = self.read_previous_code(); + if saved_code.is_empty() { + //initialize kernel. Relying on self.read_previous_code to + //know when to start a new kernel is important as + //this will be cleared by the SnipReplMemoryClean command + let _res = std::fs::remove_file(&self.kernel_file); + let _res = Command::new("jupyter-kernel") + .arg("--kernel=julia-1.5") + .arg(String::from("--KernelManager.connection_file=") + &self.kernel_file) + .spawn(); + info!("Initialized kernel at {}", self.kernel_file); + } else { + // kernel already running + info!( + "Using already loaded jupyter kernel at {}", + self.kernel_file + ); + } + + // save kernel + self.save_code(saved_code); + + Ok(()) + } + fn add_boilerplate_repl(&mut self) -> Result<(), SniprunError> { + info!("begins add boilerplate repl"); + self.code = String::from("\nprintln(\"\")\n") + + &unindent(&format!("{}{}", "\n", self.code.as_str())); + + Ok(()) + } + + fn build_repl(&mut self) -> Result<(), SniprunError> { + let actual_command = String::from("echo") + + " " + + &String::from("'include(\"") + + &self.main_file_path + + "\")" + + "' " + + "|" + + " " + + "jupyter-console" + + " " + + "--existing" + + " " + + &self.kernel_file.clone() + + " " + + "--kernel=julia-1.5" + + " " + + "--simple-prompt" + + " " + + "--no-confirm" + + " " + + "--ZMQTerminalInteractiveShell.banner=\"\""; + + write(&self.launcher_path, &actual_command) + .expect("Unable to write file for julia_jupyter"); + info!("command written to launcher:\n{}\n", actual_command); + write(&self.main_file_path, &self.code).expect("Unable to write to file for julia_jupyter"); + Ok(()) + } + + fn execute_repl(&mut self) -> Result { + if !std::path::Path::new(&self.kernel_file).exists() { + info!("no kernel file found"); + return Err(SniprunError::RuntimeError("No kernel found or provided".to_string())); + } + info!( + "json kernel file exists yet? {}", + std::path::Path::new(&self.kernel_file).exists() + ); + + info!("starting executing repl: bash {}",&self.launcher_path); + let output = Command::new("bash") + .arg(&self.launcher_path) + .output() + .expect("failed to run command"); + info!( + "executed command!, stdout = {:?}, stder = {:?}", + output.stdout, output.stderr + ); + let result = String::from_utf8(output.stdout).unwrap(); + let mut cleaned_result: Vec<_> = result.lines().collect(); + info!("collected result"); + + // first and last lines are the [In] x: prompts from jupyter-console + cleaned_result.remove(cleaned_result.len() - 1); + cleaned_result.remove(1); + cleaned_result.remove(0); + info!("result: {:?}", cleaned_result); + + info!("cleaned result: {:?}", cleaned_result); + if String::from_utf8(output.stderr.clone()).unwrap().is_empty() { + return Ok(cleaned_result.join("\n") + "\n"); + } else { + return Err(SniprunError::RuntimeError( + String::from_utf8(strip_ansi_escapes::strip(output.stderr.clone()).unwrap()) + .unwrap() + .lines() + .last() + .unwrap_or( + &String::from_utf8( + strip_ansi_escapes::strip(output.stderr.clone()).unwrap(), + ) + .unwrap(), + ) + .to_owned(), + )); + } + } +} + +#[cfg(test)] +mod test_julia_jupyter { + use super::*; + use crate::*; + + #[test] + fn run_all() { + simple_print(); + } + + fn simple_print() { + let mut data = DataHolder::new(); + data.current_bloc = String::from("println(\"a\")"); + let mut interpreter = Julia_jupyter::new(data); + let res = interpreter.run_at_level(SupportLevel::Bloc); + + // should panic if not an Ok() + let string_result = res.unwrap(); + assert!(string_result.contains(&"a")); + } +} From 148bbbfa15108c8ff0fb30bb74251a90a3933ee6 Mon Sep 17 00:00:00 2001 From: Michael Bleuez Date: Fri, 21 May 2021 20:25:35 +0200 Subject: [PATCH 4/4] Julia jupyter interpreter is up! Though it's not as simple as other interpreters... (The kernel has to be manually started and stopped) --- README.md | 16 ++++----- doc/Julia_jupyter.md | 12 +++++++ src/interpreters/Julia_jupyter.rs | 55 ++----------------------------- 3 files changed, 23 insertions(+), 60 deletions(-) create mode 100644 doc/Julia_jupyter.md diff --git a/README.md b/README.md index e77f065e..df9c2fc3 100755 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ An example in C, look in the command area: ![](ressources/visual_assets/demo_c.gif) -##### The result can be displayed in multiple (even at the same time) ways: +##### The result can be displayed in multiple (even at the same time) ways: [Classic](ressources/display_classic.md)| [Virtual Text](ressources/display_virtualtext.md) :------------------------------------------:|:------------------: @@ -95,7 +95,7 @@ Basically, it allows you to run a part of your code. Do either of: - Position the cursor on a line `:SnipRun` -- Select some visual range, `:'<,'>SnipRun` +- Select some visual range, `:'<,'>SnipRun` - Combine a motion with the operator (preferably through a shortcut!) @@ -111,7 +111,7 @@ Sniprun will then: - **Add boilerplate** when it exists. In C, it surrounds your snip with "int main() {", "}". (disclaimer: oversimplifed) - **Build** (write to a script file, or compile) the code - **Execute** the code -- Return stdout, or stderr using the +- Return stdout, or stderr using the ![](ressources/visual_assets/760091.png) @@ -275,7 +275,7 @@ require'sniprun'.setup({ -- "LongTempFloatingWindow", -- "same as above, but only long results. To use with VirtualText__ -- "Terminal" -- "display results in a vertical split }, - + -- customize highlight groups (setting this overrides colorscheme) snipruncolors = { SniprunVirtualTextOk = {bg="#66eeff",fg="#000000",ctermbg="Cyan",cterfg="Black"}, @@ -387,15 +387,15 @@ println!("-> {}", alphabet); | ------------ | ------------- | --- | ---------- | ---------------- | | Ada | Line | | Java | Bloc | | Bash/Shell | Bloc + REPL\* | | JavaScript | Bloc | -| C | Import | | Julia | Bloc | +| C | Import | | Julia | Bloc + REPL\*\* | | C++ | Import | | Lisp | Untested | | Clojure | Untested | | Lua | Bloc | | COBOL | Untested | | Lua-nvim | Bloc | -| Coffeescript | Bloc | | Markdown (GFM) | Bloc + REPL \*** | +| Coffeescript | Bloc | | Markdown (GFM) | Bloc + REPL \*\*\* | | C# | Untested | | Perl6 | Line | | D | Bloc | | Perl | Line | | Elixir | Untested | | PHP | Untested | -| Elm | Untested | | Python3 | Import +REPL\*\* | +| Elm | Untested | | Python3 | Import +REPL*\* | | Erlang | Untested | | R | Bloc + REPL \*\* | | F# | Untested | | Ruby | Bloc | | Go | Bloc | | Rust | Bloc | @@ -425,7 +425,7 @@ Due to its nature, Sniprun may have trouble with programs that : ## Troubleshooting -begin by updating the plugin and running `:SnipReset` and then `:checkhealth sniprun` +begin by updating the plugin and running `:SnipReset` and then `:checkhealth sniprun` - **Silent fail**: the sniprun binary may be incompatible with your distro/OS/arch. Use `bash ./install.sh 1` as post-install to compile locally. - Terminal and Floating Window display mode do not work: Linked to [this](https://github.com/michaelb/sniprun/issues/70) issue, no fix found yet. diff --git a/doc/Julia_jupyter.md b/doc/Julia_jupyter.md new file mode 100644 index 00000000..8123b6b1 --- /dev/null +++ b/doc/Julia_jupyter.md @@ -0,0 +1,12 @@ +The setup for the julia_jupyter interpreter is quite convoluted: + +Indeed, the Julia jupyter kernel MUST be started before Sniprun can run (and there is even a consequent delay since the kernel is so slow to start). + +You should start a julia jupyter kernel with the following command: +` jupyter-kernel --kernel=julia-1.5 --KernelManager.connection_file=$HOME/.cache/sniprun/julia_jupyter/kernel_sniprun.json` + +(adapt to your XDG_CACHE location if you're on Mac) + +You manage kernel startup AND shutodwn manually. Why? There is a terrible data race if sniprun does it. Python_jupyter works, julia doesn't. That's about it. + +If you want to use another kernel location, post a feature request at github.com/michaelb/sniprun and i'll see what I can do. diff --git a/src/interpreters/Julia_jupyter.rs b/src/interpreters/Julia_jupyter.rs index 892e0636..90fe9a5c 100644 --- a/src/interpreters/Julia_jupyter.rs +++ b/src/interpreters/Julia_jupyter.rs @@ -123,28 +123,10 @@ impl Interpreter for Julia_jupyter { impl ReplLikeInterpreter for Julia_jupyter { fn fetch_code_repl(&mut self) -> Result<(), SniprunError> { self.fetch_code()?; - let saved_code = self.read_previous_code(); - if saved_code.is_empty() { - //initialize kernel. Relying on self.read_previous_code to - //know when to start a new kernel is important as - //this will be cleared by the SnipReplMemoryClean command - let _res = std::fs::remove_file(&self.kernel_file); - let _res = Command::new("jupyter-kernel") - .arg("--kernel=julia-1.5") - .arg(String::from("--KernelManager.connection_file=") + &self.kernel_file) - .spawn(); - info!("Initialized kernel at {}", self.kernel_file); - } else { - // kernel already running - info!( - "Using already loaded jupyter kernel at {}", - self.kernel_file - ); + if !std::path::Path::new(&self.kernel_file).exists() { + info!("no kernel file found"); + return Err(SniprunError::RuntimeError("No running kernel found".to_string())); } - - // save kernel - self.save_code(saved_code); - Ok(()) } fn add_boilerplate_repl(&mut self) -> Result<(), SniprunError> { @@ -186,15 +168,6 @@ impl ReplLikeInterpreter for Julia_jupyter { } fn execute_repl(&mut self) -> Result { - if !std::path::Path::new(&self.kernel_file).exists() { - info!("no kernel file found"); - return Err(SniprunError::RuntimeError("No kernel found or provided".to_string())); - } - info!( - "json kernel file exists yet? {}", - std::path::Path::new(&self.kernel_file).exists() - ); - info!("starting executing repl: bash {}",&self.launcher_path); let output = Command::new("bash") .arg(&self.launcher_path) @@ -234,25 +207,3 @@ impl ReplLikeInterpreter for Julia_jupyter { } } } - -#[cfg(test)] -mod test_julia_jupyter { - use super::*; - use crate::*; - - #[test] - fn run_all() { - simple_print(); - } - - fn simple_print() { - let mut data = DataHolder::new(); - data.current_bloc = String::from("println(\"a\")"); - let mut interpreter = Julia_jupyter::new(data); - let res = interpreter.run_at_level(SupportLevel::Bloc); - - // should panic if not an Ok() - let string_result = res.unwrap(); - assert!(string_result.contains(&"a")); - } -}