From e0a0b25f6586cdf1b1284d97bedadfce5535ba96 Mon Sep 17 00:00:00 2001
From: s-ol
Date: Thu, 3 Dec 2020 17:38:43 +0100
Subject: move plugins into root
---
mmm/mmmfs/browser.moon | 2 +-
mmm/mmmfs/conversion.moon | 47 ++++++++---
mmm/mmmfs/fileder.moon | 32 ++++++--
mmm/mmmfs/plugins/cites.moon | 75 ------------------
mmm/mmmfs/plugins/code.moon | 12 +--
mmm/mmmfs/plugins/gltf.moon | 17 ----
mmm/mmmfs/plugins/init.moon | 8 +-
mmm/mmmfs/plugins/json.moon | 56 --------------
mmm/mmmfs/plugins/markdown.moon | 67 ----------------
mmm/mmmfs/plugins/mermaid.moon | 27 -------
mmm/mmmfs/plugins/static.moon | 33 --------
mmm/mmmfs/plugins/twitter.moon | 25 ------
mmm/mmmfs/plugins/youtube.moon | 27 -------
mmm/mmmfs/stores/fs.moon | 29 ++++---
.../cites/converts: text$moonscript -> table.moon | 73 ++++++++++++++++++
.../code/converts: text$moonscript -> table.moon | 90 ++++++++++++++++++++++
.../$mmm/plugins/code/scripts: text$html+frag.html | 5 ++
.../gltf/converts: text$moonscript -> table.moon | 16 ++++
.../$mmm/plugins/gltf/scripts: text$html+frag.html | 2 +
.../json/converts: text$moonscript -> table.moon | 54 +++++++++++++
.../converts: text$moonscript -> table.moon | 67 ++++++++++++++++
.../plugins/markdown/scripts: text$html+frag.html | 1 +
.../converts: text$moonscript -> table.moon | 29 +++++++
.../plugins/mermaid/scripts: text$html+frag.html | 1 +
.../static/converts: text$moonscript -> table.moon | 34 ++++++++
.../converts: text$moonscript -> table.moon | 21 +++++
.../converts: text$moonscript -> table.moon | 25 ++++++
root/$order | 2 +-
28 files changed, 502 insertions(+), 375 deletions(-)
delete mode 100644 mmm/mmmfs/plugins/cites.moon
delete mode 100644 mmm/mmmfs/plugins/json.moon
delete mode 100644 mmm/mmmfs/plugins/static.moon
delete mode 100644 mmm/mmmfs/plugins/twitter.moon
delete mode 100644 mmm/mmmfs/plugins/youtube.moon
create mode 100644 root/$mmm/plugins/cites/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/code/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/code/scripts: text$html+frag.html
create mode 100644 root/$mmm/plugins/gltf/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/gltf/scripts: text$html+frag.html
create mode 100644 root/$mmm/plugins/json/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/markdown/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/markdown/scripts: text$html+frag.html
create mode 100644 root/$mmm/plugins/mermaid/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/mermaid/scripts: text$html+frag.html
create mode 100644 root/$mmm/plugins/static/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/twitter/converts: text$moonscript -> table.moon
create mode 100644 root/$mmm/plugins/youtube/converts: text$moonscript -> table.moon
diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon
index 2cef8a4..2abe512 100644
--- a/mmm/mmmfs/browser.moon
+++ b/mmm/mmmfs/browser.moon
@@ -274,7 +274,7 @@ class Browser
value, key = fileder\get prop
assert key, "couldn't @get #{prop}"
- conversions = get_conversions 'mmm/dom', key.type, get_casts!
+ conversions = get_conversions fileder, 'mmm/dom', key.type, get_casts!
assert conversions, "cannot cast '#{key.type}'"
with res = apply_conversions conversions, value, fileder, prop
@editor\set if res.EDITOR then res
diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon
index d0a6842..2d25793 100644
--- a/mmm/mmmfs/conversion.moon
+++ b/mmm/mmmfs/conversion.moon
@@ -11,8 +11,6 @@ escape_pattern = (inp) ->
"^#{inp\gsub '([^%w])', '%%%1'}$"
escape_inp = (inp) -> "^#{inp\gsub '([-/])', '%%%1'}$"
-local print_conversions
-
class MermaidDebugger
new: =>
nextid = 0
@@ -55,15 +53,43 @@ class MermaidDebugger
"graph TD\n" .. @buf
+get_converts = (fileder) ->
+ assert PLUGINS
+ assert BROWSER.root
+ converts = [c for c in *PLUGINS.converts]
+
+ -- search until closest non-meta ancestor
+ local guard_self
+ max_path = fileder.path
+ if closest = max_path\match('(.-)/$mmm')
+ max_path = closest
+ guard_self = true
+
+ for ancestor in coroutine.wrap -> BROWSER.root\walk_co max_path
+ if guard_self and ancestor.path == max_path
+ break
+
+ ancestor\load! if not ancestor.loaded
+
+ if meta = ancestor.meta
+ for plugin in *meta\walk('plugins').children
+ for c in *(plugin\get('converts: table') or {})
+ table.insert converts, c
+
+ converts
+
-- attempt to find a conversion path from 'have' to 'want'
+-- * fileder - fileder to start with
-- * have - start type string or list of type strings
-- * want - stop type pattern
-- * limit - limit conversion amount
-- * debug - a table with debug hooks
-- returns a list of conversion steps
-get_conversions = (want, have, converts=PLUGINS and PLUGINS.converts, limit=5, debug) ->
+get_conversions = (fileder, want, have, converts, limit=5, debug) ->
+ converts or= get_converts fileder
+
assert have, 'need starting type(s)'
- assert converts, 'need to pass list of converts'
+ assert converts, 'need to pass list of converts'
if 'string' == type have
have = { have }
@@ -143,15 +169,14 @@ print_conversions = (conversions) ->
-- * ... - other transform parameters (fileder, key)
-- returns converted value
err_and_trace = (msg) -> debug.traceback msg, 2
-apply_conversions = (conversions, value, ...) ->
+apply_conversions = (fileder, conversions, value, key) ->
for i=#conversions,1,-1
refs\push!
step = conversions[i]
- ok, value = xpcall step.convert.transform, err_and_trace, step, value, ...
+ ok, value = xpcall step.convert.transform, err_and_trace, step, value, fileder, key
refs\pop!
if not ok
- f, k = ...
- error "error while converting #{f} #{k} from '#{step.from}' to '#{step.to}':\n#{value}"
+ error "error while converting #{fileder} #{key} from '#{step.from}' to '#{step.to}':\n#{value}"
value
@@ -160,8 +185,8 @@ apply_conversions = (conversions, value, ...) ->
-- * want - stop type pattern
-- * value - value or map from have-types to values
-- returns converted value
-convert = (have, want, value, ...) ->
- conversions, start = get_conversions want, have
+convert = (have, want, value, fileder, key) ->
+ conversions, start = get_conversions fileder, want, have
if not conversions
warn "couldn't convert from '#{have}' to '#{want}'"
@@ -170,7 +195,7 @@ convert = (have, want, value, ...) ->
if 'string' ~= type have
value = value[start]
- apply_conversions conversions, value, ...
+ apply_conversions fileder, conversions, value, key
{
:MermaidDebugger
diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon
index 871f46f..4dcc60b 100644
--- a/mmm/mmmfs/fileder.moon
+++ b/mmm/mmmfs/fileder.moon
@@ -160,16 +160,20 @@ class Fileder
-- load fact/children contents
-- called automatically by metamethods set up in constructor
- -- can take an index instance if it is already available,
+ -- can take an index instance if it is already available
load: (index) =>
assert not @loaded, "already loaded!"
@loaded = true
- if not index
- index = @store\get_index @path
+ index or= @store\get_index @path
for path_or_index in *index.children
- table.insert @children, Fileder @store, path_or_index
+ child = Fileder @store, path_or_index
+ name = child\get 'name: alpha'
+ if '$' != name\sub 1, 1
+ table.insert @children, child
+ elseif name == '$mmm'
+ @meta = child
for key in *index.facets
key = Key key
@@ -202,6 +206,22 @@ class Fileder
if match = child\walk path
return match
+ if match = @meta and @meta\walk path
+ return match
+
+ -- like :walk but yield all ancestors of path
+ -- * path - the path to walk to
+ walk_co: (path) =>
+ path = "#{@path}/#{path}" if '/' != path\sub 1, 1
+
+ return unless @path == path\sub 1, #@path
+ return if #path == #@path
+
+ coroutine.yield @
+
+ for child in *@children
+ child\walk_co path
+
-- recursively mount fileder and children at path
-- * path - the path to mount at
-- * mount_as - dont append own name to path
@@ -257,7 +277,7 @@ class Fileder
return unless #matching > 0
-- get shortest conversion path
- shortest_path, start = get_conversions want.type, [ key.type for key in *matching ], ...
+ shortest_path, start = get_conversions @, want.type, [ key.type for key in *matching ], ...
if start
for key in *matching
@@ -279,7 +299,7 @@ class Fileder
key, conversions = @find want
if key
- value = apply_conversions conversions, @facets[key], @, key
+ value = apply_conversions @, conversions, @facets[key], key
value, key
-- like @get, throw if no value or conversion path
diff --git a/mmm/mmmfs/plugins/cites.moon b/mmm/mmmfs/plugins/cites.moon
deleted file mode 100644
index 527416e..0000000
--- a/mmm/mmmfs/plugins/cites.moon
+++ /dev/null
@@ -1,75 +0,0 @@
-import div, span, sup, a, i, b from require 'mmm.dom'
-
-parse_bibtex = (src) ->
- type, key, kv = src\match '@(%w+){(.-),(.*)}'
- with info = { _type: type, _key: key }
- for key, val in kv\gmatch '([a-z]-)%s*=%s*(%b{})'
- val\sub 2, -2
- info[key] = val\gsub '[{}]', ''
- for key, val in kv\gmatch '([a-z]-)%s*=%s*(%d+)'
- info[key] = val
-
-title = () =>
- assert @title, "cite doesn't have title"
- inner = i @title
- if @url
- a inner, href: @url, style: display: 'inline'
- else
- b inner
-
-format_full = () =>
- tt = title @
- dot, com = if @title\match '[.?!]$' then '', '' else '.', ','
-
- @author or= 'N. N.'
-
- switch @_type
- when 'book', 'article'
- span with setmetatable {}, __index: table
- \insert "#{@author} (#{@year}), "
- \insert tt
- if @journal
- \insert "#{dot} "
- \insert i @journal
- \insert ", volume #{@volume}" if @volume
- else if @series
- \insert "#{dot} "
- \insert i @series
- \insert ", No. #{@number}" if @number
- \insert ", pages #{@pages}" if @pages
- \insert "#{dot} #{@publisher}" if @publisher
- if @doi
- \insert "#{dot} "
- \insert a "doi:#{@doi}", href: "https://doi.org/#{@doi}"
- when 'web', 'online'
- span with setmetatable {}, __index: table
- \insert "#{@author}"
- \insert " (#{@year})" if @year
- \insert ", "
- \insert tt
- \insert "#{com} #{@url}"
- \insert " from #{@visited}" if @visited
- else
- span with setmetatable {}, __index: table
- \insert "#{@author} (#{@year}), "
- \insert tt
- \insert "#{dot} #{@publisher}" if @publisher
- span tbl
-{
- converts: {
- {
- inp: 'cite/doi'
- out: 'URL -> text/bibtex'
- cost: 0.1
- transform: (doi) =>
- doi = doi\match '(10%.%d%d%d%d%d?%d?%d?%d?%d?/[%d%w%.%-_:;%(%)]+)'
- "http://api.crossref.org/works/#{doi}/transform/application/x-bibtex"
- }
- {
- inp: 'text/bibtex'
- out: 'mmm/dom'
- cost: 1
- transform: (bib) => format_full parse_bibtex bib
- }
- }
-}
diff --git a/mmm/mmmfs/plugins/code.moon b/mmm/mmmfs/plugins/code.moon
index 8ab760a..454f32f 100644
--- a/mmm/mmmfs/plugins/code.moon
+++ b/mmm/mmmfs/plugins/code.moon
@@ -43,7 +43,7 @@ class Editor
if @lastPreview and doc\isClean @lastPreview
-- no changes since last event
return
-
+
@lastPreview = doc\changeGeneration!
value = doc\getValue!
@@ -59,16 +59,6 @@ class Editor
-- syntax-highlighted code
{
- converts: {
- {
- inp: 'text/([^ ]*).*'
- out: 'mmm/dom'
- cost: 5
- transform: (val) =>
- lang = @from\match @convert.inp
- pre languages[lang] val
- }
- }
editors: if MODE == 'CLIENT' then {
{
inp: 'text/([^ ]*).*'
diff --git a/mmm/mmmfs/plugins/gltf.moon b/mmm/mmmfs/plugins/gltf.moon
index 28a6cf8..129a291 100644
--- a/mmm/mmmfs/plugins/gltf.moon
+++ b/mmm/mmmfs/plugins/gltf.moon
@@ -1,21 +1,4 @@
-dom = require 'mmm.dom'
-
{
- converts: {
- {
- inp: 'URL -> model/gltf-binary'
- out: 'mmm/dom'
- cost: 1
- transform: (href) =>
- dom['model-viewer'] {
- src: href
- 'auto-rotate': true
- 'camera-controls': true
- 'camera-orbit': "548.2deg 117deg 282.4m"
- }
- }
- }
-
scripts: [[
diff --git a/mmm/mmmfs/plugins/init.moon b/mmm/mmmfs/plugins/init.moon
index d46e59c..c16cdfa 100644
--- a/mmm/mmmfs/plugins/init.moon
+++ b/mmm/mmmfs/plugins/init.moon
@@ -291,17 +291,11 @@ add_plugin = (module) ->
scripts ..= plugin.scripts
add_plugin 'code'
-add_plugin 'json'
add_plugin 'markdown'
add_plugin 'mermaid'
-add_plugin 'twitter'
-add_plugin 'youtube'
-add_plugin 'cites'
add_plugin 'gltf'
-if STATIC
- add_plugin 'static'
-else
+if not STATIC
table.insert converts, {
inp: '(.+)',
out: 'URL -> %1',
diff --git a/mmm/mmmfs/plugins/json.moon b/mmm/mmmfs/plugins/json.moon
deleted file mode 100644
index cbcff46..0000000
--- a/mmm/mmmfs/plugins/json.moon
+++ /dev/null
@@ -1,56 +0,0 @@
-encode = (obj) ->
- switch type obj
- when 'string'
- string.format '%q', obj
- when 'table'
- if obj[1] or not next obj
- "[#{table.concat [encode c for c in *obj], ','}]"
- else
- "{#{table.concat ["#{encode k}: #{encode v}" for k,v in pairs obj], ', '}}"
- when 'number'
- tostring obj
- when 'boolean'
- tostring obj
- when 'nil'
- 'null'
- else
- error "unknown type '#{type obj}'"
-
-decode = if MODE == 'CLIENT'
- import Array, Object, JSON from js.global
-
- fix = (val) ->
- switch type val
- when 'userdata'
- if Array\isArray val
- [fix x for x in js.of val]
- else
- {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)}
- else
- val
-
- encode
- decode = (str) -> fix JSON\parse str
-else if cjson = require 'cjson'
- cjson.decode
-else
- warn 'only partial JSON support, please install cjson'
-
-
-{
- converts: {
- {
- inp: 'table',
- out: 'text/json',
- cost: 2
- transform: (val) => encode val
- }
- if decode
- {
- inp: 'text/json'
- out: 'table'
- cost: 1
- transform: (val) => decode val
- }
- }
-}
diff --git a/mmm/mmmfs/plugins/markdown.moon b/mmm/mmmfs/plugins/markdown.moon
index 680fdc4..c5a8f96 100644
--- a/mmm/mmmfs/plugins/markdown.moon
+++ b/mmm/mmmfs/plugins/markdown.moon
@@ -1,71 +1,4 @@
-markdown = if MODE == 'SERVER'
- success, discount = pcall require, 'discount'
- assert success, "couldn't require 'discount'"
-
- (md) ->
- res = assert discount.compile md, 'githubtags', 'fencedcode'
- res.body
-else
- assert window and window.marked, "marked.js not found"
-
- o = do
- mkobj = window\eval "(function () { return {}; })"
- (tbl) ->
- with obj = mkobj!
- for k,v in pairs(tbl)
- obj[k] = v
-
- trim = (str) -> str\match '^ *(..-) *$'
-
- window.marked\setOptions o {
- gfm: true
- smartypants: true
- langPrefix: 'lang-'
- highlight: (code, lang) =>
- code = trim code
- result = if lang and #lang > 0
- window.hljs\highlight lang, code, true
- else
- window.hljs\highlightAuto code
-
- result.value
- }
-
- window\marked
-
-assert markdown, "no markdown implementation found"
-
{
- converts: {
- {
- inp: 'text/markdown'
- out: 'text/html+frag'
- cost: 1
- transform: (md) => "
%s*', '' - html = html\gsub '%s*
%s*$', '' - html - } - } scripts: [[ ]] diff --git a/mmm/mmmfs/plugins/mermaid.moon b/mmm/mmmfs/plugins/mermaid.moon index a5cbc7c..c076e7b 100644 --- a/mmm/mmmfs/plugins/mermaid.moon +++ b/mmm/mmmfs/plugins/mermaid.moon @@ -1,31 +1,4 @@ -assert window and window.mermaid, "mermaid.js not found" - -window.mermaid\initialize { - startOnLoad: false - fontFamily: 'monospace' -} - -id_counter = 1 - { - converts: { - { - inp: 'text/mermaid-graph' - out: 'mmm/dom' - cost: 1 - transform: (source, fileder, key) => - id_counter += 1 - id = "mermaid-#{id_counter}" - with container = document\createElement 'div' - cb = (svg) => - .innerHTML = svg - .firstElementChild.style.width = '100%' - .firstElementChild.style.height = 'auto' - - window\setImmediate (_) -> - window.mermaid\render id, source, cb, container - } - } scripts: [[ ]] diff --git a/mmm/mmmfs/plugins/static.moon b/mmm/mmmfs/plugins/static.moon deleted file mode 100644 index 5bf9476..0000000 --- a/mmm/mmmfs/plugins/static.moon +++ /dev/null @@ -1,33 +0,0 @@ -extensions = { - 'image/jpeg': 'jpg' - 'image/png': 'png' - 'image/svg+xml': 'svg' - - 'video/webm': 'webm' - 'video/mp4': 'mp4' - - 'text/javascript': 'js' - 'text/css': 'css' - - 'model/gltf-binary': 'glb' -} - -{ - converts: { - { - inp: '(.+)', - out: 'URL -> %1', - cost: 5 - transform: (val, fileder, key) => - escaped_from = @from\gsub '/', '_' - if ext = extensions[@from] - escaped_from ..= ".#{ext}" - - prefix = STATIC.root or '' - - prefix .. with url = "#{fileder.path}/#{key.name}:#{escaped_from}" - print " rendering asset #{url}" - STATIC.spit url, val - } - } -} diff --git a/mmm/mmmfs/plugins/twitter.moon b/mmm/mmmfs/plugins/twitter.moon deleted file mode 100644 index 7577076..0000000 --- a/mmm/mmmfs/plugins/twitter.moon +++ /dev/null @@ -1,25 +0,0 @@ -import div, blockquote, a from require 'mmm.dom' - -{ - converts: { - { - inp: 'URL -> twitter/tweet' - out: 'mmm/dom' - cost: -4 - transform: (href) => - id = assert (href\match 'twitter.com/[^/]-/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" - if MODE == 'CLIENT' - with parent = div! - window.twttr.widgets\createTweet id, parent - else - div blockquote { - class: 'twitter-tweet' - 'data-lang': 'en' - a '(linked tweet)', :href - } - } - } - scripts: [[ - - ]] -} diff --git a/mmm/mmmfs/plugins/youtube.moon b/mmm/mmmfs/plugins/youtube.moon deleted file mode 100644 index 9086041..0000000 --- a/mmm/mmmfs/plugins/youtube.moon +++ /dev/null @@ -1,27 +0,0 @@ -import iframe from require 'mmm.dom' - -{ - converts: { - { - inp: 'URL -> youtube/video' - out: 'mmm/dom' - cost: -4 - transform: (link) => - id = link\match 'youtu%.be/([^/]+)' - id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' - id or= link\match 'youtube.com/[ev]/([^/]+)' - id or= link\match 'youtube.com/embed/([^/]+)' - - assert id, "couldn't parse youtube URL: '#{link}'" - - iframe { - width: 560 - height: 315 - frameborder: 0 - allowfullscreen: true - frameBorder: 0 - src: "//www.youtube.com/embed/#{id}" - } - } - } -} diff --git a/mmm/mmmfs/stores/fs.moon b/mmm/mmmfs/stores/fs.moon index 3d602c8..c1d613f 100644 --- a/mmm/mmmfs/stores/fs.moon +++ b/mmm/mmmfs/stores/fs.moon @@ -21,18 +21,24 @@ class FSStore extends Store @log "opening '#{opts.root}'..." -- fileders - get_order: (path, forgiving=false) => + get_order: (path, forgiving=false, include_meta=false) => entries = {} + sorted = {} for name in lfs.dir @root .. path - continue if '.' == name\sub 1, 1 - entry_path = @root .. "#{path}/#{name}" + continue if '.' == name\sub(1, 1) + continue if '$' == name\sub(1, 1) and not include_meta + entry_path = "#{@root}#{path}/#{name}" if 'directory' ~= lfs.attributes entry_path, 'mode' continue - entries[name] = :name, path: "#{path}/#{name}" + entry = :name, path: "#{path}/#{name}" + entries[name] = entry - sorted = {} - order_file = @root .. "#{path}/$order" + if '$' == name\sub 1, 1 + table.insert sorted, entry + sorted[name] = true + + order_file = "#{@root}#{path}/$order" if 'file' == lfs.attributes order_file, 'mode' for line in io.lines order_file entry = entries[line] @@ -44,6 +50,8 @@ class FSStore extends Store table.insert sorted, entry sorted[line] = true + else + forgiving = true unsorted = [entry for name, entry in pairs entries when not sorted[entry.name]] if forgiving @@ -56,7 +64,7 @@ class FSStore extends Store sorted write_order: (path, order=@get_order path, true) => - order_file = @root .. "#{path}/$order" + order_file = "#{@root}#{path}/$order" if #order == 0 os.remove order_file return @@ -67,7 +75,7 @@ class FSStore extends Store file\close! list_fileders_in: (path='') => - sorted = @get_order path + sorted = @get_order path, nil, true coroutine.wrap -> for { :path } in *sorted @@ -104,12 +112,12 @@ class FSStore extends Store rename_fileder: (path, next_name) => @log "renaming fileder #{path} -> '#{next_name}'" parent, name = dir_base path - assert os.rename path, @root .. "#{parent}/#{next_name}" + assert os.rename path, "#{@root}#{parent}/#{next_name}" move_fileder: (path, next_parent) => @log "moving fileder #{path} -> #{next_parent}/" parent, name = dir_base path - assert os.rename @root .. path, @root .. "#{next_parent}/#{name}" + assert os.rename @root .. path, "#{@root}#{next_parent}/#{name}" -- swap two childrens' order swap_fileders: (parent, name_a, name_b) => @@ -165,7 +173,6 @@ class FSStore extends Store error "two files match #{name}: #{file_name} and #{entry_name}!" file_name = entry_name - file_name and @root .. "#{path}/#{file_name}" load_facet: (path, name, type) => diff --git a/root/$mmm/plugins/cites/converts: text$moonscript -> table.moon b/root/$mmm/plugins/cites/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..73a6580 --- /dev/null +++ b/root/$mmm/plugins/cites/converts: text$moonscript -> table.moon @@ -0,0 +1,73 @@ +import div, span, sup, a, i, b from require 'mmm.dom' + +parse_bibtex = (src) -> + type, key, kv = src\match '@(%w+){(.-),(.*)}' + with info = { _type: type, _key: key } + for key, val in kv\gmatch '([a-z]-)%s*=%s*(%b{})' + val\sub 2, -2 + info[key] = val\gsub '[{}]', '' + for key, val in kv\gmatch '([a-z]-)%s*=%s*(%d+)' + info[key] = val + +title = () => + assert @title, "cite doesn't have title" + inner = i @title + if @url + a inner, href: @url, style: display: 'inline' + else + b inner + +format_full = () => + tt = title @ + dot, com = if @title\match '[.?!]$' then '', '' else '.', ',' + + @author or= 'N. N.' + + switch @_type + when 'book', 'article' + span with setmetatable {}, __index: table + \insert "#{@author} (#{@year}), " + \insert tt + if @journal + \insert "#{dot} " + \insert i @journal + \insert ", volume #{@volume}" if @volume + else if @series + \insert "#{dot} " + \insert i @series + \insert ", No. #{@number}" if @number + \insert ", pages #{@pages}" if @pages + \insert "#{dot} #{@publisher}" if @publisher + if @doi + \insert "#{dot} " + \insert a "doi:#{@doi}", href: "https://doi.org/#{@doi}" + when 'web', 'online' + span with setmetatable {}, __index: table + \insert "#{@author}" + \insert " (#{@year})" if @year + \insert ", " + \insert tt + \insert "#{com} #{@url}" + \insert " from #{@visited}" if @visited + else + span with setmetatable {}, __index: table + \insert "#{@author} (#{@year}), " + \insert tt + \insert "#{dot} #{@publisher}" if @publisher + span tbl +{ + { + inp: 'cite/doi' + out: 'URL -> text/bibtex' + cost: 0.1 + transform: (doi) => + doi = doi\match '(10%.%d%d%d%d%d?%d?%d?%d?%d?/[%d%w%.%-_:;%(%)]+)' + "http://api.crossref.org/works/#{doi}/transform/application/x-bibtex" + } + { + inp: 'text/bibtex' + out: 'mmm/dom' + cost: 1 + transform: (bib) => format_full parse_bibtex bib + } +} diff --git a/root/$mmm/plugins/code/converts: text$moonscript -> table.moon b/root/$mmm/plugins/code/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..851efba --- /dev/null +++ b/root/$mmm/plugins/code/converts: text$moonscript -> table.moon @@ -0,0 +1,90 @@ +import pre, div, button from require 'mmm.dom' +import languages from require 'mmm.highlighting' + +class Editor + o = if MODE == 'CLIENT' + mkobj = window\eval "(function () { return {}; })" + (tbl) -> + with obj = mkobj! + for k,v in pairs(tbl) + obj[k] = v + + EDITOR: true + + new: (value, mode, @fileder, @key) => + @node = div class: 'editor' + + @saveBtn = with button 'save' + .disabled = true + .onclick = (_, e) -> @save e + + @cm = window\CodeMirror @node, o { + :value + :mode + lineNumber: true + lineWrapping: true + autoRefresh: true + theme: 'hybrid' + } + + @lastSave = @cm\getDoc!\changeGeneration true + + @cm\on 'changes', (_, mirr) -> + doc = @cm\getDoc! + @saveBtn.disabled = doc\isClean @lastSave + + window\clearTimeout @timeout if @timeout + @timeout = window\setTimeout (-> @change!), 300 + + change: => + @timeout = nil + doc = @cm\getDoc! + + if @lastPreview and doc\isClean @lastPreview + -- no changes since last event + return + + @lastPreview = doc\changeGeneration! + value = doc\getValue! + + @fileder.facets[@key] = value + BROWSER\refresh! + + save: (e) => + e\preventDefault! + + doc = @cm\getDoc! + @fileder\set @key, doc\getValue! + @lastSave = doc\changeGeneration true + +[[ + editors: if MODE == 'CLIENT' then { + { + inp: 'text/([^ ]*).*' + out: 'mmm/dom' + cost: 0 + transform: (value, fileder, key) => + mode = @from\match @convert.inp + Editor value, mode, fileder, key + } + { + inp: 'URL.*' + out: 'mmm/dom' + cost: 0 + transform: (value, fileder, key) => + Editor value, nil, fileder, key + } + } +]] + +-- syntax-highlighted code +{ + { + inp: 'text/([^ ]*).*' + out: 'mmm/dom' + cost: 5 + transform: (val) => + lang = @from\match @convert.inp + pre languages[lang] val + } +} diff --git a/root/$mmm/plugins/code/scripts: text$html+frag.html b/root/$mmm/plugins/code/scripts: text$html+frag.html new file mode 100644 index 0000000..68d780b --- /dev/null +++ b/root/$mmm/plugins/code/scripts: text$html+frag.html @@ -0,0 +1,5 @@ + + + + + diff --git a/root/$mmm/plugins/gltf/converts: text$moonscript -> table.moon b/root/$mmm/plugins/gltf/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..1036eee --- /dev/null +++ b/root/$mmm/plugins/gltf/converts: text$moonscript -> table.moon @@ -0,0 +1,16 @@ +dom = require 'mmm.dom' + +{ + { + inp: 'URL -> model/gltf-binary' + out: 'mmm/dom' + cost: 1 + transform: (href) => + dom['model-viewer'] { + src: href + 'auto-rotate': true + 'camera-controls': true + 'camera-orbit': "548.2deg 117deg 282.4m" + } + } +} diff --git a/root/$mmm/plugins/gltf/scripts: text$html+frag.html b/root/$mmm/plugins/gltf/scripts: text$html+frag.html new file mode 100644 index 0000000..d2b1e44 --- /dev/null +++ b/root/$mmm/plugins/gltf/scripts: text$html+frag.html @@ -0,0 +1,2 @@ + + diff --git a/root/$mmm/plugins/json/converts: text$moonscript -> table.moon b/root/$mmm/plugins/json/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..7b150a5 --- /dev/null +++ b/root/$mmm/plugins/json/converts: text$moonscript -> table.moon @@ -0,0 +1,54 @@ +encode = (obj) -> + switch type obj + when 'string' + string.format '%q', obj + when 'table' + if obj[1] or not next obj + "[#{table.concat [encode c for c in *obj], ','}]" + else + "{#{table.concat ["#{encode k}: #{encode v}" for k,v in pairs obj], ', '}}" + when 'number' + tostring obj + when 'boolean' + tostring obj + when 'nil' + 'null' + else + error "unknown type '#{type obj}'" + +decode = if MODE == 'CLIENT' + import Array, Object, JSON from js.global + + fix = (val) -> + switch type val + when 'userdata' + if Array\isArray val + [fix x for x in js.of val] + else + {(fix e[0]), (fix e[1]) for e in js.of Object\entries(val)} + else + val + + encode + decode = (str) -> fix JSON\parse str +else if cjson = require 'cjson' + cjson.decode +else + warn 'only partial JSON support, please install cjson' + + +{ + { + inp: 'table', + out: 'text/json', + cost: 2 + transform: (val) => encode val + } + if decode + { + inp: 'text/json' + out: 'table' + cost: 1 + transform: (val) => decode val + } +} diff --git a/root/$mmm/plugins/markdown/converts: text$moonscript -> table.moon b/root/$mmm/plugins/markdown/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..4e0da31 --- /dev/null +++ b/root/$mmm/plugins/markdown/converts: text$moonscript -> table.moon @@ -0,0 +1,67 @@ +markdown = if MODE == 'SERVER' + success, discount = pcall require, 'discount' + assert success, "couldn't require 'discount'" + + (md) -> + res = assert discount.compile md, 'githubtags', 'fencedcode' + res.body +else + assert window and window.marked, "marked.js not found" + + o = do + mkobj = window\eval "(function () { return {}; })" + (tbl) -> + with obj = mkobj! + for k,v in pairs(tbl) + obj[k] = v + + trim = (str) -> str\match '^ *(..-) *$' + + window.marked\setOptions o { + gfm: true + smartypants: true + langPrefix: 'lang-' + highlight: (code, lang) => + code = trim code + result = if lang and #lang > 0 + window.hljs\highlight lang, code, true + else + window.hljs\highlightAuto code + + result.value + } + + window\marked + +assert markdown, "no markdown implementation found" + +{ + { + inp: 'text/markdown' + out: 'text/html+frag' + cost: 1 + transform: (md) => "%s*', '' + html = html\gsub '%s*
%s*$', '' + html + } +} diff --git a/root/$mmm/plugins/markdown/scripts: text$html+frag.html b/root/$mmm/plugins/markdown/scripts: text$html+frag.html new file mode 100644 index 0000000..5bfb275 --- /dev/null +++ b/root/$mmm/plugins/markdown/scripts: text$html+frag.html @@ -0,0 +1 @@ + diff --git a/root/$mmm/plugins/mermaid/converts: text$moonscript -> table.moon b/root/$mmm/plugins/mermaid/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..1eb695e --- /dev/null +++ b/root/$mmm/plugins/mermaid/converts: text$moonscript -> table.moon @@ -0,0 +1,29 @@ +-- assert window and window.mermaid, "mermaid.js not found" +if not (window and window.mermaid) + return + +window.mermaid\initialize { + startOnLoad: false + fontFamily: 'monospace' +} + +id_counter = 1 + +{ + { + inp: 'text/mermaid-graph' + out: 'mmm/dom' + cost: 1 + transform: (source, fileder, key) => + id_counter += 1 + id = "mermaid-#{id_counter}" + with container = document\createElement 'div' + cb = (svg) => + .innerHTML = svg + .firstElementChild.style.width = '100%' + .firstElementChild.style.height = 'auto' + + window\setImmediate (_) -> + window.mermaid\render id, source, cb, container + } +} diff --git a/root/$mmm/plugins/mermaid/scripts: text$html+frag.html b/root/$mmm/plugins/mermaid/scripts: text$html+frag.html new file mode 100644 index 0000000..282fbd5 --- /dev/null +++ b/root/$mmm/plugins/mermaid/scripts: text$html+frag.html @@ -0,0 +1 @@ + diff --git a/root/$mmm/plugins/static/converts: text$moonscript -> table.moon b/root/$mmm/plugins/static/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..e230856 --- /dev/null +++ b/root/$mmm/plugins/static/converts: text$moonscript -> table.moon @@ -0,0 +1,34 @@ +if not STATIC + return + +extensions = { + 'image/jpeg': 'jpg' + 'image/png': 'png' + 'image/svg+xml': 'svg' + + 'video/webm': 'webm' + 'video/mp4': 'mp4' + + 'text/javascript': 'js' + 'text/css': 'css' + + 'model/gltf-binary': 'glb' +} + +{ + { + inp: '(.+)', + out: 'URL -> %1', + cost: 5 + transform: (val, fileder, key) => + escaped_from = @from\gsub '/', '_' + if ext = extensions[@from] + escaped_from ..= ".#{ext}" + + prefix = STATIC.root or '' + + prefix .. with url = "#{fileder.path}/#{key.name}:#{escaped_from}" + print " rendering asset #{url}" + STATIC.spit url, val + } +} diff --git a/root/$mmm/plugins/twitter/converts: text$moonscript -> table.moon b/root/$mmm/plugins/twitter/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..4821823 --- /dev/null +++ b/root/$mmm/plugins/twitter/converts: text$moonscript -> table.moon @@ -0,0 +1,21 @@ +import div, blockquote, a from require 'mmm.dom' +import iframe from require 'mmm.dom' + +{ + { + inp: 'URL -> twitter/tweet' + out: 'mmm/dom' + cost: -4 + transform: (href) => + user, id = assert (href\match 'twitter.com/([^/]-)/status/(%d*)'), "couldn't parse twitter/tweet URL: '#{href}'" + + iframe { + width: 550 + height: 560 + border: 0 + frameBorder: 0 + allowfullscreen: true + src: "//twitframe.com/show?url=https%3A%2F%2Ftwitter.com%2F#{user}%2F#{id}" + } + } +} diff --git a/root/$mmm/plugins/youtube/converts: text$moonscript -> table.moon b/root/$mmm/plugins/youtube/converts: text$moonscript -> table.moon new file mode 100644 index 0000000..8983730 --- /dev/null +++ b/root/$mmm/plugins/youtube/converts: text$moonscript -> table.moon @@ -0,0 +1,25 @@ +import iframe from require 'mmm.dom' + +{ + { + inp: 'URL -> youtube/video' + out: 'mmm/dom' + cost: -4 + transform: (link) => + id = link\match 'youtu%.be/([^/]+)' + id or= link\match 'youtube.com/watch.*[?&]v=([^&]+)' + id or= link\match 'youtube.com/[ev]/([^/]+)' + id or= link\match 'youtube.com/embed/([^/]+)' + + assert id, "couldn't parse youtube URL: '#{link}'" + + iframe { + width: 560 + height: 315 + border: 0 + frameborder: 0 + allowfullscreen: true + src: "//www.youtube.com/embed/#{id}" + } + } +} diff --git a/root/$order b/root/$order index 23c4745..4d1bfa6 100644 --- a/root/$order +++ b/root/$order @@ -6,5 +6,5 @@ games projects experiments meta -static portfolio +static -- cgit v1.2.3