Skip to content

Commit 46f5a08

Browse files
authored
Merge pull request #312 from michaelb/dev
Dev
2 parents 151ada2 + 5298f9b commit 46f5a08

31 files changed

+818
-117
lines changed

.github/workflows/rust.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
persist-credentials: false
3838
- uses: dtolnay/rust-toolchain@stable
3939
- name: Build
40-
run: cargo build --verbose --release --target x86_64-unknown-linux-gnu
40+
run: cargo build --verbose --release --locked --target x86_64-unknown-linux-gnu
4141

4242
buildmsrv:
4343
name: build-msrv
@@ -59,7 +59,7 @@ jobs:
5959
persist-credentials: false
6060
- uses: dtolnay/rust-toolchain@nightly
6161
- name: build
62-
run: cargo build --release --target x86_64-unknown-linux-gnu
62+
run: cargo build --release --locked --target x86_64-unknown-linux-gnu
6363

6464
unittest:
6565
name: unit & integration tests

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## v1.3.18
2+
- Swift support (incl. REPL)
3+
- Configurable REPL timeout
4+
- Rust_original now repl capable (based on evcxr)
5+
- REPL limitation 'please re-run your snippet' removed
6+
17
## v1.3.17
28
- better fallback messages
39
- Terminal display mode fixes (courtesy of @dbeecham)

Cargo.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sniprun"
3-
version = "1.3.17"
3+
version = "1.3.18"
44
authors = ["michaelb <michael.bleuez2@gmail.com>"]
55
rust-version = "1.65"
66
edition = "2018"

