Compare commits
5 Commits
9775e00545
...
24613ea424
Author | SHA1 | Date | |
---|---|---|---|
24613ea424 | |||
3cbe77a55e | |||
cc0f881fed | |||
d39d7059b9 | |||
561c717609 |
58
command.fnl
58
command.fnl
@ -24,15 +24,21 @@
|
|||||||
|
|
||||||
(define-command
|
(define-command
|
||||||
"switch-to-buffer"
|
"switch-to-buffer"
|
||||||
[[:buffer Buffer.match #(. (Buffer.next $1.buffer) :name)]]
|
[[:buffer
|
||||||
(fn [{: frame : buffer}]
|
Buffer.match
|
||||||
|
#(. (Buffer.next $1.buffer) :name)]
|
||||||
|
]
|
||||||
|
(fn [{:frame frame :buffer buffer}]
|
||||||
(frame:show-buffer buffer)))
|
(frame:show-buffer buffer)))
|
||||||
|
|
||||||
(define-command
|
(define-command
|
||||||
"visit-location"
|
"visit-location"
|
||||||
[[:buffer Buffer.match #$1.buffer.name]
|
[[:buffer
|
||||||
[:url #{$1 $1} #($1.buffer:location)]]
|
Buffer.match
|
||||||
(fn [{: url : buffer}]
|
#$1.buffer.name]
|
||||||
|
[:url #{$1 $1} #($1.buffer:location)]
|
||||||
|
]
|
||||||
|
(fn [{:url url :buffer buffer}]
|
||||||
(buffer:visit url)))
|
(buffer:visit url)))
|
||||||
|
|
||||||
(define-command
|
(define-command
|
||||||
@ -87,7 +93,8 @@
|
|||||||
|
|
||||||
{:command c :this-param k :collected-params p}
|
{:command c :this-param k :collected-params p}
|
||||||
(let [{ : completer} (. c.params k)
|
(let [{ : completer} (. c.params k)
|
||||||
value (. (completer input-string) input-string)]
|
vals (completer input-string)
|
||||||
|
value (. vals input-string)]
|
||||||
(tset p k value)
|
(tset p k value)
|
||||||
(state-for-next-param c p))
|
(state-for-next-param c p))
|
||||||
|
|
||||||
@ -98,25 +105,26 @@
|
|||||||
state)
|
state)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(fn on-activate [self str]
|
(fn on-input-finished [self str]
|
||||||
(let [s (next-action self 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 self.state s)
|
(set self.state s)
|
||||||
{
|
{
|
||||||
|
: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 self.frame))
|
:default (and param (param.default self.frame))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
(fn update-widget-state [{ : state : widget : entry : completions-widget : prompt} result]
|
(fn update-widget-state [{ : widget : entry : completions-widget : prompt} result]
|
||||||
(set prompt.label (or result.prompt ""))
|
(set prompt.label (or result.prompt ""))
|
||||||
(set entry.sensitive state.active)
|
(set entry.sensitive result.active)
|
||||||
(if (not state.active)
|
(if (not result.active)
|
||||||
(completions-widget:hide))
|
(completions-widget:hide))
|
||||||
(set entry.text (or result.default result.error ""))
|
(set entry.text (or result.default result.error ""))
|
||||||
(match widget.parent
|
(when widget.parent
|
||||||
p (p:set_visible_child_name
|
(widget.parent:set_visible_child_name
|
||||||
(if state.active "commander" "echo-area"))))
|
(if result.active "commander" "echo-area"))))
|
||||||
|
|
||||||
(fn on-input [self str]
|
(fn on-input [self str]
|
||||||
(match self.state
|
(match self.state
|
||||||
@ -126,11 +134,12 @@
|
|||||||
completions (completer str)]
|
completions (completer str)]
|
||||||
(parent:foreach #(parent:remove $1))
|
(parent:foreach #(parent:remove $1))
|
||||||
(each [text _w (pairs completions)]
|
(each [text _w (pairs completions)]
|
||||||
(parent:add (Gtk.Button {
|
(parent:add
|
||||||
:label text
|
(Gtk.Button {
|
||||||
:on_clicked
|
:label text
|
||||||
#(update-widget-state self (self:on-activate text))
|
:on_clicked
|
||||||
})))
|
#(update-widget-state self (self:on-input-finished text))
|
||||||
|
})))
|
||||||
(parent:show_all)
|
(parent:show_all)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
@ -139,16 +148,17 @@
|
|||||||
(tset state :active true)
|
(tset state :active true)
|
||||||
(update-widget-state
|
(update-widget-state
|
||||||
self
|
self
|
||||||
{
|
{:active true
|
||||||
:prompt (or state.this-param "Command" "")
|
:prompt (or state.this-param "Command" "")
|
||||||
})
|
})
|
||||||
(entry:grab_focus))
|
(entry:grab_focus)
|
||||||
|
state)
|
||||||
|
|
||||||
(fn deactivate [{: state : entry : prompt &as self}]
|
(fn deactivate [{: state : entry : prompt &as self}]
|
||||||
(doto state
|
(doto state
|
||||||
(lume.clear)
|
(lume.clear)
|
||||||
(tset :active false))
|
(tset :active false))
|
||||||
(update-widget-state self {}))
|
(update-widget-state self {:active false}))
|
||||||
|
|
||||||
(fn invoke-interactively [self name params]
|
(fn invoke-interactively [self name params]
|
||||||
(let [c (find-command name)
|
(let [c (find-command name)
|
||||||
@ -160,7 +170,7 @@
|
|||||||
:collected-params supplied-params
|
:collected-params supplied-params
|
||||||
}]
|
}]
|
||||||
(set self.state s)
|
(set self.state s)
|
||||||
(let [r (self:on-activate nil)]
|
(let [r (self:on-input-finished nil)]
|
||||||
(update-widget-state self r)
|
(update-widget-state self r)
|
||||||
(self.entry:grab_focus)
|
(self.entry:grab_focus)
|
||||||
r)))
|
r)))
|
||||||
@ -181,7 +191,7 @@
|
|||||||
: deactivate
|
: deactivate
|
||||||
:active? (fn [self] self.state.active)
|
:active? (fn [self] self.state.active)
|
||||||
: on-input
|
: on-input
|
||||||
: on-activate
|
: on-input-finished
|
||||||
: invoke-interactively
|
: invoke-interactively
|
||||||
: entry
|
: entry
|
||||||
:widget box
|
:widget box
|
||||||
@ -198,7 +208,7 @@
|
|||||||
(self:on-input event.text)))
|
(self:on-input event.text)))
|
||||||
(tset entry :on_activate
|
(tset entry :on_activate
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(let [result (self:on-activate event.text)]
|
(let [result (self:on-input-finished event.text)]
|
||||||
(update-widget-state self result))))
|
(update-widget-state self result))))
|
||||||
self))
|
self))
|
||||||
|
|
||||||
|
@ -33,12 +33,16 @@ let pname = "dunlin";
|
|||||||
cp lume.lua "$out/share/lua/${lua.luaversion}"
|
cp lume.lua "$out/share/lua/${lua.luaversion}"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lsqlite3 = callPackage ./lsqlite3.nix { lua = lua5_3; };
|
||||||
|
|
||||||
lua = lua5_3.withPackages (ps: with ps; [
|
lua = lua5_3.withPackages (ps: with ps; [
|
||||||
lgi
|
lgi
|
||||||
luafilesystem
|
luafilesystem
|
||||||
luaposix
|
luaposix
|
||||||
readline
|
readline
|
||||||
lume
|
lume
|
||||||
|
lsqlite3
|
||||||
]);
|
]);
|
||||||
fennel_ = lua.pkgs.fennel;
|
fennel_ = lua.pkgs.fennel;
|
||||||
glib_networking_gio = "${glib-networking}/lib/gio/modules";
|
glib_networking_gio = "${glib-networking}/lib/gio/modules";
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
(local history (require :history))
|
||||||
|
(tset _G :history (history.open
|
||||||
|
(.. (os.getenv "HOME") "/.dunlin-history.db")))
|
||||||
|
|
||||||
(let [f (Frame.new my-keymap)
|
(let [f (Frame.new my-keymap)
|
||||||
b (Buffer.new "main")]
|
b (Buffer.new "main")]
|
||||||
(f:show-buffer b)
|
(f:show-buffer b)
|
||||||
|
@ -38,12 +38,15 @@
|
|||||||
contentwidget (Gtk.Box {
|
contentwidget (Gtk.Box {
|
||||||
:orientation Gtk.Orientation.VERTICAL
|
:orientation Gtk.Orientation.VERTICAL
|
||||||
})
|
})
|
||||||
update-prop (fn [name value]
|
update-prop (fn [props name value]
|
||||||
(match name
|
(match name
|
||||||
:estimated-load-progress
|
:estimated-load-progress
|
||||||
(tset progress-bar :fraction value)
|
(tset progress-bar :fraction value)
|
||||||
:uri
|
:uri
|
||||||
(tset echo-area :label value)
|
(do (tset echo-area :label value)
|
||||||
|
(_G.history:visit value (os.time)))
|
||||||
|
:title
|
||||||
|
(_G.history:title self.buffer.properties.uri value)
|
||||||
n
|
n
|
||||||
(comment (print "prop change" n value))))]
|
(comment (print "prop change" n value))))]
|
||||||
|
|
||||||
@ -91,7 +94,7 @@
|
|||||||
(b:subscribe-property-changes
|
(b:subscribe-property-changes
|
||||||
(fn [name val]
|
(fn [name val]
|
||||||
(if (= b self.buffer)
|
(if (= b self.buffer)
|
||||||
(update-prop name val)
|
(update-prop self name val)
|
||||||
(print "ignore props from background" b))))
|
(print "ignore props from background" b))))
|
||||||
(b.webview:show))
|
(b.webview:show))
|
||||||
}]
|
}]
|
||||||
|
56
history.fnl
Normal file
56
history.fnl
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
(local sqlite (require :lsqlite3))
|
||||||
|
(local lume (require :lume))
|
||||||
|
(local { : view} (require :fennel))
|
||||||
|
|
||||||
|
(fn table-exists? [db]
|
||||||
|
(accumulate [ret false
|
||||||
|
r (db:nrows "select name from sqlite_master where type = 'table' and name= 'db_version'")]
|
||||||
|
(or ret true)))
|
||||||
|
|
||||||
|
(fn migrate [db serial statement]
|
||||||
|
(if (= (db:exec statement) 0)
|
||||||
|
(db:exec (.. "update db_version set serial = " serial))
|
||||||
|
(assert false (.. "db failed: " statement))))
|
||||||
|
|
||||||
|
(fn migrate-all [db]
|
||||||
|
(when (not (table-exists? db "db_version"))
|
||||||
|
(db:exec "create table db_version (serial integer)")
|
||||||
|
(db:exec "insert into db_version values (1)"))
|
||||||
|
(let [version (accumulate [v 0
|
||||||
|
r (db:nrows "select serial from db_version")]
|
||||||
|
r.serial)]
|
||||||
|
(when (< version 2)
|
||||||
|
(migrate db 2 "create table visits (url text, timestamp integer)"))
|
||||||
|
(when (< version 3)
|
||||||
|
(migrate db 3 "create table page_titles (url text primary key, title text)"))))
|
||||||
|
|
||||||
|
(fn visit [self url timestamp]
|
||||||
|
(let [s (self.db:prepare "insert into visits (url, timestamp) values (?,?)")]
|
||||||
|
(assert (= 0 (s:bind_values url timestamp)) (view [url timestamp]))
|
||||||
|
(s:step)
|
||||||
|
(s:reset)))
|
||||||
|
|
||||||
|
(fn title [self url title]
|
||||||
|
(let [s (self.db:prepare "insert into page_titles (url, title) values (?,?) on conflict(url) do update set title = excluded.title")]
|
||||||
|
(assert (= 0 (s:bind_values url title)) url)
|
||||||
|
(s:step)
|
||||||
|
(s:reset)))
|
||||||
|
|
||||||
|
(fn find [self term]
|
||||||
|
(let [s (self.db:prepare "select v.url,pt.title,v.timestamp from visits v left join page_titles pt on v.url = pt.url where instr(v.url, ?) is not null")]
|
||||||
|
(assert (= 0 (s:bind_values term)))
|
||||||
|
(icollect [r (s:nrows)] r)))
|
||||||
|
|
||||||
|
(fn open [pathname]
|
||||||
|
(let [db (if pathname (sqlite.open pathname) (sqlite.open_memory))]
|
||||||
|
(migrate-all db)
|
||||||
|
{
|
||||||
|
: db
|
||||||
|
: visit
|
||||||
|
: title
|
||||||
|
: find
|
||||||
|
}))
|
||||||
|
|
||||||
|
{
|
||||||
|
: open
|
||||||
|
}
|
21
lsqlite3.nix
Normal file
21
lsqlite3.nix
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
fetchurl
|
||||||
|
, lua
|
||||||
|
, lib
|
||||||
|
, sqlite
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
in lua.pkgs.buildLuarocksPackage {
|
||||||
|
pname = "lsqlite3";
|
||||||
|
version = "0.9.5-1";
|
||||||
|
buildInputs = [ sqlite ] ;
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://luarocks.org/manifests/dougcurrie/lsqlite3-0.9.5-1.src.rock";
|
||||||
|
sha256 = "sha256-/a48AzkKtOS32zoT0Jt5/+GTGHObdS0XkUrc2z0u+f8=";
|
||||||
|
};
|
||||||
|
disabled = (lua.pkgs.luaOlder "5.1");
|
||||||
|
propagatedBuildInputs = [ lua ];
|
||||||
|
preBuild = ''
|
||||||
|
cd lsqlite3_fsl09y
|
||||||
|
'';
|
||||||
|
}
|
@ -20,7 +20,7 @@
|
|||||||
(let [commander (Command.commander)
|
(let [commander (Command.commander)
|
||||||
(ok err)
|
(ok err)
|
||||||
(match-try (commander:activate)
|
(match-try (commander:activate)
|
||||||
{:active true} (commander:on-activate "not-a-command")
|
{:active true} (commander:on-input-finished "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))))]
|
||||||
@ -30,9 +30,9 @@
|
|||||||
(let [commander (Command.commander)
|
(let [commander (Command.commander)
|
||||||
(ok err)
|
(ok err)
|
||||||
(match-try (commander:activate)
|
(match-try (commander:activate)
|
||||||
{:active true} (commander:on-activate "multiply")
|
{:active true} (commander:on-input-finished "multiply")
|
||||||
{:active true :prompt p1} (commander:on-activate "2")
|
{:active true :prompt p1} (commander:on-input-finished "2")
|
||||||
{:active true :prompt p2} (commander:on-activate "3")
|
{:active true :prompt p2} (commander:on-input-finished "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))))]
|
||||||
|
25
test/history.fnl
Normal file
25
test/history.fnl
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
(local { : view } (require :fennel))
|
||||||
|
|
||||||
|
(local history (require :history))
|
||||||
|
|
||||||
|
(local fake-time
|
||||||
|
(let []
|
||||||
|
(var previous 1672682104)
|
||||||
|
(fn []
|
||||||
|
(doto previous
|
||||||
|
(+ 1)))))
|
||||||
|
|
||||||
|
(let [h (history.open)]
|
||||||
|
(h:visit "http://example.com" (fake-time))
|
||||||
|
(let [actual (h:find "example.com")]
|
||||||
|
(match actual
|
||||||
|
(where [{:url "http://example.com" :timestamp t}] (> t 0)) true
|
||||||
|
?fail (assert false (view ?fail)))))
|
||||||
|
|
||||||
|
(let [h (history.open)]
|
||||||
|
(h:visit "http://example.com" (fake-time))
|
||||||
|
(h:title "http://example.com" "Page title")
|
||||||
|
(let [actual (h:find "example.com")]
|
||||||
|
(match actual
|
||||||
|
(where [{:url "http://example.com" :title "Page title" :timestamp t}] (> t 0)) true
|
||||||
|
?fail (assert false (view ?fail)))))
|
Loading…
Reference in New Issue
Block a user