Updated July 2019 : Installation instructions & mini-guide below
Fructure at RacketCon 2019.My talk (from the livestream).Slides: Real version. Extended unedited version.
Fructure is a prototype structure editor, which can currently be used to write & edit small programs in a small subset of scheme/racket. This is a personal project where I'm playing with ideas in editing, programming languages, and interaction design.
Note: now that this is getting some traffic I wanted to put up a disclaimer that some of the code is currently in a bit of a state: I've commented out some things and hacked up some others to smoothen the demo. My immediate plans are - after taking a post-racketcon break and aside from general cleanup - to unhackify the way transforms currently work, properly re-instate variadic parameters for binding forms, and do some profiling and address the current sluggishness.
fig 1: walking the grammar
fig 2: refactoring by re/destructuring
fig 3: menu closeup
I wrote a bit about my then-current direction in September 2018, just before beginning my current implementation attempt. I've completed most of what I talk about there, with varying levels of success: Fructure 1 of 2 Fructure 2 of 2. There will soon be some slightly more up-to-date notes via my racketcon slides. For more updates cyberfollow @twitter and @elsewhere. Here's an ongoing dev screenshot dump; check out the chronological overview:
fig 4: family history
Basically, you need to install racket, a couple libraries, and a font if you don't want thing to look screwy.
MacOS:
Linux, Windows: (under construction)
TO RUN:
FAQ: Q: Is it suppose to be this slow? A: It's open source.
Fructure starts in NAV(igation) mode. The selector (red) encloses a hole (yellow).
NAV keybindings
ENTER
toggles TRANSFORM modeA transform (red) maps the source (the hole) to (->) the target (selection (outlined in red) in menu (also outlined in red))
TRANSFORM keybindings
UP
/DOWN
move menu / selector: find and select an "if" expression)ENTER
performs selected transform, toggles NAV mode: transform the hole to the ifNAV keybindings (continued)
LEFT/RIGHT
move selector in preorder tree traversal: go right thrice and left twice to cycle the selection, settling on the first childThese keys (almost) suffice to build/delete arbitrary syntax, though not terribly conveniently. Build a tiny program this way. I say almost because you can't (yet, owing to a bug) input new identifiers in this way. Doing so (currently) requires being in the menu and pressing RIGHT on a lambda or define (see next step).
Approximating standard text-entry
NAV keybindings
UP/DOWN
selector to parent/first childTRANSFORM keybindings
ESC
switch to NAV mode without performing transformationRIGHT
step into current transform: (essentially) perform selected transform, and then advance the selector/menu to the first created hole. (unless last action was an undo, in which case RIGHT is a redo)LEFT
undo (back to state at last step, delimited by entering transform mode)SPACE
in current implementation the same as RIGHT, minus the redo part. eventually, it should be part of alphanumericsalphanumerics
+ (
+ )
filter menu by search buffer prefix matchBACKSPACE
erase most recent character in search bufferDELETE
erase search bufferAbstract copy/paste
NAV keybindings
TAB
capture selectionESC
clear capturesTRANSFORM keybindings
SHIFT
-LEFT
/RIGHT
un/fold transform displaySHIFT
-UP
/DOWN
extend/contract displayed menu optionsSimple settings scrubber
NAV keybindings
SPACE
switch to COMMAND modeTRANSFORM keybindings
SHIFT-SPACE
switch to COMMAND modeCOMMAND keybindings
UP/DOWN
select propertyLEFT/RIGHT
scrub propertyESC
return to NAV or TRANSFORM modeEXPERIMENTAL & FICTIONAL keybindings: lies at best, trouble at worst
NAV
F2
dump current structure to stdinCTRL
-F9
-F12
save structure to diskSHIFT
-F9
-F12
load structure from diskSHIFT
-LEFT
/RIGHT
selector to siblingDOWN
step into capturealphanumerics
(restrict selector traversal to search buffer hits aka find as you type)
TRANSFORMF2
dump current structure to stdinRCTRL
shortcut to select/insert parens