diff --git a/CHANGELOG.md b/CHANGELOG.md index 377b4564..e8b0b8ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v1.2.10 +- Neorg support +- Support for named code blocs (neorg, orgmode) +- Allow setting custom locations for the sniprun binary + ## v1.2.9 - Elixir support (with REPL capabilities) - C# support diff --git a/CHECKLIST.md b/CHECKLIST.md index 84119a4c..dd659ef3 100644 --- a/CHECKLIST.md +++ b/CHECKLIST.md @@ -5,7 +5,7 @@ - cargo fmt --all / cargo check / cargo clippy - update the changelog - bump Cargo.toml to next version - - create a version bump commit + - create a version bump commit (with cargo.toml and cargo.lock) - merge - create a new tag vX.Y.Z on master - git push origin vX.Y.Z diff --git a/Cargo.lock b/Cargo.lock index 726195d5..7148a99f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,9 +67,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -153,15 +153,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -170,27 +170,27 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -216,9 +216,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "hashbrown" @@ -311,18 +311,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" [[package]] name = "parking_lot" @@ -336,9 +336,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if 1.0.0", "libc", @@ -367,9 +367,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -411,9 +411,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -475,18 +475,18 @@ checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" [[package]] name = "serde_bytes" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" +checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" dependencies = [ "serde", ] [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" dependencies = [ "itoa", "ryu", @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "serial_test" -version = "0.10.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c789ec87f4687d022a2405cf46e0cd6284889f1839de292cadeb6c6019506f2" +checksum = "538c30747ae860d6fb88330addbbd3e0ddbe46d662d032855596d8a8ca260611" dependencies = [ "dashmap", "futures", @@ -509,9 +509,9 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "0.10.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64f9e531ce97c88b4778aad0ceee079216071cffec6ac9b904277f8f92e7fe3" +checksum = "079a83df15f85d89a68d64ae1238f142f172b1fa915d0d76b26a7cba1b659a69" dependencies = [ "proc-macro2", "quote", @@ -546,7 +546,7 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "sniprun" -version = "1.2.9" +version = "1.2.10" dependencies = [ "close_fds", "dirs", @@ -622,9 +622,9 @@ checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unindent" -version = "0.1.11" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" +checksum = "5aa30f5ea51ff7edfc797c6d3f9ec8cbd8cfedef5371766b7181d33977f4814f" [[package]] name = "unix_socket" @@ -693,9 +693,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -708,42 +717,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" diff --git a/Cargo.toml b/Cargo.toml index 4dd70cf6..6d3624a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sniprun" -version = "1.2.9" +version = "1.2.10" authors = ["michaelb "] rust-version="1.55" edition = "2018" diff --git a/README.md b/README.md index fdf74e52..602b903b 100755 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ TLDR: `Plug 'michaelb/sniprun', {'do': 'bash install.sh'}`, `:SnipRun`, `:'<,'>S # Installation, configuration, ... -See [installation instructions](https://michaelb.github.io/sniprun/sources/README.html#installation), [configuration tips](https://michaelb.github.io/sniprun/sources/README.html#configuration), [usage explanations](https://michaelb.github.io/sniprun/sources/README.html#usage) and much more useful information on the [wiki](https://michaelb.github.io/sniprun/). +See [installation instructions](https://michaelb.github.io/sniprun/sources/README.html#installation), [configuration tips](https://michaelb.github.io/sniprun/sources/README.html#configuration), [usage explanations](https://michaelb.github.io/sniprun/sources/README.html#usage) and much more useful information on the [WIKI](https://michaelb.github.io/sniprun/). ## Demos diff --git a/docs/sources/README.md b/docs/sources/README.md index 901f6639..bd9ff2d4 100755 --- a/docs/sources/README.md +++ b/docs/sources/README.md @@ -385,6 +385,7 @@ println!("-> {}", alphabet); | Lua-nvim | Bloc | Yes\*\* | | Markdown | Bloc | Yes\*\*\* | | Mathematica | Bloc | Yes\*\* | +| Neorg | Bloc | Yes\*\*\* | | OrgMode | Bloc | Yes\*\*\* | | Perl/Perl6 | Line | No | | Python3 | Import | Yes\*\* | diff --git a/docs/sources/interpreters/Neorg_original.md b/docs/sources/interpreters/Neorg_original.md new file mode 100644 index 00000000..a11ec989 --- /dev/null +++ b/docs/sources/interpreters/Neorg_original.md @@ -0,0 +1,83 @@ +## Neorg original + +the Neorg\_original interpreter helps you running code blocs defined in neorg code blocs delimiters + +inline, switches and headers are not supported/ignored + +### example 1 + + +``` +#name demo +@code bash + +echo "lol" # << you can run sniprun on this line + + + +\# or the whole visual selection following: + +for i in {1..4};do + +echo $i + +done +@end + +``` + + +### example 2 + + +``` +#name demo_run_whole_bloc << running on this line or the line below will run the entire bloc +@code rust + +println!("test"); +println!("test2"); +@end +``` + + +Even though it is possible to have empty lines in between the #name tag and the @code block for this plugin this doesn't work. The #name has to be in the line directly above the @code block + +``` +#name name_tag_not_working << this #name tag doesn't run the code below + + +@code rust + +println!("test"); +println!("test2"); +@end + +``` + + +**the language name must be there (otherwise the default * will be used) at the bloc start** and has to match the language name or the filetype associated + +\* python, but you can ofc configure that: + +``` +require'sniprun'.setup({ + interpreter_options = { + Neorg_original = { + default_filetype = 'bash' -- default filetype/language name + } + } +}) +``` + +### example 3: running named code blocs + +``` +#name mycodebloc +@code rust +println!("test"); +@end +``` + +running `:%SnipRun mycodebloc` will run this code bloc (and any code bloc named similarly, case-insensitively) + +running `:%SnipRun` without any further arguments will run all the code blocs diff --git a/docs/sources/interpreters/OrgMode_original.md b/docs/sources/interpreters/OrgMode_original.md index d77005de..acf81c50 100644 --- a/docs/sources/interpreters/OrgMode_original.md +++ b/docs/sources/interpreters/OrgMode_original.md @@ -54,3 +54,16 @@ require'sniprun'.setup({ } }) ``` + +### example 3: running named code blocs + +``` +#+NAME: mycodebloc +#+BEGIN_SRC rust +println!("test"); +#+END_SRC +``` + +running `:%SnipRun mycodebloc` will run this code bloc (and any code bloc named similarly, case-insensitively) + +running `:%SnipRun` without any further arguments will run all the code blocs diff --git a/lua/sniprun.lua b/lua/sniprun.lua index 2ba4f13d..b2aa27e0 100644 --- a/lua/sniprun.lua +++ b/lua/sniprun.lua @@ -59,8 +59,10 @@ M.config_values = { -- by an user that would be unaware of the potentially dangerous behavior live_mode_toggle='off', - -- auto-filled with the real nvim's PID - neovim_pid=0 + -- auto-filled with the real nvim's PID, sniprun's bin and source locations + neovim_pid=0, + binary_path=binary_path, + sniprun_path=sniprun_path, } @@ -183,7 +185,7 @@ function M.configure_keymaps() vim.cmd("function! SnipRunOperator(...) \n lua require'sniprun'.run('n') \n endfunction") vim.cmd("command! SnipClose :lua require'sniprun.display'.close_all()") - vim.cmd("function! ListInterpreters(A,L,P) \n let l = split(globpath('"..sniprun_path.."/docs/sources/interpreters', '*.md'),'\\n') \n let rl = [] \n for e in l \n let rl += [split(e,'/')[-1][:-4]] \n endfor \n return rl \n endfunction") + vim.cmd("function! ListInterpreters(A,L,P) \n let l = split(globpath('".. M.config_values.sniprun_path .."/docs/sources/interpreters', '*.md'),'\\n') \n let rl = [] \n for e in l \n let rl += [split(e,'/')[-1][:-4]] \n endfor \n return rl \n endfunction") vim.cmd("command! -nargs=* -complete=customlist,ListInterpreters SnipInfo :lua require'sniprun'.info()") vim.cmd("function! SnipRunLauncher(...) range \nif a:firstline == a:lastline \n lua require'sniprun'.run() \n elseif a:firstline == 1 && a:lastline == line(\"$\")\nlet g:sniprun_cli_args_list = a:000\n let g:sniprun_cli_args = join(g:sniprun_cli_args_list,\" \") \n lua require'sniprun'.run('w') \n else \n lua require'sniprun'.run('v') \n endif \n endfunction") @@ -194,7 +196,7 @@ end function M.start() if M.job_id ~= nil then return end - M.job_id = vim.fn.jobstart({ binary_path }, { rpc = true }) + M.job_id = vim.fn.jobstart({ M.config_values.binary_path }, { rpc = true }) end function M.notify(method, ...) @@ -209,7 +211,7 @@ end function M.run(mode) local range_begin, range_end = M.get_range(mode) - M.config_values["sniprun_root_dir"] = sniprun_path + M.config_values["sniprun_root_dir"] = M.config_values.sniprun_path M.notify('run', range_begin, range_end, M.config_values, vim.g.sniprun_cli_args or "" ) end @@ -293,16 +295,16 @@ end function M.info(arg) if arg == nil or arg == "" then - M.config_values["sniprun_root_dir"] = sniprun_path + M.config_values["sniprun_root_dir"] = M.config_values.sniprun_path M.notify("info",1,1,M.config_values, "") vim.wait(500) -- let enough time for the sniprun binary to generate the file print(" ") - local lines = lines_from(sniprun_path.."/ressources/infofile.txt") + local lines = lines_from(M.config_values.sniprun_path.."/ressources/infofile.txt") -- print all lines content M.display_lines_in_floating_win(lines) else --help about a particular interpreter - local lines = lines_from(sniprun_path.."/docs/sources/interpreters/"..string.gsub(arg,"%s+","")..".md") + local lines = lines_from(M.config_values.sniprun_path.."/docs/sources/interpreters/"..string.gsub(arg,"%s+","")..".md") M.display_lines_in_floating_win(lines) end end @@ -317,16 +319,19 @@ function M.health() if vim.fn.executable('cargo') == 0 then health_warn("Rust toolchain not available", {"[optionnal] Install the rust toolchain https://www.rust-lang.org/tools/install"}) else health_ok("Rust toolchain found") end - if vim.fn.executable(binary_path) == 0 then health_error("sniprun binary not found!") - else health_ok("sniprun binary found at "..binary_path) end + if vim.fn.executable(M.config_values.binary_path) == 0 then health_error("sniprun binary not found!") + else health_ok("sniprun binary found at ".. M.config_values.binary_path) end local terminate_after = M.job_id == nil local path_log_file = os.getenv('HOME').."/.cache/sniprun/sniprun.log" local path_log_file_mac = os.getenv('HOME').."/Library/Caches/sniprun/sniprun.log" - -- os.remove(path_log_file) + os.remove(path_log_file) -- check if the log is recreated - M.ping() + if pcall(M.ping) then health_ok("Sent a ping to the sniprun binary") + else health_warn("Could not send a ping to the sniprun binary - is it present, executable and compatible with your CPU architecture?") end + + os.execute("sleep 0.2") if not M.file_exists(path_log_file) and not M.file_exists(path_log_file_mac) then health_error("sniprun binary incompatible or crash at start", {"Compile sniprun locally, with a clean reinstall and 'bash ./install.sh 1' as post-install command."}) else health_ok("sniprun binary runs correctly") diff --git a/lua/sniprun/api.lua b/lua/sniprun/api.lua index 4a1045e8..f1ba4fb5 100644 --- a/lua/sniprun/api.lua +++ b/lua/sniprun/api.lua @@ -9,7 +9,7 @@ function M.run_range(range_start, range_end, filetype, config) local override = {} override.filetype = filetype local lconfig = config or sniprun.config_values - lconfig["sniprun_root_dir"] = sniprun_path + lconfig["sniprun_root_dir"] = M.config.sniprun_path sniprun.notify('run', range_start, range_end, lconfig, "", override) end @@ -19,7 +19,7 @@ function M.run_string(codestring, filetype, config) override.codestring = codestring override.filetype = filetype or "" local lconfig = config or sniprun.config_values - lconfig["sniprun_root_dir"] = sniprun_path + lconfig["sniprun_root_dir"] = M.config.sniprun_path sniprun.notify('run', 0, 0, lconfig, "", override) end diff --git a/src/interpreters/Neorg_original.rs b/src/interpreters/Neorg_original.rs new file mode 100644 index 00000000..b2f65581 --- /dev/null +++ b/src/interpreters/Neorg_original.rs @@ -0,0 +1,384 @@ +#[derive(Clone)] +#[allow(non_camel_case_types)] +pub struct Neorg_original { + support_level: SupportLevel, + data: DataHolder, + code: String, + default_filetype: String, +} + +impl Neorg_original { + pub fn get_filetype_of_embbeded_code(&mut self) -> Result { + let nvim_instance = self.data.nvim_instance.clone().unwrap(); + let mut real_nvim_instance = nvim_instance.lock().unwrap(); + + // walk the whole visual selection in case multiple code block are contained + // if so, return ReRunRanges(ranges of code blocs) so get_filetype_of_embedded code can + // return a meaningful answer for each individual code bloc + let lines = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines( + &mut real_nvim_instance, + self.data.range[0] - 1, + self.data.range[1], + false, + ) + .unwrap(); + let mut counter = 0; + let selection_line = self.data.range[0] as usize; + let mut v = vec![]; + let mut run_next_code_bloc = 0; + info!("cli args empty ? {:?}", self.get_data().cli_args.is_empty()); + for (i, l) in lines.iter().enumerate() { + // rerunranges only named tags if any are asked for + if self.get_data().cli_args.is_empty() + || (l.trim_start().to_lowercase().starts_with("#name") + && self + .get_data() + .cli_args + .contains(&l.to_lowercase().replace("#name", "").trim().to_string())) + { + run_next_code_bloc = 2; + } + + info!("checking code bloc delimiter in : {}", l); + if l.trim_start().to_lowercase().starts_with("@code") { + if run_next_code_bloc == 0 { + continue; + } + run_next_code_bloc -= 1; + if counter % 2 == 1 { + return Err(SniprunError::CustomError(String::from( + "Incomplete or nested code blocs", + ))); + } + counter += 1; + v.push((selection_line + i + 1, 0)); + } + if l.trim_start().to_lowercase().starts_with("@end") { + if run_next_code_bloc == 0 { + continue; + } + run_next_code_bloc -= 1; + if counter % 2 == 0 { + return Err(SniprunError::CustomError(String::from( + "Incomplete or nested code blocs", + ))); + } + counter += 1; + v[((counter - 1) / 2) as usize].1 = selection_line + i - 1; + } + } + if counter >= 2 { + info!("counting {} code blocs delimiters", counter); + if counter % 2 == 1 { + return Err(SniprunError::CustomError(String::from( + "Selection contains an odd number of code bloc delimiters", + ))); + } + + if v.is_empty() { + return Err(SniprunError::CustomError("No matching tag #name was found".to_string())); + } + + info!("running separately ranges : {:?}", v); + return Err(SniprunError::ReRunRanges(v)); + } + + info!("no multiple bloc was found"); + + let mut line_n = self.data.range[0]; // no matter which one + + //first check if we not on boundary of block + if self + .data + .current_line + .trim_start() + .to_lowercase() + .starts_with("#name") + { + let next_line = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines(&mut real_nvim_instance, line_n, line_n + 1, false) + .unwrap(); + self.data.current_line = next_line.join(""); + line_n += 1; + } + + if self + .data + .current_line + .trim_start() + .to_lowercase() + .starts_with("@code") + { + let flavor = self + .data + .current_line + .trim_start() + .split_whitespace() + .nth(1) + .unwrap_or("") + .to_owned(); + let end_line = real_nvim_instance + .get_current_buf() + .unwrap() + .line_count(&mut real_nvim_instance) + .unwrap(); + let capped_end_line = std::cmp::min(line_n + 400, end_line); // in case there is a very long file, don't search for nothing up to line 500k + let it = line_n + 1..capped_end_line + 1; + + let mut code_bloc = vec![]; + for i in it { + let line_i = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines(&mut real_nvim_instance, i - 1, i, false) + .unwrap() + .join(""); + if line_i.trim_start().to_lowercase().starts_with("@end") { + //found end of bloc + self.data.current_bloc = code_bloc.join("\n"); + info!( + "line to extract filetype from: {:?}", + line_i.split_whitespace().collect::>() + ); + return Ok(self.filetype_from_str(&flavor)); + } else { + info!("adding line {} to current bloc", i); + code_bloc.push(line_i.to_string()); + } + } + } + + // if we are in a block + for i in (1..line_n).rev() { + { + let line_i = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines(&mut real_nvim_instance, i - 1, i, false) + .unwrap() + .join(""); + if line_i.trim_start().to_lowercase().starts_with("@code") { + let flavor = line_i + .trim_start() + .split_whitespace() + .nth(1) + .unwrap_or("") + .to_owned(); + return Ok(self.filetype_from_str(&flavor)); + } + } + } + Ok(String::new()) + } + + /// Convert neorg code block flavor to filetype + pub fn filetype_from_str(&self, s: &str) -> String { + let cleaned_str = s.replace(&['{', '}', '.'][..], ""); + match cleaned_str.as_str() { + "bash" => "sh", + "zsh" => "sh", + "shell" => "sh", + "C++" => "cpp", + "c++" => "cpp", + "Perl" => "perl", + "python3" => "python", + "rb" => "ruby", + "R" => "r", + "jruby" => "ruby", + "objectivec" => "objcpp", + "ts" => "typescript", + "" => &self.default_filetype, + a => a, + } + .to_string() + } +} + +impl ReplLikeInterpreter for Neorg_original {} + +impl Interpreter for Neorg_original { + fn new_with_level(data: DataHolder, support_level: SupportLevel) -> Box { + //create a subfolder in the cache folder + let lwd = data.work_dir.clone() + "/neorg_original"; + let mut builder = DirBuilder::new(); + builder.recursive(true); + builder + .create(&lwd) + .expect("Could not create directory for example"); + let mut data_clone = data; + data_clone.work_dir = lwd.clone(); //trick other interpreter at creating their files here + + let ddf = String::from("python"); //default default + + let mut neorg_interpreter = Box::new(Neorg_original { + data: data_clone, + support_level, + code: String::new(), + default_filetype: ddf, + }); + + if let Some(value) = Neorg_original::get_interpreter_option( + &neorg_interpreter.get_data(), + "default_filetype", + ) { + if let Some(valid_string) = value.as_str() { + neorg_interpreter.default_filetype = valid_string.to_string(); + } + } + + neorg_interpreter + } + + fn get_supported_languages() -> Vec { + vec![String::from("Neorg"), String::from("norg")] + } + + fn get_name() -> String { + String::from("Neorg_original") + } + + 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::Import + } + + fn check_cli_args(&self) -> Result<(), SniprunError> { + info!("Checking cli-args: {:?}", self.get_data().cli_args); + + // check arguments are #name tags + let nvim_instance = self.data.nvim_instance.clone().unwrap(); + let mut real_nvim_instance = nvim_instance.lock().unwrap(); + let lines = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines( + &mut real_nvim_instance, + self.data.range[0] - 1, + self.data.range[1], + false, + ) + .unwrap(); + for tag_name in self.get_data().cli_args { + // walk the whole visual selection in case multiple code block are contained + + let mut found = false; + for (i, l) in lines.iter().enumerate() { + info!("checking named tag {} in line {}", tag_name, i); + if l.trim_start().to_lowercase().starts_with("#name") + && tag_name.to_lowercase() + == (l.to_lowercase().replace("#name", "").trim().to_string()) + { + found = true; + info!("found named tag {} in line: {}", tag_name, l); + break; + } + } + + if !found { + info!("CLI arguments for Neorg should be valid #name tags"); + } + } + + return Ok(()); + } + + fn fetch_code(&mut self) -> Result<(), SniprunError> { + 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(&[' ', '\t'][..], "") + .is_empty() + && self.support_level >= SupportLevel::Line + { + //special for neorg in case we try to run a bloc of markodwn that only has one line, + //an only Line level support + self.code = self + .data + .current_bloc + .lines() + .next() + .unwrap_or(&String::new()) + .to_string(); + } else { + // no code was retrieved + self.code = String::from(""); + } + + self.data.filetype = self.get_filetype_of_embbeded_code()?; + info!("filetype/flavor found: {}", self.data.filetype); + info!("Code to run with new filetype: {}", self.data.current_bloc); + Ok(()) + } + + fn add_boilerplate(&mut self) -> Result<(), SniprunError> { + Ok(()) + } + + fn build(&mut self) -> Result<(), SniprunError> { + Ok(()) + } + + fn execute(&mut self) -> Result { + info!("executing neorg interpreter"); + let launcher = crate::launcher::Launcher::new(self.data.clone()); + + if let Some((name, level)) = launcher.select() { + info!("Selected real interpreter: {}", name); + //launch the right interpreter ! + iter_types! { + if Current::get_name() == name { + let mut inter = Current::new_with_level(self.data.clone(), level); + return inter.run(); + } + } + } + Err(SniprunError::CustomError(String::from( + "Failed to determine language of code bloc", + ))) + } +} + +#[cfg(test)] +mod test_neorg_original { + use super::*; + + use serial_test::serial; + + #[test] + #[serial(bash)] + fn simple_bloc() { + let mut data = DataHolder::new(); + data.current_bloc = String::from("\necho 3"); + + data.filetype = String::from("bash"); + data.range = [1, 3]; + + let mut interpreter = Neorg_original::new(data); + let res = interpreter.execute(); + let string_result = res.unwrap(); + assert_eq!(string_result, "3\n"); + } +} diff --git a/src/interpreters/OrgMode_original.rs b/src/interpreters/OrgMode_original.rs index 816361e9..448e4815 100644 --- a/src/interpreters/OrgMode_original.rs +++ b/src/interpreters/OrgMode_original.rs @@ -27,14 +27,35 @@ impl OrgMode_original { let mut counter = 0; let selection_line = self.data.range[0] as usize; let mut v = vec![]; + let mut run_next_code_bloc = 0; for (i, l) in lines.iter().enumerate() { + // rerunranges only named tags if any are asked for + if self.get_data().cli_args.is_empty() + || (l.trim_start().to_lowercase().starts_with("#+name:") + && self + .get_data() + .cli_args + .contains(&l.to_lowercase().replace("#+name:", "").trim().to_string())) + { + run_next_code_bloc = 2; + } + info!("checking code bloc delimiter in : {}",l); + if l.trim_start().to_lowercase().starts_with("#+begin_src") { + if run_next_code_bloc == 0 { + continue; + } + run_next_code_bloc -= 1; if counter % 2 == 1 { return Err(SniprunError::CustomError(String::from("Incomplete or nested code blocs")))} counter += 1; v.push((selection_line + i + 1, 0)); } if l.trim_start().to_lowercase().starts_with("#+end_src") { + if run_next_code_bloc == 0 { + continue; + } + run_next_code_bloc -= 1; if counter % 2 == 0 { return Err(SniprunError::CustomError(String::from("Incomplete or nested code blocs")))} counter += 1; v[((counter - 1) / 2) as usize].1 = selection_line + i - 1; @@ -47,6 +68,9 @@ impl OrgMode_original { "Selection contains an odd number of code bloc delimiters", ))); } + if v.is_empty() { + return Err(SniprunError::CustomError("No matching tag #+NAME: was found".to_string())); + } info!("running separately ranges : {:?}", v); return Err(SniprunError::ReRunRanges(v)); } @@ -221,6 +245,46 @@ impl Interpreter for OrgMode_original { SupportLevel::Import } + fn check_cli_args(&self) -> Result<(), SniprunError> { + info!("Checking cli-args: {:?}", self.get_data().cli_args); + + // check arguments are #name tags + let nvim_instance = self.data.nvim_instance.clone().unwrap(); + let mut real_nvim_instance = nvim_instance.lock().unwrap(); + let lines = real_nvim_instance + .get_current_buf() + .unwrap() + .get_lines( + &mut real_nvim_instance, + self.data.range[0] - 1, + self.data.range[1], + false, + ) + .unwrap(); + for tag_name in self.get_data().cli_args { + // walk the whole visual selection in case multiple code block are contained + + let mut found = false; + for (i, l) in lines.iter().enumerate() { + info!("checking named tag {} in line {}", tag_name, i); + if l.trim_start().to_lowercase().starts_with("#name:") + && tag_name.to_lowercase() + == (l.to_lowercase().replace("#name:", "").trim().to_string()) + { + found = true; + info!("found named tag {} in line: {}", tag_name, l); + break; + } + } + + if !found { + info!("CLI arguments for Orgmode should be valid #+NAME tags"); + } + } + + return Ok(()); + } + fn fetch_code(&mut self) -> Result<(), SniprunError> { if !self .data @@ -262,28 +326,6 @@ impl Interpreter for OrgMode_original { } fn build(&mut self) -> Result<(), SniprunError> { - let last_line = self.code.lines().last().unwrap_or(""); - - // for some languages, handle an eventual final 'return' as a print - if last_line.starts_with("return") { - let printing_last_line = match self.data.filetype.as_str() { - // after 'fetch, contains the embbeded language filetype - "python" | "python3" | "py" | "sage.python" => { - String::from("print(") + last_line.strip_prefix("return").unwrap() + ")" - } - "rust" => { - String::from("println!(\"{}\",") - + last_line.strip_prefix("return").unwrap() - + ")" - } - "bash" => String::from("echo ") + last_line.strip_prefix("return").unwrap(), - _ => last_line.to_string(), - }; - let mut code_in_lines: Vec<&str> = self.code.lines().collect(); - code_in_lines.pop(); - code_in_lines.push(&printing_last_line); - self.code = code_in_lines.join("\n"); - } Ok(()) } diff --git a/tests/integration.rs b/tests/integration.rs index 430610b9..49507318 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -12,7 +12,6 @@ fn test_implements() { let _ = Current::default_for_filetype(); let _ = Current::get_supported_languages(); let _ = interpreter.fallback(); - let _ = interpreter.check_cli_args(); let max_level = Current::get_max_support_level(); let current_level = interpreter.get_current_level(); assert_eq!(max_level, current_level);