diff options
author | Christian Neukirchen <chneukirchen@gmail.com> | 2016-07-03 21:53:34 +0200 |
---|---|---|
committer | Christian Neukirchen <chneukirchen@gmail.com> | 2016-07-03 21:53:34 +0200 |
commit | a8ae7bf2e82c6ead3aaea725b971281cf2a19d6d (patch) | |
tree | 394b9a963e130b2ab42f85a5787e637724995c3a | |
parent | 77d7e8335578231351a25580bb4497f84e0bc219 (diff) | |
download | lrep-a8ae7bf2e82c6ead3aaea725b971281cf2a19d6d.tar.gz lrep-a8ae7bf2e82c6ead3aaea725b971281cf2a19d6d.tar.xz lrep-a8ae7bf2e82c6ead3aaea725b971281cf2a19d6d.zip |
-rw-r--r-- | README.md | 157 | ||||
-rwxr-xr-x | lrep | 6 |
2 files changed, 163 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..1b4c10e --- /dev/null +++ b/README.md @@ -0,0 +1,157 @@ +# lrep: literate read-eval-print + +`lrep` is a simple Unix filter for "literate repl" or "notebooks". +Documentation and input commands can be interleaved linewise, and the +commands drive a session whose output is merged into the document. + +The syntax is Markdown compatible. + +## Usage + + lrep [-z] [-t N] [FILES...] + +* `-z`: zap, don't run any commands, and remove the former output +* `-t N`: adjust timeout to `N` seconds (default: 0.04), + after which `lrep` will assume no further output happened. + The initial command has `20*N` seconds time to display a prompt. + +When no `FILES` are give, `lrep` reads from STDIN. + +## Syntax + +There are three kinds of lines of interest to `lrep`: + + <TAB>!!!CMD... + +Non-interactive session: just display output of `CMD`. +When `CMD` ends with `>-`, no output is shown. + + <TAB>!PS1!PS2!CMD... + +Starts a new session for `CMD...`. The `!PS2` part is optional. +`PS1` is the first prompt considered, `PS2` the second prompt. +Note that prompts often end with a space in practice! +When `CMD` ends with `>-`, no output of startup is shown. + +When `PS1` is empty, `PS2` needs to be provided. Prompt-finding is +disabled and only timeouts are used to detect when new input can be sent. +Lines to input are marked using `PS2`. + + <TAB><PS1>INPUT... + <TAB><PS2>INPUT... + +Send a line to the session, and display the output. +When `CMD` ends with `>-`, no output is shown. + + <TAB>... + +Other lines starting with `<TAB>` are assumed to be former output of +`lrep` and dropped. Use four spaces for non-`lrep` verbatim code +(or fenced blocks). + +## Algorithm + +`lrep` runs the command in a PTY, and reads according to the following scheme: + +1. Read as many bytes as possible without blocking. +2. If the last line of the string read contains PS1 or PS2 at the end, break. +3. Else, read as many bytes as possible without blocking or until timeout passed, + and go to step 2. + +(When PS1 is empty, the algorithm starts at step 3.) + +## Example + +For example, we can spawn a shell: + + !$ !sh + +To send a line to the interpreter, start it with `<TAB>PS1` + + $ uname + Linux + +Commands also can generate more than one output line: + + $ printf '%s\n' foo bar baz + foo + bar + baz + +All commands run in the same session, so you can refer to previous results: + + $ x=foo + $ y=bar + $ echo ${x}${y} + foobar + +To just one-shot show the output of a non-interactive program, use +`<TAB>!!!CMD` + + !!! uname + Linux + +Let's try something in dc(1). But since it doesn't have a prompt, we'll need +to use timed mode which is less robust and waits for 40ms without output. +Since `lrep` still needs to find the input strings, pass an alternate prompt +using `<TAB>!!PS2!CMD...`: + + !!> !dc + > 6 7 + > + + > p + 13 + +Perhaps Ruby is better. This is also an example of how to use two prompts: + + !>> !?> !irb --simple-prompt + >> 6 + + ?> 7 + => 13 + >> 6 + 7 + => 13 + +To use `lrep`, simply filter the file through the program: + + !!:!ed + :a + :A simple lrep example + : !!!echo elpmaxe na tsuj | rev + :. + :w try1.lrep + 53 + :q + :# test death detection + + !!!./lrep <try1.lrep + A simple lrep example + !!!echo elpmaxe na tsuj | rev + just an example + +Note that is exactly how this file was created. + +## Editor integration + +Vi: + + map \e :!%./lrep<CR>`` + +Emacs: + + C-x h C-u M-| lrep <RET> + +## Caveat + +`lrep` will execute arbitary code in the input files, that's exactly +its job. Be careful what you run it on. + +## Copyright + +`lrep` is in the public domain. + +To the extent possible under law, +Christian Neukirchen <chneukirchen@gmail.com> +has waived all copyright and related or +neighboring rights to this work. + +http://creativecommons.org/publicdomain/zero/1.0/ diff --git a/lrep b/lrep index 399d858..dafc644 100755 --- a/lrep +++ b/lrep @@ -2,6 +2,12 @@ # lrep [-z] [-t SECS] [FILES...] - literate read-eval-print # -*- ruby -*- +# +# To the extent possible under law, +# Christian Neukirchen <chneukirchen@gmail.com> +# has waived all copyright and related or neighboring rights to this work. +# http://creativecommons.org/publicdomain/zero/1.0/ + require 'pty' require 'io/console' require 'optparse' |