🔌 Plugin system

.lit has a flexible Plugin system, primarily to allow the author to create custom Viewers and REPLs but also includes various other types.

Anatomy of a plugin

.lit plugins are defined using the !plugin directive on a fenced code block.

```js !plugin id=foo type=bar
// implementation 
export const bar = (...args) => {
  return "I'm a plugin"
}
```

Initially it is assumed that a plugin is implemented in js but hopefully due to the flexibility this won't remain the case for long.

Scope

Generally plugins are scoped only to the .lit document they're defined in, they are evaluated sequentially and duplicates are overwritten.

If you would like to make a plugin available in all documents then you need to move them to a special config page.

Alternatively just make sure your plugin defines a filename and is an output, and then transclude it like so:

meta
Using transcluded `meta` viewer

Types

Plugins can optionally define a type= attribute. For built in types this is not necessary, but can also be used to exclude implementations that might be defined within.

Implemented yet or not?

  • parser:
  • renderer:
  • viewer:
  • transformer:
  • repl:
  • menu:
  • onsave|onload|onselect:
  • theme:
jsonUpdated 21.4w ago
[ 'theme (1): test',
  'viewer (2): meta, lang',
  'onload (2): sw, example-onload',
  'unknown (0): ',
  'repl (1): lang',
  'menu (2): example-menu, example-modal',
  'onselect (1): example-onselect',
  'onsave (1): example-onsave',
  'data (1): mydata',
  'parser (1): example-parser',
  'renderer (2): 1, example-renderer' ]

Viewer

The viewer type plugin -- which preceded the !plugin directive as !viewer -- allow the author to define how source content of a fenced code block should be viewed when rendered to html based on its lang.

This is useful for example when the source is json html or svg but as it turns out has many more uses see Viewers for details, built-in viewers and useful examples.

jspluginof=langimplementation
export const viewer = ({node, React}) => {
  return "Example viewer plugin used: " + node.data.value
}
langusageExample viewer plugin used: content 😊

REPL

Initially implemented directly but in the process of being ported to plugins by default. REPLs are one of the cornerstones of .lit allowing the reader to Execute code cells.

They take an input source from fenced code blocks and when executed add or replace an attached output.

jspluginof=langtype=replimplementation
export const repl = (src, meta, node) => {
  return `Input was ${src.length} characters long.`
}
langlangusage
content 😊
txtUpdated 33.4w ago
Input was 11 characters long.

Parser

Not yet Implemented.

jspluginid=example-parser
export const parser = (...args) => {
  return (tree) => {
    tree.data = file.data || {}
    tree.data__examplePluginActive = true
  }
}

Renderer

jspluginid=example-renderer
export const renderer = (...args) => {
  return (tree,file) => {
    file.data = file.data || {}
    file.data.__examplePluginActive = true
  }
}

On Lifecycle plugins

  • onload: Executed once on initial load of the document.
  • onselect: Executed on every cell selection, includes deselection, pos is null.
  • onsave: Executed on save (edit) but before filesystem or state is updated.
jspluginid=example-onloadtype=onload
export const onload  = (...args) => {
  alert("Custom Onload plugin executed", ...args)
}
jspluginid=example-onselecttype=onselect
export const onselect = (...args) => {
  console.info("Custom onselect plugin executed", ...args)
}
jspluginid=example-onsavetype=onsave
export const onsave = (...args) => {
  alert("Custom onsave plugin executed", ...args)
}

Custom

Since all plugins are extracted (to the global lit object) during parsing, regardless of implementation status, you can define your own. A good example is exporting data to be used in other cells.

jsplugintype=dataid=mydata
export const data = {
  type: "beer",
  bottles: 99,
}
jsusage> md
const data = lit.file.data.plugins.data.mydata
return `There are **${data.bottles}** bottles of *${data.type}* on the wall.`
mdUpdated 32w ago

There are 99 bottles of beer on the wall.