view src/editor.tp @ 245:3590ecca6bc9

Fix handling of unescaped tabs in string literals in new parser
author Mike Pavone <pavone@retrodev.com>
date Mon, 06 Jan 2014 01:03:18 -0800
parents 15aac5334b64
children
line wrap: on
line source

#{
//mquery functions
q <- foreign: :query {}
qall <- foreign: :query {}
each <- foreign: :iterable fun {}
addClass <- foreign: :node className {}
removeClass <- foreign: :node className {}
hasClass <- foreign: :node className {}
get <- foreign: :url onSuccess onFail onOther {}
newEl <- foreign: :tagname props {}

//editor.js functions
getEl <- foreign: :from idx {}
setEl <- foreign: :to idx val {}
goFullScreen <- foreign: {}
create_symbol <- foreign: :name {}

//TP Parser
parser <- foreign: #{
	parse <- foreign: :str {}
}
isLambda <- foreign: :astnode {}

//js builtins
console <- foreign: #{
	log <- foreign: :val {}
}
window <- foreign: #{}
Object <- foreign: #{
	keys <- foreign: :object {}
}

filter <- :arr pred {
	output <- arr slice: 0 0
	each: arr :idx el {
		if: (pred: el) {
			output push: el
		} else: {}
	}
	output
}

//editor code
selection <- #{
	valid? <- false
}

setSelection:withInNode <- :astnode :innode {
	fakeEvent <- #{
		stopPropagation <- :Blah {
		}
	}

	selection <- #{
		valid? <- true
		in <- {
			(innode domNode) onclick: fakeEvent
		}
		out <- {
			((astnode up) domNode) onclick: fakeEvent
		}
		next <- {
			(((astnode up) getNext: astnode) domNode) onclick: fakeEvent
		}

		previous <- {
			(((astnode up) getPrev: astnode) domNode) onclick: fakeEvent
		}
	}
}

setSelection <- :astnode {
	fakeEvent <- #{
		stopPropagation <- :Blah {
		}
	}
	selection <- #{
		valid? <- true
		in <- {
		}
		out <- {
			fakeEvent <- #{
				stopPropagation <- :Blah {
				}
			}
			((astnode up) domNode) onclick: fakeEvent
		}
		next <- {
			console log: "selection next"
			(((astnode up) getNext: astnode) domNode) onclick: fakeEvent
		}
		previous <- {
			(((astnode up) getPrev: astnode) domNode) onclick: fakeEvent
		}
	}
}

editFile <- :path {
	get: path :request {
		addClass: (q: "body") "editorMode"
		src <- request responseText
		ast <- parser parse: src
		ast populateSymbols: (foreign: null)
		ast toHTML: (q: "#src")
	}
}

selectNode <- :node {
	each: (qall: ".selected") :idx el {
		removeClass: el "selected"
	}
	addClass: node "selected"
}

selectQuery <- :selector {
	selectQuery: selector in: (foreign: undefined)
}

selectQuery:in <- :selector :context {
	each: (qall: ".selected") :idx el {
		removeClass: el "selected"
	}
	each: (qall: selector context) :idx el {
		addClass: el "selected"
	}
}

selectParent <- :node {
	each: (qall: ".selectParent") :idx el {
		removeClass: el "selectParent"
	}
	addClass: node "selectParent"
}

popInscope:onClick <- :syms :handler {
	inscope <- q: "#inscope"
	inscope innerHTML!: ""
	each: syms :idx key {
		inscope appendChild: (newEl: "li" #{
			textContent <- key
			onclick <- :Event { handler: key }
		})
	}
}

scalarClick <- :domnode astnode event {
	selectNode: domnode
	setSelection: astnode
	event stopPropagation: (foreign: undefined)
	//TODO: set focus
}

symbolClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		domnode textContent!: key
		astnode name!: key
	}
	setSelection: astnode
	event stopPropagation: (foreign: undefined)
}

assignClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .varname" in: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		(domnode firstChild) textContent!: key
		(astnode symbol) name!: key
	}
	setSelection: astnode withInNode: (astnode expression)
	event stopPropagation: (foreign: undefined)
}

opClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .opname" in: domnode
	showOps
	setSelection: astnode withInNode: (astnode left)
	event stopPropagation: (foreign: undefined)
}

