mmm / da4d528 root / articles / mmmfs / ba_log / 2019-10-27 / text$

Tree @da4d528 (Download .tar.gz)

text$ @da4d528view markup · raw · history · blame

Today I finally reached the ability of editing content inside of mmmfs directly!

Content is currently not saved anywhere, but the basis of the feature is there. For the moment this is implemented as yeat another convert that simply converts from text/.* (any textual code) to mmm/dom (web UI) [28653c9]. However this convert is only applied in the inspector view (more on that below). First, here is the convert itself:

  inp: 'text/([^ ]*).*'
  out: 'mmm/dom'
  cost: 0
  transform: (value, fileder, key) =>
    mode = @from\match @convert.inp
    Editor value, mode, fileder, key

and the main part of the code, the Editor widget:

class Editor
  new: (value, mode, @fileder, @key) =>
    @node = div class: 'editor'
    -- 'o' is a little helper for converting a Lua table to a JS object
    @cm = window\CodeMirror @node, o {
      lineNumber: true
      lineWrapping: true
      autoRefresh: true
      theme: 'hybrid'

    @cm\on 'changes', (_, mirr) ->
      window\clearTimeout @timeout if @timeout
      @timeout = window\setTimeout (-> @change!), 300

  change: =>
    @timeout = nil
    doc = @cm\getDoc!
    if @lastState and doc\isClean @lastState
      -- no changes since last event

    @lastState = doc\changeGeneration true
    value = doc\getValue!

    @fileder.facets[@key] = value

I chose the CodeMirror library as the basis for the editor, because it seemed like one of the leanest ones I could find (and yet it is quite heavy at 100kb plus styling and language support addons). The code for the editor is also quite minimale it really just creates a wrapper for the editor and tells CodeMirror to set itself up inside. Whenever changes are detected, a timeout of 300ms is started, after which the preview is refreshed to preview the changes. If more changes are made within the 300ms, the timer is reset to 300ms, so that the preview update doesn't interrupt the typing flow.

I also spent some time refactoring the global list of converts out into multiple smaller plugins (although a lot of global converts remain at the moment) [abefbf8]. A plugin can export a list of converts as well as a list of 'editors', which are essentially no different, except that they are taken into consideration only when converting content for the inspector.

Breaking the converts up into little packages like that makes it a lot easier to edit, and allows enabling and disabling individual features very easily. I am also considering moving the converts into the mmmfs data itself, to make extending the system and working inside the system more congruent, and this is a good way of testing my idea of how the modularization of the system should work.