1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
|
------------------------------------------------------
-- Search for a string in the current webview --
-- © 2010 Mason Larobina <mason.larobina@gmail.com> --
------------------------------------------------------
-- Add searching binds to normal mode
local key = lousy.bind.key
add_binds("normal", {
key({}, "/", "Search for string on current page.",
function (w) w:start_search("/") end),
key({}, "?", "Reverse search for string on current page.",
function (w) w:start_search("?") end),
key({}, "n", "Find next search result.", function (w, m)
for i=1,m.count do w:search(nil, true) end
if w.search_state.ret == false then
w:error("Pattern not found: " .. w.search_state.last_search)
elseif w.search_state.wrapped then
if w.search_state.forward then
w:warning("Search hit BOTTOM, continuing at TOP")
else
w:warning("Search hit TOP, continuing at BOTTOM")
end
end
end, {count=1}),
key({}, "N", "Find previous search result.", function (w, m)
for i=1,m.count do w:search(nil, false) end
if w.search_state.ret == false then
w:error("Pattern not found: " .. w.search_state.last_search)
elseif w.search_state.wrapped then
if w.search_state.forward then
w:warning("Search hit TOP, continuing at BOTTOM")
else
w:warning("Search hit BOTTOM, continuing at TOP")
end
end
end, {count=1}),
})
-- Setup search mode
new_mode("search", {
enter = function (w)
-- Clear old search state
w.search_state = {}
w:set_prompt()
w:set_input("/")
end,
leave = function (w)
w.ibar.input.fg = theme.ibar_fg
w.ibar.input.bg = theme.ibar_bg
-- Check if search was aborted and return to original position
local s = w.search_state
if s.marker then
w:scroll(s.marker)
s.marker = nil
end
end,
changed = function (w, text)
-- Check that the first character is '/' or '?' and update search
if string.match(text, "^[?/]") then
s = w.search_state
s.last_search = string.sub(text, 2)
if #text > 3 then
w:search(string.sub(text, 2), (string.sub(text, 1, 1) == "/"))
if s.ret == false then
if s.marker then w:scroll(s.marker) end
w.ibar.input.fg = theme.ibar_error_fg
w.ibar.input.bg = theme.ibar_error_bg
else
w.ibar.input.fg = theme.ibar_fg
w.ibar.input.bg = theme.ibar_bg
end
else
w:clear_search(false)
end
else
w:clear_search()
w:set_mode()
end
end,
activate = function (w, text)
w.search_state.marker = nil
-- Search if haven't already (won't have for short strings)
if not w.search_state.searched then
w:search(string.sub(text, 2), (string.sub(text, 1, 1) == "/"))
end
-- Ghost the last search term
if w.search_state.ret then
w:set_mode()
w:set_prompt(text)
else
w:error("Pattern not found: " .. string.sub(text, 2))
end
end,
history = {maxlen = 50},
})
-- Add binds to search mode
add_binds("search", {
key({"Control"}, "j", "Select next search result.", function (w)
w:search(w.search_state.last_search, true)
end),
key({"Control"}, "k", "Select previous result.", function (w)
w:search(w.search_state.last_search, false)
end),
})
-- Add search functions to webview
for k, m in pairs({
start_search = function (view, w, text)
if string.match(text, "^[?/]") then
w:set_mode("search")
if not string.match(text, "^/$") then w:set_input(text) end
else
return error("invalid search term, must start with '?' or '/'")
end
end,
search = function (view, w, text, forward, wrap)
if forward == nil then forward = true end
-- Get search state (or new state)
if not w.search_state then w.search_state = {} end
local s = w.search_state
-- Check if wrapping should be performed
if wrap == nil then
if s.wrap ~= nil then wrap = s.wrap else wrap = true end
end
-- Get search term
text = text or s.last_search
if not text or #text == 0 then
return w:clear_search()
end
s.last_search = text
if s.forward == nil then
-- Haven't searched before, save some state.
s.forward = forward
s.wrap = wrap
local scroll = view.scroll
s.marker = { x = scroll.x, y = scroll.y }
else
-- Invert direction if originally searching in reverse
forward = (s.forward == forward)
end
s.searched = true
s.wrapped = false
s.ret = view:search(text, text ~= string.lower(text), forward, s.wrapped);
if not s.ret and wrap then
s.wrapped = true
s.ret = view:search(text, text ~= string.lower(text), forward, s.wrapped);
end
end,
clear_search = function (view, w, clear_state)
w.ibar.input.fg = theme.ibar_fg
w.ibar.input.bg = theme.ibar_bg
view:clear_search()
if clear_state ~= false then
w.search_state = {}
else
w.search_state.searched = false
end
end,
}) do webview.methods[k] = m end
-- vim: et:sw=4:ts=8:sts=4:tw=80
|