Dict lookups: have them always interruptible

They should be now interruptible when fuzzy search is disabled
and on Android.
pull/5178/head
poire-z 5 years ago committed by Frans de Jonge
parent 8749a3c5b6
commit a82d7832b9

@ -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
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
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 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

Loading…
Cancel
Save