[doc] Tag @todo, @fixme and @warning (#5244)

This commit standardizes the various todos around the code a bit in a manner recognized by LDoc.

Besides drawing more attention by being displayed in the developer docs, they're also extractable with LDoc on the command line:

```sh
ldoc --tags todo,fixme *.lua
```

However, whether that particular usage offers any advantage over other search tools is questionable at best.

* and some random beautification
pull/5254/head
Frans de Jonge 5 years ago committed by GitHub
parent dc6d4085ea
commit a2dcfe9aec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -28,10 +28,11 @@ if [ "${tab_detected}" ]; then
exit 1 exit 1
fi fi
newline_split=$(grep -Pzo "(_|gettext)\((\n|\s)+('|\"|\[\[)" --include \*.lua --exclude={dateparser.lua,xml.lua} --recursive {reader,setupkoenv,datastorage}.lua frontend plugins spec || true) untagged_todo=$(grep -Pin "[^\-]\-\-\s+@?(todo|fixme|warning)" --include \*.lua --exclude={dateparser.lua,xml.lua} --recursive {reader,setupkoenv,datastorage}.lua frontend plugins spec || true)
if [ "${newline_split}" ]; then if [ "${untagged_todo}" ]; then
echo -e "\\n${ANSI_RED}Warning: whitespace detected between gettext() call and string." echo -e "\\n${ANSI_RED}Warning: possible improperly tagged todo, fixme or warning detected."
echo "${newline_split}" echo -e "\\n${ANSI_RED} use --- followed by @todo, @fixme or @warning."
echo "${untagged_todo}"
exit 1 exit 1
fi fi

@ -21,4 +21,5 @@ sort_modules = true
file = { file = {
'../frontend', '../frontend',
'../base/ffi', '../base/ffi',
'../platform/android/luajit-launcher/assets',
} }

@ -86,10 +86,10 @@ function FileSearcher:close()
if self.search_value then if self.search_value then
UIManager:close(self.search_dialog) UIManager:close(self.search_dialog)
if string.len(self.search_value) > 0 then if string.len(self.search_value) > 0 then
self:readDir() -- TODO this probably doesn't need to be repeated once it's been done self:readDir() --- @todo this probably doesn't need to be repeated once it's been done
self:setSearchResults() -- TODO doesn't have to be repeated if the search term is the same self:setSearchResults() --- @todo doesn't have to be repeated if the search term is the same
if #self.results > 0 then if #self.results > 0 then
self:showSearchResults() -- TODO something about no results self:showSearchResults() --- @todo something about no results
else else
UIManager:show( UIManager:show(
InfoMessage:new{ InfoMessage:new{

@ -83,7 +83,7 @@ function SetDefaults:init()
local menu_container = CenterContainer:new{ local menu_container = CenterContainer:new{
dimen = Screen:getSize(), dimen = Screen:getSize(),
} }
-- FIXME: --- @fixme
-- in this use case (an input dialog is closed and the menu container is -- in this use case (an input dialog is closed and the menu container is
-- opened immediately) we need to set the full screen dirty because -- opened immediately) we need to set the full screen dirty because
-- otherwise only the input dialog part of the screen is refreshed. -- otherwise only the input dialog part of the screen is refreshed.

@ -346,7 +346,7 @@ function ReaderGesture:addToMainMenu(menu_items)
end end
custom_multiswipes:addTableItem("multiswipes", recorded_multiswipe) custom_multiswipes:addTableItem("multiswipes", recorded_multiswipe)
-- TODO implement some nicer method in TouchMenu than this ugly hack for updating the menu --- @todo Implement some nicer method in TouchMenu than this ugly hack for updating the menu.
touchmenu_instance.item_table[3] = self:genMultiswipeSubmenu() touchmenu_instance.item_table[3] = self:genMultiswipeSubmenu()
touchmenu_instance:updateItems() touchmenu_instance:updateItems()
UIManager:close(multiswipe_recorder) UIManager:close(multiswipe_recorder)

@ -436,7 +436,7 @@ function ReaderHighlight:onHold(arg, ges)
self.view.highlight.temp[self.hold_pos.page] = boxes self.view.highlight.temp[self.hold_pos.page] = boxes
end end
UIManager:setDirty(self.dialog, "ui") UIManager:setDirty(self.dialog, "ui")
-- TODO: only mark word? --- @todo only mark word?
-- Unfortunately, CREngine does not return good coordinates -- Unfortunately, CREngine does not return good coordinates
-- UIManager:setDirty(self.dialog, "partial", self.selected_word.sbox) -- UIManager:setDirty(self.dialog, "partial", self.selected_word.sbox)
self.hold_start_tv = TimeVal.now() self.hold_start_tv = TimeVal.now()

@ -182,7 +182,7 @@ function ReaderPaging:onReadSettings(config)
end end
function ReaderPaging:onSaveSettings() function ReaderPaging:onSaveSettings()
-- TODO: only save current_page page position --- @todo only save current_page page position
self.ui.doc_settings:saveSetting("page_positions", self.page_positions) self.ui.doc_settings:saveSetting("page_positions", self.page_positions)
self.ui.doc_settings:saveSetting("last_page", self:getTopPage()) self.ui.doc_settings:saveSetting("last_page", self:getTopPage())
self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent()) self.ui.doc_settings:saveSetting("percent_finished", self:getLastPercent())
@ -203,7 +203,7 @@ function ReaderPaging:getLastPercent()
end end
function ReaderPaging:addToMainMenu(menu_items) function ReaderPaging:addToMainMenu(menu_items)
-- FIXME: repeated code with page overlap menu for readerrolling --- @fixme repeated code with page overlap menu for readerrolling
-- needs to keep only one copy of the logic as for the DRY principle. -- needs to keep only one copy of the logic as for the DRY principle.
-- The difference between the two menus is only the enabled func. -- The difference between the two menus is only the enabled func.
local page_overlap_menu = { local page_overlap_menu = {

@ -159,7 +159,7 @@ function ReaderRolling:onReadSettings(config)
self.ui.document:gotoXPointer(self.xpointer) self.ui.document:gotoXPointer(self.xpointer)
end end
-- we read last_percent just for backward compatibility -- we read last_percent just for backward compatibility
-- FIXME: remove this branch with migration script --- @fixme remove this branch with migration script
elseif last_per then elseif last_per then
self.setupXpointer = function() self.setupXpointer = function()
self:_gotoPercent(last_per) self:_gotoPercent(last_per)
@ -343,7 +343,7 @@ function ReaderRolling:getLastProgress()
end end
function ReaderRolling:addToMainMenu(menu_items) function ReaderRolling:addToMainMenu(menu_items)
-- FIXME: repeated code with page overlap menu for readerpaging --- @fixme repeated code with page overlap menu for readerpaging
-- needs to keep only one copy of the logic as for the DRY principle. -- needs to keep only one copy of the logic as for the DRY principle.
-- The difference between the two menus is only the enabled func. -- The difference between the two menus is only the enabled func.
local overlap_lines_help_text = _([[ local overlap_lines_help_text = _([[
@ -407,7 +407,7 @@ function ReaderRolling:getLastPercent()
if self.view.view_mode == "page" then if self.view.view_mode == "page" then
return self.current_page / self.old_page return self.current_page / self.old_page
else else
-- FIXME: the calculated percent is not accurate in "scroll" mode. --- @fixme the calculated percent is not accurate in "scroll" mode.
return self.ui.document:getPosFromXPointer( return self.ui.document:getPosFromXPointer(
self.ui.document:getXPointer()) / self.ui.document.info.doc_height self.ui.document:getXPointer()) / self.ui.document.info.doc_height
end end

@ -23,7 +23,7 @@ function ReaderRotation:init()
end end
end end
-- @TODO: reset rotation on new document, maybe on new page? --- @todo Reset rotation on new document, maybe on new page?
function ReaderRotation:onRotate(rotate_by) function ReaderRotation:onRotate(rotate_by)
self.current_rotation = (self.current_rotation + rotate_by) % 360 self.current_rotation = (self.current_rotation + rotate_by) % 360

@ -147,7 +147,7 @@ function ReaderSearch:onShowSearchDialog(text)
} }
do_search(self.searchFromCurrent, text, 0)() do_search(self.searchFromCurrent, text, 0)()
UIManager:show(self.search_dialog) UIManager:show(self.search_dialog)
-- TODO: regional --- @todo regional
UIManager:setDirty(self.dialog, "partial") UIManager:setDirty(self.dialog, "partial")
return true return true
end end

@ -698,8 +698,8 @@ function ReaderView:onSetScreenMode(new_mode, rotation, noskip)
if new_mode == "landscape" or new_mode == "portrait" then if new_mode == "landscape" or new_mode == "portrait" then
self.screen_mode = new_mode self.screen_mode = new_mode
-- NOTE: Hacky hack! If rotation is "true", that's actually an "interactive" flag for setScreenMode -- NOTE: Hacky hack! If rotation is "true", that's actually an "interactive" flag for setScreenMode
-- FIXME: That's because we can't store nils in a table, which is what Event:new attempts to do ;). --- @fixme That's because we can't store nils in a table, which is what Event:new attempts to do ;).
-- c.f., https://stackoverflow.com/q/7183998/ & http://lua-users.org/wiki/VarargTheSecondClassCitizen -- c.f., <https://stackoverflow.com/q/7183998/> & <http://lua-users.org/wiki/VarargTheSecondClassCitizen>
-- With a fixed Event implementation, we'd instead stick "interactive" in a third argument, -- With a fixed Event implementation, we'd instead stick "interactive" in a third argument,
-- which we could happily pass while still keeping rotation nil ;). -- which we could happily pass while still keeping rotation nil ;).
if rotation ~= nil and rotation ~= true then if rotation ~= nil and rotation ~= true then

@ -116,9 +116,6 @@ function ReaderZooming:init()
end end
function ReaderZooming:onReadSettings(config) function ReaderZooming:onReadSettings(config)
-- @TODO config file from old code base uses globalzoom_mode
-- instead of zoom_mode, we need to handle this imcompatibility
-- 04.12 2012 (houqp)
local zoom_mode = config:readSetting("zoom_mode") or local zoom_mode = config:readSetting("zoom_mode") or
G_reader_settings:readSetting("zoom_mode") or G_reader_settings:readSetting("zoom_mode") or
self.DEFAULT_ZOOM_MODE self.DEFAULT_ZOOM_MODE

@ -451,7 +451,7 @@ function ReaderUI:showReader(file, provider)
return return
end end
-- prevent crash due to incompatible bookmarks -- prevent crash due to incompatible bookmarks
-- @TODO split bookmarks from metadata and do per-engine in conversion --- @todo Split bookmarks from metadata and do per-engine in conversion.
provider = provider or DocumentRegistry:getProvider(file) provider = provider or DocumentRegistry:getProvider(file)
if provider.provider then if provider.provider then
local doc_settings = DocSettings:open(file) local doc_settings = DocSettings:open(file)

@ -52,7 +52,7 @@ function Dbg:turnOn()
return check return check
end end
-- TODO: close ev.log fd for children --- @todo close ev.log fd for children
-- create or clear ev log file -- create or clear ev log file
self.ev_log = io.open("ev.log", "w") self.ev_log = io.open("ev.log", "w")
end end

@ -497,7 +497,7 @@ function GestureDetector:handleSwipe(tev)
logger.dbg("multiswipe", multiswipe_directions) logger.dbg("multiswipe", multiswipe_directions)
end end
-- TODO: dirty hack for some weird devices, replace it with better solution --- @todo dirty hack for some weird devices, replace it with better solution
if swipe_direction == "west" and DCHANGE_WEST_SWIPE_TO_EAST then if swipe_direction == "west" and DCHANGE_WEST_SWIPE_TO_EAST then
swipe_direction = "east" swipe_direction = "east"
elseif swipe_direction == "east" and DCHANGE_EAST_SWIPE_TO_WEST then elseif swipe_direction == "east" and DCHANGE_EAST_SWIPE_TO_WEST then

@ -415,11 +415,11 @@ function Input:handleKeyBoardEv(ev)
or keycode == "RPgBack" or keycode == "RPgBack"
or keycode == "LPgFwd" or keycode == "LPgFwd"
or keycode == "RPgFwd" then or keycode == "RPgFwd" then
-- FIXME: Crappy event staggering! --- @fixme Crappy event staggering!
-- The Forma repeats every 80ms after a 400ms delay, and 500ms roughly corresponds to a flashing update, -- The Forma repeats every 80ms after a 400ms delay, and 500ms roughly corresponds to a flashing update,
-- so stuff is usually in sync when you release the key. -- so stuff is usually in sync when you release the key.
-- Obvious downside is that this ends up slower than just mashing the key. -- Obvious downside is that this ends up slower than just mashing the key.
-- FIXME: A better approach would be an onKeyRelease handler that flushes the Event queue... --- @fixme A better approach would be an onKeyRelease handler that flushes the Event queue...
self.repeat_count = self.repeat_count + 1 self.repeat_count = self.repeat_count + 1
if self.repeat_count == 1 then if self.repeat_count == 1 then
return Event:new("KeyRepeat", key) return Event:new("KeyRepeat", key)
@ -841,7 +841,7 @@ function Input:waitEvent(timeout_us)
ev = nil ev = nil
break break
elseif ev == "application forced to quit" then elseif ev == "application forced to quit" then
-- TODO: return an event that can be handled --- @todo return an event that can be handled
os.exit(0) os.exit(0)
end end
logger.warn("got error waiting for events:", ev) logger.warn("got error waiting for events:", ev)

@ -665,11 +665,11 @@ function KindleOasis2:init()
} }
} }
-- FIXME: When starting KOReader with the device upside down ("D"), touch input is registered wrong --- @fixme When starting KOReader with the device upside down ("D"), touch input is registered wrong
-- (i.e., probably upside down). -- (i.e., probably upside down).
-- If it's started upright ("U"), everything's okay, and turning it upside down after that works just fine. -- If it's started upright ("U"), everything's okay, and turning it upside down after that works just fine.
-- See #2206 & #2209 for the original KOA implementation, which obviously doesn't quite cut it here... -- See #2206 & #2209 for the original KOA implementation, which obviously doesn't quite cut it here...
-- See also https://www.mobileread.com/forums/showthread.php?t=298302&page=5 -- See also <https://www.mobileread.com/forums/showthread.php?t=298302&page=5>
-- NOTE: It'd take some effort to actually start KOReader while in a LANDSCAPE orientation, -- NOTE: It'd take some effort to actually start KOReader while in a LANDSCAPE orientation,
-- since they're only exposed inside the stock reader, and not the Home/KUAL Booklets. -- since they're only exposed inside the stock reader, and not the Home/KUAL Booklets.
local haslipc, lipc = pcall(require, "liblipclua") local haslipc, lipc = pcall(require, "liblipclua")

@ -45,7 +45,7 @@ local Kobo = Generic:new{
canHWInvert = yes, canHWInvert = yes,
} }
-- TODO: hasKeys for some devices? --- @todo hasKeys for some devices?
-- Kobo Touch: -- Kobo Touch:
local KoboTrilogy = Kobo:new{ local KoboTrilogy = Kobo:new{
@ -140,7 +140,7 @@ local KoboSnow = Kobo:new{
} }
-- Kobo Aura H2O2, Rev2: -- Kobo Aura H2O2, Rev2:
-- FIXME: Check if the Clara fix actually helps here... (#4015) --- @fixme Check if the Clara fix actually helps here... (#4015)
local KoboSnowRev2 = Kobo:new{ local KoboSnowRev2 = Kobo:new{
model = "Kobo_snow_r2", model = "Kobo_snow_r2",
hasFrontlight = yes, hasFrontlight = yes,
@ -163,7 +163,7 @@ local KoboStar = Kobo:new{
} }
-- Kobo Aura second edition, Rev 2: -- Kobo Aura second edition, Rev 2:
-- FIXME: Confirm that this is accurate? If it is, and matches the Rev1, ditch the special casing. --- @fixme Confirm that this is accurate? If it is, and matches the Rev1, ditch the special casing.
local KoboStarRev2 = Kobo:new{ local KoboStarRev2 = Kobo:new{
model = "Kobo_star_r2", model = "Kobo_star_r2",
hasFrontlight = yes, hasFrontlight = yes,
@ -452,7 +452,7 @@ function Kobo:initEventAdjustHooks()
if self.touch_mirrored_x then if self.touch_mirrored_x then
self.input:registerEventAdjustHook( self.input:registerEventAdjustHook(
self.input.adjustTouchMirrorX, self.input.adjustTouchMirrorX,
-- FIXME: what if we change the screen portrait mode? --- @fixme what if we change the screen portrait mode?
self.screen:getWidth() self.screen:getWidth()
) )
end end

@ -24,7 +24,7 @@ local KoboPowerD = BasePowerD:new{
fl_was_on = nil, fl_was_on = nil,
} }
-- TODO: Remove KOBO_LIGHT_ON_START --- @todo Remove KOBO_LIGHT_ON_START
function KoboPowerD:_syncKoboLightOnStart() function KoboPowerD:_syncKoboLightOnStart()
local new_intensity = nil local new_intensity = nil
local is_frontlight_on = nil local is_frontlight_on = nil

@ -68,7 +68,7 @@ function PocketBook:blacklistCBB()
local C = ffi.C local C = ffi.C
-- As well as on those than can't do HW inversion, as otherwise NightMode would be ineffective. -- As well as on those than can't do HW inversion, as otherwise NightMode would be ineffective.
-- FIXME: Either relax the HWInvert check, or actually enable HWInvert on PB if it's safe and it works, --- @fixme Either relax the HWInvert check, or actually enable HWInvert on PB if it's safe and it works,
-- as, currently, no PB device is marked as canHWInvert, so, the C BB is essentially *always* blacklisted. -- as, currently, no PB device is marked as canHWInvert, so, the C BB is essentially *always* blacklisted.
if not self:canUseCBB() or not self:canHWInvert() then if not self:canUseCBB() or not self:canHWInvert() then
logger.info("Blacklisting the C BB on this device") logger.info("Blacklisting the C BB on this device")

@ -201,7 +201,8 @@ function Device:init()
-- this means we can't just return one ScreenResize or SetDimensons event -- this means we can't just return one ScreenResize or SetDimensons event
UIManager:broadcastEvent(Event:new("SetDimensions", new_size)) UIManager:broadcastEvent(Event:new("SetDimensions", new_size))
UIManager:broadcastEvent(Event:new("ScreenResize", new_size)) UIManager:broadcastEvent(Event:new("ScreenResize", new_size))
-- @TODO toggle this elsewhere based on ScreenResize? --- @todo Toggle this elsewhere based on ScreenResize?
-- this triggers paged media like PDF and DjVu to redraw -- this triggers paged media like PDF and DjVu to redraw
-- CreDocument doesn't need it -- CreDocument doesn't need it
UIManager:broadcastEvent(Event:new("RedrawCurrentPage")) UIManager:broadcastEvent(Event:new("RedrawCurrentPage"))

@ -93,7 +93,7 @@ end
-- @string docfile path to the document (e.g., `/foo/bar.pdf`) -- @string docfile path to the document (e.g., `/foo/bar.pdf`)
-- @treturn DocSettings object -- @treturn DocSettings object
function DocSettings:open(docfile) function DocSettings:open(docfile)
-- TODO(zijiehe): Remove history_path, use only sidecar. --- @todo (zijiehe): Remove history_path, use only sidecar.
local new = {} local new = {}
new.history_file = self:getHistoryPath(docfile) new.history_file = self:getHistoryPath(docfile)

@ -366,7 +366,7 @@ function CreDocument:drawCurrentView(target, x, y, rect, pos)
-- to match the screen's BB type, allowing us to take shortcuts when blitting. -- to match the screen's BB type, allowing us to take shortcuts when blitting.
self.buffer = Blitbuffer.new(rect.w, rect.h, self.render_color and Blitbuffer.TYPE_BBRGB32 or nil) self.buffer = Blitbuffer.new(rect.w, rect.h, self.render_color and Blitbuffer.TYPE_BBRGB32 or nil)
end end
-- TODO: self.buffer could be re-used when no page/layout/highlights --- @todo self.buffer could be re-used when no page/layout/highlights
-- change has been made, to avoid having crengine redraw the exact -- change has been made, to avoid having crengine redraw the exact
-- same buffer. And it could only change when some other methods -- same buffer. And it could only change when some other methods
-- from here are called -- from here are called
@ -714,7 +714,7 @@ function CreDocument:setStyleSheet(new_css_file, appended_css_content )
end end
function CreDocument:setEmbeddedStyleSheet(toggle) function CreDocument:setEmbeddedStyleSheet(toggle)
-- FIXME: occasional segmentation fault when switching embedded style sheet --- @fixme occasional segmentation fault when switching embedded style sheet
logger.dbg("CreDocument: set embedded style sheet", toggle) logger.dbg("CreDocument: set embedded style sheet", toggle)
self._document:setIntProperty("crengine.doc.embedded.styles.enabled", toggle) self._document:setIntProperty("crengine.doc.embedded.styles.enabled", toggle)
end end
@ -748,7 +748,7 @@ function CreDocument:setNightmodeImages(toggle)
end end
function CreDocument:setFloatingPunctuation(enabled) function CreDocument:setFloatingPunctuation(enabled)
-- FIXME: occasional segmentation fault when toggling floating punctuation --- @fixme occasional segmentation fault when toggling floating punctuation
logger.dbg("CreDocument: set floating punctuation", enabled) logger.dbg("CreDocument: set floating punctuation", enabled)
self._document:setIntProperty("crengine.style.floating.punctuation.enabled", enabled) self._document:setIntProperty("crengine.style.floating.punctuation.enabled", enabled)
end end

@ -331,7 +331,7 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
if not Cache:willAccept(size.w * size.h + 64) then if not Cache:willAccept(size.w * size.h + 64) then
-- whole page won't fit into cache -- whole page won't fit into cache
logger.dbg("rendering only part of the page") logger.dbg("rendering only part of the page")
-- TODO: figure out how to better segment the page --- @todo figure out how to better segment the page
if not rect then if not rect then
logger.warn("aborting, since we do not have a specification for that part") logger.warn("aborting, since we do not have a specification for that part")
-- required part not given, so abort -- required part not given, so abort
@ -380,7 +380,7 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
end end
-- a hint for the cache engine to paint a full page to the cache -- a hint for the cache engine to paint a full page to the cache
-- TODO: this should trigger a background operation --- @todo this should trigger a background operation
function Document:hintPage(pageno, zoom, rotation, gamma, render_mode) function Document:hintPage(pageno, zoom, rotation, gamma, render_mode)
logger.dbg("hinting page", pageno) logger.dbg("hinting page", pageno)
self:renderPage(pageno, nil, zoom, rotation, gamma, render_mode) self:renderPage(pageno, nil, zoom, rotation, gamma, render_mode)

@ -105,7 +105,7 @@ end
function DocumentRegistry:getProviders(file) function DocumentRegistry:getProviders(file)
local providers = {} local providers = {}
-- TODO: some implementation based on mime types? --- @todo some implementation based on mime types?
for _, provider in ipairs(self.providers) do for _, provider in ipairs(self.providers) do
local suffix = string.sub(file, -string.len(provider.extension) - 1) local suffix = string.sub(file, -string.len(provider.extension) - 1)
if string.lower(suffix) == "."..provider.extension then if string.lower(suffix) == "."..provider.extension then

@ -49,7 +49,7 @@ local function _serialize(what, outt, indent, max_lv, history)
insert(outt, string.format("%q", what)) insert(outt, string.format("%q", what))
elseif type(what) == "number" then elseif type(what) == "number" then
if isUbuntuTouch then if isUbuntuTouch then
-- FIXME: the `SDL_CreateRenderer` function in Ubuntu touch somehow --- @fixme The `SDL_CreateRenderer` function in Ubuntu touch somehow
-- use a strange locale that formats number like this: 1.10000000000000g+02 -- use a strange locale that formats number like this: 1.10000000000000g+02
-- which cannot be recognized by loadfile after the number is dumped. -- which cannot be recognized by loadfile after the number is dumped.
-- Here the workaround is to preserve enough precision in "%.13e" format. -- Here the workaround is to preserve enough precision in "%.13e" format.

@ -43,7 +43,7 @@ function LuaSettings:open(file_path)
return setmetatable(new, {__index = LuaSettings}) return setmetatable(new, {__index = LuaSettings})
end end
-- TODO: DocSettings can return a LuaSettings to use following awesome features. --- @todo DocSettings can return a LuaSettings to use following awesome features.
function LuaSettings:wrap(data) function LuaSettings:wrap(data)
local new = {data = type(data) == "table" and data or {}} local new = {data = type(data) == "table" and data or {}}
return setmetatable(new, {__index = LuaSettings}) return setmetatable(new, {__index = LuaSettings})

@ -46,7 +46,7 @@ end
function ReadHistory:_indexing(start) function ReadHistory:_indexing(start)
assert(self ~= nil) assert(self ~= nil)
-- TODO(Hzj_jie): Use binary search to find an item when deleting it. --- @todo (Hzj_jie): Use binary search to find an item when deleting it.
for i = start, #self.hist, 1 do for i = start, #self.hist, 1 do
self.hist[i].index = i self.hist[i].index = i
end end
@ -60,7 +60,7 @@ function ReadHistory:_sort()
self:clearMissing() self:clearMissing()
end end
table.sort(self.hist, fileFirstOrdering) table.sort(self.hist, fileFirstOrdering)
-- TODO(zijiehe): Use binary insert instead of a loop to deduplicate. --- @todo (zijiehe): Use binary insert instead of a loop to deduplicate.
for i = #self.hist, 2, -1 do for i = #self.hist, 2, -1 do
if self.hist[i].file == self.hist[i - 1].file then if self.hist[i].file == self.hist[i - 1].file then
table.remove(self.hist, i) table.remove(self.hist, i)
@ -186,7 +186,7 @@ function ReadHistory:addItem(file)
if file ~= nil and lfs.attributes(file, "mode") == "file" then if file ~= nil and lfs.attributes(file, "mode") == "file" then
local now = os.time() local now = os.time()
table.insert(self.hist, 1, buildEntry(now, file)) table.insert(self.hist, 1, buildEntry(now, file))
-- TODO(zijiehe): We do not need to sort if we can use binary insert and --- @todo (zijiehe): We do not need to sort if we can use binary insert and
-- binary search. -- binary search.
-- util.execute("/bin/touch", "-a", file) -- util.execute("/bin/touch", "-a", file)
-- This emulates `touch -a` in LuaFileSystem's API, since it may be absent (Android) -- This emulates `touch -a` in LuaFileSystem's API, since it may be absent (Android)

@ -320,14 +320,14 @@ return {
"Q", "Q",
north = "[", north = "[",
northeast = "{", northeast = "{",
-- todo render q̃ correctly on key (not a problem in textbox?) --- @todo Render q̃ correctly on key (not a problem in textbox?)
--east = {"q̃"}, -- Old/Middle French abbreviation of que --east = {"q̃"}, -- Old/Middle French abbreviation of que
}, },
_q_ = { _q_ = {
"q", "q",
north = "[", north = "[",
northeast = "{", northeast = "{",
-- todo render q̃ correctly on key (not a problem in textbox?) --- @todo Render q̃ correctly on key (not a problem in textbox?)
--east = {"q̃"}, -- Old/Middle French abbreviation of que --east = {"q̃"}, -- Old/Middle French abbreviation of que
}, },
_R_ = { _R_ = {

@ -166,7 +166,7 @@ Returns a new rectangle for the part that we and a given rectangle share
@tparam Geom rect_b @tparam Geom rect_b
@treturn Geom @treturn Geom
]]-- ]]--
-- TODO: what happens if there is no rectangle shared? currently behaviour is undefined. --- @todo what happens if there is no rectangle shared? currently behaviour is undefined.
function Geom:intersect(rect_b) function Geom:intersect(rect_b)
-- make a copy of self -- make a copy of self
local intersected = self:copy() local intersected = self:copy()

@ -16,10 +16,10 @@ function FileMessageQueue:init()
self.filemq = self.client self.filemq = self.client
self.poller = czmq.zpoller_new(filemq.fmq_client_handle(self.client), nil) self.poller = czmq.zpoller_new(filemq.fmq_client_handle(self.client), nil)
elseif self.server ~= nil then elseif self.server ~= nil then
-- TODO: currently fmq_server_recv API is not available --- @todo currently fmq_server_recv API is not available
--self.fmq_recv = filemq.fmq_server_recv --self.fmq_recv = filemq.fmq_server_recv
self.filemq = self.server self.filemq = self.server
-- TODO: currently fmq_server_handle API is not available --- @todo currently fmq_server_handle API is not available
--self.poller = czmq.zpoller_new(filemq.fmq_server_handle(self.server), nil) --self.poller = czmq.zpoller_new(filemq.fmq_server_handle(self.server), nil)
end end
end end

@ -24,7 +24,7 @@ function StreamMessageQueue:start()
end end
local id_size = ffi.new("size_t[1]", 256) local id_size = ffi.new("size_t[1]", 256)
local buffer = ffi.new("uint8_t[?]", id_size[0]) local buffer = ffi.new("uint8_t[?]", id_size[0])
-- @todo: check return of zmq_getsockopt --- @todo: Check return of zmq_getsockopt()
zmq.zmq_getsockopt(self.socket, C.ZMQ_IDENTITY, buffer, id_size) zmq.zmq_getsockopt(self.socket, C.ZMQ_IDENTITY, buffer, id_size)
self.id = ffi.string(buffer, id_size[0]) self.id = ffi.string(buffer, id_size[0])
logger.dbg("id", #self.id, self.id) logger.dbg("id", #self.id, self.id)

@ -266,7 +266,7 @@ function NetworkMgr:getInfoMenuTable()
return { return {
text = _("Network info"), text = _("Network info"),
keep_menu_open = true, keep_menu_open = true,
-- TODO: also show network info when device is authenticated to router but offline --- @todo also show network info when device is authenticated to router but offline
enabled_func = function() return self:isWifiOn() end, enabled_func = function() return self:isWifiOn() end,
callback = function() callback = function()
if Device.retrieveNetworkInfo then if Device.retrieveNetworkInfo then
@ -350,7 +350,7 @@ function NetworkMgr:showNetworkMenu(complete_callback)
end end
-- NOTE: Fairly hackish workaround for #4387, -- NOTE: Fairly hackish workaround for #4387,
-- rescan if the first scan appeared to yield an empty list. -- rescan if the first scan appeared to yield an empty list.
-- FIXME: This *might* be an issue better handled in lj-wpaclient... --- @fixme This *might* be an issue better handled in lj-wpaclient...
if (table.getn(network_list) == 0) then if (table.getn(network_list) == 0) then
network_list, err = self:getNetworkList() network_list, err = self:getNetworkList()
if network_list == nil then if network_list == nil then

@ -1,3 +1,7 @@
--[[--
WPA client helper for Kobo.
]]
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local WpaClient = require('lj-wpaclient/wpaclient') local WpaClient = require('lj-wpaclient/wpaclient')
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
@ -9,6 +13,7 @@ local CLIENT_INIT_ERR_MSG = _("Failed to initialize network control client: %1."
local WpaSupplicant = {} local WpaSupplicant = {}
--- Gets network list.
function WpaSupplicant:getNetworkList() function WpaSupplicant:getNetworkList()
local wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface) local wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface)
if wcli == nil then if wcli == nil then
@ -25,12 +30,12 @@ function WpaSupplicant:getNetworkList()
network.signal_quality = network:getSignalQuality() network.signal_quality = network:getSignalQuality()
local saved_nw = saved_networks:readSetting(network.ssid) local saved_nw = saved_networks:readSetting(network.ssid)
if saved_nw then if saved_nw then
-- TODO: verify saved_nw.flags == network.flags? This will break if user changed the --- @todo verify saved_nw.flags == network.flags? This will break if user changed the
-- network setting from [WPA-PSK-TKIP+CCMP][WPS][ESS] to [WPA-PSK-TKIP+CCMP][ESS] -- network setting from [WPA-PSK-TKIP+CCMP][WPS][ESS] to [WPA-PSK-TKIP+CCMP][ESS]
network.password = saved_nw.password network.password = saved_nw.password
network.psk = saved_nw.psk network.psk = saved_nw.psk
end end
-- TODO: also verify bssid if it is not set to any --- @todo also verify bssid if it is not set to any
if curr_network and curr_network.ssid == network.ssid then if curr_network and curr_network.ssid == network.ssid then
network.connected = true network.connected = true
network.wpa_supplicant_id = curr_network.id network.wpa_supplicant_id = curr_network.id
@ -40,20 +45,21 @@ function WpaSupplicant:getNetworkList()
end end
local function calculatePsk(ssid, pwd) local function calculatePsk(ssid, pwd)
-- TODO: calculate PSK with native function instead of shelling out --- @todo calculate PSK with native function instead of shelling out
-- hostap's reference implementation is available at: -- hostap's reference implementation is available at:
-- * /wpa_supplicant/wpa_passphrase.c -- * /wpa_supplicant/wpa_passphrase.c
-- * /src/crypto/sha1-pbkdf2.c -- * /src/crypto/sha1-pbkdf2.c
-- see: http://docs.ros.org/diamondback/api/wpa_supplicant/html/sha1-pbkdf2_8c_source.html -- see: <http://docs.ros.org/diamondback/api/wpa_supplicant/html/sha1-pbkdf2_8c_source.html>
local fp = io.popen(("wpa_passphrase %q %q"):format(ssid, pwd)) local fp = io.popen(("wpa_passphrase %q %q"):format(ssid, pwd))
local out = fp:read("*a") local out = fp:read("*a")
fp:close() fp:close()
return string.match(out, 'psk=([a-f0-9]+)') return string.match(out, 'psk=([a-f0-9]+)')
end end
--- Authenticates network.
function WpaSupplicant:authenticateNetwork(network) function WpaSupplicant:authenticateNetwork(network)
-- TODO: support passwordless network
local err, wcli, nw_id local err, wcli, nw_id
--- @todo support passwordless network
wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface) wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface)
if not wcli then if not wcli then
return false, T(CLIENT_INIT_ERR_MSG, err) return false, T(CLIENT_INIT_ERR_MSG, err)

@ -1,3 +1,7 @@
--[[--
Checks for updates on the specified nightly build server.
]]
local ConfirmBox = require("ui/widget/confirmbox") local ConfirmBox = require("ui/widget/confirmbox")
local DataStorage = require("datastorage") local DataStorage = require("datastorage")
local Device = require("device") local Device = require("device")
@ -334,8 +338,9 @@ function OTAManager:fetchAndProcessUpdate()
end end
end end
---- Uses zsync and tar to prepare an update package.
function OTAManager:_buildLocalPackage() function OTAManager:_buildLocalPackage()
-- TODO: validate the installed package? --- @todo Validate the installed package?
local installed_package = self.installed_package local installed_package = self.installed_package
if lfs.attributes(installed_package, "mode") == "file" then if lfs.attributes(installed_package, "mode") == "file" then
return 0 return 0

@ -37,7 +37,7 @@ local function utf8Chars(input_text)
if string.len(input) < pos then return nil end if string.len(input) < pos then return nil end
local value = string.byte(input, pos) local value = string.byte(input, pos)
if band(value, 0x80) == 0 then if band(value, 0x80) == 0 then
-- TODO: check valid ranges --- @todo check valid ranges
return pos+1, value, string.sub(input, pos, pos) return pos+1, value, string.sub(input, pos, pos)
elseif band(value, 0xC0) == 0x80 -- invalid, continuation elseif band(value, 0xC0) == 0x80 -- invalid, continuation
or band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629 or band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629
@ -70,7 +70,7 @@ local function utf8Chars(input_text)
return pos+1, 0xFFFD, "\xFF\xFD" return pos+1, 0xFFFD, "\xFF\xFD"
end end
end end
-- TODO: check for valid ranges here! --- @todo check for valid ranges here!
return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left) return pos+bytes_left+1, glyph, string.sub(input, pos, pos+bytes_left)
end end
end end

@ -184,7 +184,7 @@ function Trapper:info(text, fast_refresh)
-- continue processing -- continue processing
end end
-- TODO We should try to flush any pending tap, so past --- @todo We should try to flush any pending tap, so past
-- events won't be considered action on the yet to be displayed -- events won't be considered action on the yet to be displayed
-- widget -- widget
@ -266,7 +266,7 @@ function Trapper:confirm(text, cancel_text, ok_text)
return true -- always select "OK" in ConfirmBox if no UI return true -- always select "OK" in ConfirmBox if no UI
end end
-- TODO We should try to flush any pending tap, so past --- @todo We should try to flush any pending tap, so past
-- events won't be considered action on the yet to be displayed -- events won't be considered action on the yet to be displayed
-- widget -- widget

@ -544,7 +544,7 @@ function UIManager:setDirty(widget, refreshtype, refreshregion, refreshdither)
-- callback, will be issued after painting -- callback, will be issued after painting
table.insert(self._refresh_func_stack, refreshtype) table.insert(self._refresh_func_stack, refreshtype)
if dbg.is_on then if dbg.is_on then
-- FIXME: We can't consume the return values of refreshtype by running it, because for a reason that is beyond me (scoping? gc?), that renders it useless later, meaning we then enqueue refreshes with bogus arguments... --- @fixme We can't consume the return values of refreshtype by running it, because for a reason that is beyond me (scoping? gc?), that renders it useless later, meaning we then enqueue refreshes with bogus arguments...
-- Thankfully, we can track them in _refresh()'s logging very soon after that... -- Thankfully, we can track them in _refresh()'s logging very soon after that...
logger.dbg("setDirty via a func from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil") logger.dbg("setDirty via a func from widget", widget and (widget.name or widget.id or tostring(widget)) or "nil")
end end
@ -1050,7 +1050,7 @@ function UIManager:handleInput()
if self.looper then if self.looper then
logger.info("handle input in turbo I/O looper") logger.info("handle input in turbo I/O looper")
self.looper:add_callback(function() self.looper:add_callback(function()
-- FIXME: force close looper when there is unhandled error, --- @fixme Force close looper when there is unhandled error,
-- otherwise the looper will hang. Any better solution? -- otherwise the looper will hang. Any better solution?
xpcall(function() self:handleInput() end, function(err) xpcall(function() self:handleInput() end, function(err)
io.stderr:write(err .. "\n") io.stderr:write(err .. "\n")

@ -208,7 +208,7 @@ function BBoxWidget:onSwipeAdjust(arg, ges)
end end
function BBoxWidget:onHoldAdjust(arg, ges) function BBoxWidget:onHoldAdjust(arg, ges)
-- FIXME: this is a dirty hack to disable hold gesture in page cropping --- @fixme this is a dirty hack to disable hold gesture in page cropping
-- since Kobo devices may append hold gestures to each swipe gesture rendering -- since Kobo devices may append hold gestures to each swipe gesture rendering
-- relative replacement impossible. See koreader/koreader#987 at Github. -- relative replacement impossible. See koreader/koreader#987 at Github.
--self:adjustScreenBBox(ges) --self:adjustScreenBBox(ges)

@ -187,7 +187,7 @@ function ConfigOption:init()
local padding_small = Size.padding.small -- internal padding for options names (left) local padding_small = Size.padding.small -- internal padding for options names (left)
local padding_button = Size.padding.button -- padding for underline below letters and icons local padding_button = Size.padding.button -- padding for underline below letters and icons
-- @TODO restore setting when there are more advanced settings --- @todo Restore setting when there are more advanced settings.
--local show_advanced = G_reader_settings:readSetting("show_advanced") or false --local show_advanced = G_reader_settings:readSetting("show_advanced") or false
local show_advanced = true local show_advanced = true

@ -65,7 +65,7 @@ function AlphaContainer:paintTo(bb, x, y)
end end
-- now have our childs paint to the private blitbuffer -- now have our childs paint to the private blitbuffer
-- TODO: should we clean before painting? --- @todo should we clean before painting?
self[1]:paintTo(private_bb, 0, 0) self[1]:paintTo(private_bb, 0, 0)
-- blit the private blitbuffer to our parent blitbuffer -- blit the private blitbuffer to our parent blitbuffer

@ -10,7 +10,7 @@ local BottomContainer = WidgetContainer:new()
function BottomContainer:paintTo(bb, x, y) function BottomContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize() local contentSize = self[1]:getSize()
-- FIXME --- @fixme
-- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then -- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially? -- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this -- for now, we ignore this

@ -8,7 +8,7 @@ local CenterContainer = WidgetContainer:new()
function CenterContainer:paintTo(bb, x, y) function CenterContainer:paintTo(bb, x, y)
local content_size = self[1]:getSize() local content_size = self[1]:getSize()
-- FIXME --- @fixme
-- if content_size.w > self.dimen.w or content_size.h > self.dimen.h then -- if content_size.w > self.dimen.w or content_size.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially? -- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this -- for now, we ignore this

@ -8,7 +8,7 @@ local LeftContainer = WidgetContainer:new()
function LeftContainer:paintTo(bb, x, y) function LeftContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize() local contentSize = self[1]:getSize()
-- FIXME --- @fixme
-- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then -- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially? -- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this -- for now, we ignore this

@ -8,7 +8,7 @@ local RightContainer = WidgetContainer:new()
function RightContainer:paintTo(bb, x, y) function RightContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize() local contentSize = self[1]:getSize()
-- FIXME --- @fixme
-- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then -- if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially? -- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this -- for now, we ignore this

@ -12,7 +12,7 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
local UnderlineContainer = WidgetContainer:new{ local UnderlineContainer = WidgetContainer:new{
linesize = Size.line.thick, linesize = Size.line.thick,
padding = Size.padding.tiny, padding = Size.padding.tiny,
-- TODO: shouldn't this default to black instead? --- @todo shouldn't this default to black instead?
color = Blitbuffer.COLOR_WHITE, color = Blitbuffer.COLOR_WHITE,
vertical_align = "top", vertical_align = "top",
} }

@ -411,7 +411,7 @@ function FrontLightWidget:addWarmthWidgets(num_warmth, step, vertical_group)
}) })
local text_auto_nl = TextBoxWidget:new{ local text_auto_nl = TextBoxWidget:new{
-- @TODO implement padding_right (etc.) on TextBoxWidget and remove the two-space hack --- @todo Implement padding_right (etc.) on TextBoxWidget and remove the two-space hack.
text = _("Max. at:") .. " ", text = _("Max. at:") .. " ",
face = self.larger_font_face, face = self.larger_font_face,
alignment = "right", alignment = "right",

@ -84,7 +84,7 @@ function InfoMessage:init()
local image_widget local image_widget
if self.show_icon then if self.show_icon then
-- TODO: remove self.image support, only used in filemanagersearch --- @todo remove self.image support, only used in filemanagersearch
-- this requires self.image's lifecycle to be managed by ImageWidget -- this requires self.image's lifecycle to be managed by ImageWidget
-- instead of caller, which is easy to introduce bugs -- instead of caller, which is easy to introduce bugs
if self.image then if self.image then

@ -362,7 +362,7 @@ function InputText:initTextBox(text, char_added)
} }
self[1] = self._frame self[1] = self._frame
self.dimen = self._frame:getSize() self.dimen = self._frame:getSize()
-- FIXME: self.parent is not always in the widget stack (BookStatusWidget) --- @fixme self.parent is not always in the widget stack (BookStatusWidget)
UIManager:setDirty(self.parent, function() UIManager:setDirty(self.parent, function()
return "ui", self.dimen return "ui", self.dimen
end) end)

@ -879,7 +879,7 @@ function Menu:truncatePath(text)
end end
function Menu:onCloseWidget() function Menu:onCloseWidget()
-- FIXME: --- @fixme
-- we cannot refresh regionally using the dimen field -- we cannot refresh regionally using the dimen field
-- because some menus without menu title use VerticalGroup to include -- because some menus without menu title use VerticalGroup to include
-- a text widget which is not calculated into the dimen. -- a text widget which is not calculated into the dimen.
@ -1037,7 +1037,7 @@ function Menu:switchItemTable(new_title, new_item_table, itemnumber, itemmatch)
end end
function Menu:onScreenResize(dimen) function Menu:onScreenResize(dimen)
-- @TODO investigate: could this cause minor memory leaks? --- @todo Investigate: could this cause minor memory leaks?
self:init() self:init()
return false return false
end end

@ -61,7 +61,7 @@ local Screen = Device.screen
local band = bit.band local band = bit.band
local function obtainIP() local function obtainIP()
-- TODO: check for DHCP result --- @todo check for DHCP result
local info = InfoMessage:new{text = _("Obtaining IP address…")} local info = InfoMessage:new{text = _("Obtaining IP address…")}
UIManager:show(info) UIManager:show(info)
UIManager:forceRePaint() UIManager:forceRePaint()

@ -182,7 +182,7 @@ function OPDSBrowser:editCalibreServer()
title = _("Edit local calibre host and port"), title = _("Edit local calibre host and port"),
fields = { fields = {
{ {
-- TODO: get IP address of current device --- @todo get IP address of current device
text = calibre.host or "192.168.1.1", text = calibre.host or "192.168.1.1",
hint = _("calibre host"), hint = _("calibre host"),
}, },

@ -350,6 +350,7 @@ function TextBoxWidget:_getLinePads(vertical_string)
return pads return pads
end end
---- Lays out text.
function TextBoxWidget:_renderText(start_row_idx, end_row_idx) function TextBoxWidget:_renderText(start_row_idx, end_row_idx)
local font_height = self.face.size local font_height = self.face.size
if start_row_idx < 1 then start_row_idx = 1 end if start_row_idx < 1 then start_row_idx = 1 end
@ -374,8 +375,8 @@ function TextBoxWidget:_renderText(start_row_idx, end_row_idx)
elseif self.alignment == "right" then elseif self.alignment == "right" then
pen_x = (self.width - line.width) pen_x = (self.width - line.width)
end end
--@todo don't use kerning for monospaced fonts. (houqp) --- @todo don't use kerning for monospaced fonts. (houqp)
-- refert to cb25029dddc42693cc7aaefbe47e9bd3b7e1a750 in master tree --- refer to [cb25029dddc42693cc7aaefbe47e9bd3b7e1a750](https://github.com/koreader/koreader/commit/cb25029dddc42693cc7aaefbe47e9bd3b7e1a750) in master tree
RenderText:renderUtf8Text(self._bb, pen_x, y, self.face, self:_getLineText(line), true, self.bold, self.fgcolor, nil, self:_getLinePads(line)) RenderText:renderUtf8Text(self._bb, pen_x, y, self.face, self:_getLineText(line), true, self.bold, self.fgcolor, nil, self:_getLinePads(line))
y = y + self.line_height_px y = y + self.line_height_px
end end
@ -1100,7 +1101,7 @@ function TextBoxWidget:onHoldWord(callback, ges)
local idx = char_start local idx = char_start
-- find which character the touch is holding -- find which character the touch is holding
while idx < char_end do while idx < char_end do
-- FIXME: this might break if kerning is enabled --- @fixme This might break if kerning is enabled.
char_probe_x = char_probe_x + self.char_width[self.charlist[idx]] + (self.idx_pad[idx] or 0) char_probe_x = char_probe_x + self.char_width[self.charlist[idx]] + (self.idx_pad[idx] or 0)
if char_probe_x > x then if char_probe_x > x then
-- ignore spaces -- ignore spaces

@ -1168,7 +1168,7 @@ table {
-- external link for us, so let's remove this link. -- external link for us, so let's remove this link.
html = html:gsub("<a[^>]*>%s*(<%s*img [^>]*>)%s*</a>", "%1") html = html:gsub("<a[^>]*>%s*(<%s*img [^>]*>)%s*</a>", "%1")
-- TODO: do something for <li class="gallerybox"...> so they are no more --- @todo do something for <li class="gallerybox"...> so they are no more
-- a <li> (crengine displays them one above the other) and can be displayed -- a <li> (crengine displays them one above the other) and can be displayed
-- side by side -- side by side

@ -99,9 +99,7 @@ function util.secondsToClock(seconds, withoutSeconds)
end end
end end
--- Converts seconds to a period of time string.
-- Converts seconds to a period of time string.
---- @int seconds number of seconds ---- @int seconds number of seconds
---- @bool withoutSeconds if true 1h30', if false 1h30'10'' ---- @bool withoutSeconds if true 1h30', if false 1h30'10''
---- @bool hmsFormat, if true format 1h30m10s ---- @bool hmsFormat, if true format 1h30m10s
@ -187,7 +185,7 @@ end
--[[-- --[[--
Compares values in two different tables. Compares values in two different tables.
Source: <a href="https://stackoverflow.com/a/32660766/2470572">https://stackoverflow.com/a/32660766/2470572</a> Source: <https://stackoverflow.com/a/32660766/2470572>
]] ]]
---- @param o1 Lua table ---- @param o1 Lua table
---- @param o2 Lua table ---- @param o2 Lua table
@ -227,7 +225,7 @@ end
--[[-- --[[--
Makes a deep copy of a table. Makes a deep copy of a table.
Source: <a href="https://stackoverflow.com/a/16077650/2470572">https://stackoverflow.com/a/16077650/2470572</a> Source: <https://stackoverflow.com/a/16077650/2470572>
]] ]]
---- @param o Lua table ---- @param o Lua table
---- @treturn Lua table ---- @treturn Lua table
@ -297,7 +295,7 @@ end
--- Reverse the individual greater-than-single-byte characters --- Reverse the individual greater-than-single-byte characters
-- @string string to reverse -- @string string to reverse
-- Taken from https://github.com/blitmap/lua-utf8-simple#utf8reverses -- Taken from <https://github.com/blitmap/lua-utf8-simple#utf8reverses>
function util.utf8Reverse(text) function util.utf8Reverse(text)
text = text:gsub('[%z\1-\127\194-\244][\128-\191]*', function (c) return #c > 1 and c:reverse() end) text = text:gsub('[%z\1-\127\194-\244][\128-\191]*', function (c) return #c > 1 and c:reverse() end)
return text:reverse() return text:reverse()
@ -524,10 +522,10 @@ function util.pathExists(path)
end end
--- As `mkdir -p`. --- As `mkdir -p`.
--- Unlike lfs.mkdir(), does not error if the directory already exists, and -- Unlike [lfs.mkdir](https://keplerproject.github.io/luafilesystem/manual.html#mkdir)(),
--- creates intermediate directories as needed. -- does not error if the directory already exists, and creates intermediate directories as needed.
---- @string path the directory to create -- @string path the directory to create
---- @treturn bool true on success; nil, err_message on error -- @treturn bool true on success; nil, err_message on error
function util.makePath(path) function util.makePath(path)
path = path:gsub("/+$", "") path = path:gsub("/+$", "")
if util.pathExists(path) then return true end if util.pathExists(path) then return true end
@ -563,18 +561,17 @@ local function replaceSlashChar(str)
end end
end end
--- Replaces characters that are invalid filenames. --[[--
-- Replaces characters that are invalid filenames.
-- Replaces the characters <code>\/:*?"<>|</code> with an <code>_</code>
-- unless an optional path is provided. Replaces the characters `\/:*?"<>|` with an `_` unless an optional path is provided. These characters are problematic on Windows filesystems. On Linux only the `/` poses a problem.
-- These characters are problematic on Windows filesystems. On Linux only
-- <code>/</code> poses a problem. If an optional path is provided, @{util.getFilesystemType}() will be used to determine whether stricter VFAT restrictions should be applied.
-- If an optional path is provided, util.getFilesystemType() will be used ]]
-- to determine whether stricter VFAT restrictions should be applied.
---- @string str ---- @string str
---- @string path ---- @string path
---- @int limit ---- @int limit
---- @treturn string ---- @treturn string safe filename
function util.getSafeFilename(str, path, limit, limit_ext) function util.getSafeFilename(str, path, limit, limit_ext)
local filename, suffix = util.splitFileNameSuffix(str) local filename, suffix = util.splitFileNameSuffix(str)
local replaceFunc = replaceAllInvalidChars local replaceFunc = replaceAllInvalidChars
@ -683,12 +680,14 @@ function util.getMenuText(item)
return text return text
end end
--- Replaces invalid UTF-8 characters with a replacement string. --[[--
-- Replaces invalid UTF-8 characters with a replacement string.
-- Based on http://notebook.kulchenko.com/programming/fixing-malformed-utf8-in-lua
---- @string str the string to be checked for invalid characters Based on <http://notebook.kulchenko.com/programming/fixing-malformed-utf8-in-lua>.
---- @string replacement the string to replace invalid characters with @string str the string to be checked for invalid characters
---- @treturn string valid UTF-8 @string replacement the string to replace invalid characters with
@treturn string valid UTF-8
]]
function util.fixUtf8(str, replacement) function util.fixUtf8(str, replacement)
local pos = 1 local pos = 1
local len = #str local len = #str
@ -754,12 +753,14 @@ local HTML_ENTITIES_TO_UTF8 = {
{"&#x(%x+);", function(x) return util.unicodeCodepointToUtf8(tonumber(x,16)) end}, {"&#x(%x+);", function(x) return util.unicodeCodepointToUtf8(tonumber(x,16)) end},
{"&amp;", "&"}, -- must be last {"&amp;", "&"}, -- must be last
} }
--- Replace HTML entities with their UTF8 equivalent in text --[[--
-- Replace HTML entities with their UTF8 equivalent in text.
-- Supports only basic ones and those with numbers (no support
-- for named entities like &eacute;) Supports only basic ones and those with numbers (no support for named entities like `&eacute;`).
--- @int string text with HTML entities
--- @treturn string UTF8 text @int string text with HTML entities
@treturn string UTF8 text
]]
function util.htmlEntitiesToUtf8(text) function util.htmlEntitiesToUtf8(text)
for _, t in ipairs(HTML_ENTITIES_TO_UTF8) do for _, t in ipairs(HTML_ENTITIES_TO_UTF8) do
text = text:gsub(t[1], t[2]) text = text:gsub(t[1], t[2])
@ -767,12 +768,14 @@ function util.htmlEntitiesToUtf8(text)
return text return text
end end
--- Convert simple HTML to plain text --[[--
-- This may fail on complex HTML (with styles, scripts, comments), but should Convert simple HTML to plain text.
-- be fine enough with simple HTML as found in EPUB's <dc:description>.
-- This may fail on complex HTML (with styles, scripts, comments), but should be fine enough with simple HTML as found in EPUB's `<dc:description>`.
--- @string text HTML text
--- @treturn string plain text @string text HTML text
@treturn string plain text
]]
function util.htmlToPlainText(text) function util.htmlToPlainText(text)
-- Replace <br> and <p> with \n -- Replace <br> and <p> with \n
text = text:gsub("%s*<%s*br%s*/?>%s*", "\n") -- <br> and <br/> text = text:gsub("%s*<%s*br%s*/?>%s*", "\n") -- <br> and <br/>

@ -184,7 +184,7 @@ function BackgroundRunner:_execute()
should_ignore = true should_ignore = true
end end
elseif type(job.when) == "string" then elseif type(job.when) == "string" then
-- TODO(Hzj_jie): Implement "idle" mode --- @todo (Hzj_jie): Implement "idle" mode
if job.when == "best-effort" then if job.when == "best-effort" then
should_execute = (round > 0) should_execute = (round > 0)
elseif job.when == "idle" then elseif job.when == "idle" then

@ -410,8 +410,8 @@ end
function CalibreCompanion:getFreeSpace(arg) function CalibreCompanion:getFreeSpace(arg)
logger.dbg("FREE_SPACE", arg) logger.dbg("FREE_SPACE", arg)
-- TODO: portable free space calculation? --- @todo Portable free space calculation?
-- assume we have 1GB of free space on device -- Assume we have 1GB of free space on device.
local free_space = { local free_space = {
free_space_on_device = 1024*1024*1024, free_space_on_device = 1024*1024*1024,
} }

@ -248,7 +248,7 @@ function MyClipping:parseHighlight(highlights, book)
image.drawer = item.drawer image.drawer = item.drawer
clipping.image = self:getImage(image) clipping.image = self:getImage(image)
end end
-- TODO: store chapter info when exporting highlights --- @todo Store chapter info when exporting highlights.
if clipping.text and clipping.text ~= "" or clipping.image then if clipping.text and clipping.text ~= "" or clipping.image then
table.insert(book, { clipping }) table.insert(book, { clipping })
end end

@ -32,7 +32,7 @@ local function include_fold(template, start_tag, end_tag, fold_func, init_func)
local filename = assert(loadstring('return '..string.sub(template, end1 + 1, start2 - 1)))() local filename = assert(loadstring('return '..string.sub(template, end1 + 1, start2 - 1)))()
assert(filename) assert(filename)
local fin = assert(io.open(filename)) local fin = assert(io.open(filename))
-- TODO: detect cyclic inclusion? --- @todo Detect cyclic inclusion?
result = fold_func(result, include_fold(fin:read('*a'), start_tag, end_tag, fold_func, init_func), filename) result = fold_func(result, include_fold(fin:read('*a'), start_tag, end_tag, fold_func, init_func), filename)
fin:close() fin:close()
end end

@ -382,7 +382,7 @@ function EpubDownloadBackend:createEpub(epub_path, html, url, include_images, me
-- ---------------------------------------------------------------- -- ----------------------------------------------------------------
-- OEBPS/stylesheet.css -- OEBPS/stylesheet.css
-- TODO: We told it we'd include a stylesheet.css, so it's probably best --- @todo We told it we'd include a stylesheet.css, so it's probably best
-- that we do. In theory, we could try to fetch any *.css files linked in -- that we do. In theory, we could try to fetch any *.css files linked in
-- the main html. -- the main html.
epub:add("OEBPS/stylesheet.css", [[ epub:add("OEBPS/stylesheet.css", [[
@ -400,7 +400,7 @@ function EpubDownloadBackend:createEpub(epub_path, html, url, include_images, me
-- Add our own first section for first page, with page name as title -- Add our own first section for first page, with page name as title
table.insert(toc_ncx_parts, string.format([[<navPoint id="navpoint-%s" playOrder="%s"><navLabel><text>%s</text></navLabel><content src="content.html"/>]], num, num, page_htmltitle)) table.insert(toc_ncx_parts, string.format([[<navPoint id="navpoint-%s" playOrder="%s"><navLabel><text>%s</text></navLabel><content src="content.html"/>]], num, num, page_htmltitle))
table.insert(toc_ncx_parts, np_end) table.insert(toc_ncx_parts, np_end)
-- TODO: Not essential for most articles, but longer articles might benefit --- @todo Not essential for most articles, but longer articles might benefit
-- from parsing <h*> tags and constructing a proper TOC -- from parsing <h*> tags and constructing a proper TOC
while cur_level > 0 do while cur_level > 0 do
table.insert(toc_ncx_parts, np_end) table.insert(toc_ncx_parts, np_end)

@ -57,7 +57,7 @@ local function getFeedLink(possible_link)
end end
end end
-- TODO: implement as NetworkMgr:afterWifiAction with configuration options --- @todo Implement as NetworkMgr:afterWifiAction with configuration options.
function NewsDownloader:afterWifiAction() function NewsDownloader:afterWifiAction()
if not wifi_enabled_before_action then if not wifi_enabled_before_action then
NetworkMgr:promptWifiOff() NetworkMgr:promptWifiOff()

@ -44,7 +44,7 @@ function Send2Ebook:downloadFileAndRemove(connection_url, remote_path, local_dow
end end
end end
-- TODO: implement as NetworkMgr:afterWifiAction with configuration options --- @todo Implement as NetworkMgr:afterWifiAction with configuration options.
function Send2Ebook:afterWifiAction() function Send2Ebook:afterWifiAction()
if not wifi_enabled_before_action then if not wifi_enabled_before_action then
NetworkMgr:promptWifiOff() NetworkMgr:promptWifiOff()

@ -629,7 +629,7 @@ end
function ReaderStatistics:getBookProperties() function ReaderStatistics:getBookProperties()
local props = self.view.document:getProps() local props = self.view.document:getProps()
if props.title == "No document" or props.title == "" then if props.title == "No document" or props.title == "" then
-- FIXME: sometimes crengine returns "No document", try one more time --- @fixme Sometimes crengine returns "No document", try one more time.
props = self.view.document:getProps() props = self.view.document:getProps()
end end
return props return props

@ -1,7 +1,7 @@
local Device = require("device") local Device = require("device")
local command local command
-- TODO(hzj-jie): Does pocketbook provide ntpdate? --- @todo (hzj-jie): Does pocketbook provide ntpdate?
if Device:isKobo() then if Device:isKobo() then
command = "ntpd -q -n -p pool.ntp.org" command = "ntpd -q -n -p pool.ntp.org"
elseif Device:isCervantes() or Device:isKindle() or Device:isPocketBook() then elseif Device:isCervantes() or Device:isKindle() or Device:isPocketBook() then

@ -1,3 +1,7 @@
--[[--
@module koplugin.wallabag
]]
local DataStorage = require("datastorage") local DataStorage = require("datastorage")
local DocSettings = require("docsettings") local DocSettings = require("docsettings")
local Event = require("ui/event") local Event = require("ui/event")
@ -320,6 +324,9 @@ function Wallabag:getArticleList()
return self:callAPI( "GET", articles_url, nil, "", "" ) return self:callAPI( "GET", articles_url, nil, "", "" )
end end
--- Download Wallabag article.
-- @string article
-- @treturn int 1 failed, 2 skipped, 3 downloaded
function Wallabag:download(article) function Wallabag:download(article)
local skip_article = false local skip_article = false
local item_url = "/api/entries/" .. article.id .. "/export.epub" local item_url = "/api/entries/" .. article.id .. "/export.epub"
@ -333,7 +340,7 @@ function Wallabag:download(article)
if attr then if attr then
-- File already exists, skip it. Preferably only skip if the date of local file is newer than server's. -- File already exists, skip it. Preferably only skip if the date of local file is newer than server's.
-- newsdownloader.koplugin has a date parser but it is available only if the plugin is activated. -- newsdownloader.koplugin has a date parser but it is available only if the plugin is activated.
-- TODO: find a better solution --- @todo find a better solution
if self.is_dateparser_available then if self.is_dateparser_available then
local server_date = self.dateparser.parse(article.updated_at) local server_date = self.dateparser.parse(article.updated_at)
if server_date < attr.modification then if server_date < attr.modification then

@ -185,7 +185,7 @@ describe("KOSync modules #notest #nocov", function()
body = {} body = {}
} }
-- TODO: Test kosync module --- @todo Test kosync module
local function mockKOSyncClient() --luacheck: ignore local function mockKOSyncClient() --luacheck: ignore
package.loaded["KOSyncClient"] = nil package.loaded["KOSyncClient"] = nil
local c = require("KOSyncClient") local c = require("KOSyncClient")

@ -21,8 +21,7 @@ describe("ReaderBookmark module", function()
readerui.highlight:onHoldRelease() readerui.highlight:onHoldRelease()
assert.truthy(readerui.highlight.highlight_dialog) assert.truthy(readerui.highlight.highlight_dialog)
readerui.highlight:onHighlight() readerui.highlight:onHighlight()
-- TODO: replace scheduleIn with nextTick UIManager:nextTick(function()
UIManager:scheduleIn(1, function()
UIManager:close(readerui.highlight.highlight_dialog) UIManager:close(readerui.highlight.highlight_dialog)
UIManager:close(readerui) UIManager:close(readerui)
end) end)
@ -30,20 +29,21 @@ describe("ReaderBookmark module", function()
end end
local function toggler_dogear(readerui) local function toggler_dogear(readerui)
readerui.bookmark:onToggleBookmark() readerui.bookmark:onToggleBookmark()
--- @todo Replace scheduleIn with nextTick
UIManager:scheduleIn(1, function() UIManager:scheduleIn(1, function()
UIManager:close(readerui) UIManager:close(readerui)
end) end)
UIManager:run() UIManager:run()
end end
local function show_bookmark_menu(readerui) local function show_bookmark_menu(readerui)
UIManager:scheduleIn(1, function() UIManager:nextTick(function()
UIManager:close(readerui.bookmark.bookmark_menu) UIManager:close(readerui.bookmark.bookmark_menu)
UIManager:close(readerui) UIManager:close(readerui)
end) end)
UIManager:run() UIManager:run()
end end
describe("bookmark for EPUB document", function() describe("EPUB document", function()
local readerui local readerui
setup(function() setup(function()
DocSettings:open(sample_epub):purge() DocSettings:open(sample_epub):purge()
@ -57,7 +57,7 @@ describe("ReaderBookmark module", function()
UIManager:show(readerui) UIManager:show(readerui)
readerui.rolling:onGotoPage(10) readerui.rolling:onGotoPage(10)
end) end)
it("should does bookmark comparison properly", function() it("should compare bookmarks properly", function()
assert.truthy(readerui.bookmark:isBookmarkSame( assert.truthy(readerui.bookmark:isBookmarkSame(
{ notes = 'foo', page = 1, pos0 = 0, pos1 = 2, }, { notes = 'foo', page = 1, pos0 = 0, pos1 = 2, },
{ notes = 'foo', page = 1, pos0 = 0, pos1 = 2, })) { notes = 'foo', page = 1, pos0 = 0, pos1 = 2, }))
@ -68,13 +68,13 @@ describe("ReaderBookmark module", function()
{ notes = 'foo0', page = 1, pos0 = 0, pos1 = 0, }, { notes = 'foo0', page = 1, pos0 = 0, pos1 = 0, },
{ notes = 'foo', page = 1, pos0 = 0, pos1 = 2, })) { notes = 'foo', page = 1, pos0 = 0, pos1 = 2, }))
end) end)
it("should show dogear after togglering non-bookmarked page", function() it("should show dogear after toggling non-bookmarked page", function()
assert.falsy(readerui.view.dogear_visible) assert.falsy(readerui.view.dogear_visible)
toggler_dogear(readerui) toggler_dogear(readerui)
Screen:shot("screenshots/reader_bookmark_dogear_epub.png") Screen:shot("screenshots/reader_bookmark_dogear_epub.png")
assert.truthy(readerui.view.dogear_visible) assert.truthy(readerui.view.dogear_visible)
end) end)
it("should not show dogear after togglering bookmarked page", function() it("should not show dogear after toggling bookmarked page", function()
assert.truthy(readerui.view.dogear_visible) assert.truthy(readerui.view.dogear_visible)
toggler_dogear(readerui) toggler_dogear(readerui)
Screen:shot("screenshots/reader_bookmark_nodogear_epub.png") Screen:shot("screenshots/reader_bookmark_nodogear_epub.png")
@ -125,7 +125,7 @@ describe("ReaderBookmark module", function()
end) end)
end) end)
describe("bookmark for PDF document", function() describe("PDF document", function()
local readerui local readerui
setup(function() setup(function()
DocSettings:open(sample_pdf):purge() DocSettings:open(sample_pdf):purge()
@ -167,12 +167,12 @@ describe("ReaderBookmark module", function()
{ notes = 'foo', pos0 = { page = 1 , x = 1, y = 3}, { notes = 'foo', pos0 = { page = 1 , x = 1, y = 3},
pos1 = { page = 1, x = 20, y = 2 }, })) pos1 = { page = 1, x = 20, y = 2 }, }))
end) end)
it("should show dogear after togglering non-bookmarked page", function() it("should show dogear after toggling non-bookmarked page", function()
toggler_dogear(readerui) toggler_dogear(readerui)
Screen:shot("screenshots/reader_bookmark_dogear_pdf.png") Screen:shot("screenshots/reader_bookmark_dogear_pdf.png")
assert.truthy(readerui.view.dogear_visible) assert.truthy(readerui.view.dogear_visible)
end) end)
it("should not show dogear after togglering bookmarked page", function() it("should not show dogear after toggling bookmarked page", function()
toggler_dogear(readerui) toggler_dogear(readerui)
Screen:shot("screenshots/reader_bookmark_nodogear_pdf.png") Screen:shot("screenshots/reader_bookmark_nodogear_pdf.png")
assert.truthy(not readerui.view.dogear_visible) assert.truthy(not readerui.view.dogear_visible)

@ -77,8 +77,8 @@ describe("Readerhighlight module", function()
UIManager:quit() UIManager:quit()
readerui.rolling:onGotoPage(page) readerui.rolling:onGotoPage(page)
UIManager:show(readerui) UIManager:show(readerui)
-- HACK: Mock UIManager:run x and y for readerui.dimen --- @fixme HACK: Mock UIManager:run x and y for readerui.dimen
-- TODO: refactor readerview's dimen handling so we can get rid of --- @todo Refactor readerview's dimen handling so we can get rid of
-- this workaround -- this workaround
readerui:paintTo(Screen.bb, 0, 0) readerui:paintTo(Screen.bb, 0, 0)
end) end)

Loading…
Cancel
Save