Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions builtin-programs/calibrate/calibrate-page.folk
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@ fn codeToPostScript
Wish the web server handles route "/calibrate" with hidden true handler {
package require base64

set defaultGeom [dict get [lindex [Query! /someone/ claims the default program geometry is /defaultGeom/] 0] defaultGeom]
fn defaultGeomGet {key} { return [string map {mm ""} [dict get $defaultGeom $key]] }

set camera $QUERY(camera)
set display $QUERY(display)

# Query the camera resolution for proper aspect ratio in preview (defaults to 1920x1080)
set cameraOpts [QueryOne! camera $camera has width /width/ height /height/]
set cameraWidth [dict get $cameraOpts width]
set cameraHeight [dict get $cameraOpts height]
Expect! camera $camera has width /cameraWidth/ height /cameraHeight/

upvar ^html ^html
html [csubst {
Expand Down Expand Up @@ -120,7 +115,7 @@ Wish the web server handles route "/calibrate" with hidden true handler {
<script>
boardPrintThroughFolk.addEventListener('click', (e) => {
folk.run(`
set maker [dict get [lindex [Query! /someone/ claims the makeCalibrationBoardPdf is /maker/] 0] maker]
Expect! the makeCalibrationBoardPdf is /maker/
set boardPdf [{*}\$maker]
set boardPdfFile [file tempfile /tmp/folk-calibration-board-XXXXXX].pdf
set fd [open \$boardPdfFile wb]; puts \$fd \$boardPdf; close \$fd
Expand Down Expand Up @@ -180,7 +175,7 @@ Wish the web server handles route "/calibrate" with hidden true handler {
document.getElementById('projected-tag-slider').addEventListener('input', (e) => {
const scale = e.target.value / 100.0;
folk.run(tcl`
set HoldDefaultModel! [dict get [lindex [Query! /someone/ claims the calibration HoldDefaultModel! is /hdm/] 0] hdm]
Expect! the calibration HoldDefaultModel! is /HoldDefaultModel!/
{*}[set HoldDefaultModel!] \${scale}
`);
});
Expand Down
4 changes: 2 additions & 2 deletions builtin-programs/calibrate/calibrate.folk
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ When camera /camera/ has width /cameraWidth/ height /cameraHeight/ &\
rmse $poseRmse \
tags [dict merge $printedTags $projectedTags]]

set seenPoses [dict get [lindex [Query! the calibration last-seen poses are /seenPoses/] 0] seenPoses]
Expect! the calibration last-seen poses are /seenPoses/
lappend seenPoses $pose
if {[llength $seenPoses] > $SEEN_POSES_MAX} {
set seenPoses [lreplace $seenPoses 0 0]
Expand Down Expand Up @@ -365,7 +365,7 @@ When camera /camera/ has width /cameraWidth/ height /cameraHeight/ &\
# If the corners have _not_ moved a lot since last _saved_
# calibration pose, this isn't different enough to be a good
# calibration pose to save.
set calibrationPoses [dict get [lindex [Query! the calibration poses from camera $camera to display $display are /calibrationPoses/] 0] calibrationPoses]
Expect! the calibration poses from camera $camera to display $display are /calibrationPoses/
if {[llength $calibrationPoses] > 0} {
set prevCalibrationPose [lindex $calibrationPoses end]
if {[$modelLib meanTagsDifference $pose(tags) $prevCalibrationPose(tags)] < 50} {
Expand Down
10 changes: 3 additions & 7 deletions builtin-programs/calibrate/calibration-board.folk
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ fn makeCalibrationBoardPs {} {
package require linalg
namespace import ::math::linearalgebra::add

set formats [dict get [QueryOne! the paper formats are /formats/] formats]
set formatName letter
set defaultFormatMatches [Query! paper format /format/ is the default paper format]
if {[llength $defaultFormatMatches] > 0} {
set candidate [dict get [lindex $defaultFormatMatches 0] format]
if {[dict exists $formats $candidate]} { set formatName $candidate }
}
Expect! the paper formats are /formats/
set formatName [QueryOne! paper format /./ is the default paper format \
-default letter]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you allow flags to be passed in after query parameters? I suppose this is more of an edge case, but -- might be needed in the future.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, I think we allow flags anywhere? + it reads better this way, I think, without the letter right up next to paper

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I like the idea of eventually supporting --

lassign [dict get $formats($formatName) pageSize] PageWidth PageHeight

set innerToOuter 0.333333
Expand Down
30 changes: 12 additions & 18 deletions builtin-programs/editor/print-editor.folk
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
fn editorToPrintOptions {editor} {
set program [dict get [QueryOne! editor $editor has selected program /program/] program]
set code [dict get [QueryOne! editor buffer for $program is /code/] code]
Expect! editor $editor has selected program /program/
Expect! editor buffer for $program is /code/

set fontOptions [dict get [QueryOne! editor $editor on program $program has font options with /...opts/] opts]
Expect! editor $editor on program $program has font options with /...fontOptions/
set textScale $fontOptions(scale)
set margin [dict get [QueryOne! editor $editor has margin /margin/] margin]
Expect! editor $editor has margin /margin/

set formats [dict get [QueryOne! the paper formats are /formats/] formats]
set formatName letter
set defaultFormatMatches [Query! paper format /format/ is the default paper format]
if {[llength $defaultFormatMatches] > 0} {
set candidate [dict get [lindex $defaultFormatMatches 0] format]
if {[dict exists $formats $candidate]} { set formatName $candidate }
}
Expect! the paper formats are /formats/
set formatName [QueryOne! paper format /./ is the default paper format \
-default letter]
set fmt $formats($formatName)
set mToPt 2834.646
return [dict merge $fmt \
Expand All @@ -35,14 +31,12 @@ When the codeToPostScript is /codeToPostScript/ &\

set preview [list $editor preview]
Wish $preview has a canvas
set formats [dict get [QueryOne! the paper formats are /formats/] formats]
set formatName letter
set defaultFormatMatches [Query! paper format /format/ is the default paper format]
if {[llength $defaultFormatMatches] > 0} {
set candidate [dict get [lindex $defaultFormatMatches 0] format]
if {[dict exists $formats $candidate]} { set formatName $candidate }
}

Expect! the paper formats are /formats/
set formatName [QueryOne! paper format /./ is the default paper format \
-default letter]
set fmt $formats($formatName)

set mToPt 2834.646
set previewGeom [list width [/ [lindex $fmt(pageSize) 0] $mToPt] \
height [/ [lindex $fmt(pageSize) 1] $mToPt]]
Expand Down
11 changes: 2 additions & 9 deletions builtin-programs/esc-pos.folk
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ When the print library is /printLib/ &\
writeFolkFile $id $code
writeMetaFile $printer $id

set matches [Query! /someone/ claims $printer is at /address/]
set matchDict [lindex $matches 0]
if {![dict exists $matchDict address]} { return }
set address [dict get $matchDict address]

Expect! $printer is at /address/
set printerSocket [socket stream ${address}:9100]

fconfigure $printerSocket -translation binary -buffering none
Expand Down Expand Up @@ -44,10 +40,7 @@ When the print library is /printLib/ &\
}

fn writeMetaFile {printer id} {
set matches [Query! /someone/ claims $printer has tag geometry /geometry/]
set matchDict [lindex $matches 0]
if {![dict exists $matchDict geometry]} { return }
set geometry [dict get $matchDict geometry]
Expect! $printer has tag geometry /geometry/
set metaFile [open "$saveDir/$id.meta.folk" w]
puts $metaFile [subst {Claim tag \$this has geometry {$geometry}}]
close $metaFile
Expand Down
5 changes: 2 additions & 3 deletions builtin-programs/keyboard.folk
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ When /keyboard/ is a keyboard device {
Claim $keyboard has keymaps [dict create]

When /page/ is a keyboard with path $keyboard locale /locale/ {
set localKeymaps [dict getdef [lindex [Query! $keyboard has keymaps /localKeymaps/] 0] localKeymaps {}]
set localKeymaps [QueryOne! $keyboard has keymaps /./ -default {}]
if {[dict exists $localKeymaps $locale]} {
return
}
Expand Down Expand Up @@ -126,8 +126,7 @@ When /keyboard/ is a keyboard device {
tvSec tvUsec type code value

if {$type == 0x01} { ;# EV_KEY
set localKeymaps [dict getdef [lindex [Query! /someone/ claims $keyboard has keymaps /localKeymaps/] \
0] localKeymaps {}]
set localKeymaps [QueryOne! $keyboard has keymaps /./ -default {}]

lassign [dict values $localKeymaps] activeKeymap
if {$activeKeymap eq ""} {
Expand Down
26 changes: 11 additions & 15 deletions builtin-programs/print/print.folk
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,9 @@ When $::thisNode claims printer /name/ is a cups printer with /...options/ {
}

Subscribe: print code /code/ {
set formats [dict get [QueryOne! the paper formats are /formats/] formats]
set formatName letter
set defaultFormatMatches [Query! paper format /format/ is the default paper format]
if {[llength $defaultFormatMatches] > 0} {
set candidate [dict get [lindex $defaultFormatMatches 0] format]
if {[dict exists $formats $candidate]} { set formatName $candidate }
}
Expect! the paper formats are /formats/
set formatName [QueryOne! paper format /./ is the default paper format \
-default letter]
set fmt $formats($formatName)

set mToPt 2834.646
Expand Down Expand Up @@ -345,20 +341,20 @@ Subscribe: print pdf /pdfPath/ with /...options/ {
set args [list]

if {![dict exists $options printer]} {
set defaultPrinterMatches [Query! printer /printer/ is the default printer]
if {[llength $defaultPrinterMatches] > 0} {
dict set options printer [dict get [lindex $defaultPrinterMatches 0] printer]
}
try {
dict set options printer \
[QueryOne! printer /./ is the default printer]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you want a flag like -takefirst instead of try/on here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I suppose this is just in case nothing is returned, never mind.

} on error e {}
}
if {[dict exists $options printer]} {
lappend args -P $options(printer)
}

if {![dict exists $options format]} {
set defaultFormatMatches [Query! paper format /format/ is the default paper format]
if {[llength $defaultFormatMatches] > 0} {
dict set options format [dict get [lindex $defaultFormatMatches 0] format]
}
try {
dict set options format \
[QueryOne! paper format /./ is the default paper format]
} on error e {}
}
if {[dict exists $options format]} {
lappend args -o media=$options(format)
Expand Down
2 changes: 1 addition & 1 deletion builtin-programs/web/index.folk
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Wish the web server handles route "/" with handler {
</script>
</head>
<body>
[dict get [QueryOne! the web navigation HTML is /nav/] nav]
[QueryOne! the web navigation HTML is /./]
[HtmlWhen the collected results for [list /programName/ has program code /programCode/] are /programs/ {
emitHtmlForPrograms $programs

Expand Down
9 changes: 3 additions & 6 deletions builtin-programs/web/new.folk
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,8 @@ Wish the web server handles route "/new" with nav "<button>New program</button>"
namespace import ::math::linearalgebra::matmul
namespace import ::math::linearalgebra::scale

set quadLib [dict get [lindex [Query! the quad library is /quadLib/] 0] quadLib]

set dims [lindex [Query! display /disp/ has width /displayWidth/ height /displayHeight/] 0]
set disp [dict get $dims disp]
set displayWidth [dict get $dims displayWidth]; set displayHeight [dict get $dims displayHeight]
Expect! the quad library is /quadLib/
Expect! display /disp/ has width /displayWidth/ height /displayHeight/

set x [expr {int(double(${(left + (left/window.innerWidth) * w)}) * (double($displayWidth) / ${window.innerWidth}))}]
set y [expr {int(double(${(top + (top/window.innerHeight) * h)}) * (double($displayHeight) / ${window.innerHeight}))}]
Expand All @@ -183,7 +180,7 @@ Wish the web server handles route "/new" with nav "<button>New program</button>"
# Create 3D vertices in meters that will project to the desired pixel coordinates
# Using a depth of 1.5 meters from the projector center
set depth 1.5
set displayIntrinsics [dict get [lindex [Query! display $disp has intrinsics /displayIntrinsics/] 0] displayIntrinsics]
Expect! display $disp has intrinsics /displayIntrinsics/

# Convert pixel coordinates to 3D coordinates in projector space
set fx [dict get $displayIntrinsics fx]
Expand Down
2 changes: 1 addition & 1 deletion builtin-programs/web/page.folk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Wish the web server handles route {/page/(.*)$} with handler {
set programDir [dict get [QueryOne! the program save directory is /saveDir/] saveDir]
Expect! the program save directory is /programDir/
set program_id $1
set filenames [list \
"$programDir/$program_id.folk" \
Expand Down
2 changes: 1 addition & 1 deletion builtin-programs/web/printed-programs.folk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Wish the web server handles route {/printed-programs/([^/]+)\.folk$} with handler {
set programDir [dict get [QueryOne! the program save directory is /programDir/] programDir]
Expect! the program save directory is /programDir/
set filename "$programDir/$1.folk"
set fp [open $filename r]
set data [read $fp]
Expand Down
2 changes: 1 addition & 1 deletion builtin-programs/web/program.folk
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Wish the web server handles route {/program/(.*)$} with handler {
set programName $1
set match [QueryOne! $programName has program code /programCode/]
Expect! $programName has program code /programCode/]
if {$match eq ""} {
html "<html><body>Program not found: [htmlEscape $programName]</body></html>"
return
Expand Down
6 changes: 3 additions & 3 deletions lib/folk.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ ${message} with environment [list [list this $chan __ctx $ctx __seq ${seqNumber}
console.log('watchCollected', statement);

const retractKey = await this.send(tcl`Say when the collected results for ${statement} are /result/ {
if {![info exists ::wsLib]} { set ::wsLib [dict get [lindex [Query! /someone/ claims the websocket library is /wsLib/] 0] wsLib] }
if {![info exists ::wsLib]} { set ::wsLib [QueryOne! the websocket library is /./] }
$::wsLib wsEmitMsg $__ctx [list ${channel.prefix} $result]
} with environment [list [list this $this __ctx $__ctx]]`);
channel.retractKey = retractKey;
Expand All @@ -352,7 +352,7 @@ ${message} with environment [list [list this $chan __ctx $ctx __seq ${seqNumber}
});

const retractKey = await this.send(tcl`
if {![info exists ::wsLib]} { set ::wsLib [dict get [lindex [Query! /someone/ claims the websocket library is /wsLib/] 0] wsLib] }
if {![info exists ::wsLib]} { set ::wsLib [QueryOne! the websocket library is /./] }
set statement ${statement}

# enumerate variable names this statement uses
Expand Down Expand Up @@ -393,7 +393,7 @@ ${message} with environment [list [list this $chan __ctx $ctx __seq ${seqNumber}
});

const retractKey = await this.send(tcl`
if {![info exists ::wsLib]} { set ::wsLib [dict get [lindex [Query! /someone/ claims the websocket library is /wsLib/] 0] wsLib] }
if {![info exists ::wsLib]} { set ::wsLib [QueryOne! the websocket library is /./] }
set pattern ${statement}

set body {
Expand Down
45 changes: 44 additions & 1 deletion prelude.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ proc On {event args} {
}
}

# Synchronous, sampling query of the db. Returns a list of dicts where
# each dict is a statement matching the pattern.
#
# Query! is like QuerySimple! but with added support for & joins, and
# it'll automatically also query the claimized pattern (the pattern
# with `/someone/ claims` prepended).
Expand Down Expand Up @@ -700,15 +703,55 @@ proc Query! {args} {
}
return $results
}

# Synchronous, sampling query of the db. Throws unless there is
# exactly 1 statement result. Returns a dict whose keys are bound keys
# from the pattern and whose values are corresponding terms from the
# statement.
#
# Use like this:
#
# Claim the dog is cool
# sleep 0.5
# puts [dict get [QueryOne! the dog is /val/] val] ;# -> cool
#
proc QueryOne! {args} {
set results [Query! {*}$args]
set pattern [list]
for {set i 0} {$i < [llength $args]} {incr i} {
set arg [lindex $args $i]
if {$arg eq "-default"} {
incr i
set default [lindex $args $i]
} else {
lappend pattern $arg
}
}

set results [Query! {*}$args]
if {[llength $results] == 0 && [info exists default]} {
return $default
}
if {[llength $results] != 1} {
error "QueryOne! of ($args) had [llength $results] results. Should be one result!"
}

if {{/./} in $args} {
return [dict get [lindex $results 0] .]
}
return [lindex $results 0]
}

# Like QueryOne!, but introduces the bindings directly into caller
# scope.
#
# Expect! the dog is /val/
# puts $val ;# -> cool
#
proc Expect! {args} {
dict for {k v} [QueryOne! {*}$args] {
uplevel [list set $k $v]
}
}
proc ForEach! {args} {
set body [lindex $args end]
set pattern [lreplace $args end end]
Expand Down