diff --git a/awesome/rc.lua b/awesome/rc.lua
index 673478d..4eb3550 100644
--- a/awesome/rc.lua
+++ b/awesome/rc.lua
@@ -108,7 +108,7 @@ vicious.register(uptimewidget, vicious.widgets.uptime, "uptime ${eth0 down_kb} up ${eth0 up_kb}', 3)
+vicious.register(netwidget, vicious.widgets.net, "down ${wifi0 down_kb} up ${wifi0 up_kb}", 3)
-- Date
datewidget = widget({ type = "textbox" })
diff --git a/awesome/themes/dustin/theme.lua b/awesome/themes/dustin/theme.lua
index 472226a..786ca78 100644
--- a/awesome/themes/dustin/theme.lua
+++ b/awesome/themes/dustin/theme.lua
@@ -4,13 +4,16 @@
theme = {}
-theme.font = "termsyn 8"
+theme.font = "terminus 8"
-theme.bg_normal = "#222222"
-theme.bg_focus = "#535d6c"
+--theme.bg_normal = "#222222"
+theme.bg_normal = "#000000"
+--theme.bg_focus = "#535d6c"
+theme.bg_focus = "#005566"
theme.bg_urgent = "#ff0000"
theme.bg_minimize = "#444444"
+--theme.fg_normal = "#aaaaaa"
theme.fg_normal = "#aaaaaa"
theme.fg_focus = "#ffffff"
theme.fg_urgent = "#ffffff"
@@ -18,7 +21,8 @@ theme.fg_minimize = "#ffffff"
theme.border_width = "1"
theme.border_normal = "#000000"
-theme.border_focus = "#535d6c"
+--theme.border_focus = "#535d6c"
+theme.border_focus = "#004466"
theme.border_marked = "#91231c"
-- There are other variable sets
diff --git a/luakit/binds.lua b/luakit/binds.lua
new file mode 100644
index 0000000..4fc718c
--- /dev/null
+++ b/luakit/binds.lua
@@ -0,0 +1,588 @@
+-----------------
+-- Keybindings --
+-----------------
+
+-- Binding aliases
+local key, buf, but = lousy.bind.key, lousy.bind.buf, lousy.bind.but
+local cmd, any = lousy.bind.cmd, lousy.bind.any
+
+-- Util aliases
+local match, join = string.match, lousy.util.table.join
+local strip, split = lousy.util.string.strip, lousy.util.string.split
+
+-- Globals or defaults that are used in binds
+local scroll_step = globals.scroll_step or 20
+local zoom_step = globals.zoom_step or 0.1
+
+-- Add binds to a mode
+function add_binds(mode, binds, before)
+ assert(binds and type(binds) == "table", "invalid binds table type: " .. type(binds))
+ mode = type(mode) ~= "table" and {mode} or mode
+ for _, m in ipairs(mode) do
+ local mdata = get_mode(m)
+ if mdata and before then
+ mdata.binds = join(binds, mdata.binds or {})
+ elseif mdata then
+ mdata.binds = mdata.binds or {}
+ for _, b in ipairs(binds) do table.insert(mdata.binds, b) end
+ else
+ new_mode(m, { binds = binds })
+ end
+ end
+end
+
+-- Add commands to command mode
+function add_cmds(cmds, before)
+ add_binds("command", cmds, before)
+end
+
+-- Adds the default menu widget bindings to a mode
+menu_binds = {
+ -- Navigate items
+ key({}, "j", function (w) w.menu:move_down() end),
+ key({}, "k", function (w) w.menu:move_up() end),
+ key({}, "Down", function (w) w.menu:move_down() end),
+ key({}, "Up", function (w) w.menu:move_up() end),
+ key({}, "Tab", function (w) w.menu:move_down() end),
+ key({"Shift"}, "Tab", function (w) w.menu:move_up() end),
+}
+
+-- Add binds to special mode "all" which adds its binds to all modes.
+add_binds("all", {
+ key({}, "Escape", "Return to `normal` mode.",
+ function (w) w:set_mode() end),
+
+ key({"Control"}, "[", "Return to `normal` mode.",
+ function (w) w:set_mode() end),
+
+ -- Mouse bindings
+ but({}, 8, "Go back.",
+ function (w) w:back() end),
+
+ but({}, 9, "Go forward.",
+ function (w) w:forward() end),
+
+ -- Open link in new tab or navigate to selection
+ but({}, 2, [[Open link under mouse cursor in new tab or navigate to the
+ contents of `luakit.selection.primary`.]],
+ function (w, m)
+ -- Ignore button 2 clicks in form fields
+ if not m.context.editable then
+ -- Open hovered uri in new tab
+ local uri = w.view.hovered_uri
+ if uri then
+ w:new_tab(uri, false)
+ else -- Open selection in current tab
+ uri = luakit.selection.primary
+ if uri then w:navigate(w:search_open(uri)) end
+ end
+ end
+ end),
+
+ -- Open link in new tab when Ctrl-clicked.
+ but({"Control"}, 1, "Open link under mouse cursor in new tab.",
+ function (w, m)
+ local uri = w.view.hovered_uri
+ if uri then
+ w:new_tab(uri, false)
+ end
+ end),
+
+ -- Zoom binds
+ but({"Control"}, 4, "Increase text zoom level.",
+ function (w, m) w:zoom_in() end),
+
+ but({"Control"}, 5, "Reduce text zoom level.",
+ function (w, m) w:zoom_out() end),
+
+ -- Horizontal mouse scroll binds
+ but({"Shift"}, 4, "Scroll left.",
+ function (w, m) w:scroll{ xrel = -scroll_step } end),
+
+ but({"Shift"}, 5, "Scroll right.",
+ function (w, m) w:scroll{ xrel = scroll_step } end),
+})
+
+add_binds("normal", {
+ -- Autoparse the `[count]` before a binding and re-call the hit function
+ -- with the count removed and added to the opts table.
+ any([[Meta-binding to detect the `^[count]` syntax. The `[count]` is parsed
+ and stripped from the internal buffer string and the value assigned to
+ `state.count`. Then `lousy.bind.hit()` is re-called with the modified
+ buffer string & original modifier state.
+
+ #### Example binding
+
+ lousy.bind.key({}, "%", function (w, state)
+ w:scroll{ ypct = state.count }
+ end, { count = 0 })
+
+ This binding demonstrates several concepts. Firstly that you are able to
+ specify per-binding default values of `count`. In this case if the user
+ types `"%"` the document will be scrolled vertically to `0%` (the top).
+
+ If the user types `"100%"` then the document will be scrolled to `100%`
+ (the bottom). All without the need to use `lousy.bind.buf` bindings
+ everywhere and or using a `^(%d*)` pattern prefix on every binding which
+ would like to make use of the `[count]` syntax.]],
+ function (w, m)
+ local count, buf
+ if m.buffer then
+ count = string.match(m.buffer, "^(%d+)")
+ end
+ if count then
+ buf = string.sub(m.buffer, #count + 1, (m.updated_buf and -2) or -1)
+ local opts = join(m, {count = tonumber(count)})
+ opts.buffer = (#buf > 0 and buf) or nil
+ if lousy.bind.hit(w, m.binds, m.mods, m.key, opts) then
+ return true
+ end
+ end
+ return false
+ end),
+
+ key({}, "i", "Enter `insert` mode.",
+ function (w) w:set_mode("insert") end),
+
+ key({}, ":", "Enter `command` mode.",
+ function (w) w:set_mode("command") end),
+
+ -- Scrolling
+ key({}, "j", "Scroll document down.",
+ function (w) w:scroll{ yrel = scroll_step } end),
+
+ key({}, "k", "Scroll document up.",
+ function (w) w:scroll{ yrel = -scroll_step } end),
+
+ key({}, "h", "Scroll document left.",
+ function (w) w:scroll{ xrel = -scroll_step } end),
+
+ key({}, "l", "Scroll document right.",
+ function (w) w:scroll{ xrel = scroll_step } end),
+
+ key({}, "Down", "Scroll document down.",
+ function (w) w:scroll{ yrel = scroll_step } end),
+
+ key({}, "Up", "Scroll document up.",
+ function (w) w:scroll{ yrel = -scroll_step } end),
+
+ key({}, "Left", "Scroll document left.",
+ function (w) w:scroll{ xrel = -scroll_step } end),
+
+ key({}, "Right", "Scroll document right.",
+ function (w) w:scroll{ xrel = scroll_step } end),
+
+ key({}, "^", "Scroll to the absolute left of the document.",
+ function (w) w:scroll{ x = 0 } end),
+
+ key({}, "$", "Scroll to the absolute right of the document.",
+ function (w) w:scroll{ x = -1 } end),
+
+ key({}, "0", "Scroll to the absolute left of the document.",
+ function (w, m)
+ if not m.count then w:scroll{ y = 0 } else return false end
+ end),
+
+ key({"Control"}, "e", "Scroll document down.",
+ function (w) w:scroll{ yrel = scroll_step } end),
+
+ key({"Control"}, "y", "Scroll document up.",
+ function (w) w:scroll{ yrel = -scroll_step } end),
+
+ key({"Control"}, "d", "Scroll half page down.",
+ function (w) w:scroll{ ypagerel = 0.5 } end),
+
+ key({"Control"}, "u", "Scroll half page up.",
+ function (w) w:scroll{ ypagerel = -0.5 } end),
+
+ key({"Control"}, "f", "Scroll page down.",
+ function (w) w:scroll{ ypagerel = 1.0 } end),
+
+ key({"Control"}, "b", "Scroll page up.",
+ function (w) w:scroll{ ypagerel = -1.0 } end),
+
+ key({}, "space", "Scroll page down.",
+ function (w) w:scroll{ ypagerel = 1.0 } end),
+
+ key({"Shift"}, "space", "Scroll page up.",
+ function (w) w:scroll{ ypagerel = -1.0 } end),
+
+ key({}, "BackSpace", "Scroll page up.",
+ function (w) w:scroll{ ypagerel = -1.0 } end),
+
+ key({}, "Page_Down", "Scroll page down.",
+ function (w) w:scroll{ ypagerel = 1.0 } end),
+
+ key({}, "Page_Up", "Scroll page up.",
+ function (w) w:scroll{ ypagerel = -1.0 } end),
+
+ key({}, "Home", "Go to the end of the document.",
+ function (w) w:scroll{ y = 0 } end),
+
+ key({}, "End", "Go to the top of the document.",
+ function (w) w:scroll{ y = -1 } end),
+
+ -- Specific scroll
+ buf("^gg$", "Go to the top of the document.",
+ function (w, b, m) w:scroll{ ypct = m.count } end, {count=0}),
+
+ buf("^G$", "Go to the bottom of the document.",
+ function (w, b, m) w:scroll{ ypct = m.count } end, {count=100}),
+
+ buf("^%%$", "Go to `[count]` percent of the document.",
+ function (w, b, m) w:scroll{ ypct = m.count } end),
+
+ -- Zooming
+ key({}, "+", "Enlarge text zoom of the current page.",
+ function (w, m) w:zoom_in(zoom_step * m.count) end, {count=1}),
+
+ key({}, "-", "Reduce text zom of the current page.",
+ function (w, m) w:zoom_out(zoom_step * m.count) end, {count=1}),
+
+ key({}, "=", "Reset zoom level.",
+ function (w, m) w:zoom_set() end),
+
+ buf("^z[iI]$", [[Enlarge text zoom of current page with `zi` or `zI` to
+ reduce full zoom.]],
+ function (w, b, m)
+ w:zoom_in(zoom_step * m.count, b == "zI")
+ end, {count=1}),
+
+ buf("^z[oO]$", [[Reduce text zoom of current page with `zo` or `zO` to
+ reduce full zoom.]],
+ function (w, b, m)
+ w:zoom_out(zoom_step * m.count, b == "zO")
+ end, {count=1}),
+
+ -- Zoom reset or specific zoom ([count]zZ for full content zoom)
+ buf("^z[zZ]$", [[Set current page zoom to `[count]` percent with
+ `[count]zz`, use `[count]zZ` to set full zoom percent.]],
+ function (w, b, m)
+ w:zoom_set(m.count/100, b == "zZ")
+ end, {count=100}),
+
+ -- Fullscreen
+ key({}, "F11", "Toggle fullscreen mode.",
+ function (w) w.win.fullscreen = not w.win.fullscreen end),
+
+ -- Clipboard
+ key({}, "p", [[Open a URL based on the current primary selection contents
+ in the current tab.]],
+ function (w)
+ local uri = luakit.selection.primary
+ if not uri then w:notify("No primary selection...") return end
+ w:navigate(w:search_open(uri))
+ end),
+
+ key({}, "P", [[Open a URL based on the current primary selection contents
+ in `[count=1]` new tab(s).]],
+ function (w, m)
+ local uri = luakit.selection.primary
+ if not uri then w:notify("No primary selection...") return end
+ for i = 1, m.count do w:new_tab(w:search_open(uri)) end
+ end, {count = 1}),
+
+ -- Yanking
+ key({}, "y", "Yank current URI to primary selection.",
+ function (w)
+ local uri = string.gsub(w.view.uri or "", " ", "%%20")
+ luakit.selection.primary = uri
+ w:notify("Yanked uri: " .. uri)
+ end),
+
+ -- Commands
+ key({"Control"}, "a", "Increment last number in URL.",
+ function (w) w:navigate(w:inc_uri(1)) end),
+
+ key({"Control"}, "x", "Decrement last number in URL.",
+ function (w) w:navigate(w:inc_uri(-1)) end),
+
+ key({}, "o", "Open one or more URLs.",
+ function (w) w:enter_cmd(":open ") end),
+
+ key({}, "t", "Open one or more URLs in a new tab.",
+ function (w) w:enter_cmd(":tabopen ") end),
+
+ key({}, "w", "Open one or more URLs in a new window.",
+ function (w) w:enter_cmd(":winopen ") end),
+
+ key({}, "O", "Open one or more URLs based on current location.",
+ function (w) w:enter_cmd(":open " .. (w.view.uri or "")) end),
+
+ key({}, "T",
+ "Open one or more URLs based on current location in a new tab.",
+ function (w) w:enter_cmd(":tabopen " .. (w.view.uri or "")) end),
+
+ key({}, "W",
+ "Open one or more URLs based on current locaton in a new window.",
+ function (w) w:enter_cmd(":winopen " .. (w.view.uri or "")) end),
+
+ -- History
+ key({}, "H", "Go back in the browser history `[count=1]` items.",
+ function (w, m) w:back(m.count) end),
+
+ key({}, "L", "Go forward in the browser history `[count=1]` times.",
+ function (w, m) w:forward(m.count) end),
+
+ key({}, "XF86Back", "Go back in the browser history.",
+ function (w, m) w:back(m.count) end),
+
+ key({}, "XF86Forward", "Go forward in the browser history.",
+ function (w, m) w:forward(m.count) end),
+
+ key({"Control"}, "o", "Go back in the browser history.",
+ function (w, m) w:back(m.count) end),
+
+ key({"Control"}, "i", "Go forward in the browser history.",
+ function (w, m) w:forward(m.count) end),
+
+ -- Tab
+ key({"Control"}, "Page_Up", "Go to previous tab.",
+ function (w) w:prev_tab() end),
+
+ key({"Control"}, "Page_Down", "Go to next tab.",
+ function (w) w:next_tab() end),
+
+ key({"Control"}, "Tab", "Go to next tab.",
+ function (w) w:next_tab() end),
+
+ key({"Shift","Control"}, "Tab", "Go to previous tab.",
+ function (w) w:prev_tab() end),
+
+ buf("^gT$", "Go to previous tab.",
+ function (w) w:prev_tab() end),
+
+ buf("^gt$", "Go to next tab (or `[count]` nth tab).",
+ function (w, b, m)
+ if not w:goto_tab(m.count) then w:next_tab() end
+ end, {count=0}),
+
+ buf("^g0$", "Go to first tab.",
+ function (w) w:goto_tab(1) end),
+
+ buf("^g$$", "Go to last tab.",
+ function (w) w:goto_tab(-1) end),
+
+ key({"Control"}, "t", "Open a new tab.",
+ function (w) w:new_tab(globals.homepage) end),
+
+ key({"Control"}, "w", "Close current tab.",
+ function (w) w:close_tab() end),
+
+ key({}, "d", "Close current tab (or `[count]` tabs).",
+ function (w, m) for i=1,m.count do w:close_tab() end end, {count=1}),
+
+ key({}, "<", "Reorder tab left `[count=1]` positions.",
+ function (w, m)
+ w.tabs:reorder(w.view, w.tabs:current() - m.count)
+ end, {count=1}),
+
+ key({}, ">", "Reorder tab right `[count=1]` positions.",
+ function (w, m)
+ w.tabs:reorder(w.view,
+ (w.tabs:current() + m.count) % w.tabs:count())
+ end, {count=1}),
+
+ buf("^gH$", "Open homepage in new tab.",
+ function (w) w:new_tab(globals.homepage) end),
+
+ buf("^gh$", "Open homepage.",
+ function (w) w:navigate(globals.homepage) end),
+
+ buf("^gy$", "Duplicate current tab.",
+ function (w) w:new_tab(w.view.history or "") end),
+
+ key({}, "r", "Reload current tab.",
+ function (w) w:reload() end),
+
+ key({}, "R", "Reload current tab (skipping cache).",
+ function (w) w:reload(true) end),
+
+ key({"Control"}, "c", "Stop loading the current tab.",
+ function (w) w.view:stop() end),
+
+ key({"Control", "Shift"}, "R", "Restart luakit (reloading configs).",
+ function (w) w:restart() end),
+
+ -- Window
+ buf("^ZZ$", "Quit and save the session.",
+ function (w) w:save_session() w:close_win() end),
+
+ buf("^ZQ$", "Quit and don't save the session.",
+ function (w) w:close_win() end),
+
+ buf("^D$", "Quit and don't save the session.",
+ function (w) w:close_win() end),
+
+ -- Enter passthrough mode
+ key({"Control"}, "z",
+ "Enter `passthrough` mode, ignores all luakit keybindings.",
+ function (w) w:set_mode("passthrough") end),
+})
+
+add_binds("insert", {
+ key({"Control"}, "z",
+ "Enter `passthrough` mode, ignores all luakit keybindings.",
+ function (w) w:set_mode("passthrough") end),
+})
+
+readline_bindings = {
+ key({"Shift"}, "Insert",
+ "Insert contents of primary selection at cursor position.",
+ function (w) w:insert_cmd(luakit.selection.primary) end),
+
+ key({"Control"}, "w", "Delete previous word.",
+ function (w) w:del_word() end),
+
+ key({"Control"}, "u", "Delete until beginning of current line.",
+ function (w) w:del_line() end),
+
+ key({"Control"}, "h", "Delete character to the left.",
+ function (w) w:del_backward_char() end),
+
+ key({"Control"}, "d", "Delete character to the right.",
+ function (w) w:del_forward_char() end),
+
+ key({"Control"}, "a", "Move cursor to beginning of current line.",
+ function (w) w:beg_line() end),
+
+ key({"Control"}, "e", "Move cursor to end of current line.",
+ function (w) w:end_line() end),
+
+ key({"Control"}, "f", "Move cursor forward one character.",
+ function (w) w:forward_char() end),
+
+ key({"Control"}, "b", "Move cursor backward one character.",
+ function (w) w:backward_char() end),
+
+ key({"Mod1"}, "f", "Move cursor forward one word.",
+ function (w) w:forward_word() end),
+
+ key({"Mod1"}, "b", "Move cursor backward one word.",
+ function (w) w:backward_word() end),
+}
+
+add_binds({"command", "search"}, readline_bindings)
+
+-- Switching tabs with Mod1+{1,2,3,...}
+mod1binds = {}
+for i=1,10 do
+ table.insert(mod1binds,
+ key({"Mod1"}, tostring(i % 10), "Jump to tab at index "..i..".",
+ function (w) w.tabs:switch(i) end))
+end
+add_binds("normal", mod1binds)
+
+-- Command bindings which are matched in the "command" mode from text
+-- entered into the input bar.
+add_cmds({
+ buf("^%S+!",
+ [[Detect bang syntax in `:command!` and recursively calls
+ `lousy.bind.match_cmd(..)` removing the bang from the command string
+ and setting `bang = true` in the bind opts table.]],
+ function (w, cmd, opts)
+ local cmd, args = string.match(cmd, "^(%S+)!+(.*)")
+ if cmd then
+ opts = join(opts, { bang = true })
+ return lousy.bind.match_cmd(w, opts.binds, cmd .. args, opts)
+ end
+ end),
+
+ cmd("c[lose]", "Close current tab.",
+ function (w) w:close_tab() end),
+
+ cmd("print", "Print current page.",
+ function (w) w.view:eval_js("print()") end),
+
+ cmd("stop", "Stop loading.",
+ function (w) w.view:stop() end),
+
+ cmd("reload", "Reload page",
+ function (w) w:reload() end),
+
+ cmd("restart", "Restart browser (reload config files).",
+ function (w) w:restart() end),
+
+ cmd("write", "Save current session.",
+ function (w) w:save_session() end),
+
+ cmd("noh[lsearch]", "Clear search highlighting.",
+ function (w) w:clear_search() end),
+
+ cmd("back", "Go back in the browser history `[count=1]` items.",
+ function (w, a) w:back(tonumber(a) or 1) end),
+
+ cmd("f[orward]", "Go forward in the browser history `[count=1]` items.",
+ function (w, a) w:forward(tonumber(a) or 1) end),
+
+ cmd("inc[rease]", "Increment last number in URL.",
+ function (w, a) w:navigate(w:inc_uri(tonumber(a) or 1)) end),
+
+ cmd("o[pen]", "Open one or more URLs.",
+ function (w, a) w:navigate(w:search_open(a)) end),
+
+ cmd("t[abopen]", "Open one or more URLs in a new tab.",
+ function (w, a) w:new_tab(w:search_open(a)) end),
+
+ cmd("w[inopen]", "Open one or more URLs in a new window.",
+ function (w, a) window.new{w:search_open(a)} end),
+
+ cmd({"javascript", "js"}, "Evaluate JavaScript snippet.",
+ function (w, a) w.view:eval_js(a) end),
+
+ -- Tab manipulation commands
+ cmd("tab", "Execute command and open result in new tab.",
+ function (w, a) w:new_tab() w:run_cmd(":" .. a) end),
+
+ cmd("tabd[o]", "Execute command in each tab.",
+ function (w, a) w:each_tab(function (v) w:run_cmd(":" .. a) end) end),
+
+ cmd("tabdu[plicate]", "Duplicate current tab.",
+ function (w) w:new_tab(w.view.history) end),
+
+ cmd("tabfir[st]", "Switch to first tab.",
+ function (w) w:goto_tab(1) end),
+
+ cmd("tabl[ast]", "Switch to last tab.",
+ function (w) w:goto_tab(-1) end),
+
+ cmd("tabn[ext]", "Switch to the next tab.",
+ function (w) w:next_tab() end),
+
+ cmd("tabp[revious]", "Switch to the previous tab.",
+ function (w) w:prev_tab() end),
+
+ cmd("q[uit]", "Close the current window.",
+ function (w, a, o) w:close_win(o.bang) end),
+
+ cmd({"viewsource", "vs"}, "View the source code of the current document.",
+ function (w, a, o) w:toggle_source(not o.bang and true or nil) end),
+
+ cmd({"wqall", "wq"}, "Save the session and quit.",
+ function (w, a, o) w:save_session() w:close_win(o.bang) end),
+
+ cmd("lua", "Evaluate Lua snippet.", function (w, a)
+ if a then
+ local ret = assert(
+ loadstring("return function(w) return "..a.." end"))()(w)
+ if ret then print(ret) end
+ else
+ w:set_mode("lua")
+ end
+ end),
+
+ cmd("dump", "Dump current tabs html to file.",
+ function (w, a)
+ local fname = string.gsub(w.win.title, '[^%w%.%-]', '_')..'.html' -- sanitize filename
+ local file = a or luakit.save_file("Save file", w.win, xdg.download_dir or '.', fname)
+ if file then
+ local fd = assert(io.open(file, "w"), "failed to open: " .. file)
+ local html = assert(w.view:eval_js("document.documentElement.outerHTML"), "Unable to get HTML")
+ assert(fd:write(html), "unable to save html")
+ io.close(fd)
+ w:notify("Dumped HTML to: " .. file)
+ end
+ end),
+})
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
diff --git a/luakit/globals.lua b/luakit/globals.lua
new file mode 100644
index 0000000..b8b4a25
--- /dev/null
+++ b/luakit/globals.lua
@@ -0,0 +1,85 @@
+-- Global variables for luakit
+globals = {
+ homepage = "http://luakit.org/",
+ -- homepage = "http://github.com/mason-larobina/luakit",
+ scroll_step = 40,
+ zoom_step = 0.1,
+ max_cmd_history = 100,
+ max_srch_history = 100,
+ -- http_proxy = "http://example.com:3128",
+ default_window_size = "800x600",
+
+ -- Disables loading of hostnames from /etc/hosts (for large host files)
+ -- load_etc_hosts = false,
+ -- Disables checking if a filepath exists in search_open function
+ -- check_filepath = false,
+}
+
+-- Make useragent
+local _, arch = luakit.spawn_sync("uname -sm")
+-- Only use the luakit version if in date format (reduces identifiability)
+local lkv = string.match(luakit.version, "^(%d+.%d+.%d+)")
+globals.useragent = string.format("Mozilla/5.0 (%s) AppleWebKit/%s+ (KHTML, like Gecko) WebKitGTK+/%s luakit%s",
+ string.sub(arch, 1, -2), luakit.webkit_user_agent_version,
+ luakit.webkit_version, (lkv and ("/" .. lkv)) or "")
+
+-- Search common locations for a ca file which is used for ssl connection validation.
+local ca_files = {
+ -- $XDG_DATA_HOME/luakit/ca-certificates.crt
+ luakit.data_dir .. "/ca-certificates.crt",
+ "/etc/certs/ca-certificates.crt",
+ "/etc/ssl/certs/ca-certificates.crt",
+}
+-- Use the first ca-file found
+for _, ca_file in ipairs(ca_files) do
+ if os.exists(ca_file) then
+ soup.ssl_ca_file = ca_file
+ break
+ end
+end
+
+-- Change to stop navigation sites with invalid or expired ssl certificates
+soup.ssl_strict = false
+
+-- Set cookie acceptance policy
+cookie_policy = { always = 0, never = 1, no_third_party = 2 }
+soup.accept_policy = cookie_policy.always
+
+-- List of search engines. Each item must contain a single %s which is
+-- replaced by URI encoded search terms. All other occurances of the percent
+-- character (%) may need to be escaped by placing another % before or after
+-- it to avoid collisions with lua's string.format characters.
+-- See: http://www.lua.org/manual/5.1/manual.html#pdf-string.format
+search_engines = {
+ duckduckgo = "https://duckduckgo.com/?q=%s",
+ github = "https://github.com/search?q=%s",
+ google = "https://google.com/search?q=%s",
+ imdb = "http://www.imdb.com/find?s=all&q=%s",
+ wikipedia = "https://en.wikipedia.org/wiki/Special:Search?search=%s",
+}
+
+-- Set google as fallback search engine
+search_engines.default = search_engines.google
+-- Use this instead to disable auto-searching
+--search_engines.default = "%s"
+
+-- Per-domain webview properties
+-- See http://webkitgtk.org/reference/webkitgtk/stable/WebKitWebSettings.html
+domain_props = { --[[
+ ["all"] = {
+ enable_scripts = false,
+ enable_plugins = false,
+ enable_private_browsing = false,
+ user_stylesheet_uri = "",
+ },
+ ["youtube.com"] = {
+ enable_scripts = true,
+ enable_plugins = true,
+ },
+ ["bbs.archlinux.org"] = {
+ user_stylesheet_uri = "file://" .. luakit.data_dir .. "/styles/dark.css",
+ enable_private_browsing = true,
+ }, ]]
+}
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
diff --git a/luakit/modes.lua b/luakit/modes.lua
new file mode 100644
index 0000000..bd15c67
--- /dev/null
+++ b/luakit/modes.lua
@@ -0,0 +1,163 @@
+-------------------------------
+-- luakit mode configuration --
+-------------------------------
+
+-- Table of modes and their callback hooks
+local modes = {}
+local lousy = require "lousy"
+local join = lousy.util.table.join
+local order = 0
+
+-- Add new mode table (optionally merges with original mode)
+function new_mode(name, desc, mode, replace)
+ assert(string.match(name, "^[%w-_]+$"), "invalid mode name: " .. name)
+ -- Detect optional description
+ if type(desc) == "table" then
+ desc, mode, replace = nil, desc, mode
+ end
+ local traceback = debug.traceback("Creation traceback:", 2)
+ order = order + 1
+ modes[name] = join({ order = order, traceback = traceback },
+ (not replace and modes[name]) or {}, mode or {},
+ { name = name, desc = desc })
+end
+
+-- Get mode table
+function get_mode(name) return modes[name] end
+
+function get_modes() return lousy.util.table.clone(modes) end
+
+-- Attach window & input bar signals for mode hooks
+window.init_funcs.modes_setup = function (w)
+ -- Calls the `enter` and `leave` mode hooks.
+ w:add_signal("mode-changed", function (_, name, ...)
+ local leave = (w.mode or {}).leave
+
+ -- Get new modes functions/hooks/data
+ local mode = assert(modes[name], "invalid mode: " .. name)
+
+ -- Call last modes leave hook.
+ if leave then leave(w) end
+
+ -- Create w.mode object
+ w.mode = mode
+
+ -- Update window binds
+ w:update_binds(name)
+
+ -- Call new modes enter hook.
+ if mode.enter then mode.enter(w, ...) end
+
+ w:emit_signal("mode-entered", mode)
+ end)
+
+ local input = w.ibar.input
+
+ -- Calls the changed hook on input widget changed.
+ input:add_signal("changed", function ()
+ local changed = w.mode.changed
+ if changed then changed(w, input.text) end
+ end)
+
+ input:add_signal("property::position", function ()
+ local move_cursor = w.mode.move_cursor
+ if move_cursor then move_cursor(w, input.position) end
+ end)
+
+ -- Calls the `activate` hook on input widget activate.
+ input:add_signal("activate", function ()
+ local mode = w.mode
+ if mode and mode.activate then
+ local text, hist = input.text, mode.history
+ if mode.activate(w, text) == false then return end
+ -- Check if last history item is identical
+ if hist and hist.items and hist.items[hist.len or -1] ~= text then
+ table.insert(hist.items, text)
+ end
+ end
+ end)
+end
+
+-- Add mode related window methods
+window.methods.set_mode = lousy.mode.set
+local mget = lousy.mode.get
+window.methods.is_mode = function (w, name) return name == mget(w) end
+
+-- Setup normal mode
+new_mode("normal", [[When luakit first starts you will find yourself in this
+ mode.]], {
+ enter = function (w)
+ w:set_prompt()
+ w:set_input()
+ end,
+})
+
+new_mode("all", [[Special meta-mode in which the bindings for this mode are
+ present in all modes.]])
+
+-- Setup insert mode
+new_mode("insert", [[When clicking on form fields luakit will enter the insert
+ mode which allows you to enter text in form fields without accidentally
+ triggering normal mode bindings.]], {
+ enter = function (w)
+ w:set_prompt("-- INSERT --")
+ w:set_input()
+ w.view:focus()
+ end,
+ -- Send key events to webview
+ passthrough = true,
+})
+
+new_mode("passthrough", [[Luakit will pass every key event to the WebView
+ until the user presses Escape.]], {
+ enter = function (w)
+ w:set_prompt("-- PASS THROUGH --")
+ w:set_input()
+ end,
+ -- Send key events to webview
+ passthrough = true,
+ -- Don't exit mode when clicking outside of form fields
+ reset_on_focus = false,
+ -- Don't exit mode on navigation
+ reset_on_navigation = false,
+})
+
+-- Setup command mode
+new_mode("command", [[Enter commands.]], {
+ enter = function (w)
+ w:set_prompt()
+ w:set_input(":")
+ end,
+ changed = function (w, text)
+ -- Auto-exit command mode if user backspaces ":" in the input bar.
+ if not string.match(text, "^:") then w:set_mode() end
+ end,
+ activate = function (w, text)
+ w:set_mode()
+ local cmd = string.sub(text, 2)
+ if not string.find(cmd, "%S") then return end
+
+ local success, match = xpcall(
+ function () return w:match_cmd(cmd) end,
+ function (err) w:error(debug.traceback(err, 3)) end)
+
+ if success and not match then
+ w:error(string.format("Not a browser command: %q", cmd))
+ end
+ end,
+ history = {maxlen = 50},
+})
+
+new_mode("lua", [[Execute arbitrary Lua commands within the luakit
+ environment.]], {
+ enter = function (w)
+ w:set_prompt(">")
+ w:set_input("")
+ end,
+ activate = function (w, text)
+ w:set_input("")
+ local ret = assert(loadstring("return function(w) return "..text.." end"))()(w)
+ if ret then print(ret) end
+ end,
+ history = {maxlen = 50},
+})
diff --git a/luakit/rc.lua b/luakit/rc.lua
new file mode 100644
index 0000000..c03a6bd
--- /dev/null
+++ b/luakit/rc.lua
@@ -0,0 +1,181 @@
+-----------------------------------------------------------------------
+-- luakit configuration file, more information at http://luakit.org/ --
+-----------------------------------------------------------------------
+
+require "lfs"
+
+if unique then
+ unique.new("org.luakit")
+ -- Check for a running luakit instance
+ if unique.is_running() then
+ if uris[1] then
+ for _, uri in ipairs(uris) do
+ if lfs.attributes(uri) then uri = os.abspath(uri) end
+ unique.send_message("tabopen " .. uri)
+ end
+ else
+ unique.send_message("winopen")
+ end
+ luakit.quit()
+ end
+end
+
+-- Load library of useful functions for luakit
+require "lousy"
+
+-- Small util functions to print output (info prints only when luakit.verbose is true)
+function warn(...) io.stderr:write(string.format(...) .. "\n") end
+function info(...) if luakit.verbose then io.stdout:write(string.format(...) .. "\n") end end
+
+-- Load users global config
+-- ("$XDG_CONFIG_HOME/luakit/globals.lua" or "/etc/xdg/luakit/globals.lua")
+require "globals"
+
+-- Load users theme
+-- ("$XDG_CONFIG_HOME/luakit/theme.lua" or "/etc/xdg/luakit/theme.lua")
+lousy.theme.init(lousy.util.find_config("theme.lua"))
+theme = assert(lousy.theme.get(), "failed to load theme")
+
+-- Load users window class
+-- ("$XDG_CONFIG_HOME/luakit/window.lua" or "/etc/xdg/luakit/window.lua")
+require "window"
+
+-- Load users webview class
+-- ("$XDG_CONFIG_HOME/luakit/webview.lua" or "/etc/xdg/luakit/webview.lua")
+require "webview"
+
+-- Load users mode configuration
+-- ("$XDG_CONFIG_HOME/luakit/modes.lua" or "/etc/xdg/luakit/modes.lua")
+require "modes"
+
+-- Load users keybindings
+-- ("$XDG_CONFIG_HOME/luakit/binds.lua" or "/etc/xdg/luakit/binds.lua")
+require "binds"
+
+----------------------------------
+-- Optional user script loading --
+----------------------------------
+
+require "webinspector"
+
+-- Add sqlite3 cookiejar
+require "cookies"
+
+-- Cookie blocking by domain (extends cookies module)
+-- Add domains to the whitelist at "$XDG_CONFIG_HOME/luakit/cookie.whitelist"
+-- and blacklist at "$XDG_CONFIG_HOME/luakit/cookie.blacklist".
+-- Each domain must be on it's own line and you may use "*" as a
+-- wildcard character (I.e. "*google.com")
+--require "cookie_blocking"
+
+-- Block all cookies by default (unless whitelisted)
+--cookies.default_allow = false
+
+-- Add uzbl-like form filling
+require "formfiller"
+
+-- Add proxy support & manager
+require "proxy"
+
+-- Add quickmarks support & manager
+require "quickmarks"
+
+-- Add session saving/loading support
+require "session"
+
+-- Add command to list closed tabs & bind to open closed tabs
+require "undoclose"
+
+-- Add command to list tab history items
+require "tabhistory"
+
+-- Add greasemonkey-like javascript userscript support
+require "userscripts"
+
+-- Add bookmarks support
+require "bookmarks"
+require "bookmarks_chrome"
+
+-- Add download support
+require "downloads"
+require "downloads_chrome"
+
+-- Example using xdg-open for opening downloads / showing download folders
+--downloads.add_signal("open-file", function (file, mime)
+-- luakit.spawn(string.format("xdg-open %q", file))
+-- return true
+--end)
+
+-- Add vimperator-like link hinting & following
+require "follow"
+
+-- Use a custom charater set for hint labels
+--local s = follow.label_styles
+--follow.label_maker = s.sort(s.reverse(s.charset("asdfqwerzxcv")))
+
+-- Match only hint labels
+--follow.pattern_maker = follow.pattern_styles.match_label
+
+-- Add command history
+require "cmdhist"
+
+-- Add search mode & binds
+require "search"
+
+-- Add ordering of new tabs
+require "taborder"
+
+-- Save web history
+require "history"
+require "history_chrome"
+
+require "introspector"
+
+-- Add command completion
+require "completion"
+
+-- NoScript plugin, toggle scripts and or plugins on a per-domain basis.
+-- `,ts` to toggle scripts, `,tp` to toggle plugins, `,tr` to reset.
+-- Remove all "enable_scripts" & "enable_plugins" lines from your
+-- domain_props table (in config/globals.lua) as this module will conflict.
+--require "noscript"
+
+require "follow_selected"
+require "go_input"
+require "go_next_prev"
+require "go_up"
+
+-----------------------------
+-- End user script loading --
+-----------------------------
+
+-- Restore last saved session
+local w = (session and session.restore())
+if w then
+ for i, uri in ipairs(uris) do
+ w:new_tab(uri, i == 1)
+ end
+else
+ -- Or open new window
+ window.new(uris)
+end
+
+-------------------------------------------
+-- Open URIs from other luakit instances --
+-------------------------------------------
+
+if unique then
+ unique.add_signal("message", function (msg, screen)
+ local cmd, arg = string.match(msg, "^(%S+)%s*(.*)")
+ local w = lousy.util.table.values(window.bywidget)[1]
+ if cmd == "tabopen" then
+ w:new_tab(arg)
+ elseif cmd == "winopen" then
+ w = window.new((arg ~= "") and { arg } or {})
+ end
+ w.win.screen = screen
+ w.win.urgency_hint = true
+ end)
+end
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
diff --git a/luakit/theme.lua b/luakit/theme.lua
new file mode 100644
index 0000000..e53390b
--- /dev/null
+++ b/luakit/theme.lua
@@ -0,0 +1,74 @@
+--------------------------
+-- Default luakit theme --
+--------------------------
+
+local theme = {}
+
+-- Default settings
+theme.font = "terminus 8"
+theme.fg = "#fff"
+theme.bg = "#000"
+
+-- Genaral colours
+theme.success_fg = "#0f0"
+theme.loaded_fg = "#33AADD"
+theme.error_fg = "#FFF"
+theme.error_bg = "#F00"
+
+-- Warning colours
+theme.warning_fg = "#F00"
+theme.warning_bg = "#FFF"
+
+-- Notification colours
+theme.notif_fg = "#444"
+theme.notif_bg = "#FFF"
+
+-- Menu colours
+theme.menu_fg = "#000"
+theme.menu_bg = "#fff"
+theme.menu_selected_fg = "#000"
+theme.menu_selected_bg = "#FF0"
+theme.menu_title_bg = "#fff"
+theme.menu_primary_title_fg = "#f00"
+theme.menu_secondary_title_fg = "#666"
+
+-- Proxy manager
+theme.proxy_active_menu_fg = '#000'
+theme.proxy_active_menu_bg = '#FFF'
+theme.proxy_inactive_menu_fg = '#888'
+theme.proxy_inactive_menu_bg = '#FFF'
+
+-- Statusbar specific
+theme.sbar_fg = "#fff"
+theme.sbar_bg = "#000"
+
+-- Downloadbar specific
+theme.dbar_fg = "#fff"
+theme.dbar_bg = "#000"
+theme.dbar_error_fg = "#F00"
+
+-- Input bar specific
+--theme.ibar_fg = "#000"
+--theme.ibar_bg = "#fff"
+theme.ibar_bg = "#000"
+theme.ibar_fg = "#fff"
+
+-- Tab label
+--theme.tab_fg = "#888"
+theme.tab_fg = "#aaa"
+--theme.tab_bg = "#222"
+theme.tab_bg = "#000"
+theme.tab_ntheme = "#ddd"
+theme.selected_fg = "#fff"
+--theme.selected_bg = "#000"
+theme.selected_bg = "#056"
+theme.selected_ntheme = "#ddd"
+theme.loading_fg = "#33AADD"
+theme.loading_bg = "#000"
+
+-- Trusted/untrusted ssl colours
+theme.trust_fg = "#0F0"
+theme.notrust_fg = "#F00"
+
+return theme
+-- vim: et:sw=4:ts=8:sts=4:tw=80
diff --git a/luakit/webview.lua b/luakit/webview.lua
new file mode 100644
index 0000000..a7a7a59
--- /dev/null
+++ b/luakit/webview.lua
@@ -0,0 +1,350 @@
+--------------------------
+-- WebKit WebView class --
+--------------------------
+
+-- Webview class table
+webview = {}
+
+-- Table of functions which are called on new webview widgets.
+webview.init_funcs = {
+ -- Set useragent
+ set_useragent = function (view, w)
+ view.user_agent = globals.useragent
+ end,
+
+ -- Check if checking ssl certificates
+ checking_ssl = function (view, w)
+ local ca_file = soup.ssl_ca_file
+ if ca_file and os.exists(ca_file) then
+ w.checking_ssl = true
+ end
+ end,
+
+ -- Update window and tab titles
+ title_update = function (view, w)
+ view:add_signal("property::title", function (v)
+ w:update_tablist()
+ if w.view == v then
+ w:update_win_title()
+ end
+ end)
+ end,
+
+ -- Update uri label in statusbar
+ uri_update = function (view, w)
+ view:add_signal("property::uri", function (v)
+ w:update_tablist()
+ if w.view == v then
+ w:update_uri()
+ end
+ end)
+ end,
+
+ -- Update history indicator
+ hist_update = function (view, w)
+ view:add_signal("load-status", function (v, status)
+ if w.view == v then
+ w:update_hist()
+ end
+ end)
+ end,
+
+ -- Update tab titles
+ tablist_update = function (view, w)
+ view:add_signal("load-status", function (v, status)
+ if status == "provisional" or status == "finished" or status == "failed" then
+ w:update_tablist()
+ end
+ end)
+ end,
+
+ -- Update scroll widget
+ scroll_update = function (view, w)
+ view:add_signal("expose", function (v)
+ if w.view == v then
+ w:update_scroll()
+ end
+ end)
+ end,
+
+ -- Update progress widget
+ progress_update = function (view, w)
+ for _, sig in ipairs({"load-status", "property::progress"}) do
+ view:add_signal(sig, function (v)
+ if w.view == v then
+ w:update_progress()
+ w:update_ssl()
+ end
+ end)
+ end
+ end,
+
+ -- Display hovered link in statusbar
+ link_hover_display = function (view, w)
+ view:add_signal("link-hover", function (v, link)
+ if w.view == v and link then
+ w:update_uri(link)
+ end
+ end)
+ view:add_signal("link-unhover", function (v)
+ if w.view == v then
+ w:update_uri()
+ end
+ end)
+ end,
+
+ -- Clicking a form field automatically enters insert mode.
+ form_insert_mode = function (view, w)
+ view:add_signal("button-press", function (v, mods, button, context)
+ -- Clear start search marker
+ (w.search_state or {}).marker = nil
+
+ if button == 1 and context.editable then
+ view:emit_signal("form-active")
+ end
+ end)
+ -- Emit root-active event in button release to prevent "missing"
+ -- buttons or links when the input bar hides.
+ view:add_signal("button-release", function (v, mods, button, context)
+ if button == 1 and not context.editable then
+ view:emit_signal("root-active")
+ end
+ end)
+ view:add_signal("form-active", function ()
+ if not w.mode.passthrough then
+ w:set_mode("insert")
+ end
+ end)
+ view:add_signal("root-active", function ()
+ if w.mode.reset_on_focus ~= false then
+ w:set_mode()
+ end
+ end)
+ end,
+
+ -- Catch keys in non-passthrough modes
+ mode_key_filter = function (view, w)
+ view:add_signal("key-press", function ()
+ if not w.mode.passthrough then
+ return true
+ end
+ end)
+ end,
+
+ -- Try to match a button event to a users button binding else let the
+ -- press hit the webview.
+ button_bind_match = function (view, w)
+ view:add_signal("button-release", function (v, mods, button, context)
+ (w.search_state or {}).marker = nil
+ if w:hit(mods, button, { context = context }) then
+ return true
+ end
+ end)
+ end,
+
+ -- Reset the mode on navigation
+ mode_reset_on_nav = function (view, w)
+ view:add_signal("load-status", function (v, status)
+ if status == "provisional" and w.view == v then
+ if w.mode.reset_on_navigation ~= false then
+ w:set_mode()
+ end
+ end
+ end)
+ end,
+
+ -- Domain properties
+ domain_properties = function (view, w)
+ view:add_signal("load-status", function (v, status)
+ if status ~= "committed" or v.uri == "about:blank" then return end
+ -- Get domain
+ local domain = lousy.uri.parse(v.uri).host
+ -- Strip leading www.
+ domain = string.match(domain or "", "^www%.(.+)") or domain or "all"
+ -- Build list of domain props tables to join & load.
+ -- I.e. for luakit.org load .luakit.org, luakit.org, .org
+ local props = {domain_props.all or {}, domain_props[domain] or {}}
+ repeat
+ table.insert(props, 2, domain_props["."..domain] or {})
+ domain = string.match(domain, "%.(.+)")
+ until not domain
+ -- Join all property tables
+ for k, v in pairs(lousy.util.table.join(unpack(props))) do
+ info("Domain prop: %s = %s (%s)", k, tostring(v), domain)
+ view[k] = v
+ end
+ end)
+ end,
+
+ -- Action to take on mime type decision request.
+ mime_decision = function (view, w)
+ -- Return true to accept or false to reject from this signal.
+ view:add_signal("mime-type-decision", function (v, uri, mime)
+ info("Requested link: %s (%s)", uri, mime)
+ -- i.e. block binary files like *.exe
+ --if mime == "application/octet-stream" then
+ -- return false
+ --end
+ end)
+ end,
+
+ -- Action to take on window open request.
+ --window_decision = function (view, w)
+ -- view:add_signal("new-window-decision", function (v, uri, reason)
+ -- if reason == "link-clicked" then
+ -- window.new({uri})
+ -- else
+ -- w:new_tab(uri)
+ -- end
+ -- return true
+ -- end)
+ --end,
+
+ create_webview = function (view, w)
+ -- Return a newly created webview in a new tab
+ view:add_signal("create-web-view", function (v)
+ return w:new_tab()
+ end)
+ end,
+
+ -- Creates context menu popup from table (and nested tables).
+ -- Use `true` for menu separators.
+ --populate_popup = function (view, w)
+ -- view:add_signal("populate-popup", function (v)
+ -- return {
+ -- true,
+ -- { "_Toggle Source", function () w:toggle_source() end },
+ -- { "_Zoom", {
+ -- { "Zoom _In", function () w:zoom_in() end },
+ -- { "Zoom _Out", function () w:zoom_out() end },
+ -- true,
+ -- { "Zoom _Reset", function () w:zoom_set() end }, }, },
+ -- }
+ -- end)
+ --end,
+
+ -- Action to take on resource request.
+ resource_request_decision = function (view, w)
+ view:add_signal("resource-request-starting", function(v, uri)
+ info("Requesting: %s", uri)
+ -- Return false to cancel the request.
+ end)
+ end,
+}
+
+-- These methods are present when you index a window instance and no window
+-- method is found in `window.methods`. The window then checks if there is an
+-- active webview and calls the following methods with the given view instance
+-- as the first argument. All methods must take `view` & `w` as the first two
+-- arguments.
+webview.methods = {
+ -- Reload with or without ignoring cache
+ reload = function (view, w, bypass_cache)
+ if bypass_cache then
+ view:reload_bypass_cache()
+ else
+ view:reload()
+ end
+ end,
+
+ -- Toggle source view
+ toggle_source = function (view, w, show)
+ if show == nil then
+ view.view_source = not view.view_source
+ else
+ view.view_source = show
+ end
+ view:reload()
+ end,
+
+ -- Zoom functions
+ zoom_in = function (view, w, step, full_zoom)
+ view.full_content_zoom = not not full_zoom
+ step = step or globals.zoom_step or 0.1
+ view.zoom_level = view.zoom_level + step
+ end,
+
+ zoom_out = function (view, w, step, full_zoom)
+ view.full_content_zoom = not not full_zoom
+ step = step or globals.zoom_step or 0.1
+ view.zoom_level = math.max(0.01, view.zoom_level) - step
+ end,
+
+ zoom_set = function (view, w, level, full_zoom)
+ view.full_content_zoom = not not full_zoom
+ view.zoom_level = level or 1.0
+ end,
+
+ -- History traversing functions
+ back = function (view, w, n)
+ view:go_back(n or 1)
+ end,
+
+ forward = function (view, w, n)
+ view:go_forward(n or 1)
+ end,
+}
+
+function webview.methods.scroll(view, w, new)
+ local s = view.scroll
+ for _, axis in ipairs{ "x", "y" } do
+ -- Relative px movement
+ if rawget(new, axis.."rel") then
+ s[axis] = s[axis] + new[axis.."rel"]
+
+ -- Relative page movement
+ elseif rawget(new, axis .. "pagerel") then
+ s[axis] = s[axis] + math.ceil(s[axis.."page_size"] * new[axis.."pagerel"])
+
+ -- Absolute px movement
+ elseif rawget(new, axis) then
+ local n = new[axis]
+ if n == -1 then
+ s[axis] = s[axis.."max"]
+ else
+ s[axis] = n
+ end
+
+ -- Absolute page movement
+ elseif rawget(new, axis.."page") then
+ s[axis] = math.ceil(s[axis.."page_size"] * new[axis.."page"])
+
+ -- Absolute percent movement
+ elseif rawget(new, axis .. "pct") then
+ s[axis] = math.ceil(s[axis.."max"] * (new[axis.."pct"]/100))
+ end
+ end
+end
+
+function webview.new(w)
+ local view = widget{type = "webview"}
+
+ view.show_scrollbars = false
+ view.enforce_96_dpi = false
+
+ -- Call webview init functions
+ for k, func in pairs(webview.init_funcs) do
+ func(view, w)
+ end
+ return view
+end
+
+-- Insert webview method lookup on window structure
+table.insert(window.indexes, 1, function (w, k)
+ if k == "view" then
+ local view = w.tabs[w.tabs:current()]
+ if view and type(view) == "widget" and view.type == "webview" then
+ w.view = view
+ return view
+ end
+ end
+ -- Lookup webview method
+ local func = webview.methods[k]
+ if not func then return end
+ local view = w.view
+ if view then
+ return function (_, ...) return func(view, w, ...) end
+ end
+end)
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80
diff --git a/luakit/window.lua b/luakit/window.lua
new file mode 100644
index 0000000..5e921d6
--- /dev/null
+++ b/luakit/window.lua
@@ -0,0 +1,859 @@
+------------------
+-- Window class --
+------------------
+
+require "lfs"
+
+-- Window class table
+window = {}
+
+-- List of active windows by window widget
+window.bywidget = setmetatable({}, { __mode = "k" })
+
+-- Widget construction aliases
+local function entry() return widget{type="entry"} end
+local function eventbox() return widget{type="eventbox"} end
+local function hbox() return widget{type="hbox"} end
+local function label() return widget{type="label"} end
+local function notebook() return widget{type="notebook"} end
+local function vbox() return widget{type="vbox"} end
+
+-- Build and pack window widgets
+function window.build()
+ -- Create a table for widgets and state variables for a window
+ local w = {
+ win = widget{type="window"},
+ ebox = eventbox(),
+ layout = vbox(),
+ paned = widget{type="vpaned"},
+ tabs = notebook(),
+ -- Tablist widget
+ tablist = lousy.widget.tablist(),
+ -- Status bar widgets
+ sbar = {
+ layout = hbox(),
+ ebox = eventbox(),
+ -- Left aligned widgets
+ l = {
+ layout = hbox(),
+ ebox = eventbox(),
+ uri = label(),
+ hist = label(),
+ loaded = label(),
+ },
+ -- Fills space between the left and right aligned widgets
+ sep = eventbox(),
+ -- Right aligned widgets
+ r = {
+ layout = hbox(),
+ ebox = eventbox(),
+ buf = label(),
+ ssl = label(),
+ tabi = label(),
+ scroll = label(),
+ },
+ },
+
+ -- Vertical menu window widget (completion results, bookmarks, qmarks, ..)
+ menu = lousy.widget.menu(),
+
+ -- Input bar widgets
+ ibar = {
+ layout = hbox(),
+ ebox = eventbox(),
+ prompt = label(),
+ input = entry(),
+ },
+ closed_tabs = {}
+ }
+
+ -- Assemble window
+ w.ebox.child = w.paned
+ w.paned:pack1(w.layout)
+ w.win.child = w.ebox
+
+ -- Pack tablist
+ w.layout:pack(w.tablist.widget)
+
+ -- Pack notebook
+ w.layout:pack(w.tabs, { expand = true, fill = true })
+
+ -- Pack left-aligned statusbar elements
+ local l = w.sbar.l
+ l.layout:pack(l.uri)
+ l.layout:pack(l.hist)
+ l.layout:pack(l.loaded)
+ l.ebox.child = l.layout
+
+ -- Pack right-aligned statusbar elements
+ local r = w.sbar.r
+ r.layout:pack(r.buf)
+ r.layout:pack(r.ssl)
+ r.layout:pack(r.tabi)
+ r.layout:pack(r.scroll)
+ r.ebox.child = r.layout
+
+ -- Pack status bar elements
+ local s = w.sbar
+ s.layout:pack(l.ebox)
+ s.layout:pack(s.sep, { expand = true, fill = true })
+ s.layout:pack(r.ebox)
+ s.ebox.child = s.layout
+ w.layout:pack(s.ebox)
+
+ -- Pack menu widget
+ w.layout:pack(w.menu.widget)
+ w.menu:hide()
+
+ -- Pack input bar
+ local i = w.ibar
+ i.layout:pack(i.prompt)
+ i.layout:pack(i.input, { expand = true, fill = true })
+ i.ebox.child = i.layout
+ w.layout:pack(i.ebox)
+
+ -- Other settings
+ i.input.show_frame = false
+ w.tabs.show_tabs = false
+ l.loaded:hide()
+ l.hist:hide()
+ l.uri.selectable = true
+ r.ssl:hide()
+
+ -- Allows indexing of window struct by window widget
+ window.bywidget[w.win] = w
+
+ return w
+end
+
+-- Table of functions to call on window creation. Normally used to add signal
+-- handlers to the new windows widgets.
+window.init_funcs = {
+ -- Attach notebook widget signals
+ notebook_signals = function (w)
+ w.tabs:add_signal("page-added", function (nbook, view, idx)
+ luakit.idle_add(function ()
+ w:update_tab_count()
+ w:update_tablist()
+ return false
+ end)
+ end)
+ w.tabs:add_signal("switch-page", function (nbook, view, idx)
+ w.view = nil
+ w:set_mode()
+ -- Update widgets after tab switch
+ luakit.idle_add(function ()
+ w:update_tab_count()
+ w:update_win_title()
+ w:update_uri()
+ w:update_progress()
+ w:update_tablist()
+ w:update_buf()
+ w:update_ssl()
+ w:update_hist()
+ return false
+ end)
+ end)
+ w.tabs:add_signal("page-reordered", function (nbook, view, idx)
+ w:update_tab_count()
+ w:update_tablist()
+ end)
+ end,
+
+ last_win_check = function (w)
+ w.win:add_signal("destroy", function ()
+ -- call the quit function if this was the last window left
+ if #luakit.windows == 0 then luakit.quit() end
+ if w.close_win then w:close_win() end
+ end)
+ end,
+
+ key_press_match = function (w)
+ w.win:add_signal("key-press", function (_, mods, key)
+ -- Match & exec a bind
+ local success, match = xpcall(
+ function () return w:hit(mods, key) end,
+ function (err) w:error(debug.traceback(err, 3)) end)
+
+ if success and match then
+ return true
+ end
+ end)
+ end,
+
+ tablist_tab_click = function (w)
+ w.tablist:add_signal("tab-clicked", function (_, index, mods, button)
+ if button == 1 then
+ w.tabs:switch(index)
+ return true
+ elseif button == 2 then
+ w:close_tab(w.tabs[index])
+ return true
+ end
+ end)
+ end,
+
+ apply_window_theme = function (w)
+ local s, i = w.sbar, w.ibar
+
+ -- Set foregrounds
+ for wi, v in pairs({
+ [s.l.uri] = theme.uri_sbar_fg,
+ [s.l.hist] = theme.hist_sbar_fg,
+ [s.l.loaded] = theme.sbar_loaded_fg,
+ [s.r.buf] = theme.buf_sbar_fg,
+ [s.r.tabi] = theme.tabi_sbar_fg,
+ [s.r.scroll] = theme.scroll_sbar_fg,
+ [i.prompt] = theme.prompt_ibar_fg,
+ [i.input] = theme.input_ibar_fg,
+ }) do wi.fg = v end
+
+ -- Set backgrounds
+ for wi, v in pairs({
+ [s.l.ebox] = theme.sbar_bg,
+ [s.r.ebox] = theme.sbar_bg,
+ [s.sep] = theme.sbar_bg,
+ [s.ebox] = theme.sbar_bg,
+ [i.ebox] = theme.ibar_bg,
+ [i.input] = theme.input_ibar_bg,
+ }) do wi.bg = v end
+
+ -- Set fonts
+ for wi, v in pairs({
+ [s.l.uri] = theme.uri_sbar_font,
+ [s.l.hist] = theme.hist_sbar_font,
+ [s.l.loaded] = theme.sbar_loaded_font,
+ [s.r.buf] = theme.buf_sbar_font,
+ [s.r.ssl] = theme.ssl_sbar_font,
+ [s.r.tabi] = theme.tabi_sbar_font,
+ [s.r.scroll] = theme.scroll_sbar_font,
+ [i.prompt] = theme.prompt_ibar_font,
+ [i.input] = theme.input_ibar_font,
+ }) do wi.font = v end
+ end,
+
+ set_default_size = function (w)
+ local size = globals.default_window_size or "800x600"
+ if string.match(size, "^%d+x%d+$") then
+ w.win:set_default_size(string.match(size, "^(%d+)x(%d+)$"))
+ else
+ warn("E: window.lua: invalid window size: %q", size)
+ end
+ end,
+
+ set_window_icon = function (w)
+ local path = (luakit.dev_paths and os.exists("./extras/luakit.png")) or
+ os.exists("/usr/share/pixmaps/luakit.png")
+ if path then w.win.icon = path end
+ end,
+
+ clear_urgency_hint = function (w)
+ w.win:add_signal("focus", function ()
+ w.win.urgency_hint = false
+ end)
+ end,
+}
+
+-- Helper functions which operate on the window widgets or structure.
+window.methods = {
+ -- Wrapper around the bind plugin's hit method
+ hit = function (w, mods, key, opts)
+ local opts = lousy.util.table.join(opts or {}, {
+ enable_buffer = w:is_mode("normal"),
+ buffer = w.buffer,
+ })
+
+ local caught, newbuf = lousy.bind.hit(w, w.binds, mods, key, opts)
+ if w.win then -- Check binding didn't cause window to exit
+ w.buffer = newbuf
+ w:update_buf()
+ end
+ return caught
+ end,
+
+ -- Wrapper around the bind plugin's match_cmd method
+ match_cmd = function (w, buffer)
+ return lousy.bind.match_cmd(w, get_mode("command").binds, buffer)
+ end,
+
+ -- enter command or characters into command line
+ enter_cmd = function (w, cmd, opts)
+ w:set_mode("command")
+ w:set_input(cmd, opts)
+ end,
+
+ -- run command as if typed into the command line
+ run_cmd = function (w, cmd, opts)
+ w:enter_cmd(cmd, opts)
+ w:activate()
+ end,
+
+ -- insert a string into the command line at the current cursor position
+ insert_cmd = function (w, str)
+ if not str then return end
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+ local left, right = string.sub(text, 1, pos), string.sub(text, pos+1)
+ i.text = left .. str .. right
+ i.position = pos + #str
+ end,
+
+ -- Emulates pressing the Return key in input field
+ activate = function (w)
+ w.ibar.input:emit_signal("activate")
+ end,
+
+ del_word = function (w)
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+ if text and #text > 1 and pos > 1 then
+ local left, right = string.sub(text, 2, pos), string.sub(text, pos+1)
+ if not string.find(left, "%s") then
+ left = ""
+ elseif string.find(left, "%w+%s*$") then
+ left = string.sub(left, 0, string.find(left, "%w+%s*$") - 1)
+ elseif string.find(left, "%W+%s*$") then
+ left = string.sub(left, 0, string.find(left, "%W+%s*$") - 1)
+ end
+ i.text = string.sub(text, 1, 1) .. left .. right
+ i.position = #left + 1
+ end
+ end,
+
+ del_line = function (w)
+ local i = w.ibar.input
+ if not string.match(i.text, "^[:/?]$") then
+ i.text = string.sub(i.text, 1, 1)
+ i.position = -1
+ end
+ end,
+
+ del_backward_char = function (w)
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+
+ if pos > 1 then
+ i.text = string.sub(text, 0, pos - 1) .. string.sub(text, pos + 1)
+ i.position = pos - 1
+ end
+ end,
+
+ del_forward_char = function (w)
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+
+ i.text = string.sub(text, 0, pos) .. string.sub(text, pos + 2)
+ i.position = pos
+ end,
+
+ beg_line = function (w)
+ local i = w.ibar.input
+ i.position = 1
+ end,
+
+ end_line = function (w)
+ local i = w.ibar.input
+ i.position = -1
+ end,
+
+ forward_char = function (w)
+ local i = w.ibar.input
+ i.position = i.position + 1
+ end,
+
+ backward_char = function (w)
+ local i = w.ibar.input
+ local pos = i.position
+ if pos > 1 then
+ i.position = pos - 1
+ end
+ end,
+
+ forward_word = function (w)
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+ if text and #text > 1 then
+ local right = string.sub(text, pos+1)
+ if string.find(right, "%w+") then
+ local _, move = string.find(right, "%w+")
+ i.position = pos + move
+ end
+ end
+ end,
+
+ backward_word = function (w)
+ local i = w.ibar.input
+ local text = i.text
+ local pos = i.position
+ if text and #text > 1 and pos > 1 then
+ local left = string.reverse(string.sub(text, 2, pos))
+ if string.find(left, "%w+") then
+ local _, move = string.find(left, "%w+")
+ i.position = pos - move
+ end
+ end
+ end,
+
+ -- Shows a notification until the next keypress of the user.
+ notify = function (w, msg, set_mode)
+ if set_mode ~= false then w:set_mode() end
+ w:set_prompt(msg, { fg = theme.notif_fg, bg = theme.notif_bg })
+ end,
+
+ warning = function (w, msg, set_mode)
+ if set_mode ~= false then w:set_mode() end
+ w:set_prompt(msg, { fg = theme.warning_fg, bg = theme.warning_bg })
+ end,
+
+ error = function (w, msg, set_mode)
+ if set_mode ~= false then w:set_mode() end
+ w:set_prompt("Error: "..msg, { fg = theme.error_fg, bg = theme.error_bg })
+ end,
+
+ -- Set and display the prompt
+ set_prompt = function (w, text, opts)
+ local prompt, ebox, opts = w.ibar.prompt, w.ibar.ebox, opts or {}
+ prompt:hide()
+ -- Set theme
+ fg, bg = opts.fg or theme.ibar_fg, opts.bg or theme.ibar_bg
+ if prompt.fg ~= fg then prompt.fg = fg end
+ if ebox.bg ~= bg then ebox.bg = bg end
+ -- Set text or remain hidden
+ if text then
+ prompt.text = lousy.util.escape(text)
+ prompt:show()
+ end
+ end,
+
+ -- Set display and focus the input bar
+ set_input = function (w, text, opts)
+ local input, opts = w.ibar.input, opts or {}
+ input:hide()
+ -- Set theme
+ fg, bg = opts.fg or theme.ibar_fg, opts.bg or theme.ibar_bg
+ if input.fg ~= fg then input.fg = fg end
+ if input.bg ~= bg then input.bg = bg end
+ -- Set text or remain hidden
+ if text then
+ input.text = ""
+ input:show()
+ input:focus()
+ input.text = text
+ input.position = opts.pos or -1
+ end
+ end,
+
+ -- GUI content update functions
+ update_tab_count = function (w)
+ w.sbar.r.tabi.text = string.format("[%d/%d]", w.tabs:current(), w.tabs:count())
+ end,
+
+ update_win_title = function (w)
+ local uri, title = w.view.uri, w.view.title
+ title = (title or "luakit") .. ((uri and " - " .. uri) or "")
+ local max = globals.max_title_len or 80
+ if #title > max then title = string.sub(title, 1, max) .. "..." end
+ w.win.title = title
+ end,
+
+ update_uri = function (w, link)
+ w.sbar.l.uri.text = lousy.util.escape((link and "Link: " .. link)
+ or (w.view and w.view.uri) or "about:blank")
+ end,
+
+ update_progress = function (w)
+ local p = w.view.progress
+ local loaded = w.sbar.l.loaded
+ if not w.view:loading() or p == 1 then
+ loaded:hide()
+ else
+ loaded:show()
+ loaded.text = string.format("(%d%%)", p * 100)
+ end
+ end,
+
+ update_scroll = function (w)
+ local scroll, label = w.view.scroll, w.sbar.r.scroll
+ local y, max, text = scroll.y, scroll.ymax
+ if max == 0 then text = "All"
+ elseif y == 0 then text = "Top"
+ elseif y == max then text = "Bot"
+ else text = string.format("%2d%%", (y / max) * 100)
+ end
+ if label.text ~= text then label.text = text end
+ end,
+
+ update_ssl = function (w)
+ local trusted = w.view:ssl_trusted()
+ local ssl = w.sbar.r.ssl
+ if trusted ~= nil and not w.checking_ssl then
+ ssl.fg = theme.notrust_fg
+ ssl.text = "(nocheck)"
+ ssl:show()
+ elseif trusted == true then
+ ssl.fg = theme.trust_fg
+ ssl.text = "(trust)"
+ ssl:show()
+ elseif trusted == false then
+ ssl.fg = theme.notrust_fg
+ ssl.text = "(notrust)"
+ ssl:show()
+ else
+ ssl:hide()
+ end
+ end,
+
+ update_hist = function (w)
+ local hist = w.sbar.l.hist
+ local back, forward = w.view:can_go_back(), w.view:can_go_forward()
+ local s = (back and "+" or "") .. (forward and "-" or "")
+ if s ~= "" then
+ hist.text = '['..s..']'
+ hist:show()
+ else
+ hist:hide()
+ end
+ end,
+
+ update_buf = function (w)
+ local buf = w.sbar.r.buf
+ if w.buffer then
+ buf.text = lousy.util.escape(string.format(" %-3s", w.buffer))
+ buf:show()
+ else
+ buf:hide()
+ end
+ end,
+
+ update_binds = function (w, mode)
+ -- Generate the list of active key & buffer binds for this mode
+ w.binds = lousy.util.table.join((get_mode(mode) or {}).binds or {}, get_mode('all').binds or {})
+ -- Clear & hide buffer
+ w.buffer = nil
+ w:update_buf()
+ end,
+
+ update_tablist = function (w)
+ local current = w.tabs:current()
+ local fg, bg, nfg, snfg = theme.tab_fg, theme.tab_bg, theme.tab_ntheme, theme.selected_ntheme
+ local lfg, bfg, gfg = theme.tab_loading_fg, theme.tab_notrust_fg, theme.tab_trust_fg
+ local escape = lousy.util.escape
+ local tabs, tfmt = {}, ' %s %s'
+
+ for i, view in ipairs(w.tabs.children) do
+ -- Get tab number theme
+ local ntheme = nfg
+ if view:loading() then -- Show loading on all tabs
+ ntheme = lfg
+ elseif current == i then -- Show ssl trusted/untrusted on current tab
+ local trusted = view:ssl_trusted()
+ ntheme = snfg
+ if trusted == false or (trusted ~= nil and not w.checking_ssl) then
+ ntheme = bfg
+ elseif trusted then
+ ntheme = gfg
+ end
+ end
+ local title = view.title or view.uri or "(Untitled)"
+ tabs[i] = {
+ title = string.format(tfmt, ntheme or fg, i, escape(title)),
+ fg = (current == i and theme.tab_selected_fg) or fg,
+ bg = (current == i and theme.tab_selected_bg) or bg,
+ }
+ end
+
+ if #tabs < 2 then tabs, current = {}, 0 end
+ w.tablist:update(tabs, current)
+ end,
+
+ new_tab = function (w, arg, switch, order)
+ local view
+ -- Use blank tab first
+ if w.has_blank and w.tabs:count() == 1 and w.tabs[1].uri == "about:blank" then
+ view = w.tabs[1]
+ end
+ w.has_blank = nil
+ -- Make new webview widget
+ if not view then
+ view = webview.new(w)
+ -- Get tab order function
+ if not order and taborder then
+ order = (switch == false and taborder.default_bg)
+ or taborder.default
+ end
+ pos = w.tabs:insert((order and order(w, view)) or -1, view)
+ if switch ~= false then w.tabs:switch(pos) end
+ end
+ -- Load uri or webview history table
+ if type(arg) == "string" then view.uri = arg
+ elseif type(arg) == "table" then view.history = arg end
+ -- Update statusbar widgets
+ w:update_tab_count()
+ w:update_tablist()
+ return view
+ end,
+
+ -- close the current tab
+ close_tab = function (w, view, blank_last)
+ view = view or w.view
+ -- Treat a blank last tab as an empty notebook (if blank_last=true)
+ if blank_last ~= false and w.tabs:count() == 1 then
+ if not view:loading() and view.uri == "about:blank" then return end
+ w:new_tab("about:blank", false)
+ w.has_blank = true
+ end
+ -- Save tab history
+ local tab = {hist = view.history,}
+ -- And relative location
+ local index = w.tabs:indexof(view)
+ if index ~= 1 then tab.after = w.tabs[index-1] end
+ table.insert(w.closed_tabs, tab)
+ view:destroy()
+ w:update_tab_count()
+ w:update_tablist()
+ end,
+
+ close_win = function (w, force)
+ -- Ask plugins if it's OK to close last window
+ if not force and (#luakit.windows == 1) then
+ local emsg = luakit.emit_signal("can-close", w)
+ if emsg then
+ assert(type(emsg) == "string", "invalid exit error message")
+ w:error(string.format("Can't close luakit: %s (force close "
+ .. "with :q! or :wq!)", emsg))
+ return false
+ end
+ end
+
+ w:emit_signal("close")
+
+ -- Close all tabs
+ while w.tabs:count() ~= 0 do
+ w:close_tab(nil, false)
+ end
+
+ -- Destroy tablist
+ w.tablist:destroy()
+
+ -- Remove from window index
+ window.bywidget[w.win] = nil
+
+ -- Clear window struct
+ w = setmetatable(w, {})
+
+ -- Recursively remove widgets from window
+ local children = lousy.util.recursive_remove(w.win)
+ -- Destroy all widgets
+ for i, c in ipairs(lousy.util.table.join(children, {w.win})) do
+ if c.hide then c:hide() end
+ c:destroy()
+ end
+
+ -- Remove all window table vars
+ for k, _ in pairs(w) do w[k] = nil end
+
+ -- Quit if closed last window
+ if #luakit.windows == 0 then luakit.quit() end
+ end,
+
+ -- Navigate current view or open new tab
+ navigate = function (w, uri, view)
+ view = view or w.view
+ if view then
+ local js = string.match(uri, "^javascript:(.+)$")
+ if js then
+ return view:eval_js(luakit.uri_decode(js))
+ end
+ view.uri = uri
+ else
+ return w:new_tab(uri)
+ end
+ end,
+
+ -- Save, restart luakit and reload session.
+ restart = function (w)
+ -- Generate luakit launch command.
+ local args = {({string.gsub(luakit.execpath, " ", "\\ ")})[1]}
+ if luakit.verbose then table.insert(args, "-v") end
+ -- Relaunch without libunique bindings?
+ if luakit.nounique then table.insert(args, "-U") end
+
+ -- Get new config path
+ local conf
+ if luakit.confpath ~= "/etc/xdg/luakit/rc.lua" and os.exists(luakit.confpath) then
+ conf = luakit.confpath
+ table.insert(args, string.format("-c %q", conf))
+ end
+
+ -- Check config has valid syntax
+ local cmd = table.concat(args, " ")
+ if luakit.spawn_sync(cmd .. " -k") ~= 0 then
+ return w:error("Cannot restart, syntax error in configuration file"..((conf and ": "..conf) or "."))
+ end
+
+ -- Save session.
+ local wins = {}
+ for _, w in pairs(window.bywidget) do table.insert(wins, w) end
+ session.save(wins)
+
+ -- Replace current process with new luakit instance.
+ luakit.exec(cmd)
+ end,
+
+ -- Intelligent open command which can detect a uri or search argument.
+ search_open = function (w, arg)
+ local lstring = lousy.util.string
+ local match, find = string.match, string.find
+
+ -- Detect blank uris
+ if not arg or match(arg, "^%s*$") then return "about:blank" end
+
+ -- Strip whitespace and split by whitespace into args table
+ local args = lstring.split(lstring.strip(arg))
+
+ -- Guess if first argument is an address, search engine, file
+ if #args == 1 then
+ local uri = args[1]
+ if uri == "about:blank" then return uri end
+
+ -- Check if search engine name
+ if search_engines[uri] then
+ return string.format(search_engines[uri], "")
+ end
+
+ -- Navigate if . or / in uri (I.e. domains, IP's, scheme://)
+ if find(uri, "%.") or find(uri, "/") then return uri end
+
+ -- Navigate if this is a javascript-uri
+ if find(uri, "^javascript:") then return uri end
+
+ -- Valid hostnames to check
+ local hosts = { "localhost" }
+ if globals.load_etc_hosts ~= false then
+ hosts = lousy.util.get_etc_hosts()
+ end
+
+ -- Check hostnames
+ for _, h in pairs(hosts) do
+ if h == uri or match(uri, "^"..h..":%d+$") then return uri end
+ end
+
+ -- Check for file in filesystem
+ if globals.check_filepath ~= false then
+ if lfs.attributes(uri) then return "file://" .. uri end
+ end
+ end
+
+ -- Find search engine (or use search_engines.default)
+ local engine = "default"
+ if args[1] and search_engines[args[1]] then
+ engine = args[1]
+ table.remove(args, 1)
+ end
+
+ -- URI encode search terms
+ local terms = luakit.uri_encode(table.concat(args, " "))
+ return string.format(search_engines[engine], terms)
+ end,
+
+ -- Increase (or decrease) the last found number in the current uri
+ inc_uri = function (w, arg)
+ local uri = string.gsub(w.view.uri, "(%d+)([^0-9]*)$", function (num, rest)
+ return string.format("%0"..#num.."d", tonumber(num) + (arg or 1)) .. rest
+ end)
+ return uri
+ end,
+
+ -- Tab traversing functions
+ next_tab = function (w, n)
+ w.tabs:switch((((n or 1) + w.tabs:current() -1) % w.tabs:count()) + 1)
+ end,
+
+ prev_tab = function (w, n)
+ w.tabs:switch(((w.tabs:current() - (n or 1) -1) % w.tabs:count()) + 1)
+ end,
+
+ goto_tab = function (w, n)
+ if n and (n == -1 or n > 0) then
+ return w.tabs:switch((n <= w.tabs:count() and n) or -1)
+ end
+ end,
+
+ -- For each tab, switches to that tab and calls the given function passing
+ -- it the view contained in the tab.
+ each_tab = function (w, fn)
+ for index = 1, w.tabs:count() do
+ w:goto_tab(index)
+ fn(w.tabs[index])
+ end
+ end,
+
+ -- If argument is form-active or root-active, emits signal. Ignores all
+ -- other signals.
+ emit_form_root_active_signal = function (w, s)
+ if s == "form-active" then
+ w.view:emit_signal("form-active")
+ elseif s == "root-active" then
+ w.view:emit_signal("root-active")
+ end
+ end,
+}
+
+-- Ordered list of class index functions. Other classes (E.g. webview) are able
+-- to add their own index functions to this list.
+window.indexes = {
+ -- Find function in window.methods first
+ function (w, k) return window.methods[k] end
+}
+
+-- Create new window
+function window.new(uris)
+ local w = window.build()
+
+ -- Set window metatable
+ setmetatable(w, {
+ __index = function (_, k)
+ -- Check widget structure first
+ local v = rawget(w, k)
+ if v then return v end
+ -- Call each window index function
+ for _, index in ipairs(window.indexes) do
+ v = index(w, k)
+ if v then return v end
+ end
+ end,
+ })
+
+ -- Setup window widget for signals
+ lousy.signal.setup(w)
+
+ -- Call window init functions
+ for _, func in pairs(window.init_funcs) do
+ func(w)
+ end
+
+ -- Populate notebook with tabs
+ for _, uri in ipairs(uris or {}) do
+ w:new_tab(w:search_open(uri), false)
+ end
+
+ -- Make sure something is loaded
+ if w.tabs:count() == 0 then
+ w:new_tab(w:search_open(globals.homepage), false)
+ end
+
+ -- Set initial mode
+ w:set_mode()
+
+ -- Show window
+ w.win:show()
+
+ return w
+end
+
+-- vim: et:sw=4:ts=8:sts=4:tw=80