summaryrefslogtreecommitdiffstats
path: root/virtual-programs/terminal.folk
blob: a604fbd71fe1feb4c736c1a06d11439909da4fce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Terminal
#
# Spawn terminals with any command (default "bash"):
#   Wish $this is a terminal
#   Wish $this is a terminal spawning "any command"
#
# Send keyboard events to the terminal:
#   Claim $thing has keyboard input
#
# Optionally, draw the terminal on an arbitrary region:
#   Claim $thing has terminal region $region
#
#
# Example program: Tie it all together with a simple vim editor...
#
#   When $this points up at /target/ & /target/ has program /anything/ {
#     Wish $this is a terminal spawning "vim ~/folk-printed-programs/$target.folk"
#     When $this has region /r/ {
#       Claim $this has terminal region [region move $r right 350px]
#     }
#     Claim $this has keyboard input
#   }
#
#
# Note: Terminals are killed after ::termExpireMs of being unmatched.
#

source lib/terminal.tcl

set ::termExpireMs [expr {10*60*1000}] ;# 10 minutes
set ::termInstances [dict create]
set ::termTimeouts [dict create]

proc ::matchTerminal {id cmd} {
  set termKey "$id $cmd"
  if {$termKey ni $::termInstances} {
    dict set ::termInstances $termKey [Terminal::create 12 43 $cmd]
  }
  if {$termKey in $::termTimeouts} {
    after cancel [dict get $::termTimeouts $termKey]
    dict unset ::termTimeouts $termKey
  }
  dict get $::termInstances $termKey
}

proc ::unmatchTerminal {id cmd} {
  set termKey "$id $cmd"
  dict set ::termTimeouts $termKey [
    after $::termExpireMs "::destroyTerminal [list $termKey]"
  ]
}

proc ::destroyTerminal {termKey} {
  Terminal::destroy [dict get $::termInstances $termKey]
  dict unset ::termInstances $termKey
  dict unset ::termTimeouts $termKey
}

When /anyone/ wishes /thing/ is a terminal {
  Wish $thing is a terminal spawning bash
}

When /thing/ has terminal region /r/ & /r/ has keyboard input {
  Claim $thing has keyboard input
}

When /anyone/ wishes /thing/ is a terminal spawning /cmd/ {
  set term [::matchTerminal $thing $cmd]
  On unmatch { ::unmatchTerminal $thing $cmd }

  When $::thisProcess has step count /c/ {
    set body {
      Wish region $region is labelled [Terminal::read $term]
    }
    When $thing has terminal region /region/ $body
    When /nobody/ claims $thing has terminal region /x/ & $thing has region /region/ $body
  }

  When /anyone/ claims $thing has keyboard input \
    & keyboard /anyone/ claims key /key/ is /direction/ timestamp /timestamp/ {
    if {$direction != "up"} {
      Terminal::write $term $key
    }
  }
}