a colorforth-like thing in coffeescript
# colorforth inspired programming system | |
module 'colorcode' | |
imports ['b4', 'key'], ()-> | |
$jq('#rhs') | |
.html( | |
''' | |
<div id="rhs-block" tabindex="0"/> | |
<div id="rhs-status" tabindex="1"/> | |
''') | |
.css | |
background : '#121212' | |
'font-family': 'consolas' | |
'font-size' : '12pt' | |
'color' : '#ccc' | |
'outline-style' : 'none' | |
rhs = $d3.select '#rhs-block' | |
rhs.style | |
height: "640px" | |
$d3.select('#rhs-status').style('background':'red').text '??' | |
kTESTBLOCK = [ | |
# color names: | |
0x20000000, 0x21000001, 0x22000002, 0x23000003 | |
0x24000004, 0x25000005, 0x26000006, 0x27000007 | |
0x28000008, 0x29000009, 0x2A00000A, 0x2B00000B | |
0x2C00000C, 0x2D00000D, 0x2E00000E, 0x2F00000F | |
# a copy of block 38 from arrayforth | |
# <newline> |w "- clock" <newline> | |
0x20003800, 0x6F00000d, 0x2F003801, 0x68000000 | |
# |r "sec" |w "-n" |g "utime" |y "60 60" | |
0x61023973, 0x6F000b8d, 0x22003802, 0xDB00003c, 0xDB00003c | |
# |y "* 24 *" |g "mod" ; | |
0x6B00000a, 0xdb000018, 0x6B00000a, 0x62024bed, 0x6200001b | |
# <newline> |r "minute" |w "-n" |g "sec 60 / ;" | |
0x68000000, 0x21003803, 0x6F000b8d, 0x62023973, 0xd200003c | |
0x6200000f, 0x6200001b | |
] | |
class BlockDB | |
constructor: -> | |
@db = null | |
@ready = false | |
@sname = 'blocks' | |
@version = 2 | |
# callbacks: | |
OnInitialize: => | |
OnBlockLoaded: (block)=> | |
init: => | |
# console.log 'in BlockDB.init' | |
rq = window.indexedDB.open @sname, @version | |
rq.onupgradeneeded = (e)=> | |
console.log '* upgrading db to version ' + @version | |
@db = e.target.result | |
@db.createObjectStore(@sname, autoIncrement: true) | |
rq.onsuccess = (e)=> | |
@db = e.target.result | |
#console.log 'db loaded:', @db | |
tx = @db.transaction([@sname], 'readwrite') | |
os = tx.objectStore(@sname) | |
os.count() | |
.onsuccess = (e)=> | |
if e.target.result == 0 | |
os.add(kTESTBLOCK).onsuccess = (e)=> @OnInitialize() | |
else @OnInitialize() | |
rq.onerror = (e)=> | |
console.log 'error!!!' | |
console.log e | |
rq.onblocked = (e)=> | |
console.log 'blocked!!!' | |
console.log e | |
window.rq = rq | |
console.log rq | |
loadBlock: (n)=> | |
rq = @db.transaction([@sname], 'readwrite') | |
.objectStore(@sname) | |
.get(n) | |
rq.onsuccess = (e)=> | |
@OnBlockLoaded(n, e.target.result) | |
# encoder | |
# hex(int(''.join(bin(ord(ch)-32)[2:].zfill(6) for ch in reversed(s)), 2)) | |
pal = | |
k:0x0, r:0x1, g:0x2, y:0x3, b:0x4, m:0x5, c:0x6, w:0x7 | |
K:0x8, R:0x9, G:0xA, Y:0xB, B:0xC, M:0xD, C:0xE, W:0xF | |
lex = | |
0x0:'k', 0x1:'r', 0x2:'g', 0x3:'y', 0x4:'b', 0x5:'m', 0x6:'c', 0x7:'w' | |
0x8:'K', 0x9:'R', 0xA:'G', 0xB:'Y', 0xC:'B', 0xD:'M', 0xE:'C', 0xF:'W' | |
0x3800: 'block 38 from arrayforth:' | |
0x3801: 'clock', 0x3802: "utime", 0x3803:'minute' | |
sixbit = (word) -> | |
res = '' | |
while (bits = word & 0x3F) | |
res += String.fromCharCode(bits + 32).toLowerCase() | |
word >>>= 6 | |
return res | |
decode = (code) -> | |
# first byte is the meta-data, rest is the value | |
word = code & 0x00FFFFFF | |
meta = (code & 0xFF000000) >>> 24 | |
kind = (meta & 0xF0) >>> 4 | |
color = (meta & 0x0F) | |
switch kind | |
when 0xf then "0x#{ word.toString 16 }" | |
when 0xd then "#{word.toString 10}" | |
when 0x2 then lex[ word ] | |
when 0x6 then sixbit(word) | |
else "<0x#{ kind.toString 16 }>" | |
class ColorMemo | |
constructor: -> | |
@cursor = 1 | |
@block = [] | |
@nodes = [] | |
showBlock: (bnum, block)=> | |
breakNext = false | |
@block = block | |
@nodes = rhs.selectAll('code').data(block) | |
@nodes.enter() | |
.append('code') | |
.style | |
'padding' : '2px' | |
'margin' : '2px' | |
'margin-right': '0px' # because of the cursor | |
'font-family' : 'consolas' | |
'font-size' : '14pt' | |
'display' : 'block' | |
'outline' : 'none' # to hide tabindex focus | |
float: (d)-> | |
if (d>>24 & 0xF) then 'left' else 'none' | |
clear: (d)-> | |
if breakNext then breakNext = false; result = 'left' | |
else result = switch (d>>24 & 0xF) | |
when 0 then breakNext = true ; 'left' | |
when 8 then breakNext = true ; 'none' | |
else 'none' | |
color: (d)-> | |
switch (d >>> 24) & 0x0F | |
when pal.k then 'black' ; when pal.K then '#666' | |
when pal.r then '#c22' ; when pal.R then '#f44' | |
when pal.g then '#090' ; when pal.G then '#0e0' | |
when pal.y then '#a83' ; when pal.Y then '#fc4' | |
when pal.b then '#33f' ; when pal.B then '#66f' | |
when pal.m then '#a0a' ; when pal.M then '#d4d' | |
when pal.c then '#299' ; when pal.C then '#4dd' | |
when pal.w then '#aaa' ; when pal.W then '#fff' | |
else '#888' | |
.html (d)-> | |
decode(d) | |
.on 'click', (d, i)=> | |
@cursor = i; @drawCursor() | |
# end of @nodes.enter() | |
@drawCursor() | |
$jq('#rhs-block').focus() | |
drawCursor: => | |
@nodes.attr 'class', (d, i)=> | |
rev = (d>>24 & 0x0f)==0 | |
if i == @cursor then (if rev then 'rev cur' else 'cur') | |
else if rev then 'rev' else 'word' | |
keyDown: (e)=> | |
switch e.which | |
when $key.RIGHT then @cursor++ | |
when $key.LEFT then @cursor-- | |
when $key.UP then @cursor -= 5 | |
when $key.DOWN then @cursor += 5 | |
if @cursor >= @block.length then @cursor = @block.length-1 | |
if @cursor < 0 then @cursor = 0 | |
@drawCursor() | |
db = new BlockDB | |
cm = new ColorMemo | |
db.OnBlockLoaded = cm.showBlock | |
db.OnInitialize = -> | |
$colorcode.db = db | |
$colorcode.cm = cm | |
$jq("#rhs").off 'keydown' | |
$jq("#rhs").on 'keydown', cm.keyDown | |
console.log '--- ready to load the first block. ---' | |
db.loadBlock(1) | |
$jq("#rhs-content").focus() | |
$d3.select('#rhs-status').style('background':'green').text 'ok' | |
$d3.select('#rhs-status').style('background':'gold').text '...' | |
console.log 'initializing the db.' | |
db.init() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment