Quill

Quill is a nim js library for making text editors, it is made completely in nim and is designed to be easy to use.

Example

The example can be found at https://thatrandomperson5.github.io/Quill/example

Docs

Docs can be found at https://thatrandomperson5.github.io/Quill/quill

Installing

nimble install https://github.com/thatrandomperson5/Quill

Guide

We first need to add some css to our main html file:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/thatrandomperson5/quill@master/js/quill.css">

After that we can start coding. A quill has a structure to get it to work:

  • Create the quill
  • Set any default text
  • Add onDraw
    • Main html generation
    • Sector entering or forced redraw
  • Init extentions and then quill

Here is a basic example:

# From tests
import quill, dom

var myquill = newQuill(document.getElementById("quill"), "70vh") # create the quill with height of 70
myquill.text = "Hello world" # Set the default text
myquill.onDraw = proc (q: var Quill, str: cstring, isDel: bool) =
  # Main html generation
  let txt = document.createElement("span")
  txt.appendChild document.createTextNode(str)
  q.draw(txt)

myquill.init() # Start the quill

Note: There is no reason to redraw if you don't use insert(), will be explained in more detail later on.

This is the most basic quill! But it does not do anything, so is there anything diffrent then a normal textarea? Well, the draw proc takes html, so you can color and style as much as you want! Try making the span a random color! You can also use the features described below to help you.

Insert and sectors

You can have a insert() call in your ondraw proc. This adds text, for example an indent, to your quill. This inserts at the current cursor position, if you want to add text a diffrent way, use the text= proc.

There are also sectors, which reduce the text passed to onDraw. Say for example your quill only needed to process words and you have this sentance: hello world good souls. Normally your draw proc would get passed the whole thing each time, but when processing "world", your code does not need anything from "hello". So, when you detect a space, you would enter a sector using enter(). This would mean if the word "hello" was changed to "hi" you would get passed "hi" instead of "hi world good souls". This feature is mainly for efficiency, and a full example can be found in the tests folder.

Note: Why is my inserted text not showing? You have to have a myquill.forceRedraw() at the end to make it show.

Warning: forceRedraw() and enter() must be the last call in your draw proc, also note that enter() replaces forceRedraw().

Gutter

To add a gutter (numbers on the side), just add the code below:

# After import quill
import quill/ext/gutters

# Right before myquill.init()
myquill.initGutter()

Types

Quill = ref object
  internalElm: Element
  onDraw*: QuillOnDraw
  sectors: seq[int]
  current: int
  plen: int
QuillOnDraw = (var Quill, cstring, bool) -> void
QuillOnSegment = (Quill, cstring) -> seq[cstring]

Procs

proc draw(q: var Quill; n: Node) {....raises: [], tags: [].}
Draw dom node n to quill q
proc element(q: Quill): Element {....raises: [], tags: [].}
For extentions, like quill/ext/gutters
proc enter(q: var Quill; pos: int) {....raises: [Exception], tags: [RootEffect].}

Enter a new sector at pos relative to the current sector

Note: Must be the last call in a onDraw

proc eventElement(q: Quill): Element {....raises: [], tags: [].}
For extentions, like quill/ext/gutters
proc forceRedraw(q: var Quill) {....raises: [Exception], tags: [RootEffect].}
Force the redrawing of quill q
proc init(q: var Quill) {....raises: [Exception], tags: [RootEffect].}
"Turns on" the quill, nothing will work or show properly until this is called
proc insert(q: var Quill; text: cstring) {....raises: [], tags: [].}
Insert text at users current position
proc newQuill(e: Element; height: cstring = "30vh"): Quill {....raises: [],
    tags: [].}

Create a new quill of height height and make all needed elements

Note: Might not look right without the proper css

proc text(q: Quill): cstring {....raises: [], tags: [].}
Get the text/value of a quill, directly what the user inputed
proc text=(q: var Quill; replacment: cstring) {....raises: [], tags: [].}
Set the text of a quill (as an user input, so you cannot set html tags)
proc visualElement(q: Quill): Element {....raises: [], tags: [].}
For extentions, like quill/ext/gutters