REPL Presentation
Run a REPL presentation.
This package allows building presentations using only a REPL environment.
Features
- Easy to write and minimal slide markup.
- Built-in navigation commands to move and jump between slides.
- Slide fragments (i.e., incremental slides).
- Progress display.
- Text alignment (left, right, centered, flush) and horizontal rules.
- ANSI colors and styling.
- Emoji support.
- Executable slide code.
- Programmatic interface.
- Command-line interface (CLI).
- Watch mode with automatic reload (aka, "hot reloading").
Authoring
A REPL presentation source file is a text file which includes minimal markup for delineating slides, slide fragments, speaker notes, code, text alignment, and styling.
Slides
To delineate a new slide, use three dashes ---
.
This is the first slide.
---
This is the second slide.
Leading and trailing whitespace between slides is removed.
Slide Fragments
To delineate a slide fragment (i.e., incremental slide), use two dashes --
.
This is an incremental slide.
--
...which includes some more text
--
...and even more text
--
...and even more text
Leading and trailing whitespace between slide fragments is removed. To manually space slide fragments, use the ANSI escape cope \s
.
List items are separated by blank lines...
\s
--
• Item 1.
\s
--
• Item 2.
\s
--
• Item 3.
--
\s
...by using the ANSI escape code to reset styling.
Code Blocks
To delineate slide code, use three backticks.
This is a slide with code.
```
var x = 3.14;
```
By default, code blocks are assumed to be JavaScript. To explicitly specify the code block language, include the language identifier after the first set of backticks.
This is a slide with code.
```javascript
var x = 3.14;
```
Only JavaScript code blocks are runnable. To run JavaScript code on the current slide, invoke the presentation command runSlide()
at the REPL prompt.
Speaker Notes
To delineate speaker notes, use three tildes ~~~
after a slide's content and before delineating the next slide.
This is a slide
~~~
...with speaker notes.
Text Alignment
To align text, use the following markup at the start of a content line to align
Character Sequence | Description |
---|---|
\| | Centered |
< | Left-aligned |
<< | Left-flushed |
> | Right-aligned |
>> | Right-flushed |
For example,
| This text is center-aligned.
---
< This text is left-aligned.
---
<< This text is left-flushed.
---
> This text is right-aligned.
---
>> This text is right-flushed.
The space separating the alignment character sequence from the text is required.
ANSI Colors and Styling
To apply ANSI colors and styling, use the following markup
Escape Code | Description |
---|---|
\x | Foreground color |
\X | Background color |
\* | Bold |
\_ | Underlined |
\! | Reverse colors |
\s | Reset to normal |
For example,
\rThis text is colored red.\s
---
\gThis text is colored green.\s
---
\YThe text background is yellow.\s
---
\bThis text is bold.\s
---
\_This text is underlined.\s
---
\!This text has inverted colors.\s
---
\_\*This text is both underlined and bold.\s\s
Emoji
To include an emoji, insert the relevant emoji code. For example,
:books: :grinning: :+1: :man: :woman:
Note, however, that emoji support is limited to emoji which are two columns wide. Accordingly, not all emoji are supported.
Horizontal Rules
To insert horizontal rules, use the following markup at the start of a line
Character Sequence | Description |
---|---|
/ | Content width |
// | Full screen |
For example, to insert a horizontal rule spanning the content width
Rule length matches the length of this sentence.
/
More content below.
To insert a horizontal rule spanning the slide width
Rule spans the slide width.
//
More content below.
The default rule character is -
. To specify an alternative rule character sequence, provide a pattern. For example,
/=+
//=+
Custom patterns can include Unicode and ANSI colors. For example,
/\r=\s\**\s\r=\b=\s\**\s\b=
//\r=\s\**\s\r=\b=\s\**\s\b=
And lastly, custom patterns can include emoji. For example,
/ :grinning: :+1:
// :grinning: :+1:
Usage
var Presentation = require( '@stdlib/repl/presentation' );
Presentation( [text,] repl[, options] )
Returns a REPL presentation instance for running a presentation in a provided repl
.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Close the REPL:
repl.close();
The function accepts the following options
:
- borderTop: top border character sequence. Default:
'*'
. - borderBottom: bottom border character sequence. Default:
'*'
. - borderLeft: left border character sequence. Default:
'* '
. - borderRight: right border character sequence. Default:
' *'
. - counter: slide counter. Can either be
true
,false
, or'progress'
. Default:false
. - width: presentation width. If
null
, the presentation width is either computed based on the screen size (if a REPL output stream is TTY) or set to80
characters. Default:null
. - height: presentation height. If
null
, the presentation height is either computed based on the screen size (if a REPL output stream is TTY) or set to25
rows. Default:null
. - workspace: REPL workspace name. A presentation instance adds presentation commands to the specified workspace, thus allowing presentation navigation and interaction. Default:
'presentation'
. - load: file path specifying a presentation file to load. If a presentation
text
is provided, this option is ignored. - autoClear:
boolean
indicating whether to automatically clear the screen before writing a rendered slide to the REPL. Default:true
. - loop:
boolean
indicating whether to "loop" a presentation (i.e., proceed to the first slide after the last slide and have the last slide precede the first slide). Default:false
.
To initialize a presentation upon instantiating a Presentation
instance, either provide a string
as the first argument containing the presentation text to render or set the load
option to specify a presentation file to load.
Presentation.prototype.currentSlide
Returns the current presentation slide index.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Return the current presentation slide index:
var idx = pres.currentSlide;
// ...
// Close the REPL:
repl.close();
Note: the returned index is the nominal (i.e., one-based) slide index.
Presentation.prototype.end()
Jumps to the last fragment of the last slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the last fragment of the last slide:
pres.end();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.first()
Jumps to the first slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the first slide:
pres.first();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.firstFragment()
Jumps to the first fragment of the current slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the first fragment of the current slide:
pres.firstFragment();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.height
Returns the presentation height.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// Return the presentation height:
var height = pres.height;
// Close the REPL:
repl.close();
Presentation.prototype.jump( n )
Jumps a specified number of slides.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the third previous slide:
pres.jump( -3 );
// ...
// Jump to the slide after the next:
pres.jump( 2 );
// ...
// Close the REPL:
repl.close();
Presentation.prototype.jumpTo( n )
Jumps to a specified slide, where n
is the nominal (i.e., one-based) slide number.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the fourth slide:
pres.jumpTo( 4 );
// ...
// Close the REPL:
repl.close();
Presentation.prototype.last()
Jumps to the last slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the last slide:
pres.last();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.lastFragment()
Jumps to the last fragment of the current slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Jump to the last fragment of the current slide:
pres.lastFragment();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.length
Returns the presentation length (i.e., number of slides).
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Return the presentation length:
var len = pres.length;
// ...
// Close the REPL:
repl.close();
Presentation.prototype.load( file )
Loads a presentation from a file
.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Load a presentation from a file:
try {
pres.load( './path/to/presentation.txt' );
} catch ( error ) {
console.error( error.message );
}
// ...
// Close the REPL:
repl.close();
Note: relative file paths are resolved relative to the current working directory.
Presentation.prototype.next()
Moves the presentation to the next slide or slide fragment.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Move to the next slide or slide fragment:
pres.next();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.nextSlide()
Moves the presentation to the next slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Move to the next slide:
pres.nextSlide();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.prev()
Moves the presentation to the previous slide or slide fragment.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Move to the previous slide or slide fragment:
pres.prev();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.prevSlide()
Moves the presentation to the previous slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Move to the previous slide:
pres.prevSlide();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.reload()
Reloads a presentation.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Reload a presentation:
try {
pres.reload();
} catch ( error ) {
console.error( error.message );
}
// ...
// Close the REPL:
repl.close();
Presentation.prototype.render()
Renders the current presentation slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Render the current presentation slide:
var slide = pres.render();
if ( slide === null ) {
console.log( 'Unable to render slide.' );
}
// ...
// Close the REPL:
repl.close();
Presentation.prototype.run( done )
Runs any code on the current presentation slide.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Run any code on the current slide:
pres.run( done );
function done() {
// Close the REPL:
repl.close();
}
Presentation.prototype.show()
Shows a presentation slide (i.e., writes a rendered slide to the presentation REPL)
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Show the current presentation slide:
pres.show();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.slideHeight
Returns the presentation content height.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// Return the presentation slide content height:
var h = pres.slideHeight;
// Close the REPL:
repl.close();
Presentation.prototype.slideWidth
Returns the presentation content width.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// Return the presentation slide content width:
var h = pres.slideWidth;
// Close the REPL:
repl.close();
Presentation.prototype.unwatch( [error] )
Stops watching a presentation file for changes.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Watch a presentation source file:
try {
pres.watch();
} catch ( error ) {
console.error( error.message );
}
// ...
// Stop watching a presentation source file:
pres.unwatch();
// ...
// Close the REPL:
repl.close();
Presentation.prototype.watch()
Watches a presentation source file for changes.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// ...
// Watch a presentation source file:
try {
pres.watch();
} catch ( error ) {
console.error( error.message );
}
// ...
// Close the REPL:
repl.close();
Note: the method does not track source file "renames". If the source presentation file is renamed, watching stops.
Presentation.prototype.width
Returns the presentation width.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
// Return the presentation width:
var width = pres.width;
// Close the REPL:
repl.close();
Commands
REPL instances running a REPL presentation support the following commands within the presentation workspace...
blank()
Renders a blank screen.
In [1]: blank();
currentSlide
Returns the nominal current presentation slide index (one-based).
In [1]: var idx = currentSlide;
end()
Jumps to the last fragment of the last presentation slide.
In [1]: end();
first()
Jumps to the first presentation slide.
In [1]: first();
firstFragment()
Jumps to the first fragment of the current presentation slide.
In [1]: firstFragment();
jump( n )
Jumps a specified number of slides.
In [1]: jump( 2 ); // jump two slides forward
In [2]: jump( -2 ); // jump two slide backward
jumpTo( n )
Jumps to a specified presentation slide, where n
is the nominal presentation slide index (one-based).
In [1]: jumpTo( 2 ); // jump to the second slide
last()
Jumps to the first fragment of the last presentation slide.
In [1]: last();
lastFragment()
Jumps to the last fragment of the current presentation slide.
In [1]: lastFragment();
loadPresentation( file )
Loads a presentation from a file.
In [1]: loadPresentation( './path/to/presentation.txt' );
Note: relative file paths are resolved relative to the current working directory.
next()
Moves to the next presentation slide or slide fragment.
In [1]: next();
nextSlide()
Moves to the next presentation slide.
In [1]: nextSlide();
numSlides
Returns the number of presentation slides.
In [1]: var len = numSlides;
pres()
Prints presentation help text and shortcuts.
In [1]: pres();
prev()
Moves to the previous presentation slide or slide fragment.
In [1]: prev();
prevSlide()
Moves to the previous presentation slide.
In [1]: prevSlide();
redraw()
Redraws the current presentation slide.
In [1]: redraw();
reloadPresentation()
Reloads a presentation.
In [1]: reloadPresentation();
renderSlide()
Renders the current presentation slide.
In [1]: var str = renderSlide();
runSlide()
Runs slide code.
In [1]: runSlide();
unwatch( [error] )
Stops watching a source presentation file for changes.
In [1]: unwatch();
watch()
Watches a source presentation file for changes.
In [1]: watch();
Note: "Renaming" a source file is not tracked. If a source presentation file is renamed, watching stops.
Shortcuts
Command | Shortcut | Description |
---|---|---|
blank | b | Render a blank screen. |
end | L | Jump to the last fragment of the last slide. |
first | f | Jump to the first slide. |
firstFragment | ff | Jump to the first slide fragment. |
jump | g | Jump a specified number of slides. |
jumpTo | j | Jump to a specified slide. |
last | l | Jump to the first fragment of the last slide. |
lastFragment | lf | Jump to the last slide fragment. |
loadPresentation | lp | Load a presentation. |
next | n | Move to the next slide or slide fragment. |
nextSlide | N | Move to the next slide. |
pres | h | Print presentation help text. |
prev | p | Move to the previous slide or slide fragment. |
prevSlide | P | Move to the previous slide. |
redraw | rd | Redraw the current slide. |
reloadPresentation | rlp | Reload the current presentation. |
runSlide | r | Run slide code. |
unwatch | uw | Stop watching a source file for changes. |
watch | w | Watch a source file for changes. |
Events
A REPL presentation emits the following events...
'watch'
This event is emitted upon watching a source presentation file.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
function onWatch() {
console.log( 'Watching a source file.' );
}
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
pres.on( 'watch', onWatch );
// ...
// Close the REPL:
repl.close();
'change'
When watching a source presentation file, this event is emitted whenever a source presentation file changes.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
function onChange() {
console.log( 'Source file changed.' );
}
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
pres.on( 'change', onChange );
// ...
// Close the REPL:
repl.close();
'unwatch'
This event is emitted upon no longer watching a source presentation file.
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
function onUnwatch( error ) {
console.log( 'No longer watching a source file.' );
if ( error ) {
console.error( error.message );
}
// Include logic to, e.g., restart watching a source presentation file...
}
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
// Create a new REPL presentation:
var pres = new Presentation( repl );
pres.on( 'unwatch', onUnwatch );
// ...
// Close the REPL:
repl.close();
Notes
- Multiple presentations can be run simultaneously within the same REPL environment. To do so, assign each presentation instance to a unique workspace.
Examples
var join = require( 'path' ).join;
var debug = require( '@stdlib/streams/node/debug-sink' );
var REPL = require( '@stdlib/repl' );
var Presentation = require( '@stdlib/repl/presentation' );
function onExit() {
console.log( '' );
console.log( 'REPL closed.' );
}
// Create a new REPL:
var repl = new REPL({
'output': debug()
});
repl.on( 'exit', onExit );
// Create a new REPL presentation:
var pres = new Presentation( repl, {
'counter': 'progress'
});
// Load a presentation file:
pres.load( join( __dirname, 'examples', 'presentation.txt' ) );
// Get the number of slides:
var len = pres.length;
// Render the first slide:
pres.show();
// Automate the slide show:
setTimeout( next, 100 );
function next() {
// If we are finished with the slide show, close the REPL...
if ( pres.currentSlide === len ) {
return repl.close();
}
pres.next().show();
setTimeout( next, 100 );
}
CLI
Usage
Usage: stdlib-repl-presentation [options] [<filepath>]
Options:
-h, --help Print this message.
-V, --version Print the package version.
--border-top <str> Top border. Default: '*'.
--border-bottom <str> Bottom border. Default: '*'.
--border-left <str> Left border. Default: '* '.
--border-right <str> Right border. Default: ' *'.
--counter <value> Show slide counter.
--width <width> Presentation width.
--height <height> Presentation height.
--workspace <workspace> REPL workspace name. Default: presentation.
--input-prompt <prompt> Input prompt. Default: 'In [%d]: '.
--output-prompt <prompt> Output prompt. Default: 'Out[%d]: '.
--padding <padding> Empty lines between commands. Default: 1.
--save <filepath> File to save REPL command history.
--logfile <filepath> File to log REPL commands and printed output.
--timeout <timeout> Milliseconds before terminating a command.
--quiet Disable printing of REPL logs and diagnostics.
--no-autoclear Disable automatic clearing when rendering.
--loop Loop a presentation.
--watch Watch the source presentation file for changes.
Notes
- Use as a standard stream is not currently supported on Windows.
- If provided presentation text over
stdin
, thefilepath
argument and thewatch
option are ignored.
Examples
$ stdlib-repl-presentation ./path/to/presentation.txt
To use as a standard stream,
cat ./path/to/presentation.txt | stdlib-repl-presentation