Compare commits
17 Commits
6efbc34576
...
da06309e75
Author | SHA1 | Date | |
---|---|---|---|
da06309e75 | |||
daa244c0b3 | |||
69d8aa4131 | |||
cc2caae372 | |||
b8d86c65cb | |||
e4ed51e137 | |||
36edd12c6e | |||
fb834f496c | |||
28080a1387 | |||
0ea9ba1b92 | |||
6454620307 | |||
454f9ae094 | |||
5069e6aff1 | |||
dea9d925a5 | |||
dd139c9796 | |||
a5612fce2a | |||
bbd67b3a16 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
doc/index.html
|
1
.overmind.env
Normal file
1
.overmind.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
OVERMIND_AUTO_RESTART=test
|
2
Makefile
2
Makefile
@ -2,4 +2,4 @@ doc/index.html: doc/index.md
|
|||||||
pandoc -t html -f gfm < $< > $@
|
pandoc -t html -f gfm < $< > $@
|
||||||
|
|
||||||
watch:
|
watch:
|
||||||
while true ; do ( find . -type f | entr -d sh test/run.sh ) ;done
|
find . -type f | entr -c -d sh test/run.sh
|
||||||
|
10
buffer.fnl
10
buffer.fnl
@ -33,6 +33,14 @@
|
|||||||
(let [b (new-buffer name)]
|
(let [b (new-buffer name)]
|
||||||
(tset buffers name b)
|
(tset buffers name b)
|
||||||
b))
|
b))
|
||||||
:current (fn [] (let [k (next buffers)] (. buffers k)))
|
|
||||||
:find (fn [term] (. buffers term))
|
:find (fn [term] (. buffers term))
|
||||||
|
;; will rename this to "find" once we've got rid of the
|
||||||
|
;; only remaining call to the existing Buffer.find
|
||||||
|
:match (fn [s] (collect [name buffer (pairs buffers)]
|
||||||
|
(if (string.find name s)
|
||||||
|
(values name buffer))))
|
||||||
|
:next (fn [buffer]
|
||||||
|
(let [n (or (next buffers buffer.name) (next buffers))]
|
||||||
|
(. buffers n)))
|
||||||
|
|
||||||
})
|
})
|
||||||
|
179
command.fnl
179
command.fnl
@ -1,23 +1,16 @@
|
|||||||
(local { : Gtk } (require :lgi))
|
(local { : Gtk } (require :lgi))
|
||||||
(local { : view } (require :fennel))
|
(local { : view } (require :fennel))
|
||||||
|
(local lume (require :lume))
|
||||||
|
|
||||||
(local commands {})
|
(local commands {})
|
||||||
|
|
||||||
(local Buffer (require :buffer))
|
(local Buffer (require :buffer))
|
||||||
|
|
||||||
(fn by-pairs [a]
|
(fn define-command [name ordered-params function]
|
||||||
(let [iter (fn [_ a]
|
|
||||||
(match a
|
|
||||||
[k v & rest] (values rest k v)
|
|
||||||
_ nil))]
|
|
||||||
(values iter a a)))
|
|
||||||
|
|
||||||
(fn define-command [name function ordered-params]
|
|
||||||
;; required parameter names and default arguments
|
;; required parameter names and default arguments
|
||||||
(let [param-names (icollect [_ name val (by-pairs ordered-params)]
|
(let [param-names (icollect [_ [name] (pairs ordered-params)] name)
|
||||||
name)
|
params (collect [_ [name completer default] (pairs ordered-params)]
|
||||||
params (collect [_ name val (by-pairs ordered-params)]
|
(values name {: completer : default}))
|
||||||
(values name val))
|
|
||||||
v {: name
|
v {: name
|
||||||
: function
|
: function
|
||||||
: param-names
|
: param-names
|
||||||
@ -26,15 +19,27 @@
|
|||||||
|
|
||||||
(define-command
|
(define-command
|
||||||
"quit-browser"
|
"quit-browser"
|
||||||
#(Gtk.main_quit) [])
|
[]
|
||||||
|
#(Gtk.main_quit))
|
||||||
|
|
||||||
|
(define-command
|
||||||
|
"switch-to-buffer"
|
||||||
|
[[:buffer
|
||||||
|
Buffer.match
|
||||||
|
#(. (Buffer.next $1.buffer) :name)]
|
||||||
|
]
|
||||||
|
(fn [{:frame frame :buffer buffer}]
|
||||||
|
(frame:show-buffer buffer)))
|
||||||
|
|
||||||
(define-command
|
(define-command
|
||||||
"visit-location"
|
"visit-location"
|
||||||
|
[[:buffer
|
||||||
|
Buffer.match
|
||||||
|
#($1.buffer.name)]
|
||||||
|
[:url #(doto {} (tset $1 $1)) #(do "http://www.example.com")]
|
||||||
|
]
|
||||||
(fn [{:url url :buffer buffer}]
|
(fn [{:url url :buffer buffer}]
|
||||||
(let [b (Buffer.find buffer)] (: b :visit url)))
|
(buffer:visit url)))
|
||||||
[:buffer (fn [] (. (Buffer.current) :name))
|
|
||||||
:url #(do "http://www.example.com")
|
|
||||||
])
|
|
||||||
|
|
||||||
(fn find-command [name]
|
(fn find-command [name]
|
||||||
(. commands name))
|
(. commands name))
|
||||||
@ -46,10 +51,6 @@
|
|||||||
:this-param nil
|
:this-param nil
|
||||||
})
|
})
|
||||||
|
|
||||||
(var state default-state)
|
|
||||||
(fn reset-state []
|
|
||||||
(set state default-state))
|
|
||||||
|
|
||||||
(fn next-param [command params]
|
(fn next-param [command params]
|
||||||
(accumulate [v nil
|
(accumulate [v nil
|
||||||
_ k (ipairs command.param-names)
|
_ k (ipairs command.param-names)
|
||||||
@ -59,8 +60,9 @@
|
|||||||
(fn invoke-command [command params]
|
(fn invoke-command [command params]
|
||||||
(command.function params))
|
(command.function params))
|
||||||
|
|
||||||
(fn next-action [state input-string]
|
(fn next-action [self input-string]
|
||||||
(let [state-for-next-param
|
(let [state self.state
|
||||||
|
state-for-next-param
|
||||||
(fn [c params]
|
(fn [c params]
|
||||||
(match (next-param c params)
|
(match (next-param c params)
|
||||||
k1 {
|
k1 {
|
||||||
@ -69,7 +71,9 @@
|
|||||||
:collected-params params
|
:collected-params params
|
||||||
:active true
|
:active true
|
||||||
}
|
}
|
||||||
_ (do (invoke-command c params) {:active false})))]
|
_ (let [params (lume.extend {} {:frame self.frame} params)]
|
||||||
|
(invoke-command c params)
|
||||||
|
{:active false})))]
|
||||||
|
|
||||||
(match state
|
(match state
|
||||||
{:active false} state
|
{:active false} state
|
||||||
@ -86,8 +90,10 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
{:command c :this-param k :collected-params p}
|
{:command c :this-param k :collected-params p}
|
||||||
(do
|
(let [{ : completer} (. c.params k)
|
||||||
(tset p k input-string)
|
vals (completer input-string)
|
||||||
|
value (. vals input-string)]
|
||||||
|
(tset p k value)
|
||||||
(state-for-next-param c p))
|
(state-for-next-param c p))
|
||||||
|
|
||||||
{:command c :this-param nil :collected-params p}
|
{:command c :this-param nil :collected-params p}
|
||||||
@ -98,75 +104,102 @@
|
|||||||
state)
|
state)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(fn on-input [str]
|
(fn on-activate [self str]
|
||||||
(let [s (next-action state str)
|
(let [s (next-action self str)
|
||||||
param (if s.active (. (. s.command :params) s.this-param))]
|
param (if s.active (. (. s.command :params) s.this-param))]
|
||||||
(set state s)
|
(set self.state s)
|
||||||
{
|
{
|
||||||
:active s.active
|
:active s.active
|
||||||
:error s.error
|
:error s.error
|
||||||
:prompt (if s.active (or s.this-param "Command?" "") "")
|
:prompt (if s.active (or s.this-param "Command?" "") "")
|
||||||
:default (and param (param))
|
:default (and param (param.default self.frame))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
(local prompt (Gtk.Label { :label ""}))
|
(fn update-widget-state [{ : entry : completions-widget : prompt} result]
|
||||||
|
(set prompt.label (or result.prompt ""))
|
||||||
|
(set entry.sensitive result.active)
|
||||||
|
(if (not result.active)
|
||||||
|
(completions-widget:hide))
|
||||||
|
(set entry.text (or result.default result.error "")))
|
||||||
|
|
||||||
(fn update-widget-state [w result]
|
(fn on-input [self str]
|
||||||
(set prompt.label (or result.prompt ""))
|
(match self.state
|
||||||
(set w.sensitive result.active)
|
{:command c :this-param param-name}
|
||||||
(set w.text
|
(let [parent self.completions-widget
|
||||||
(or result.default result.error "")))
|
{ : completer} (. c.params param-name)
|
||||||
|
completions (completer str)]
|
||||||
|
(parent:foreach #(parent:remove $1))
|
||||||
|
(each [text _w (pairs completions)]
|
||||||
|
(parent:add (Gtk.Button {
|
||||||
|
:label text
|
||||||
|
:on_clicked
|
||||||
|
#(update-widget-state self (self:on-activate text))
|
||||||
|
})))
|
||||||
|
(parent:show_all)
|
||||||
|
)))
|
||||||
|
|
||||||
(local widget
|
|
||||||
(let [w (Gtk.Entry {
|
|
||||||
:sensitive false
|
|
||||||
})]
|
|
||||||
(tset w :on_activate
|
|
||||||
(fn [event]
|
|
||||||
(update-widget-state w (on-input event.text))))
|
|
||||||
w))
|
|
||||||
|
|
||||||
(local box
|
(fn activate [{: state : entry : prompt}]
|
||||||
(let [box
|
|
||||||
(Gtk.Box {
|
|
||||||
:orientation Gtk.Orientation.HORIZONTAL
|
|
||||||
})]
|
|
||||||
|
|
||||||
(box:pack_start prompt false false 15)
|
|
||||||
(box:pack_start widget true true 5)
|
|
||||||
box))
|
|
||||||
|
|
||||||
(fn activate []
|
|
||||||
(tset state :active true)
|
(tset state :active true)
|
||||||
(set widget.sensitive true)
|
(set entry.sensitive true)
|
||||||
(set widget.text "")
|
(set entry.text "")
|
||||||
(set prompt.label (or state.this-param "Command" ""))
|
(set prompt.label (or state.this-param "Command" ""))
|
||||||
(widget:grab_focus)
|
(entry:grab_focus)
|
||||||
state)
|
state)
|
||||||
|
|
||||||
(fn invoke-interactively [name params]
|
(fn invoke-interactively [self name params]
|
||||||
(let [c (find-command name)
|
(let [c (find-command name)
|
||||||
|
supplied-params (collect [k v (pairs params)]
|
||||||
|
(values k (v self.frame)))
|
||||||
s {
|
s {
|
||||||
:active true
|
:active true
|
||||||
:command c
|
:command c
|
||||||
:collected-params params
|
:collected-params supplied-params
|
||||||
}]
|
}]
|
||||||
(set state s)
|
(set self.state s)
|
||||||
(let [r (on-input nil)]
|
(let [r (self:on-activate nil)]
|
||||||
(update-widget-state widget r)
|
(update-widget-state self r)
|
||||||
(widget:grab_focus)
|
(self.entry:grab_focus)
|
||||||
r)))
|
r)))
|
||||||
|
|
||||||
(fn active? [] state.active)
|
(fn new-commander [frame]
|
||||||
|
(let [entry (Gtk.Entry {:sensitive false })
|
||||||
|
prompt (Gtk.Label { :label ""})
|
||||||
|
box (Gtk.Box {
|
||||||
|
:orientation Gtk.Orientation.VERTICAL
|
||||||
|
})
|
||||||
|
hbox (Gtk.Box {
|
||||||
|
:orientation Gtk.Orientation.HORIZONTAL
|
||||||
|
})
|
||||||
|
completions (Gtk.FlowBox)
|
||||||
|
self {
|
||||||
|
:state default-state
|
||||||
|
: activate
|
||||||
|
:active? (fn [self] self.state.active)
|
||||||
|
: on-input
|
||||||
|
: on-activate
|
||||||
|
: invoke-interactively
|
||||||
|
: entry
|
||||||
|
:widget box
|
||||||
|
: prompt
|
||||||
|
: frame
|
||||||
|
:completions-widget completions
|
||||||
|
}]
|
||||||
|
(hbox:pack_start prompt false false 15)
|
||||||
|
(hbox:pack_start entry true true 5)
|
||||||
|
(box:pack_start hbox true false 0)
|
||||||
|
(box:pack_start completions true true 0)
|
||||||
|
(tset entry :on_changed
|
||||||
|
(fn [event]
|
||||||
|
(self:on-input event.text)))
|
||||||
|
(tset entry :on_activate
|
||||||
|
(fn [event]
|
||||||
|
(let [result (self:on-activate event.text)]
|
||||||
|
(update-widget-state self result))))
|
||||||
|
self))
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
: activate
|
:commander new-commander
|
||||||
: active?
|
|
||||||
: define-command
|
: define-command
|
||||||
: on-input
|
|
||||||
: invoke-interactively
|
|
||||||
:widget box
|
|
||||||
:_ {
|
|
||||||
: reset-state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
15
default.nix
15
default.nix
@ -19,11 +19,26 @@
|
|||||||
, writeText
|
, writeText
|
||||||
}:
|
}:
|
||||||
let pname = "dunlin";
|
let pname = "dunlin";
|
||||||
|
lume = let lua = lua5_3; in lua53Packages.buildLuaPackage rec {
|
||||||
|
pname = "lume";
|
||||||
|
version = "1";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
repo = "lume"; owner = "rxi";
|
||||||
|
rev = "98847e7812cf28d3d64b289b03fad71dc704547d";
|
||||||
|
hash = "sha256-/u23EqgjjkU8FV9oXvMNXBkY8JAOJUhJAzXTSibJthU=";
|
||||||
|
};
|
||||||
|
buildPhase = ":";
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p "$out/share/lua/${lua.luaversion}"
|
||||||
|
cp lume.lua "$out/share/lua/${lua.luaversion}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
lua = lua5_3.withPackages (ps: with ps; [
|
lua = lua5_3.withPackages (ps: with ps; [
|
||||||
lgi
|
lgi
|
||||||
luafilesystem
|
luafilesystem
|
||||||
luaposix
|
luaposix
|
||||||
readline
|
readline
|
||||||
|
lume
|
||||||
]);
|
]);
|
||||||
fennel_ = lua.pkgs.fennel;
|
fennel_ = lua.pkgs.fennel;
|
||||||
glib_networking_gio = "${glib-networking}/lib/gio/modules";
|
glib_networking_gio = "${glib-networking}/lib/gio/modules";
|
||||||
|
16
dunlin.fnl
16
dunlin.fnl
@ -9,18 +9,12 @@
|
|||||||
;;; when we decide how to do an init file/rc file, this will go in it
|
;;; when we decide how to do an init file/rc file, this will go in it
|
||||||
|
|
||||||
(local my-keymap {
|
(local my-keymap {
|
||||||
"g" #(Command.invoke-interactively
|
"g" ["visit-location" {:buffer #$1.buffer }]
|
||||||
"visit-location"
|
"M-q" ["quit-browser" {}]
|
||||||
{:buffer "main"})
|
|
||||||
"M-q" #(Command.invoke-interactively
|
|
||||||
"quit-browser"
|
|
||||||
{})
|
|
||||||
"C-x" {
|
"C-x" {
|
||||||
"C-c"
|
"C-c" ["quit-browser" {}]
|
||||||
#(Command.invoke-interactively
|
"b" ["switch-to-buffer" {}]
|
||||||
"quit-browser"
|
}
|
||||||
{})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
(let [f (Frame.new my-keymap)
|
(let [f (Frame.new my-keymap)
|
||||||
|
18
frame.fnl
18
frame.fnl
@ -1,5 +1,7 @@
|
|||||||
(local { : Gtk : Gdk : WebKit2 : cairo } (require :lgi))
|
(local { : Gtk : Gdk : WebKit2 : cairo } (require :lgi))
|
||||||
(local { : view } (require :fennel))
|
(local { : view } (require :fennel))
|
||||||
|
(local lume (require :lume))
|
||||||
|
|
||||||
(local Command (require :command))
|
(local Command (require :command))
|
||||||
(local keymap (require :keymap))
|
(local keymap (require :keymap))
|
||||||
|
|
||||||
@ -8,7 +10,9 @@
|
|||||||
(fn new-frame [global-keymap]
|
(fn new-frame [global-keymap]
|
||||||
(let [hpad 2
|
(let [hpad 2
|
||||||
vpad 2
|
vpad 2
|
||||||
|
self {}
|
||||||
recogniser (keymap.recogniser global-keymap)
|
recogniser (keymap.recogniser global-keymap)
|
||||||
|
commander (Command.commander self)
|
||||||
window (Gtk.Window {
|
window (Gtk.Window {
|
||||||
:title "Dunlin"
|
:title "Dunlin"
|
||||||
:default_width 800
|
:default_width 800
|
||||||
@ -30,16 +34,16 @@
|
|||||||
|
|
||||||
(tset window :on_key_release_event
|
(tset window :on_key_release_event
|
||||||
(fn [window event]
|
(fn [window event]
|
||||||
(when (not (Command.active?))
|
(when (not (commander:active?))
|
||||||
(match (recogniser:accept-event event)
|
(match (recogniser:accept-event event)
|
||||||
c (c)
|
[name params] (commander:invoke-interactively name params)
|
||||||
(nil prompt) (print "prompted" prompt)))
|
(nil prompt) (print "prompted" prompt)))
|
||||||
(when (and event.state.MOD1_MASK
|
(when (and event.state.MOD1_MASK
|
||||||
(= event.keyval (string.byte "x")))
|
(= event.keyval (string.byte "x")))
|
||||||
(Command.activate))))
|
(commander:activate))))
|
||||||
|
|
||||||
(doto container
|
(doto container
|
||||||
(: :pack_start Command.widget false false vpad)
|
(: :pack_start commander.widget false false vpad)
|
||||||
(: :pack_start progress-bar false false vpad)
|
(: :pack_start progress-bar false false vpad)
|
||||||
(: :pack_start contentwidget true true vpad))
|
(: :pack_start contentwidget true true vpad))
|
||||||
(window:add container)
|
(window:add container)
|
||||||
@ -52,11 +56,13 @@
|
|||||||
:show-buffer (fn [self b]
|
:show-buffer (fn [self b]
|
||||||
(each [_ w (pairs (contentwidget:get_children))]
|
(each [_ w (pairs (contentwidget:get_children))]
|
||||||
(w:hide))
|
(w:hide))
|
||||||
|
(tset self :buffer b)
|
||||||
(contentwidget:pack_start b.webview true true 0)
|
(contentwidget:pack_start b.webview true true 0)
|
||||||
(b.webview:show))
|
(b.webview:show))
|
||||||
}]
|
}]
|
||||||
(table.insert frames f)
|
(lume.extend self f)
|
||||||
f)))
|
(table.insert frames self)
|
||||||
|
self)))
|
||||||
|
|
||||||
|
|
||||||
{ :new new-frame :frames frames }
|
{ :new new-frame :frames frames }
|
||||||
|
54
keymap.fnl
54
keymap.fnl
@ -1,6 +1,24 @@
|
|||||||
(local { : Gdk } (require :lgi))
|
(local { : Gdk } (require :lgi))
|
||||||
(local { : view } (require :fennel))
|
(local { : view } (require :fennel))
|
||||||
|
|
||||||
|
(local modifier-keyvals
|
||||||
|
{
|
||||||
|
;; These aren't canonical or official, this is just the
|
||||||
|
;; result of pressing keys on my keyboard. If Gtk/Gdk/GI
|
||||||
|
;; implemented KeyEvent.is_modifier we wouldn't have to
|
||||||
|
;; do this
|
||||||
|
65507 :control_l
|
||||||
|
65505 :shift_l
|
||||||
|
269025067 :fn
|
||||||
|
65515 :windows
|
||||||
|
65513 :alt_l
|
||||||
|
65027 :alt_gr
|
||||||
|
65508 :control_r
|
||||||
|
})
|
||||||
|
|
||||||
|
(fn modifier? [keyval]
|
||||||
|
(. modifier-keyvals keyval))
|
||||||
|
|
||||||
(fn keychord->spec [keychord]
|
(fn keychord->spec [keychord]
|
||||||
(let [Mod Gdk.ModifierType
|
(let [Mod Gdk.ModifierType
|
||||||
symbol (keychord:match "(%w+)$")
|
symbol (keychord:match "(%w+)$")
|
||||||
@ -26,13 +44,17 @@
|
|||||||
(bor m (. Gdk.ModifierType k)))]
|
(bor m (. Gdk.ModifierType k)))]
|
||||||
(spec->index {:keyval event.keyval : modmask})))
|
(spec->index {:keyval event.keyval : modmask})))
|
||||||
|
|
||||||
|
(fn designates-command? [tbl]
|
||||||
|
;; a keymap entry has a string as key, a command
|
||||||
|
;; definition is a numerically-indexed array
|
||||||
|
(if (. tbl 1) true))
|
||||||
|
|
||||||
(fn compile-keymap [input]
|
(fn compile-keymap [input]
|
||||||
(collect [k v (pairs input)]
|
(collect [k v (pairs input)]
|
||||||
(let [f (-> k keychord->spec spec->index)]
|
(let [f (-> k keychord->spec spec->index)]
|
||||||
(match (type v)
|
(if (designates-command? v)
|
||||||
"function" (values f v)
|
(values f v)
|
||||||
"table" (values f (compile-keymap v))))))
|
(values f (compile-keymap v))))))
|
||||||
|
|
||||||
(fn recogniser [source-keymap]
|
(fn recogniser [source-keymap]
|
||||||
(let [keymap (compile-keymap source-keymap)]
|
(let [keymap (compile-keymap source-keymap)]
|
||||||
@ -40,20 +62,20 @@
|
|||||||
{
|
{
|
||||||
:accept-event
|
:accept-event
|
||||||
(fn [_ e]
|
(fn [_ e]
|
||||||
(let [c (event->index e)
|
(when (not (modifier? e.keyval))
|
||||||
v (. m c)]
|
(let [c (event->index e)
|
||||||
(match (type v)
|
v (. m c)]
|
||||||
"table" (do
|
(if v
|
||||||
|
(if (designates-command? v)
|
||||||
|
(do
|
||||||
|
(set m keymap)
|
||||||
|
v)
|
||||||
|
(do
|
||||||
(set m v)
|
(set m v)
|
||||||
(values nil (.. c " ")))
|
(values nil (.. c " "))))
|
||||||
"function" (do
|
(do
|
||||||
(set m keymap)
|
(set m keymap)
|
||||||
v)
|
(values nil (.. "No binding for " (view e) " ")))))))
|
||||||
"nil" (do
|
|
||||||
(set m keymap)
|
|
||||||
(values nil (.. "No binding for " (view e) " ")))
|
|
||||||
|
|
||||||
)))
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
42
musing.md
42
musing.md
@ -36,14 +36,52 @@ lua's standard types
|
|||||||
|
|
||||||
## next steps
|
## next steps
|
||||||
|
|
||||||
* change define-command so that the parameters are ordered
|
* [done] change define-command so that the parameters are ordered
|
||||||
* display unbound key error
|
* display unbound key error
|
||||||
* ESC to cancel interactive command
|
* ESC to cancel interactive command
|
||||||
* autocomplete command name
|
* autocomplete command name
|
||||||
* parameters with non-string values (e.g. buffer)
|
* parameters with non-string values (e.g. buffer)
|
||||||
* show current url when command inactive
|
* show current url when command inactive
|
||||||
* show prompts for parameter
|
* [done] show prompts for parameter
|
||||||
* multiple buffers
|
* multiple buffers
|
||||||
- create buffer
|
- create buffer
|
||||||
- list buffers (where does the output go?)
|
- list buffers (where does the output go?)
|
||||||
- find and switch to buffer
|
- find and switch to buffer
|
||||||
|
|
||||||
|
|
||||||
|
how do we do the buffer list thing?
|
||||||
|
- generate html, or
|
||||||
|
- use native widgets
|
||||||
|
|
||||||
|
native widgets seems neater
|
||||||
|
- how do we permit commands to insert widgets into the frame?
|
||||||
|
- how do we get rid of them?
|
||||||
|
|
||||||
|
we could have an "output overlay" inserted underneath the commander.
|
||||||
|
could we use the same thing for completions? we haven't addressed
|
||||||
|
non-string parameters yet, really
|
||||||
|
|
||||||
|
M-x switch-to-buffer
|
||||||
|
Buffer mai_
|
||||||
|
|
||||||
|
+------+ +---------+
|
||||||
|
| main | | mailing |
|
||||||
|
+------+ +---------+
|
||||||
|
|
||||||
|
|
||||||
|
-----
|
||||||
|
|
||||||
|
so there are two things going on here
|
||||||
|
|
||||||
|
1) how to implement switch-to-buffer with appropriate autocomplete
|
||||||
|
on the buffer name - perhaps involving showing buffer thumbnails etc
|
||||||
|
|
||||||
|
2) in emacs, not all buffers are files - e.g. the buffer list, or the
|
||||||
|
process list, or the magit status buffer - there is a well-used
|
||||||
|
affordance for elisp to put semi-persistent interactable content
|
||||||
|
onscreen - do we need such a thing here or is it ok to say "just call
|
||||||
|
gtk" to command authors
|
||||||
|
|
||||||
|
are these the same problem or are they separate problems? do we have
|
||||||
|
the second problem? What I will do is address the first one and
|
||||||
|
see if it's generalisable once I've done it.
|
||||||
|
@ -3,41 +3,48 @@
|
|||||||
(local Command (require :command))
|
(local Command (require :command))
|
||||||
|
|
||||||
(var happened false)
|
(var happened false)
|
||||||
(fn before [] (set happened false) (Command._.reset-state))
|
(fn before [] (set happened false))
|
||||||
|
|
||||||
(Command.define-command "no-args-command" #(set happened true) [])
|
(Command.define-command
|
||||||
|
"no-args-command"
|
||||||
|
[]
|
||||||
|
#(set happened true))
|
||||||
|
|
||||||
(Command.define-command
|
(Command.define-command
|
||||||
"multiply"
|
"multiply"
|
||||||
(fn [{: a : b }] (set happened (* (tonumber a) (tonumber b))))
|
[[:a #{$1 $1} #"3"]
|
||||||
[:a #(do "3") :b #(do "2")])
|
[:b #{$1 $1} #"2"]]
|
||||||
|
(fn [{: a : b }] (set happened (* (tonumber a) (tonumber b)))))
|
||||||
|
|
||||||
(before)
|
(before)
|
||||||
(let [(ok err)
|
(let [commander (Command.commander)
|
||||||
(match-try (Command.activate)
|
(ok err)
|
||||||
{:active true} (Command.on-input "not-a-command")
|
(match-try (commander:activate)
|
||||||
|
{:active true} (commander:on-activate "not-a-command")
|
||||||
(where {:error e :active false} (e:match "can't find command")) true
|
(where {:error e :active false} (e:match "can't find command")) true
|
||||||
(catch
|
(catch
|
||||||
x (values nil (view x))))]
|
x (values nil (view x))))]
|
||||||
(assert ok err))
|
(assert ok err))
|
||||||
|
|
||||||
(before)
|
(before)
|
||||||
(let [(ok err)
|
(let [commander (Command.commander)
|
||||||
(match-try (Command.activate)
|
(ok err)
|
||||||
{:active true} (Command.on-input "multiply")
|
(match-try (commander:activate)
|
||||||
{:active true :prompt p1} (Command.on-input "2")
|
{:active true} (commander:on-activate "multiply")
|
||||||
{:active true :prompt p2} (Command.on-input "3")
|
{:active true :prompt p1} (commander:on-activate "2")
|
||||||
|
{:active true :prompt p2} (commander:on-activate "3")
|
||||||
(where {:active false} (= happened 6)) true
|
(where {:active false} (= happened 6)) true
|
||||||
(catch
|
(catch
|
||||||
x (values nil (view x))))]
|
x (values nil (view x))))]
|
||||||
(assert ok err))
|
(assert ok err))
|
||||||
|
|
||||||
(before)
|
(before)
|
||||||
(let [(ok err)
|
(let [commander (Command.commander)
|
||||||
|
(ok err)
|
||||||
(match
|
(match
|
||||||
(Command.invoke-interactively
|
(commander:invoke-interactively
|
||||||
"multiply"
|
"multiply"
|
||||||
{:a "7" :b "9"})
|
{:a #"7" :b #"9"})
|
||||||
(where {:active false} (= happened 63)) true
|
(where {:active false} (= happened 63)) true
|
||||||
x (values nil (.. "wrong answer " (view x) " " (view happened)))
|
x (values nil (.. "wrong answer " (view x) " " (view happened)))
|
||||||
nil (values nil "???"))]
|
nil (values nil "???"))]
|
||||||
|
@ -6,13 +6,15 @@
|
|||||||
|
|
||||||
(local Mod Gdk.ModifierType)
|
(local Mod Gdk.ModifierType)
|
||||||
|
|
||||||
(local km
|
(local km {
|
||||||
{"a"
|
"a" {
|
||||||
{"a" #1
|
"a" ["command-1"]
|
||||||
"b" #2}
|
"b" ["command-2" {:arg-1 "10" :arg-2 "11"}]
|
||||||
"b"
|
}
|
||||||
{"z" #3}
|
"b" {
|
||||||
"c" #4
|
"z" ["command-3"]
|
||||||
|
}
|
||||||
|
"c" ["command-4"]
|
||||||
})
|
})
|
||||||
|
|
||||||
(fn fake-key-event [c]
|
(fn fake-key-event [c]
|
||||||
@ -40,8 +42,16 @@
|
|||||||
(let [r (keymap.recogniser km)
|
(let [r (keymap.recogniser km)
|
||||||
(ok err)
|
(ok err)
|
||||||
(match (r:accept-event (fake-key-event "c"))
|
(match (r:accept-event (fake-key-event "c"))
|
||||||
(where f (= (f) 4)) true
|
["command-4"] true
|
||||||
x (values false (view x))
|
x (values false (view x))
|
||||||
nil (values false "???"))]
|
nil (values false "???"))]
|
||||||
|
(assert ok err))
|
||||||
|
|
||||||
|
(let [r (keymap.recogniser km)
|
||||||
|
(ok err)
|
||||||
|
(match-try
|
||||||
|
(r:accept-event (fake-key-event "a"))
|
||||||
|
nil (r:accept-event (fake-key-event "b"))
|
||||||
|
["command-2" {:arg-1 "10" :arg-2 "11"}] true
|
||||||
|
(catch x (values false (view x))))]
|
||||||
(assert ok err))
|
(assert ok err))
|
||||||
|
Loading…
Reference in New Issue
Block a user