Decorations

Dendron uses a design split between the engine and plugin to add decorations for the editor. The engine is responsible for the heavier work of computing the decorations to be displayed, while the plugin then converts the engine output to be displayed by VSCode.

This part of the documentation describes the plugin side, see decorators in engine for the engine side.

Overview

sequenceDiagram participant VSCode participant plugin participant engine VSCode->>plugin: user opens new note, scrolls, or types plugin->>engine: ask for decorations VSCode->>plugin: user types again engine->>plugin: plain decoration objects plugin->>engine: ask for decorations engine->>plugin: plain decoration objects plugin->>VSCode: VSCode decorations

This shows a brief example of how VSCode, plugin, and engine interact with each other to display the decorations. A few points of importance:

  • The plugin ignores the engine response if the user did something like typing that made the decorations stale.
    • This is because applying stale decorations can cause them to appear in the wrong places inside the document, but not applying decorations at least retains the old decorations at the correct places.
    • This is especially an issue if the user adds new lines in the middle of a note.
  • Engine sends plain objects, which the plugin converts to VSCode objects. This is necessary because the engine API can't pass VSCode objects, and we want to keep the engine more independent from the plugin.
  • The plugin converts the the plain objects into the objects VSCode expects and applies them.

Entry

LifeCycle

updateDecorations(editor) {
  ctx = "updateDecorations"

  // try to get the note, if no note, return
  note = getNoteFromDocument else return

  inputRanges = mergeOverlappingRanges(editor.visibleRanges)
  resp = engine.getDecorations(inputRanges)

  ...
  log {"error":null,"decorationsLength":110,"diagnosticsLength":0}
  activeDecorations = resp.data | mapDecoration
  editor.setDecorations activeDecorations

  allWarnings = data?.diagnostics
  delayedFrontmatterWarning allWarnings
}

// applies colors
mapDecoration(decorator) {
    switch decorator.type
        case type:
            handle(type)
}

Reference

Cook

Updating an existing decoration

First, look at windowDecorations.ts and locate the map* function for the decoration you are interested in. If there is no function for that decoration, then check mapBasicDecoration. If you can make the change you are interested in by changing the VSCode decoration object that is generated, make that change and you are done. If not, check Updating an existing decoration to find how to add more information to the decoration object.

Adding a new decoration

First, go the decorators in engine to make the engine generate your decoration. Once you are done, go to the mapDecoration function in windowDecorations.ts, add a new case for your new decoration, and write a map* function to map the plain decoration object to a VSCode decoration object. Finally, remember to add tests for your new decoration.

Testing decorations

To test your decoration, edit the file WindowDecorations.test.ts. The test will roughly look like:

const blockAnchorDecorations = allDecorations!.get(DECORATION_TYPE.blockAnchor);
expect(blockAnchorDecorations.length).toEqual(1);
expect(
  isTextDecorated("^anchor-1", blockAnchorDecorations!, document)
).toBeTruthy();

Past Tasks


Children
  1. Diagram

Backlinks