diff --git a/src/calibre/gui2/tweak_book/search.py b/src/calibre/gui2/tweak_book/search.py
index 02cd4d4e5e..49d25b7e6d 100644
--- a/src/calibre/gui2/tweak_book/search.py
+++ b/src/calibre/gui2/tweak_book/search.py
@@ -203,13 +203,15 @@ class ModeBox(QComboBox):
def __init__(self, parent):
QComboBox.__init__(self, parent)
- self.addItems([_('Normal'), _('Regex'), _('Regex-function')])
+ self.addItems([_('Normal'), _('Fuzzy'), _('Regex'), _('Regex-function')])
self.setToolTip('' + _(
'''Select how the search expression is interpreted
- Normal
- - The search expression is treated as normal text, calibre will look for the exact text,
- except that spaces are allowed to match any number of spaces and line breaks.
+ - The search expression is treated as normal text, calibre will look for the exact text
+ - Fuzzy
+ - The search expression is treated as "fuzzy" which means spaces will match any space character,
+ including tabs and line breaks. Plain quotes will match the typographical equivalents, etc.
- Regex
- The search expression is interpreted as a regular expression. See the User Manual for more help on using regular expressions.
- Regex-function
@@ -218,11 +220,11 @@ class ModeBox(QComboBox):
@property
def mode(self):
- return ('normal', 'regex', 'function')[self.currentIndex()]
+ return ('normal', 'fuzzy', 'regex', 'function')[self.currentIndex()]
@mode.setter
def mode(self, val):
- self.setCurrentIndex({'regex':1, 'function':2}.get(val, 0))
+ self.setCurrentIndex({'fuzzy': 1, 'regex':2, 'function':3}.get(val, 0))
class SearchWidget(QWidget):
@@ -345,8 +347,8 @@ class SearchWidget(QWidget):
self.functions.setText('')
def mode_changed(self, idx):
- self.da.setVisible(idx > 0)
- function_mode = idx == 2
+ self.da.setVisible(idx > 1)
+ function_mode = idx == 3
self.rl.setVisible(not function_mode)
self.rl2.setVisible(function_mode)
self.replace_text.setVisible(not function_mode)
@@ -740,10 +742,12 @@ class EditSearch(QFrame): # {{{
self.function.setText('')
def mode_changed(self, idx):
- self.dot_all.setVisible(idx > 0)
- self.functions_container.setVisible(idx == 2)
- self.la3.setVisible(idx < 2)
- self.replace.setVisible(idx < 2)
+ mode = self.mode_box.mode
+ self.dot_all.setVisible(mode in ('regex', 'function'))
+ function_mode = mode == 'function'
+ self.functions_container.setVisible(function_mode)
+ self.la3.setVisible(not function_mode)
+ self.replace.setVisible(not function_mode)
def show_search(self, search=None, search_index=-1, state=None):
self.title.setText('' + (_('Add search') if search_index == -1 else _('Edit search')))
@@ -1271,10 +1275,13 @@ class InvalidRegex(regex.error):
def get_search_regex(state):
raw = state['find']
- is_regex = state['mode'] != 'normal'
+ is_regex = state['mode'] not in ('normal', 'fuzzy')
if not is_regex:
- parts = (regex.escape(x, special_only=True) for x in raw.split())
- raw = r'\s+'.join(parts)
+ if state['mode'] == 'fuzzy':
+ from calibre.gui2.viewer.search import text_to_regex
+ raw = text_to_regex(raw)
+ else:
+ raw = regex.escape(raw, special_only=True)
flags = REGEX_FLAGS
if not state['case_sensitive']:
flags |= regex.IGNORECASE
@@ -1292,7 +1299,7 @@ def get_search_regex(state):
def get_search_function(state):
ans = state['replace']
- is_regex = state['mode'] != 'normal'
+ is_regex = state['mode'] not in ('normal', 'fuzzy')
if not is_regex:
# We dont want backslash escape sequences interpreted in normal mode
return lambda m: ans
diff --git a/src/calibre/gui2/tweak_book/text_search.py b/src/calibre/gui2/tweak_book/text_search.py
index b3bfba7c46..0f00763580 100644
--- a/src/calibre/gui2/tweak_book/text_search.py
+++ b/src/calibre/gui2/tweak_book/text_search.py
@@ -30,8 +30,7 @@ class ModeBox(QComboBox):
'''Select how the search expression is interpreted
- Normal
- - The search expression is treated as normal text, calibre will look for the exact text,
- except that spaces are allowed to match any number of spaces and line breaks.
+ - The search expression is treated as normal text, calibre will look for the exact text.
- Regex
- The search expression is interpreted as a regular expression. See the User Manual for more help on using regular expressions.
'''))