mirror of
https://github.com/koreader/koreader.git
synced 2025-12-18 12:02:09 +01:00
Dict lookups: have them always interruptible
They should be now interruptible when fuzzy search is disabled and on Android.
This commit is contained in:
@@ -673,41 +673,29 @@ function ReaderDictionary:startSdcv(word, dict_names, fuzzy_search)
|
||||
end
|
||||
end
|
||||
|
||||
local results_str = nil
|
||||
if Device:isAndroid() then
|
||||
local A = require("android")
|
||||
results_str = A.stdout(unpack(args))
|
||||
else
|
||||
local cmd = util.shell_escape(args)
|
||||
-- cmd = "sleep 7 ; " .. cmd -- uncomment to simulate long lookup time
|
||||
local cmd = util.shell_escape(args)
|
||||
-- cmd = "sleep 7 ; " .. cmd -- uncomment to simulate long lookup time
|
||||
|
||||
-- Some sdcv lookups, when using fuzzy search with many dictionaries
|
||||
-- and a really bad selected text, can take up to 10 seconds.
|
||||
-- It is nice to be able to cancel it when noticing wrong text was
|
||||
-- selected.
|
||||
-- Because sdcv starts outputing its output only at the end when it has
|
||||
-- done its work, we can use Trapper:dismissablePopen() to cancel it as
|
||||
-- long as we are waiting for output.
|
||||
-- When fuzzy search is enabled, we have a lookup_progress_msg that can
|
||||
-- be used to catch a tap and trigger cancellation.
|
||||
-- When fuzzy search is disabled, we provide false instead so an
|
||||
-- invisible non-event-forwarding TrapWidget is used to catch a tap
|
||||
-- and trigger cancellation (invisible so there's no need for repaint
|
||||
-- and refresh with the usually fast non-fuzzy search lookups).
|
||||
-- We must ensure we will have some output to be readable (if no
|
||||
-- definition found, sdcv will output some message on stderr, and
|
||||
-- let stdout empty) by appending an "echo":
|
||||
cmd = cmd .. "; echo"
|
||||
local completed, results_str = Trapper:dismissablePopen(cmd, self.lookup_progress_msg or false)
|
||||
lookup_cancelled = not completed
|
||||
|
||||
if self.lookup_progress_msg then
|
||||
-- Some sdcv lookups, when using fuzzy search with many dictionaries
|
||||
-- and a really bad selected text, can take up to 10 seconds.
|
||||
-- It is nice to be able to cancel it when noticing wrong text was selected.
|
||||
-- As we have a lookup_progress_msg (that can be used to catch a tap
|
||||
-- and trigger cancellation), and because sdcv starts outputing its
|
||||
-- output only at the end when it has done its work, we can
|
||||
-- use Trapper:dismissablePopen() to cancel it as long as we are waiting
|
||||
-- for output.
|
||||
-- We must ensure we will have some output to be readable (if no
|
||||
-- definition found, sdcv will output some message on stderr, and
|
||||
-- let stdout empty) by appending an "echo":
|
||||
cmd = cmd .. "; echo"
|
||||
local completed
|
||||
completed, results_str = Trapper:dismissablePopen(cmd, self.lookup_progress_msg)
|
||||
lookup_cancelled = not completed
|
||||
else
|
||||
-- Fuzzy search disabled, usual option for people who don't want
|
||||
-- a "Looking up..." InfoMessage and usually fast: do a classic
|
||||
-- blocking io.popen()
|
||||
local std_out = io.popen(cmd, "r")
|
||||
if std_out then
|
||||
results_str = std_out:read("*all")
|
||||
std_out:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
if results_str and results_str ~= "\n" then -- \n is when lookup was cancelled
|
||||
local ok, results = pcall(JSON.decode, results_str)
|
||||
if ok and results then
|
||||
|
||||
@@ -314,8 +314,9 @@ Notes and limitations:
|
||||
3) We need a @{ui.widget.trapwidget|TrapWidget} or @{ui.widget.infomessage|InfoMessage},
|
||||
that, as a modal, will catch any @{ui.event|Tap event} happening during
|
||||
`cmd` execution. This can be an existing already displayed widget, or
|
||||
provided as a string (a new TrapWidget will be created). If nil, an invisible
|
||||
TrapWidget will be used instead.
|
||||
provided as a string (a new TrapWidget will be created). If nil, true or false,
|
||||
an invisible TrapWidget will be used instead (if nil or true, the event will be
|
||||
resent; if false, the event will not be resent).
|
||||
|
||||
If we really need to have more control, we would need to use `select()` via `ffi`
|
||||
or do low level non-blocking reading on the file descriptor.
|
||||
@@ -324,7 +325,7 @@ collect indefinitely, the best option would be to compile any `timeout.c`
|
||||
and use it as a wrapper.
|
||||
|
||||
@string cmd shell `cmd` to execute and get output from
|
||||
@param trap_widget_or_string already shown widget, string or nil
|
||||
@param trap_widget_or_string already shown widget, string, or nil, true or false
|
||||
@treturn boolean completed (`true` if not interrupted, `false` if dismissed)
|
||||
@treturn string output of command
|
||||
]]
|
||||
@@ -358,10 +359,15 @@ function Trapper:dismissablePopen(cmd, trap_widget_or_string)
|
||||
UIManager:show(trap_widget)
|
||||
UIManager:forceRePaint()
|
||||
else
|
||||
-- Use an invisible TrapWidget that resend event
|
||||
-- Use an invisible TrapWidget that resend event, but not if
|
||||
-- trap_widget_or_string is false (rather than nil or true)
|
||||
local resend_event = true
|
||||
if trap_widget_or_string == false then
|
||||
resend_event = false
|
||||
end
|
||||
trap_widget = TrapWidget:new{
|
||||
text = nil,
|
||||
resend_event = true,
|
||||
resend_event = resend_event,
|
||||
}
|
||||
UIManager:show(trap_widget)
|
||||
own_trap_widget_invisible = true
|
||||
@@ -472,11 +478,12 @@ Notes and limitations:
|
||||
4) We need a @{ui.widget.trapwidget|TrapWidget} or @{ui.widget.infomessage|InfoMessage},
|
||||
that, as a modal, will catch any @{ui.event|Tap event} happening during
|
||||
`cmd` execution. This can be an existing already displayed widget, or
|
||||
provided as a string (a new TrapWidget will be created). If nil, an invisible
|
||||
TrapWidget will be used instead.
|
||||
provided as a string (a new TrapWidget will be created). If nil, true or false,
|
||||
an invisible TrapWidget will be used instead (if nil or true, the event will be
|
||||
resent; if false, the event will not be resent).
|
||||
|
||||
@function task lua function to execute and get return values from
|
||||
@param trap_widget_or_string already shown widget, string or nil
|
||||
@param trap_widget_or_string already shown widget, string, or nil, true or false
|
||||
@boolean task_returns_simple_string[opt=false] true if task returns a single string
|
||||
@treturn boolean completed (`true` if not interrupted, `false` if dismissed)
|
||||
@return ... return values of task
|
||||
@@ -504,10 +511,15 @@ function Trapper:dismissableRunInSubprocess(task, trap_widget_or_string, task_re
|
||||
UIManager:show(trap_widget)
|
||||
UIManager:forceRePaint()
|
||||
else
|
||||
-- Use an invisible TrapWidget that resend event
|
||||
-- Use an invisible TrapWidget that resend event, but not if
|
||||
-- trap_widget_or_string is false (rather than nil or true)
|
||||
local resend_event = true
|
||||
if trap_widget_or_string == false then
|
||||
resend_event = false
|
||||
end
|
||||
trap_widget = TrapWidget:new{
|
||||
text = nil,
|
||||
resend_event = true,
|
||||
resend_event = resend_event,
|
||||
}
|
||||
UIManager:show(trap_widget)
|
||||
own_trap_widget_invisible = true
|
||||
|
||||
@@ -115,16 +115,13 @@ function TrapWidget:_dismissAndResent(evtype, ev)
|
||||
self.dismiss_callback()
|
||||
UIManager:close(self)
|
||||
if self.resend_event and evtype and ev then
|
||||
-- XXX There may be timing problems that could cause crashes, as we
|
||||
-- There may be some timing issues that could cause crashes, as we
|
||||
-- use nextTick, if the dismiss_callback uses UIManager:scheduleIn()
|
||||
-- or has set up some widget that may catch that event while not being
|
||||
-- yet fully initialiazed.
|
||||
-- It happened mostly when I had some bug somewhere, and it was a quite
|
||||
-- (It happened mostly when I had some bug somewhere, and it was a quite
|
||||
-- reliable sign of a bug somewhere, but the stacktrace was unrelated
|
||||
-- to the bug location.
|
||||
-- Fix to avoid crashes: in GestureRange:match(), check that self.range()
|
||||
-- does not return nil before using it:
|
||||
-- if not range or not range:contains(gs.pos) then return false
|
||||
-- to the bug location.)
|
||||
UIManager:nextTick(function() UIManager:handleInputEvent(Event:new(evtype, ev)) end)
|
||||
end
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user