funClick <- :domnode astnode event {
	selectParent: domnode
	selectQuery: ".selectParent > .funpart" in: domnode
	symtable <- astnode symbols
	syms <- filter: (symtable allSymbols: (foreign: undefined)) :sym {
		isLambda: ((symtable find: sym) def)
	}
	inner <- if: (astnode receiver) != (foreign: null) {
		astnode receiver
	} else: {
		(astnode args) getEl: 0
	}
	setSelection: astnode withInNode: inner
	popInscope: syms onClick: :key {
		astnode name!: key
		parts <- key split: ":"
		nodes <- []
		each: (domnode children) :idx val{
			nodes push: val
		}
		partIdx <- 0
		nodeIdx <- 0
		lastWasNamePart <- true
		while: { partIdx < (parts length) || nodeIdx < (nodes length) } do: {
			if: nodeIdx < (nodes length) {
				node <-getEl: nodes nodeIdx
				nodeIdx <- nodeIdx + 1
				if: (hasClass: node "funpart") {
					if: partIdx < (parts length) {
						postfix <- if: partIdx = 0 && nodeIdx = 2 && (parts length) = 1 && (nodes length) = 2 { "" } else: { ":" }
						t <- (getEl: parts partIdx)
						node textContent!: (getEl: parts partIdx) . postfix
						partIdx <- partIdx + 1
					} else: {
						domnode removeChild: node
					}
					lastWasNamePart <- true
				} else: {
					if: (not: lastWasNamePart) && partIdx < (parts length) && nodeIdx > 0 {
						domnode insertBefore: (newEl: "span" #{
							className <- "funpart selected"
							textContent <- (getEl: parts partIdx) . ":"
						}) node
						partIdx <- partIdx + 1
					}
					lastWasNamePart <- false
				}
			} else: {
				console log: "part: " . (getEl: parts partIdx)
				domnode appendChild: (newEl: "span" #{
					className <- "funpart selected"
					textContent <- (getEl: parts partIdx) . ":"
				})
				partIdx <- partIdx + 1
			}
		}
	}
	event stopPropagation: (foreign: undefined)
}

replaceNode:with <- :astnode domnode :newnode {

}

lambdaClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		replaceNode: astnode domnode with: (create_symbol: key)
	}
	inner <- if: ((astnode args) length) > 0 {
		(astnode args) getEl: 0
	} else: {
		(astnode expressions) getEl: 0
	}
	setSelection: astnode withInNode: inner
	event stopPropagation: (foreign: undefined)
}

objectClick <- :domnode astnode event {
	selectNode: domnode
	popInscope: ((astnode symbols) allSymbols: (foreign: undefined)) onClick: :key {
		console log: "fooobar!"
	}
	setSelection: astnode withInNode: ((astnode messages) getEl: 0)
	event stopPropagation: (foreign: undefined)
}

visible <- "showops"

showOps <- {
	each: (qall: ".controls") :idx el {
		removeClass: el visible
		addClass: el "showops"
	}
	visible <- "showops"
}

showLit <- {
	each: (qall: ".controls") :idx el {
		removeClass: el visible
		addClass: el "showlit"
	}
	visible <- "showlit"
}

main <- {
	get: "/src/" :data {
		fakeEl <- newEl: "div" #{
			innerHTML <- data response
		}
		each: (qall: "a" fakeEl) :idx el {
			if: ((el textContent) = "../") {} else: {
				nel <- newEl: "a" #{
					href <- "/edit/src/" + (el textContent)
					textContent <- el textContent
				}
				nel onclick!: :event {
					link <- foreign: this
					path <- link href
					path <- path substr: (path indexOf: "/edit/") + 5
					editFile: path
					foreign: false
				}
				li <- newEl: "li"
				li appendChild: nel
				(q: "#browser ul") appendChild: li
			}
		}
	}

	//bind handlers for editor buttons
	each: (qall: ".controls li") :idx el {
		el onclick!: :event {
			srcel <- (q: "#src")
			srcel textContent!: (srcel textContent) + (el textContent)
		}
	}
	(q: "#ops_button") onclick!: :event {
		showOps
	}
	(q: "#lit_button") onclick!: :event {
		showLit
	}

	(q: "#in") onclick!: :event {
		console log: "inwards"
		if: (selection valid?) {
			selection in
		}
	}

	(q: "#out") onclick!: :event {
		console log: "outwards"
		if: (selection valid?) {
			selection out
		}
	}

	(q: "#next") onclick!: :event {
		if: (selection valid?) {
			selection next
		}
	}

	(q: "#prev") onclick!: :event {
		if: (selection valid?) {
			selection previous
		}
	}

	path <- (window location) pathname
	if: (path indexOf: "/edit/") = 0 {
		editFile: (path substr: 5)
	}
	(q: "#fullscreen") onclick!: :event {
		goFullScreen:
	}
}

}