From ab6867c8faa3e8cc0d90c114aacc4d8f0e49d53a Mon Sep 17 00:00:00 2001 From: zwim <36999612+zwim@users.noreply.github.com> Date: Thu, 15 Jul 2021 12:53:28 +0200 Subject: [PATCH] FileManager: allow case sensitive file search (#7956) Bump base for cre.cpp cleanup and utf8proc FFI. Add a checkbutton for case sensitive search in FileBrowser, and use Utf8Proc.lowercase() for case insensitive search. Also use it in ReaderUserHyph as a replacement for crengine getLowercasedWord(). --- base | 2 +- .../filemanager/filemanagerfilesearcher.lua | 53 ++++++++++++++++++- frontend/apps/filemanager/filemanagermenu.lua | 2 +- .../apps/reader/modules/readeruserhyph.lua | 23 ++++---- frontend/document/credocument.lua | 19 ------- 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/base b/base index dfa6f748a..be4537e12 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit dfa6f748a5d0734c8fc99d4de509610394484527 +Subproject commit be4537e12d6b86dac6ae4667c9fe96a96ce4f7e0 diff --git a/frontend/apps/filemanager/filemanagerfilesearcher.lua b/frontend/apps/filemanager/filemanagerfilesearcher.lua index f8a6962a4..826877e9f 100644 --- a/frontend/apps/filemanager/filemanagerfilesearcher.lua +++ b/frontend/apps/filemanager/filemanagerfilesearcher.lua @@ -1,12 +1,17 @@ +local CheckButton = require("ui/widget/checkbutton") local CenterContainer = require("ui/widget/container/centercontainer") local DocumentRegistry = require("document/documentregistry") local Font = require("ui/font") +local HorizontalGroup = require("ui/widget/horizontalgroup") +local HorizontalSpan = require("ui/widget/horizontalspan") local InfoMessage = require("ui/widget/infomessage") local InputContainer = require("ui/widget/container/inputcontainer") local InputDialog = require("ui/widget/inputdialog") local Menu = require("ui/widget/menu") local Size = require("ui/size") local UIManager = require("ui/uimanager") +local Utf8Proc = require("ffi/utf8proc") +local VerticalGroup = require("ui/widget/verticalgroup") local lfs = require("libs/libkoreader-lfs") local BaseUtil = require("ffi/util") local util = require("util") @@ -73,9 +78,24 @@ function FileSearcher:setSearchResults() if keywords == "*" then -- one * to show all files self.results = self.files else + if not self.case_sensitive then + keywords = Utf8Proc.lowercase(keywords) + end + -- replace '.' with '%.' + keywords = keywords:gsub("%.","%%%.") + -- replace '*' with '.*' + keywords = keywords:gsub("%*","%.%*") + -- replace '?' with '.' + keywords = keywords:gsub("%?","%.") for __,f in pairs(self.files) do - if string.find(string.lower(f.name), string.lower(keywords)) and string.sub(f.name,-4) ~= ".sdr" then - table.insert(self.results, f) + if self.case_sensitive then + if string.find(f.name, keywords) and string.sub(f.name,-4) ~= ".sdr" then + table.insert(self.results, f) + end + else + if string.find(Utf8Proc.lowercase(f.name), keywords) and string.sub(f.name,-4) ~= ".sdr" then + table.insert(self.results, f) + end end end end @@ -138,6 +158,35 @@ function FileSearcher:onShowFileSearch() }, }, } + -- checkbox + self.check_button_case = CheckButton:new{ + text = _("Case sensitive"), + checked = self.case_sensitive, + parent = self.search_dialog, + callback = function() + if not self.check_button_case.checked then + self.check_button_case:check() + self.case_sensitive = true + else + self.check_button_case:unCheck() + self.case_sensitive = false + end + end, + } + + local checkbox_shift = math.floor((self.search_dialog.width - self.search_dialog._input_widget.width) / 2 + 0.5) + local check_buttons = HorizontalGroup:new{ + HorizontalSpan:new{width = checkbox_shift}, + VerticalGroup:new{ + align = "left", + self.check_button_case, + }, + } + + -- insert check buttons before the regular buttons + local nb_elements = #self.search_dialog.dialog_frame[1] + table.insert(self.search_dialog.dialog_frame[1], nb_elements-1, check_buttons) + UIManager:show(self.search_dialog) self.search_dialog:onShowKeyboard() end diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index f3def2da2..304db9780 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -662,8 +662,8 @@ To: text = _("File search"), help_text = _([[Search a book by filename in the current or home folder and its subfolders. +Wildcards for one '?' or more '*' characters can be used. A search for '*' will show all files. -Search string supports Lua patterns. Tap a book in the search results to open it.]]), callback = function() diff --git a/frontend/apps/reader/modules/readeruserhyph.lua b/frontend/apps/reader/modules/readeruserhyph.lua index c9863b349..efd8959a0 100644 --- a/frontend/apps/reader/modules/readeruserhyph.lua +++ b/frontend/apps/reader/modules/readeruserhyph.lua @@ -4,6 +4,7 @@ local FFIUtil = require("ffi/util") local InfoMessage = require("ui/widget/infomessage") local InputDialog = require("ui/widget/inputdialog") local UIManager = require("ui/uimanager") +local Utf8Proc = require("ffi/utf8proc") local WidgetContainer = require("ui/widget/container/widgetcontainer") local lfs = require("libs/libkoreader-lfs") local logger = require("logger") @@ -29,7 +30,8 @@ end -- Unload is done automatically when a new dictionary is loaded. function ReaderUserHyph:loadDictionary(name, reload) if G_reader_settings:isTrue("hyph_user_dict") and lfs.attributes(name, "mode") == "file" then - local ret = self.ui.document:setUserHyphenationDict(name, reload) + logger.dbg("set user hyphenation dict", name, reload) + local ret = cre.setUserHyphenationDict(name, reload) -- this should only happen, if a user edits a dictionary by hand or the user messed -- with the dictionary file by hand. -> Warning and disable. if ret == self.USER_DICT_ERROR_NOT_SORTED then @@ -45,7 +47,8 @@ function ReaderUserHyph:loadDictionary(name, reload) logger.warn("UserHyph: Dictionary " .. name .. " has corrupted entries.") end else - self.ui.document:setUserHyphenationDict() -- clear crengine user hyph dict + logger.dbg("reset user hyphenation dict") + cre.setUserHyphenationDict("", true) -- clear crengine user hyph dict end end @@ -101,7 +104,7 @@ function ReaderUserHyph:checkHyphenation(suggestion, word) end suggestion = suggestion:gsub("-","") - if self.ui.document:getLowercasedWord(suggestion) == self.ui.document:getLowercasedWord(word) then + if Utf8Proc.lowercase(suggestion) == Utf8Proc.lowercase(word) then return true -- characters match (case insensitive) end return false @@ -117,22 +120,22 @@ function ReaderUserHyph:updateDictionary(word, hyphenation) return end - local word_lower = self.ui.document:getLowercasedWord(word) + local word_lower = Utf8Proc.lowercase(word) local line local dict = io.open(dict_file, "r") if dict then line = dict:read() --search entry - while line and self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) < word_lower do + while line and Utf8Proc.lowercase(line:sub(1, line:find(";") - 1)) < word_lower do new_dict:write(line .. "\n") line = dict:read() end -- last word = nil if EOF, else last_word=word if found in file, else last_word is word after the new entry if line then - local last_word = self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) - if last_word == self.ui.document:getLowercasedWord(word) then + local last_word = Utf8Proc.lowercase(line:sub(1, line:find(";") - 1)) + if last_word == Utf8Proc.lowercase(word) then line = nil -- word found end else @@ -172,14 +175,14 @@ function ReaderUserHyph:modifyUserEntry(word) if not self.ui.document then return end - local suggested_hyphenation = self.ui.document:getHyphenationForWord(word) + local suggested_hyphenation = cre.getHyphenationForWord(word) local input_dialog input_dialog = InputDialog:new{ title = T(_("Hyphenate: %1"), word), description = _("Add hyphenation positions with hyphens ('-') or spaces (' ')."), input = suggested_hyphenation, - old_hyph_lowercase = self.ui.document:getLowercasedWord(suggested_hyphenation), + old_hyph_lowercase = Utf8Proc.lowercase(suggested_hyphenation), input_type = "string", buttons = { { @@ -207,7 +210,7 @@ function ReaderUserHyph:modifyUserEntry(word) if self:checkHyphenation(new_suggestion, word) then -- don't save if no changes - if self.ui.document:getLowercasedWord(new_suggestion) ~= input_dialog.old_hyph_lowercase then + if Utf8Proc.lowercase(new_suggestion) ~= input_dialog.old_hyph_lowercase then self:updateDictionary(word, new_suggestion) end UIManager:close(input_dialog) diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 30b46a692..a13c1f796 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -980,25 +980,6 @@ function CreDocument:setTextHyphenationSoftHyphensOnly(toggle) self._document:setStringProperty("crengine.textlang.hyphenation.soft.hyphens.only", toggle and 1 or 0) end -function CreDocument:setUserHyphenationDict(dict, reload) - logger.dbg("CreDocument: set textlang hyphenation dict", dict or "none") - return self._document:setUserHyphenationDict(dict or "", reload or false) -end - -function CreDocument:getHyphenationForWord(word) - if word then - return self._document:getHyphenationForWord(word) - end - return word -end - -function CreDocument:getLowercasedWord(word) - if word then - return self._document:getLowercasedWord(word) - end - return word -end - function CreDocument:setTextHyphenationForceAlgorithmic(toggle) logger.dbg("CreDocument: set textlang hyphenation force algorithmic", toggle) self._document:setStringProperty("crengine.textlang.hyphenation.force.algorithmic", toggle and 1 or 0)