Some of you might get a kick out of this. After watching Bret Victor's talk I spent a few hours writing an "instant" version of Codea inside Codea. Basically it gives you a keyboard and you can write Codea code, any code you write is instantly run and drawn behind your code.
It's pretty interesting. Here's the code and a screenshot.

Main file is Here: http://pastebin.com/8enSYdgZ — does not paste into forums due to Emoji.
Buffer
Buffer = class()
function Buffer:init()
self.buffer = {}
self.font = "Inconsolata"
self.fontSize = 20
-- x = line, y = pos
self.cursor = vec2(1,1)
self.t = 0
self.cursorBlink = 0
end
function Buffer:setStyle()
textMode(CORNER)
font( self.font )
fill(255)
fontSize( self.fontSize )
textWrapWidth(10000)
end
function Buffer:cursorToScreen(c)
-- Get a subset of the buffer
local lines = table_slice( self.buffer, 1, c.x )
local l = self.buffer[c.x]
local upToStr = self:bufferToString(lines)
local lstr = nil
if l then
lstr = table.concat(l)
end
pushStyle()
self:setStyle()
local lw = 0
local _,lh = textSize("A")
local emptyLine = true
if lstr and lstr ~= "" then
lw,lh = textSize(string.sub(lstr,1,c.y - 1))
emptyLine = false
end
local pw,ph = textSize(upToStr)
if emptyLine then
ph = ph + lh
end
popStyle()
return lw,(ph - lh/2)
end
function Buffer:bufferToString(b)
local bstrings = {}
for k,v in pairs(b) do
table.insert(bstrings, table.concat( b[k] ) )
end
return table.concat( bstrings, "\n" )
end
function Buffer:moveCursor(o)
self.cursor = self.cursor + o
self.cursor.x = math.max(1, math.min(self.cursor.x, #self.buffer))
local l = self.buffer[self.cursor.x]
local y = self.cursor.y
y = math.max(1, math.min(y, #l + 1))
self.cursor.y = y
end
function Buffer:insertCharacter(c)
local l = self.buffer[self.cursor.x]
if l == nil then
l = {}
self.buffer[self.cursor.x] = l
end
if c == "\n" then
local start = table_slice(l,1,self.cursor.y)
local tail = table_slice(l,self.cursor.y+1,#l)
table[self.cursor.x] = start
table.insert(self.buffer, self.cursor.x+1, tail)
self.cursor = vec2( self.cursor.x + 1, 1 )
elseif c == BACKSPACE then
if self.cursor.y == 1 then
-- delete line
local prevLine = self.buffer[self.cursor.x - 1]
table.remove(self.buffer, self.cursor.x)
if prevLine then
self.cursor = vec2(self.cursor.x - 1, #prevLine + 1)
table_append( prevLine, l )
end
else
-- delete character
table.remove(l, self.cursor.y - 1 )
self.cursor = vec2(self.cursor.x, self.cursor.y - 1 )
end
else
table.insert(l, self.cursor.y, c)
self.cursor = vec2( self.cursor.x, self.cursor.y + 1 )
end
end
function Buffer:draw()
self.t = self.t + 8 * DeltaTime
self.cursorBlink = (math.sin(self.t) + 1) * 128
pushStyle()
self:setStyle()
local str = self:toString()
local w,h = textSize(str)
pushMatrix()
translate( 40, -40 )
text(str, 0, HEIGHT - h)
-- Draw cursor
-- Cursor pos x,y
local cpx,cpy = self:cursorToScreen(self.cursor)
fill(0, 87, 255, self.cursorBlink)
rectMode(CENTER)
rect(cpx,HEIGHT - cpy,5,22)
popMatrix()
popStyle()
end
function Buffer:clear()
self.cursor = vec2(1,1)
self.buffer = {}
end
function Buffer:toString()
return self:bufferToString(self.buffer)
end
function Buffer:toStringWithoutActiveLine()
local bstrings = {}
for k,v in pairs(self.buffer) do
if k ~= self.cursor.x then
table.insert(bstrings, table.concat( self.buffer[k] ) )
end
end
return table.concat( bstrings, "\n" )
end
EmButton
-- Emoji Button
EmButton = class()
function EmButton:init(pos,txt)
-- you can accept and set parameters here
self.pos = pos
self.text = txt
self.action = nil
self.highlight = false
self.color = color(255,255,255,255)
end
function EmButton:size()
pushStyle()
self:setStyle()
local w,h = textSize(self.text)
popStyle()
return w,h
end
function EmButton:hitTest(lp)
local w,h = self:size()
local left,right = self.pos.x - w/2, self.pos.x + w/2
local top,bottom = self.pos.y + h/2, self.pos.y - h/2
if lp.x > left and lp.x < right and
lp.y > bottom and lp.y < top then
return true
end
return false
end
function EmButton:setStyle()
fill(self.color)
noStroke()
textMode(CENTER)
fontSize(50)
font("AppleColorEmoji")
end
function EmButton:draw()
pushMatrix()
translate(self.pos.x,self.pos.y)
pushStyle()
self:setStyle()
text(self.text,0,0)
popStyle()
popMatrix()
end
function EmButton:touched(touch)
if touch.state == ENDED then
-- Tapped
if self:hitTest( vec2(touch.x,touch.y) ) then
if self.action then self.action() end
end
end
end
Util
function table_append (t1, t2)
local t1s = #t1
for k,v in pairs(t2) do t1[k + t1s] = v end
end
function table_slice (values,i1,i2)
local res = {}
local n = #values
-- default values for range
i1 = i1 or 1
i2 = i2 or n
if i2 < 0 then
i2 = n + i2 + 1
elseif i2 > n then
i2 = n
end
if i1 < 1 or i1 > n then
return {}
end
local k = 1
for i = i1,i2 do
res[k] = values[i]
k = k + 1
end
return res
end
Main file is Here: http://pastebin.com/8enSYdgZ — does not paste into forums due to Emoji.
I knew someone will write something like this. I thought it's gonna be done first by @bortels as he's kinda an adventurer coder (is that term existed?). :D
This is very basic but very fun nevertheless. I think it would interest kids as it's more interactive. I'm gonna give it to my 5 y.o son and see how he respons this. Thank you, @simeon. :)
local pKey = EmButton(vec2(0,0), "A")
pKey.action = function()
if displayMode() == STANDARD then
displayMode(FULLSCREEN_NO_BUTTONS)
else displayMode(STANDARD)
print(buffer:toString()) end
end
keys = {closeKey,startKey,leftKey,
rightKey,endKey,upKey,
downKey,keyKey,pKey}
minor addition to main to allow cut/paste
Nice change @Ipda41001.
@John also made a really good change by using pcall() to execute the code block, and only executing the last-working-block. This allows it to ignore runtime errors and always draw something on the screen.
Love this!
Here's code using the pcall idea to catch errors.
local chunk, loadErr = loadstring(str)
if chunk then
local status, err = pcall(chunk)
if status then
lastGood = chunk
clearOutput()
print("allgood")
else
clearOutput()
print(err)
end
else
if lastGood then
pcall(lastGood)
end
clearOutput()
print(loadErr)
end
Run it non-fullscreen and move the output window up to see error feedback as you type.
Simeon you used a function "chunk()". Is that a lua function? What it actually does? I figured out it executes the command we typed but Where can I learn about it more?
@rashedlatif "chunk" was my choice of variable name. Basically the loadstring() function accepts an arbitrary "chunk" of Lua code and returns it as an executable "chunk". I store that in a variable called "chunk" which I later execute by putting function call parentheses after the variable name (i.e. chunk()).
However @dylanf's method is much, much better. Using the built in Lua function pcall() to execute the chunk isolates run-time errors so that they don't crash or interrupt the app.
Makes Sence :) thanks Simeon. I m still very beginner in lua. But no doubt these kinds of features are very powerful ones.
It looks like you're new here. If you want to get involved, click one of these buttons!