diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2018-11-09 13:14:56 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2018-11-09 13:14:56 +0000 |
| commit | fa977b6a5d6f6063479a97917810ef393c312e76 (patch) | |
| tree | b21984147c34293fe91e76eef13bfd969b3a7368 | |
| parent | add $order mechanism (diff) | |
| parent | add deploy script (diff) | |
| download | mmm-fa977b6a5d6f6063479a97917810ef393c312e76.tar.gz mmm-fa977b6a5d6f6063479a97917810ef393c312e76.zip | |
Merge branch 'new-tup'
36 files changed, 442 insertions, 372 deletions
@@ -1,6 +1,6 @@ +dist ##### TUP GITIGNORE ##### ##### Lines below automatically generated by Tup. ##### Do not edit. .tup /.gitignore -/dist @@ -1,40 +1,15 @@ -.gitignore +include_rules !download = |> ^ DOWNLOAD %O^ curl -L https://github.com/fengari-lua/fengari-web/releases/download/@(FENGARI_VERSION)/`basename %o` > %o |> !sassc = |> ^ SCSS %b^ sassc -mauto %f %o |> | %o.map # download fengari dependencies -: |> !download |> dist/fengari-web.js -: |> !download |> dist/fengari-web.js.map -: static/* |> cp %f dist/ |> dist/%b +: |> !download |> root/fengari-web.js +: |> !download |> root/fengari-web.js.map +: static/* |> cp %f root/ |> root/%b # render stylesheet -: scss/main.scss |> !sassc |> dist/main.css +: scss/main.scss |> !sassc |> root/main.css -# preload full mmmfs tree -preload root -preload root/articles -preload root/articles/mmmfs -preload root/articles/mmmfs/empty -preload root/articles/mmmfs/image -preload root/articles/mmmfs/markdown -preload root/articles/realities -preload root/animations -preload root/animations/twisted -preload root/animations/koch -preload root/experiments -preload root/experiments/center_of_mass -preload root/experiments/tags -preload root/meta -preload root/meta/mmm.dom -preload root/meta/test_mmm.component -preload root/meta/todo - -# preload all of mmm -preload mmm -preload mmm/dom -preload mmm/mmmfs -preload mmm/component - -# render static content and compile sources -run moon tup.moon +# bundle for client loading +: mmm/.bundle.lua | <modules> |> ^ WRAP %d^ moon bundle.moon %o --wrap %f |> root/mmm.bundle.lua diff --git a/Tuprules.lua b/Tuprules.lua new file mode 100644 index 0000000..77b1ed8 --- /dev/null +++ b/Tuprules.lua @@ -0,0 +1,3 @@ +tup.creategitignore() + +root = tup.nodevariable '.' diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..3c408e7 --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1,3 @@ +.gitignore + +&root = . diff --git a/bundle.moon b/bundle.moon index 5d855ea..1c6b5f6 100644 --- a/bundle.moon +++ b/bundle.moon @@ -2,23 +2,50 @@ output_name = assert arg[1], "please specify the output directory" escape = (str) -> string.format '%q', str +readfile = (name) -> + file = io.open name, 'r' + with file\read '*all' + file\close + with io.open output_name, 'w' - \write "local p = package.preload\n" + -- final wrap mode + if arg[2] == '--wrap' + assert #arg == 3, "too many arguments for 'wrap' mode" + bundle = arg[3] + + bundle = dofile bundle + \write "local p = package.preload\n" + for { :module, :file, :source } in *bundle + module = escape module + \write "if not p[#{module}] then p[#{module}] = load(#{escape source}, #{escape file}) end\n" - for i=2, #arg - file_name = arg[i] + -- iterative bundling mode + else + \write "return {\n" - file = io.open file_name, 'r' - code = file\read '*all' - file\close! + this = assert arg[2] + addmod = (module, file, source) -> + modname = "#{this}.#{module}" + modname = this if module == 'init' + \write " +{ + module = #{escape modname}, + file = #{escape "#{this}/#{file}"}, + source = #{escape source}, +}," - module = file_name\gsub '/', '.' - module = module\gsub '%.lua$', '' - module = module\gsub '%.init$', '' - module = module\match '^dist%.(.*)' + for file in *arg[3,] + if dirname = file\match '^([%w-_]+)/%.bundle%.lua$' + bundle = dofile file + for { :module, :file, :source } in *bundle + addmod module, file, source + else + module = file\gsub '%.lua$', '' + continue if module\match '%.server' + module = module\gsub '%.client$', '' + module = module\gsub '%.init$', '' + addmod module, file, readfile file - file_name = escape file_name - code = escape code - module = escape module + \write "}" - \write "if not p[#{module}] then p[#{module}] = load(#{code}, #{file_name}) end\n" + \close! diff --git a/bundle_fileder.moon b/bundle_fileder.moon new file mode 100644 index 0000000..01aa0a4 --- /dev/null +++ b/bundle_fileder.moon @@ -0,0 +1,117 @@ +require 'mmm' +import Fileder, Key from require 'mmm.mmmfs.fileder' +import opairs from require 'mmm.ordered' +import to_lua from require 'moonscript.base' +require 'lfs' + +-- usage: +-- moon bundle_fileder.moon <dirname> <facets>... -- <children>... +{ dirname } = arg + +assert dirname, "please specify the fileder dirname" + +facets = {} +children_bundles = {} + +do + addto = facets + for file in *arg[2,] + continue if file == 'Tupdefault.lua' + + if file == '--' + addto = children_bundles + continue + table.insert addto, file + + +readfile = (name) -> + file = io.open name, 'r' + with file\read '*all' + file\close! + +-- load a fs file as a fileder facet +load_facet = (filename) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + + value = readfile filename + + key, value + +-- escape a string for lua aparser +escape = (str) -> string.format '%q', tostring str + +-- compile a moonscript facet to lua +compile = (old, new, val) -> "-- this facet has been transpiled from '#{old}' +-- to '#{new}' for execution in the browser. +-- refer to the original facet as the source. +#{to_lua val}" + +-- dump a fileder subtree as Lua source +dump_fileder = do + _dump = (fileder, root=false) -> + code = "Fileder {" + + for key, val in pairs fileder.facets + if key.original + key = "fromcache(#{escape key}, #{escape key.original})" + else + key = escape key + code ..= "\n[#{key}] = #{escape val}," + + for child in *fileder.children + code ..= "\n#{_dump child}," + + code ..= "\n}" + code + + + (fileder) -> " +local mmmfs = require 'mmm.mmmfs' +local Key, Fileder = mmmfs.Key, mmmfs.Fileder +local function fromcache(str, orig) + local key = Key(str) + key.original = Key(orig) + return key +end + +return #{_dump fileder, true} + " + +with io.open '$bundle.lua', 'w' + \write dump_fileder with Fileder 'name: alpha': dirname + order = nil + children = {} + + for facet in *facets + if facet == '$order' + order = [line for line in io.lines facet] + continue + key, value = load_facet facet + .facets[key] = value + + if key.type\match '^text/moonscript %->' + new_key = Key key.name, key.type\gsub '^text/moonscript %-> (.*)', 'text/lua -> %1' + new_key.original = key + .facets[new_key] = compile key, new_key, value + + for child in *children_bundles + -- @BUG: child bundles are malformed due to Tup bug ($ symbol) + child = child\gsub '/%.lua$', '/$bundle.lua' + + dirname = assert child\match '^([%w-_%.]+)/%$bundle%.lua$' + children[dirname] = dofile child + + if order + -- order from order file + for i, name in pairs order + child = assert children[name], "child in $order but not fs: #{name} of #{path}" + table.insert .children, child + children[name] = nil + + -- sort remainder alphabeticalally + for name, child in opairs children + table.insert .children, child + warn "child #{name} of #{path} not in $order!" if order + + \close! diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..128d334 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +shopt -s globstar +cd $(dirname $0)/root +rm -rf ../dist +mkdir ../dist +cp --parents $(git check-ignore **) ../dist diff --git a/dump_tree.moon b/dump_tree.moon deleted file mode 100644 index a35a223..0000000 --- a/dump_tree.moon +++ /dev/null @@ -1,61 +0,0 @@ -package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath -require 'mmm.init' -import Key from require 'mmm.mmmfs' -import load_fileder from require 'mmm.mmmfs.fs' -import to_lua from require 'moonscript.base' - --- usage: --- moon render.moon <output> [fileder_path] -{ output_name, path } = arg - -assert output_name, "please specify the output filename as an argument" -path or= '/' - -root = load_fileder 'root' .. path -root\mount path - --- dump a fileder subtree as Lua source -dump_fileder = do - escape = (str) -> string.format '%q', tostring str - - compile = (old, new, val) -> escape " --- this property has been transpiled from '#{old}' --- to '#{new}' for execution in the browser. --- refer to the original property as the source. -#{to_lua val}" - - _dump = (fileder) -> - code = "Fileder {" - - for key, val in pairs fileder.props - code ..= " - [#{escape key}] = #{escape val}," - - if key.type\match '^text/moonscript %->' - newkey = Key key.name, key.type\gsub '^text/moonscript %-> (.*)', 'text/lua -> %1' - code ..= " - [fromcache(#{escape newkey}, #{escape key})] = #{compile key, newkey, val}," - - for child in *fileder.children - code ..= " - #{_dump child}," - - code ..= " - }" - code - - - (fileder) -> " - local mmmfs = require 'mmm.mmmfs' - local Key, Fileder = mmmfs.Key, mmmfs.Fileder - local function fromcache(str, orig) - local key = Key(str) - key.original = Key(orig) - return key - end - - return #{_dump fileder} - " - -with io.open output_name, 'w' - \write dump_fileder root diff --git a/mmm/Tupdefault b/mmm/Tupdefault new file mode 100644 index 0000000..b98f543 --- /dev/null +++ b/mmm/Tupdefault @@ -0,0 +1,4 @@ +include_rules + +: foreach *.moon |> ^ MOON %f^ moonc -o %o %f 2>/dev/null |> %B.lua <modules> +: <modules> |> ^ BNDL %d^ moon &(root)/bundle.moon %o %d %<modules> |> .bundle.lua ../<modules> diff --git a/mmm/mmmfs/browser.moon b/mmm/mmmfs/browser.moon index a40b5cf..43afa2e 100644 --- a/mmm/mmmfs/browser.moon +++ b/mmm/mmmfs/browser.moon @@ -13,6 +13,7 @@ code_cast = (lang) -> } casts = { + code_cast 'javascript', code_cast 'moonscript', code_cast 'lua', code_cast 'markdown', @@ -23,7 +24,7 @@ for convert in *converts table.insert casts, convert class Browser - new: (@root, path='/', rehydrate=false) => + new: (@root, path='', rehydrate=false) => -- root fileder assert @root, 'root fileder is nil' @@ -40,12 +41,11 @@ class Browser -- (re)set every time @path changes @active = @path\map @root\walk - -- currently active property + -- currently active facet -- (re)set to default when @active changes - @prop = @active\map (fileder) -> + @facet = @active\map (fileder) -> return unless fileder - last = @prop and @prop\get! - -- (fileder\find 'mmm/dom') or next fileder.props + last = @facet and @facet\get! Key if last then last.type else 'mmm/dom' -- whether inspect tab is active @@ -69,10 +69,10 @@ class Browser href = '' path = path\match '^/(.*)' - \append path_segment 'root', '/' + \append path_segment 'root', '' while path - name, rest = path\match '^(%w+)/(.*)' + name, rest = path\match '^([%w-_%.]+)/(.*)' if not name name = path @@ -82,17 +82,17 @@ class Browser \append '/' \append path_segment name, href - \append span 'view property:', style: { 'margin-right': '0' } + \append span 'view facet:', style: { 'margin-right': '0' } \append @active\map (fileder) -> onchange = (_, e) -> - { :type } = @prop\get! - @prop\set Key name: e.target.value, :type + { :type } = @facet\get! + @facet\set Key name: e.target.value, :type - current = @prop\get! + current = @facet\get! current = current and current.name with select :onchange, disabled: not fileder if fileder - for i, value in ipairs fileder\get_prop_names! + for i, value in ipairs fileder\get_facets! label = if value == '' then '(main)' else value \append option label, :value, selected: value == current \append @inspect\map (enabled) -> @@ -101,11 +101,11 @@ class Browser -- append or patch #browser-content main\append with get_or_create 'div', 'browser-content', class: 'content' - \append (@prop\map (p) -> @get_content p), (rehydrate and .node.lastChild) + \append (@facet\map (p) -> @get_content p), (rehydrate and .node.lastChild) if rehydrate -- force one rerender to set onclick handlers etc - @prop\set @prop\get! + @facet\set @facet\get! inspector = @inspect\map (enabled) -> if enabled then @get_inspector! @@ -123,13 +123,13 @@ class Browser active = @active\get! return disp_error "fileder not found!" unless active - return disp_error "property not found!" unless prop + return disp_error "facet not found!" unless prop ok, res, trace = xpcall convert, err_and_trace, active, prop if ok res or disp_error "[no conversion path to #{prop.type}]" - elseif res\match '%[nossr%]$' + elseif res and res.match and res\match '%[nossr%]$' warn '(SSR disabled)' div! else @@ -137,9 +137,9 @@ class Browser disp_error "error: #{res}\n#{trace}" get_inspector: => - -- active property in inspect tab - -- (re)set to match when @prop changes - @inspect_prop = @prop\map (prop) -> + -- active facet in inspect tab + -- (re)set to match when @facet changes + @inspect_prop = @facet\map (prop) -> active = @active\get! key = active\find prop key = key.original if key and key.original @@ -153,12 +153,12 @@ class Browser fileder = @active\get! onchange = (_, e) -> - { :name } = @prop\get! + { :name } = @facet\get! @inspect_prop\set Key e.target.value with select :onchange if fileder - for key, _ in pairs fileder.props + for key, _ in pairs fileder.facets value = key\tostring! \append option value, :value, selected: value == current @inspect\map (enabled) -> diff --git a/mmm/mmmfs/conversion.moon b/mmm/mmmfs/conversion.moon index 6896c7d..6f20e22 100644 --- a/mmm/mmmfs/conversion.moon +++ b/mmm/mmmfs/conversion.moon @@ -52,12 +52,8 @@ converts = { (html) -> div html else (html) -> - tmp = document\createElement 'div' - tmp.innerHTML = html - -- if tmp.childElementCount == 1 - -- tmp.firstChild - -- else - tmp + with document\createElement 'div' + .innerHTML = html }, { inp: 'text/lua -> (.+)', @@ -81,6 +77,14 @@ if MODE == 'SERVER' out: 'text/lua -> %1', transform: single moon.to_lua } +else + table.insert converts, { + inp: 'text/javascript -> (.+)', + out: '%1', + transform: (source) -> + f = js.new window.Function, source + f! + } do local markdown diff --git a/mmm/mmmfs/fileder.moon b/mmm/mmmfs/fileder.moon index 63fc9f8..d08d80c 100644 --- a/mmm/mmmfs/fileder.moon +++ b/mmm/mmmfs/fileder.moon @@ -1,7 +1,7 @@ require = relative ..., 1 import get_conversions, apply_conversions from require '.conversion' --- Key of a Fileder Property +-- Key of a Fileder Facet -- contains: -- * @name - key name or '' for main content -- * @type - type string (type -> type -> type) @@ -34,16 +34,16 @@ class Key -- Fileder itself -- contains: --- * @props - Property Map (Key to Value) +-- * @facets - Facet Map (Key to Value) -- * @children - Children Array class Fileder - -- instantiate from props and children tables - -- or mix in one table (numeric keys are children, remainder props) - -- prop-keys are passed to Key constructor - new: (props, children) => + -- instantiate from facets and children tables + -- or mix in one table (numeric keys are children, remainder facets) + -- facet-keys are passed to Key constructor + new: (facets, children) => if not children - children = for i, child in ipairs props - props[i] = nil + children = for i, child in ipairs facets + facets[i] = nil child -- automatically mount children on insert @@ -59,13 +59,13 @@ class Fileder @children[i] = child -- automatically reify string keys on insert - @props = setmetatable {}, __newindex: (t, key, v) -> + @facets = setmetatable {}, __newindex: (t, key, v) -> rawset t, key, nil -- fix for fengari.io rawset t, (Key key), v - -- copy props - for k, v in pairs props - @props[k] = v + -- copy facets + for k, v in pairs facets + @facets[k] = v -- recursively walk to and return the fileder with @path == path -- * path - the path to walk to @@ -107,21 +107,21 @@ class Fileder for child in *@children child\iterate depth - 1 - -- get all unique names associated with properties (list) - get_prop_names: => + -- get all facet names (list) + get_facets: => names = {} - for key in pairs @props + for key in pairs @facets names[key.name] = true [name for name in pairs names] - -- find property key according to criteria, nil if no value or conversion path + -- find facet and type according to criteria, nil if no value or conversion path -- * ... - arguments like Key find: (...) => want = Key ... - -- filter props by name - matching = [ key for key in pairs @props when key.name == want.name ] + -- filter facets by name + matching = [ key for key in pairs @facets when key.name == want.name ] return unless #matching > 0 -- get shortest conversion path @@ -134,7 +134,7 @@ class Fileder error "couldn't find key after resolution?" - -- get property according to criteria, nil if no value or conversion path + -- get and convert facet according to criteria, nil if no value or conversion path -- * ... - arguments like Key get: (...) => want = Key ... @@ -143,7 +143,7 @@ class Fileder key, conversions = @find want if key - value = apply_conversions conversions, @props[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/fs.server.moon b/mmm/mmmfs/fs.server.moon deleted file mode 100644 index a1f5293..0000000 --- a/mmm/mmmfs/fs.server.moon +++ /dev/null @@ -1,61 +0,0 @@ -import Fileder from require 'mmm.mmmfs.fileder' -import opairs from require 'mmm.ordered' -require 'lfs' - -readfile = (name) -> - file = io.open name, 'r' - with file\read '*all' - file\close! - --- load a fs file as a fileder property -load_property = (path, filename) -> - key = (filename\match '(.*)%.%w+') or filename - key = key\gsub '%$', '/' - - value = readfile path .. filename - - key, value - --- load a fs directory as a fileder -load_fileder = (path='root/', name='') -> - path = path .. name - path ..= '/' unless '/' == path\sub -1 - - with Fileder 'name: alpha': name - order = nil - children = {} - - for entry in lfs.dir path - continue if entry == '.' or entry == '..' - continue if entry == 'init.moon' - - if entry == '$order' - order = [line for line in io.lines path .. entry] - continue - - attr = lfs.attributes path .. entry - switch attr.mode - when 'file' - key, value = load_property path, entry - .props[key] = value - when 'directory' - children[entry] = load_fileder path, entry - else - error "unknown file type: #{attr.mode}" - - if order - -- order from order file - for i, name in pairs order - child = assert children[name], "child in $order but not fs: #{name} of #{path}" - table.insert .children, child - children[name] = nil - - -- sort remainder alphabeticalally - for name, child in opairs children - table.insert .children, child - warn "child #{name} of #{path} not in $order!" if order - -{ - :load_property - :load_fileder -} diff --git a/mmm/mmmfs/init.moon b/mmm/mmmfs/init.moon index 94823d9..4dd5c32 100644 --- a/mmm/mmmfs/init.moon +++ b/mmm/mmmfs/init.moon @@ -15,8 +15,8 @@ render = (root, path) -> table.insert(on_load, function() local path = #{string.format '%q', path} local browser = require 'mmm.mmmfs.browser' - local root = require 'root' - root:mount() + local root = dofile '/$bundle.lua' + root:mount('', true) BROWSER = browser.Browser(root, path, true) end) diff --git a/render.moon b/render.moon index 66272ec..5284e66 100644 --- a/render.moon +++ b/render.moon @@ -1,22 +1,28 @@ -package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath -require 'mmm.init' +require 'mmm' import render from require 'mmm.mmmfs' -import load_fileder from require 'mmm.mmmfs.fs' -- usage: --- moon render.moon <output> <fileder_path> -{ output_name, path } = arg +-- moon render.moon <path_to_root> +{ root } = arg -assert output_name, "please specify the output filename as an argument" -assert path, "please specify the path name to build as an argument" +assert root, "please specify the relative root path as an argument" -root = load_fileder 'root' .. path -root\mount path +require 'lfs' +cwd = lfs.currentdir! +path = '' + +while root\find '^%.%./' + root = root\match '^%.%./(.*)' + cwd, trimmed = cwd\match '(.*)(/[^/]+)$' + path = trimmed .. path + +root = dofile '$bundle.lua' +root\mount path, true content, rehydrate = render root, path assert content, "no content" -with io.open output_name, 'w' +with io.open 'index.html', 'w' \write "<!DOCTYPE html> <html> <head> @@ -39,8 +45,7 @@ with io.open output_name, 'w' <script src=\"//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js\"></script> <script src=\"/fengari-web.js\"></script> <script type=\"application/lua\" src=\"/mmm.bundle.lua\"></script> - <script type=\"application/lua\" src=\"/root.bundle.lua\"></script> - <script defer type=\"application/lua\" src=\"/mmm/init.lua\"></script> + <script type=\"application/lua\">require 'mmm'</script> #{rehydrate} </body> diff --git a/root/Tupdefault.lua b/root/Tupdefault.lua new file mode 100644 index 0000000..e4e433c --- /dev/null +++ b/root/Tupdefault.lua @@ -0,0 +1,30 @@ +facets = tup.glob '*' +inputs = '' +for i, file in ipairs(facets) do + inputs = inputs .. " '" .. file .. "'" +end + +LUA_PATH = {} +LUA_PATH += root .. '/?.lua' +LUA_PATH += root .. '/?.server.lua' +LUA_PATH += root .. '/?/init.lua' +LUA_PATH += root .. '/?/init.server.lua' +LUA_PATH = 'LUA_PATH="' .. table.concat(LUA_PATH, ';') .. '"' + +bundle = LUA_PATH .. ' moon ' .. root .. '/bundle_fileder.moon' +render = LUA_PATH .. ' moon ' .. root .. '/render.moon' + +facets += '<children>' +facets += root .. '/<modules>' + +tup.rule( + facets, + '^ BNDL %d^ ' .. bundle .. ' %d ' .. inputs .. ' -- %<children>', + { '$bundle.lua', '../<children>' } +) + +tup.rule( + '$bundle.lua', + '^ HTML %d^ ' .. render .. ' ' .. root, + 'index.html' +) diff --git a/root/articles/mmmfs/gallery.moon b/root/articles/mmmfs/gallery.moon deleted file mode 100644 index 4713101..0000000 --- a/root/articles/mmmfs/gallery.moon +++ /dev/null @@ -1,49 +0,0 @@ -import define_fileders from require 'mmm.mmmfs' -import div, h1, a, img, br from require 'mmm.dom' - -Fileder = define_fileders ... - -with Fileder { - 'name: alpha': 'gallery', - 'title: text/plain': "A Gallery of 25 random pictures, come in!", - 'preview: fn -> mmm/dom': => div { - 'the first pic as a little taste:', - br!, - img src: @children[1]\get 'preview', 'URL -> image/png' - } - 'fn -> mmm/dom': => - link = (child) -> a { - href: '#', - onclick: -> BROWSER\navigate child.path - img src: child\gett 'preview', 'URL -> image/png' - } - - content = [link child for child in *@children] - table.insert content, 1, h1 'gallery index' - div content - - 'slideshow: fn -> mmm/dom': => - import ReactiveVar, text, elements from require 'mmm.component' - - index = ReactiveVar 1 - - prev = (i) -> math.max 1, i - 1 - next = (i) -> math.min #@children, i + 1 - - e = elements - e.div { - e.div { - e.a 'prev', href: '#', onclick: -> index\transform prev - index\map (i) -> text " image ##{i} " - e.a 'next', href: '#', onclick: -> index\transform next - }, - index\map (i) -> img src: @children[i]\gett nil, 'URL -> image/png' - } - } - for i=1,25 - id = 120 + i - .children[i] = Fileder { - 'name: alpha': "image#{id}" - 'URL -> image/png': "https://picsum.photos/600/600/?image=#{id}" - 'preview: URL -> image/png': "https://picsum.photos/200/200/?image=#{id}" - } diff --git a/root/articles/mmmfs/gallery/link_to_image/URL -> image$png b/root/articles/mmmfs/gallery/link_to_image/URL -> image$png new file mode 100644 index 0000000..7cf76ff --- /dev/null +++ b/root/articles/mmmfs/gallery/link_to_image/URL -> image$png @@ -0,0 +1 @@ +https://picsum.photos/600/600/?image=101 diff --git a/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png b/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png new file mode 100644 index 0000000..2b2233b --- /dev/null +++ b/root/articles/mmmfs/gallery/link_to_image/preview: URL -> image$png @@ -0,0 +1 @@ +https://picsum.photos/200/200/?image=101 diff --git a/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..5285629 --- /dev/null +++ b/root/articles/mmmfs/gallery/preview: text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,7 @@ +import div, img, br from require 'mmm.dom' + +=> div { + 'the first pic as a little taste:', + br!, + img src: @children[1]\get 'preview', 'URL -> image/png' +} diff --git a/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon b/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon new file mode 100644 index 0000000..0178ac2 --- /dev/null +++ b/root/articles/mmmfs/gallery/slideshow: text$moonscript -> fn -> mmm$component.moon @@ -0,0 +1,19 @@ +import ReactiveVar, text, elements from require 'mmm.component' +import div, a, img from elements + +=> + index = ReactiveVar 1 + + prev = (i) -> math.max 1, i - 1 + next = (i) -> math.min #@children, i + 1 + + div { + div { + a 'prev', href: '#', onclick: -> index\transform prev + index\map (i) -> text " image ##{i} " + a 'next', href: '#', onclick: -> index\transform next + }, + index\map (i) -> + child = assert @children[i], "image not found!" + img src: @children[i]\gett 'URL -> image/png' + } diff --git a/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..9bdac54 --- /dev/null +++ b/root/articles/mmmfs/gallery/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,12 @@ +import div, h1, a, img, br from require 'mmm.dom' + +=> + link = (child) -> a { + href: '#', + onclick: -> BROWSER\navigate child.path + img src: child\gett 'preview', 'URL -> image/png' + } + + content = [link child for child in *@children] + table.insert content, 1, h1 'gallery index' + div content diff --git a/root/articles/mmmfs/gallery/title: text$plain b/root/articles/mmmfs/gallery/title: text$plain new file mode 100644 index 0000000..ad74eec --- /dev/null +++ b/root/articles/mmmfs/gallery/title: text$plain @@ -0,0 +1 @@ +A Gallery of 25 random pictures, come on in! diff --git a/root/articles/mmmfs/ignore -> text\$markdown.md b/root/articles/mmmfs/ignore -> text\$markdown.md deleted file mode 100644 index 1c1b4f9..0000000 --- a/root/articles/mmmfs/ignore -> text\$markdown.md +++ /dev/null @@ -1,7 +0,0 @@ -## this is a markdown version or something. - -There's no content here so switch back to the real one! -(Assuming there is a switching UI by the time you are reading this, which I assume since you are reading this at all. -If you are reading this in the source, then c'mon, just scroll past and give me a break.) - -(the switching UI has now been built.) diff --git a/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js b/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js new file mode 100644 index 0000000..de56531 --- /dev/null +++ b/root/articles/mmmfs/language_support/javascript/text$javascript -> mmm$dom.js @@ -0,0 +1,15 @@ +const e = (elem, children) => { + const node = document.createElement(elem); + + if (typeof children === 'string') + node.innerText = children; + else + children.forEach(child => node.appendChild(child)); + + return node; +}; + +return e('article', [ + e('h1', 'JavaScript'), + e('p', 'JavaScript is supported natively in the browser but is not currently pre-rendered on the server.'), +]); diff --git a/root/articles/mmmfs/language_support/javascript/title: text$plain b/root/articles/mmmfs/language_support/javascript/title: text$plain new file mode 100644 index 0000000..581fbc7 --- /dev/null +++ b/root/articles/mmmfs/language_support/javascript/title: text$plain @@ -0,0 +1 @@ +JavaScript diff --git a/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua b/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua new file mode 100644 index 0000000..62e79f1 --- /dev/null +++ b/root/articles/mmmfs/language_support/lua/text$lua -> mmm$dom.lua @@ -0,0 +1,9 @@ +local d = require 'mmm.dom' + +local lua = d.a { 'Lua', href = 'https://www.lua.org/' } +local fengari = d.a { 'fengari.io', href = 'https://fengari.io/' } + +return d.article { + d.h1 'Lua', + d.p { lua, ' is fully supported using ', fengari, ' on the Client.' } +} diff --git a/root/articles/mmmfs/language_support/lua/title: text$plain b/root/articles/mmmfs/language_support/lua/title: text$plain new file mode 100644 index 0000000..0f9d550 --- /dev/null +++ b/root/articles/mmmfs/language_support/lua/title: text$plain @@ -0,0 +1 @@ +Lua diff --git a/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon b/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon new file mode 100644 index 0000000..5cc50e6 --- /dev/null +++ b/root/articles/mmmfs/language_support/moonscript/text$moonscript -> mmm$dom.moon @@ -0,0 +1,10 @@ +import a, article, h1, p from require 'mmm.dom' + +moonscript = a 'MoonScript', href: 'https://moonscript.org/' +lua = a 'Lua', href: 'https://www.lua.org/' +fengari = a 'fengari.io', href: 'https://fengari.io/' + +article { + h1 'MoonScript', + p moonscript, " is compiled to ", lua, " on the server, which is then executed on the client using ", fengari, "." +} diff --git a/root/articles/mmmfs/language_support/moonscript/title: text$plain b/root/articles/mmmfs/language_support/moonscript/title: text$plain new file mode 100644 index 0000000..f8871ac --- /dev/null +++ b/root/articles/mmmfs/language_support/moonscript/title: text$plain @@ -0,0 +1 @@ +MoonScript diff --git a/root/articles/mmmfs/language_support/preview: text$markdown b/root/articles/mmmfs/language_support/preview: text$markdown new file mode 100644 index 0000000..d6c2845 --- /dev/null +++ b/root/articles/mmmfs/language_support/preview: text$markdown @@ -0,0 +1,6 @@ +this Fileder contains some minimal examples showing support for various languages `mmmfs` supports currently. + +Language support is mostly limited by the fact that `mmmfs` currently targets web browsers, +on the server any scripting language that can be executed can theoretically be integrated with minimal effort. + +Using the inspector mode to view the source of the Fileders below is encouraged. diff --git a/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon new file mode 100644 index 0000000..4ae0679 --- /dev/null +++ b/root/articles/mmmfs/language_support/text$moonscript -> fn -> mmm$dom.moon @@ -0,0 +1,16 @@ +import article, h1, p, ul, li, a from require 'mmm.dom' + +single = (a) -> a + +=> + children = for child in *@children + title = child\gett 'title: text/plain' + li a title, href: child.path, onclick: (e) => + e\preventDefault! + BROWSER\navigate child.path + + article { + h1 single @gett 'title: text/plain' + p single @gett 'preview: mmm/dom' + ul children + } diff --git a/root/articles/mmmfs/language_support/title: text$plain b/root/articles/mmmfs/language_support/title: text$plain new file mode 100644 index 0000000..ae06474 --- /dev/null +++ b/root/articles/mmmfs/language_support/title: text$plain @@ -0,0 +1 @@ +scripting language support diff --git a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon index 5619747..de28192 100644 --- a/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon +++ b/root/articles/mmmfs/text$moonscript -> fn -> mmm$dom.moon @@ -28,12 +28,53 @@ table.insert args, style: { 'list-style': 'none', 'font-size': '0.8em' } ol table.unpack args - append h1 'mmmfs', style: { 'margin-bottom': 0 } -- @TODO: s/filesystem/a way of organizing files/g - append p "a file and operating system to live in", style: { 'margin-top': 0, 'margin-bottom': '1em' } + append h1 'mmmfs', style: { 'margin-bottom': 0 } + append p "a file and operating system to live in", style: { 'margin-top': 0, 'padding-bottom': '0.2em', 'border-bottom': '1px solid black' } + + append h2 "motivation" + append p "Today, computer users are losing more and more control over their data. Between web and cloud + applications holding customer data hostage for providing the services, unappealing and limited mobile file + browsing experiences and the non-interoperable, proprietary file formats holding on to their own data has + become infeasible for many users. mmmfs is an attempt at rethinking file-systems and the computer user + experience to give control back to and empower users." + + append p "mmmfs tries to provide a filesystem that is powerful enough to let you use it as your canvas for thinking, + and working at the computer. mmmfs is made for more than just storing information. Files in mmmfs can interact + and morph to create complex behaviours." + + append p "Let us take as an example the simple task of collecting and arranging a mixed collection of images and texts + in order to brainstorm. To create an assemblage of pictures and text, many might be tempted to open an + Application like Microsoft Word or Adobe Photoshop and create a new document there. Both photoshop files and + word documents are capable of containing texts and images, but when the files are saved, direct access to the + contained data is lost. It is for example a non-trivial and unenjoyable task to edit an image file contained + in a word document in another application and have the changes apply to the document. In the same way, + text contained in a photoshop document cannot be edited in a text editor of your choice." + + append p "mmmfs tries to change all this. In mmmfs, files can contain other files and so the collage document + becomes a container for the collected images and texts just as a regular directory would. This way the individual + files remain accessible and can be modified whenever necessary, while the collage document can be edited to + change the order, sizes and spatial arrangement of it's content if this is wanted, for example." + + append p "The mmmfs file-type system also allows storing types of information that have become impractical to use + with current filesystems simply because noone has cared to make suitable applications for them. It is not common + practice, for example, to store direct links to online content on the disk for example. In mmmfs, a link to a + picture can be stored wherever an actual picture is expected for example, the system will take care of retrieving + the real picture as necessary." -- @TODO: motivation / outline problem + need - -- @TODO: quote http://pchiusano.github.io/2013-05-22/future-of-software.html on Applications + -- * applications don't let users *do* things (http://pchiusano.github.io/2013-05-22/future-of-software.html) + -- * applications are just (collections of) files - most users don't know this (anymore) + -- * users should know their system and how to move around in it + -- * filesystem trees are only *okay* for organizing information: + -- - users sooner or later choose something smarter because: + -- * filesystems work the same in every folder, even though the context can be very different + -- * appliances put their complex, structured data into opaque blocks + -- * the FS should be able to solve the structure issue + -- * the benefit is interoperability: edit the image of your report + -- * in image editor while the document editor automatically refreshes + -- * file formats dont mean much to users, they are meant for applications - let applications take care of converting them + -- * report.doc, report.pdf, report_orignal.pdf, report_old.doc, report2.doc.... append p do fileder = footnote "fileder: file + folder. 'node', 'table' etc. are too general to be used all over." @@ -91,52 +132,46 @@ }, } - append div for child in *@children preview child append h2 "details" -- @TODO s/parts: dimensions, aspects? - -- @TODO: first mention both properties & children; then go into detail + -- @TODO: first mention both facets & children; then go into detail -- @TODO: main content append do name = html.i 'name' type = html.i 'type' - p "Fileders are made up of two main parts. The first is the list of ", (html.i 'properties'), ", + p "Fileders are made up of two main parts. The first is the list of ", (html.i 'facets'), ", which are values identified by a ", name, " and ", type, ". These values are queried using strings like ", (code 'title: text/plain'), " or ", (code 'mmm/dom'), ", which describe both the ", name, - " of a property (", (moon '"title"'), " and ", (moon '""'), ", the unnamed/main property) and the ", type, - " of a property. Property types can be something resembling a MIME-type or a more complex structure - (see ", (html.i "type chains"), " below). A fileder can have multiple properties of different types - set that share a ", name, ". In this case the overlapping properties are considered equivalent and the one + " of a facet (", (moon '"title"'), " and ", (moon '""'), ", the unnamed/main facet) and the ", type, + " of a facet. Facet types can be something resembling a MIME-type or a more complex structure + (see ", (html.i "type chains"), " below). A fileder can have multiple facets of different types + set that share a ", name, ". In this case the overlapping facets are considered equivalent and the one with the most appropriate ", type, " is selected, depending on the query. - The unnamed property is considered a fileder's 'main content', i.e. what you are interested in when viewing it." + The unnamed facet is considered a fileder's 'main content', i.e. what you are interested in when viewing it." append p "The second part of a fileder is the list of it's children, which are fileders itself. The children are stored in an ordered list and currently identified by their ", (code 'name: alpha'), - " property for UI and navigation purposes only (not sure if this is a good idea tbh)." - --- append do --- github = footnote a 's-ol/mmm', href: 'https://github.com/s-ol/mmm/tree/master/app/mmmfs' --- "Oh and also everything is on github and stuff", github, --- " if you care about that." + " facet for UI and navigation purposes only (not sure if this is a good idea tbh)." append do mmmdom = code ('mmm/dom'), footnote span (code 'mmm/dom'), " is a polymorphic content type; on the server it is just an HTML string (like ", (code 'text/html'), "), but on the client it is a JS DOM Element instance." - p "What you are viewing right now is the main property of the root fileder. - The property is queried as ", mmmdom, ", a website fragment (DOM node). This website fragment + p "What you are viewing right now is the main facet of the root fileder. + The facet is queried as ", mmmdom, ", a website fragment (DOM node). This website fragment is then added to the page in the main content area, where you are most likely reading it right now." p "Anyway, this node is set up as a very generic sort of index thing and just lists its children-fileders' alongside this text part you are reading.", br!, "For each child it displays the ", (code 'title: text/plain'), - " and shows the ", (code 'preview: mmm/dom'), " property (if set)." + " and shows the ", (code 'preview: mmm/dom'), " facet (if set)." append h3 "converts" - append p "So far I have always listed properties as they are being queried, but a main feature of mmmfs is + append p "So far I have always listed facets as they are being queried, but a main feature of mmmfs is type conversion. This means that you generally ask for content in whichever format suits your application, and rely on the type resolution mechanism to make that happen." @@ -159,7 +194,7 @@ preview title, content ]] append p "Here the code that renders these previews. You can see it ", (html.i "asks"), " for the - properties ", (code 'title: text/plain'), ' and ', (code 'preview: mmm/dom'), "), but the values don't actually have to + facets ", (code 'title: text/plain'), ' and ', (code 'preview: mmm/dom'), "), but the values don't actually have to be ", (html.i "defined"), " as these types. For example, the markdown child below only provides ", (code 'preview'), " as ", (code 'text/markdown'), ":" @@ -189,7 +224,7 @@ Fileder { ]] append h3 "type chains" - append p "In addition, a property type can be encoded using multiple types in a ", (code 'type chain'), ". + append p "In addition, a facet type can be encoded using multiple types in a ", (code 'type chain'), ". For example the root node you are viewing currently is actually defined as ", (code 'fn -> mmm/dom'), ", meaning it's value is a pre moon function returing a regular ", (code 'mmm/dom'), " value." diff --git a/test.moon b/test.moon deleted file mode 100644 index 7d18982..0000000 --- a/test.moon +++ /dev/null @@ -1,16 +0,0 @@ -package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath -require 'mmm.init' -import render from require 'mmm.mmmfs' -import load_fileder from require 'mmm.mmmfs.fs' - --- usage: --- moon render.moon <output> <fileder_path> -{ output_name, path } = arg - -assert output_name, "please specify the output filename as an argument" -assert path, "please specify the path name to build as an argument" - -root = load_fileder 'root' .. path -root\mount path - -print root diff --git a/tup.moon b/tup.moon deleted file mode 100644 index 1888a00..0000000 --- a/tup.moon +++ /dev/null @@ -1,47 +0,0 @@ -package.moonpath = './?.server.moon;./?/init.server.moon;' .. package.moonpath -require 'lfs' -require 'mmm.init' - --- enumerate moonscript source files -enum_dir = do - yieldtree = (dir) -> - for entry in lfs.dir dir - if entry != '.' and entry != '..' then - entry = dir .. "/" .. entry - attr = lfs.attributes entry - switch attr.mode - when 'file' then coroutine.yield entry, attr - when 'directory' yieldtree entry - - (dir) -> - assert dir and dir ~= '', "directory parameter is missing or empty" - dir = dir\sub 1, -2 if '/' == dir\sub -1 - - coroutine.wrap -> yieldtree dir - --- COMPILE MOONSCRIPT -for file in enum_dir 'mmm' - continue if file\match '%.server%.moon$' - basename = assert file\match '(.*)%.moon$' - basename = (file\match '(.*)%.client') or basename - print ": #{file} |> ^ MOON %b > %o^ moonc -o %o %f |> dist/#{basename}.lua {mmm_src}" - --- GENERATE BUNDLES -print ": {mmm_src} |> ^ BUNDLE mmm^ moon bundle.moon %o %f |> dist/mmm.bundle.lua" - --- COMPILE AND DUMP TREE -print ": |> ^ DUMP root^ moon dump_tree.moon %o |> dist/root.lua" - --- PRE-RENDER TREE -import load_fileder from require 'mmm.mmmfs.fs' - -root = load_fileder! -root\mount! - -for fileder in coroutine.wrap root\iterate - name = fileder\gett 'name: alpha' - { :path, :source_module } = fileder - - path = '/' if path == '' - - print ": |> ^ HTML #{path}^ moon render.moon %o '#{path}' |> dist#{path}/index.html" |