doc/sources/common_options.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ require('sniprun').setup({
4141
some_specific_option = value,
4242
some_other_option = other_value,
4343
}
44-
}
45-
},
44+
},
45+
-- ...
4646
})
4747
EOF
4848
```
@@ -65,7 +65,7 @@ require('sniprun').setup({
6565
--# the hint is available for every interpreter
6666
--# but may not be always respected
6767
}
68-
},
68+
},
6969
})
7070
EOF
7171
```
@@ -83,11 +83,35 @@ interpreter_options = {
8383
}
8484
```
8585

86+
### The "repl_timeout" key
87+
88+
REPL-enabled interpreters _sometime_ have mechanisms in place to limit how long a snippet of code
89+
can run. Be it because an infinite loop was (unintentionally?) run, or "something happened" which
90+
can make the interpreter unsuable in the meantime, limiting that 'meantime' is generally a good idea.
91+
92+
By default, this timeout is set to 30s, after which, if no result was produced, the message:
93+
`Interpreter limitation: reached the repl timeout` is returned (as an error).
94+
95+
Note that running an infinite loop may still cause the underlying REPL of the language (in the
96+
cases where one is used) to be stuck. The only purpose of this timeout is actually to warn the user
97+
something is taking 'probably' too long. This is why after getting such an error, it's better to
98+
run a `SnipReset` before trying to continue using the interpreter.
99+
100+
This key is customizable per-interpreter, though only some (most) REPL-enabled interpreter will respect it:
101+
102+
```lua
103+
interpreter_options = {
104+
Python3_fifo = {
105+
repl_timeout = 900, -- 900s = 15min max runtime
106+
},
107+
```
108+
109+
86110
### The "error_truncate" key
87111

88112
Also available for every interpreter if you don't like how sniprun truncate some outputs by default (auto), but it will not have an effect on all interpreters.
89113

90-
```
114+
```lua
91115
interpreter_options = {
92116
Python3_original = {
93117
error_truncate = "auto" --# Truncate runtime errors 'long', 'short' or 'auto'
@@ -120,6 +144,7 @@ sniprun internally expect, or be straight out incompatible with the formers. Be
120144

121145
Exceptions:
122146
- Scala_original has both interpreter and compiler keys that should be set consistently with each other
123-
- *_jupyter, Generic, GFM_original, Orgmode_original, and Neorg_original do not support any of these keys, as they rely on the interpreter for the code's block language.
147+
- *_jupyter, Generic, GFM_original, Orgmode_original, and Neorg_original do not support any of these keys,
148+
as they rely on the underlying interpreter for the code's block language and use its configuration.
124149

125150

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
## TypeScript original
22

3-
Requires `ts-node`, usually installed from npm
3+
Prior to NodeJS v22.6.0:
4+
Install `ts-node`, usually installed from npm
45

56
`sudo npm install -g ts-node typescript`
7+
8+
---
9+
10+
If you have NodeJS v22.6.0+:
11+
12+
```lua
13+
require'sniprun'.setup({
14+
interpreter_options = {
15+
TypeScript_original = {
16+
interpreter = 'node'
17+
}
18+
}
19+
}
20+
})
21+
```
22+
23+
[^1]: `ts-node` and `typescript` packages are no longer needed for newer NodeJS versions

ressources/CONTRIBUTING_REPL.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ Just like you implemented the Interpreter trait for a conventional runner, you'l
2626

2727
1. Running something in the background:
2828

29-
Unfortunately, this require a first workaround. It's mainly due to how sniprun can't really launch a background process that stays alive, even when the thread executing the user's command exits, and sorta re-launch itself some time later (the interpreters needs some time to launch) to execute the input. The first user command will always fail with a message ("launching .. interpreter in the background, please re-run last snippet").
3029
```rust
3130
fn fetch_code_repl(&mut self) -> Result<(), SniprunError> {
3231
if !self.read_previous_code().is_empty() {
@@ -57,11 +56,11 @@ Just like you implemented the Interpreter trait for a conventional runner, you'l
5756

5857
let pause = std::time::Duration::from_millis(100);
5958
std::thread::sleep(pause);
60-
self.save_code("kernel_launched\nimport sys".to_owned());
6159

62-
Err(SniprunError::CustomError(
63-
"Python3 kernel launched, re-run your snippet".to_owned(),
64-
))
60+
self.save_code("kernel_launched\n".to_owned());
61+
let v = vec![(self.data.range[0] as usize, self.data.range[1] as usize)];
62+
Err(SniprunError::ReRunRanges(v)) // special error that tells sniprun to re-run a snippet
63+
// which is simpler than to embed calls to fetch/build/.. here
6564
}
6665
```
6766
The important thing to note is that `self.read_previous_code()` is used to determine whether a kernel was already launched; (`self.get_pid()/set_pid()` can be used to store an incrementing number of 'runs' or the child's PID, or whatever.

ressources/demo_display.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/daemonizer.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
/**
2-
Derived from https://github.com/immortal/fork
3-
*/
1+
//! Derived from https://github.com/immortal/fork
42
53
/// Fork result
64
pub enum Fork {

src/display.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ pub fn display_floating_window(
439439
.current_bloc
440440
.lines()
441441
.filter(|&line| !line.is_empty())
442-
.last()
442+
.next_back()
443443
.unwrap_or(&data.current_line)
444444
.len();
445445
let row = data.range[0] + data.current_bloc.trim_end_matches('\n').lines().count() as i64 - 1;
@@ -533,7 +533,7 @@ fn shorten_ok(message: &str) -> String {
533533
+ message
534534
.lines()
535535
.filter(|&s| !s.is_empty())
536-
.last()
536+
.next_back()
537537
.unwrap_or("")
538538
}
539539

src/interpreter.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ pub trait InterpreterUtils {
199199
fn contains_main(entry: &str, snippet: &str, comment: &str) -> bool;
200200
fn error_truncate(data: &DataHolder) -> ErrTruncate;
201201

202+
fn get_repl_timeout(data: &DataHolder) -> u64;
202203
fn get_compiler_or(data: &DataHolder, or: &str) -> String;
203204
fn get_interpreter_or(data: &DataHolder, or: &str) -> String;
204205
}
@@ -303,6 +304,16 @@ impl<T: Interpreter> InterpreterUtils for T {
303304
None
304305
}
305306

307+
/// returns the configured time (in seconds) to wait for a repl response
308+
/// Default: 30s
309+
fn get_repl_timeout(data: &DataHolder) -> u64 {
310+
if let Some(timeout) = T::get_interpreter_option(data, "repl_timeout") {
311+
timeout.as_u64().unwrap_or(30)
312+
} else {
313+
30
314+
}
315+
}
316+
306317
fn get_compiler_or(data: &DataHolder, or: &str) -> String {
307318
if let Some(compiler) = T::get_interpreter_option(data, "compiler") {
308319
if let Some(compiler_valid_str) = compiler.as_str() {

src/interpreters/Clojure_fifo.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(clippy::zombie_processes)]
12
use crate::interpreters::import::*;
23

34
#[derive(Clone)]
@@ -42,9 +43,9 @@ impl Clojure_fifo {
4243
pause = pause.saturating_add(std::time::Duration::from_millis(50));
4344

4445
// timeout after 30s if no result found
45-
if start.elapsed().as_secs() > 30 {
46+
if start.elapsed().as_secs() > Clojure_fifo::get_repl_timeout(&self.data) {
4647
return Err(SniprunError::InterpreterLimitationError(String::from(
47-
"reached the 30s timeout",
48+
"reached the repl timeout",
4849
)));
4950
}
5051

@@ -294,13 +295,10 @@ impl ReplLikeInterpreter for Clojure_fifo {
294295
};
295296

296297
self.save_code("kernel_launched\n".to_owned());
297-
298-
let pause = std::time::Duration::from_millis(300);
298+
let pause = std::time::Duration::from_millis(100);
299299
std::thread::sleep(pause);
300-
301-
Err(SniprunError::CustomError(
302-
"Clojure interactive kernel launched, re-run your snippet".to_owned(),
303-
))
300+
let v = vec![(self.data.range[0] as usize, self.data.range[1] as usize)];
301+
Err(SniprunError::ReRunRanges(v))
304302
}
305303
}
306304

src/interpreters/Elixir_original.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(clippy::zombie_processes)]
12
use crate::interpreters::import::*;
23

34
#[derive(Clone)]
@@ -240,13 +241,11 @@ impl ReplLikeInterpreter for Elixir_original {
240241
),
241242
};
242243

244+
self.save_code("kernel_launched\n".to_owned());
243245
let pause = std::time::Duration::from_millis(100);
244246
std::thread::sleep(pause);
245-
self.save_code("kernel_launched".to_owned());
246-
247-
Err(SniprunError::CustomError(
248-
"elixir kernel launched, re-run your snippet".to_owned(),
249-
))
247+
let v = vec![(self.data.range[0] as usize, self.data.range[1] as usize)];
248+
Err(SniprunError::ReRunRanges(v))
250249
}
251250
}
252251

src/interpreters/FSharp_fifo.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(clippy::zombie_processes)]
12
use crate::interpreters::import::*;
23

34
#[derive(Clone)]
@@ -38,9 +39,9 @@ impl FSharp_fifo {
3839
pause = pause.saturating_add(std::time::Duration::from_millis(50));
3940

4041
// timeout after 30s if no result found
41-
if start.elapsed().as_secs() > 30 {
42+
if start.elapsed().as_secs() > FSharp_fifo::get_repl_timeout(&self.data) {
4243
return Err(SniprunError::InterpreterLimitationError(String::from(
43-
"reached the 30s timeout",
44+
"reached the repl timeout",
4445
)));
4546
}
4647

@@ -282,9 +283,12 @@ impl ReplLikeInterpreter for FSharp_fifo {
282283
let pause = std::time::Duration::from_millis(2000); // prevent an user from re-running the snippet
283284
// before dotnet launches (2-3 secs)
284285
std::thread::sleep(pause);
285-
Err(SniprunError::CustomError(
286-
"F# interactive kernel launched, re-run your snippet".to_owned(),
287-
))
286+
287+
self.save_code("kernel_launched\n".to_owned());
288+
let pause = std::time::Duration::from_millis(100);
289+
std::thread::sleep(pause);
290+
let v = vec![(self.data.range[0] as usize, self.data.range[1] as usize)];
291+
Err(SniprunError::ReRunRanges(v))
288292
}
289293
}
290294

src/interpreters/Go_original.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ impl Go_original {
124124
}
125125

126126
fn parse_import_path(p: &str) -> String {
127-
p.replace('\"', "").split('/').last().unwrap().to_string()
127+
p.replace('\"', "")
128+
.split('/')
129+
.next_back()
130+
.unwrap()
131+
.to_string()
128132
}
129133
}
130134

src/interpreters/JS_TS_bun.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![allow(clippy::zombie_processes)]
12
use crate::interpreters::import::*;
23

34
#[derive(Clone)]
@@ -31,9 +32,9 @@ impl JS_TS_bun {
3132
pause = pause.saturating_add(std::time::Duration::from_millis(50));
3233

3334
// timeout after 30s if no result found
34-
if start.elapsed().as_secs() > 30 {
35+
if start.elapsed().as_secs() > JS_TS_bun::get_repl_timeout(&self.data) {
3536
return Err(SniprunError::InterpreterLimitationError(String::from(
36-
"reached the 30s timeout",
37+
"reached the repl timeout",
3738
)));
3839
}
3940

@@ -220,7 +221,7 @@ impl Interpreter for JS_TS_bun {
220221
.unwrap()
221222
.lines()
222223
.filter(|l| l.contains("Error:"))
223-
.last()
224+
.next_back()
224225
.unwrap_or(&String::from_utf8(output.stderr).unwrap())
225226
.to_string(),
226227
))

0 commit comments

Comments
 (0)