mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Viewer: Allow using search expressions for --open-at
This commit is contained in:
parent
2843ec81e1
commit
30fe553c28
@ -131,7 +131,10 @@ View an e-book.
|
|||||||
'the string "something". The form toc-href:something will match the '
|
'the string "something". The form toc-href:something will match the '
|
||||||
'href (internal link destination) of toc nodes. The matching is exact. '
|
'href (internal link destination) of toc nodes. The matching is exact. '
|
||||||
'If you want to match a substring, use the form toc-href-contains:something. '
|
'If you want to match a substring, use the form toc-href-contains:something. '
|
||||||
'The form ref:something will use Reference mode references.'))
|
'The form ref:something will use Reference mode references. The form search:something will'
|
||||||
|
' search for something after opening the book. The form regex:something will search'
|
||||||
|
' for the regular expression something after opening the book.'
|
||||||
|
))
|
||||||
a('--continue', default=False, action='store_true', dest='continue_reading',
|
a('--continue', default=False, action='store_true', dest='continue_reading',
|
||||||
help=_('Continue reading the last opened book'))
|
help=_('Continue reading the last opened book'))
|
||||||
|
|
||||||
@ -197,7 +200,7 @@ def main(args=sys.argv):
|
|||||||
oat = opts.open_at
|
oat = opts.open_at
|
||||||
if oat and not (
|
if oat and not (
|
||||||
oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or
|
oat.startswith('toc:') or oat.startswith('toc-href:') or oat.startswith('toc-href-contains:') or
|
||||||
oat.startswith('epubcfi(/') or is_float(oat) or oat.startswith('ref:')):
|
oat.startswith('epubcfi(/') or is_float(oat) or oat.startswith('ref:') or oat.startswith('search:') or oat.startswith('regex:')):
|
||||||
raise SystemExit(f'Not a valid --open-at value: {opts.open_at}')
|
raise SystemExit(f'Not a valid --open-at value: {opts.open_at}')
|
||||||
|
|
||||||
if get_session_pref('singleinstance', False):
|
if get_session_pref('singleinstance', False):
|
||||||
|
@ -319,9 +319,10 @@ def search_in_name(name, search_query, ctx_size=75):
|
|||||||
yield match.span()
|
yield match.span()
|
||||||
else:
|
else:
|
||||||
spans = []
|
spans = []
|
||||||
a = lambda s, l: spans.append((s, s + l))
|
|
||||||
primary_collator_without_punctuation().find_all(search_query.text, raw, a, search_query.mode == 'word')
|
|
||||||
miter = lambda: spans
|
miter = lambda: spans
|
||||||
|
if raw:
|
||||||
|
a = lambda s, l: spans.append((s, s + l))
|
||||||
|
primary_collator_without_punctuation().find_all(search_query.text, raw, a, search_query.mode == 'word')
|
||||||
|
|
||||||
for (start, end) in miter():
|
for (start, end) in miter():
|
||||||
before = raw[max(0, start-ctx_size):start]
|
before = raw[max(0, start-ctx_size):start]
|
||||||
@ -454,9 +455,16 @@ class SearchInput(QWidget): # {{{
|
|||||||
def find_previous(self):
|
def find_previous(self):
|
||||||
self.emit_search(backwards=True)
|
self.emit_search(backwards=True)
|
||||||
|
|
||||||
def focus_input(self, text=None):
|
def focus_input(self, text=None, search_type=None, case_sensitive=None):
|
||||||
if text and hasattr(text, 'rstrip'):
|
if text and hasattr(text, 'rstrip'):
|
||||||
self.search_box.setText(text)
|
self.search_box.setText(text)
|
||||||
|
if search_type is not None:
|
||||||
|
idx = self.query_type.findData(search_type)
|
||||||
|
if idx < 0:
|
||||||
|
idx = self.query_type.findData('normal')
|
||||||
|
self.query_type.setCurrentIndex(idx)
|
||||||
|
if case_sensitive is not None:
|
||||||
|
self.case_sensitive.setChecked(bool(case_sensitive))
|
||||||
self.search_box.setFocus(Qt.FocusReason.OtherFocusReason)
|
self.search_box.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
le = self.search_box.lineEdit()
|
le = self.search_box.lineEdit()
|
||||||
le.end(False)
|
le.end(False)
|
||||||
@ -668,8 +676,8 @@ class SearchPanel(QWidget): # {{{
|
|||||||
def update_hidden_message(self):
|
def update_hidden_message(self):
|
||||||
self.hidden_message.setVisible(self.results.current_result_is_hidden)
|
self.hidden_message.setVisible(self.results.current_result_is_hidden)
|
||||||
|
|
||||||
def focus_input(self, text=None):
|
def focus_input(self, text=None, search_type=None, case_sensitive=None):
|
||||||
self.search_input.focus_input(text)
|
self.search_input.focus_input(text, search_type, case_sensitive)
|
||||||
|
|
||||||
def search_cleared(self):
|
def search_cleared(self):
|
||||||
self.results.clear_all_results()
|
self.results.clear_all_results()
|
||||||
|
@ -99,6 +99,7 @@ class EbookViewer(MainWindow):
|
|||||||
t.setSingleShot(True), t.setInterval(3000), t.setTimerType(Qt.TimerType.VeryCoarseTimer)
|
t.setSingleShot(True), t.setInterval(3000), t.setTimerType(Qt.TimerType.VeryCoarseTimer)
|
||||||
connect_lambda(t.timeout, self, lambda self: self.save_annotations(in_book_file=False))
|
connect_lambda(t.timeout, self, lambda self: self.save_annotations(in_book_file=False))
|
||||||
self.pending_open_at = open_at
|
self.pending_open_at = open_at
|
||||||
|
self.pending_search = None
|
||||||
self.base_window_title = _('E-book viewer')
|
self.base_window_title = _('E-book viewer')
|
||||||
self.setDockOptions(QMainWindow.DockOption.AnimatedDocks | QMainWindow.DockOption.AllowTabbedDocks | QMainWindow.DockOption.AllowNestedDocks)
|
self.setDockOptions(QMainWindow.DockOption.AnimatedDocks | QMainWindow.DockOption.AllowTabbedDocks | QMainWindow.DockOption.AllowNestedDocks)
|
||||||
self.setWindowTitle(self.base_window_title)
|
self.setWindowTitle(self.base_window_title)
|
||||||
@ -195,6 +196,7 @@ class EbookViewer(MainWindow):
|
|||||||
self.web_view.highlights_changed.connect(self.highlights_changed)
|
self.web_view.highlights_changed.connect(self.highlights_changed)
|
||||||
self.web_view.update_reading_rates.connect(self.update_reading_rates)
|
self.web_view.update_reading_rates.connect(self.update_reading_rates)
|
||||||
self.web_view.edit_book.connect(self.edit_book)
|
self.web_view.edit_book.connect(self.edit_book)
|
||||||
|
self.web_view.content_file_changed.connect(self.content_file_changed)
|
||||||
self.actions_toolbar.initialize(self.web_view, self.search_dock.toggleViewAction())
|
self.actions_toolbar.initialize(self.web_view, self.search_dock.toggleViewAction())
|
||||||
at.update_action_state(False)
|
at.update_action_state(False)
|
||||||
self.setCentralWidget(self.web_view)
|
self.setCentralWidget(self.web_view)
|
||||||
@ -310,11 +312,11 @@ class EbookViewer(MainWindow):
|
|||||||
if not is_visible:
|
if not is_visible:
|
||||||
self.toc.scroll_to_current_toc_node()
|
self.toc.scroll_to_current_toc_node()
|
||||||
|
|
||||||
def show_search(self, text, trigger=False):
|
def show_search(self, text, trigger=False, search_type=None, case_sensitive=None):
|
||||||
self.search_dock.setVisible(True)
|
self.search_dock.setVisible(True)
|
||||||
self.search_dock.activateWindow()
|
self.search_dock.activateWindow()
|
||||||
self.search_dock.raise_()
|
self.search_dock.raise_()
|
||||||
self.search_widget.focus_input(text)
|
self.search_widget.focus_input(text, search_type, case_sensitive)
|
||||||
if trigger:
|
if trigger:
|
||||||
self.search_widget.trigger()
|
self.search_widget.trigger()
|
||||||
|
|
||||||
@ -425,6 +427,11 @@ class EbookViewer(MainWindow):
|
|||||||
self.loading_overlay.hide()
|
self.loading_overlay.hide()
|
||||||
self.actions_toolbar.update_action_state(True)
|
self.actions_toolbar.update_action_state(True)
|
||||||
|
|
||||||
|
def content_file_changed(self, fname):
|
||||||
|
if self.pending_search:
|
||||||
|
search, self.pending_search = self.pending_search, None
|
||||||
|
self.show_search(text=search['query'], trigger=True, search_type=search['type'], case_sensitive=search['case_sensitive'])
|
||||||
|
|
||||||
def show_error(self, title, msg, details):
|
def show_error(self, title, msg, details):
|
||||||
self.loading_overlay.hide()
|
self.loading_overlay.hide()
|
||||||
error_dialog(self, title, msg, det_msg=details or None, show=True)
|
error_dialog(self, title, msg, det_msg=details or None, show=True)
|
||||||
@ -526,6 +533,7 @@ class EbookViewer(MainWindow):
|
|||||||
if self.shutting_down:
|
if self.shutting_down:
|
||||||
return
|
return
|
||||||
open_at, self.pending_open_at = self.pending_open_at, None
|
open_at, self.pending_open_at = self.pending_open_at, None
|
||||||
|
self.pending_search = None
|
||||||
self.web_view.clear_caches()
|
self.web_view.clear_caches()
|
||||||
if not ok:
|
if not ok:
|
||||||
self.actions_toolbar.update_action_state(False)
|
self.actions_toolbar.update_action_state(False)
|
||||||
@ -577,6 +585,12 @@ class EbookViewer(MainWindow):
|
|||||||
initial_position = {'type': 'cfi', 'data': open_at}
|
initial_position = {'type': 'cfi', 'data': open_at}
|
||||||
elif open_at.startswith('ref:'):
|
elif open_at.startswith('ref:'):
|
||||||
initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]}
|
initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]}
|
||||||
|
elif open_at.startswith('search:'):
|
||||||
|
self.pending_search = {'type': 'normal', 'query': open_at[len('search:'):], 'case_sensitive': False}
|
||||||
|
initial_position = {'type': 'bookpos', 'data': 0}
|
||||||
|
elif open_at.startswith('regex:'):
|
||||||
|
self.pending_search = {'type': 'regex', 'query': open_at[len('regex:'):], 'case_sensitive': True}
|
||||||
|
initial_position = {'type': 'bookpos', 'data': 0}
|
||||||
elif is_float(open_at):
|
elif is_float(open_at):
|
||||||
initial_position = {'type': 'bookpos', 'data': float(open_at)}
|
initial_position = {'type': 'bookpos', 'data': float(open_at)}
|
||||||
highlights = self.current_book_data['annotations_map']['highlight']
|
highlights = self.current_book_data['annotations_map']['highlight']
|
||||||
|
@ -462,6 +462,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
paged_mode_changed = pyqtSignal()
|
paged_mode_changed = pyqtSignal()
|
||||||
standalone_misc_settings_changed = pyqtSignal(object)
|
standalone_misc_settings_changed = pyqtSignal(object)
|
||||||
view_created = pyqtSignal(object)
|
view_created = pyqtSignal(object)
|
||||||
|
content_file_changed = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
self._host_widget = None
|
self._host_widget = None
|
||||||
@ -623,6 +624,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
|
|
||||||
def on_content_file_changed(self, data):
|
def on_content_file_changed(self, data):
|
||||||
self.current_content_file = data
|
self.current_content_file = data
|
||||||
|
self.content_file_changed.emit(self.current_content_file)
|
||||||
|
|
||||||
def start_book_load(self, initial_position=None, highlights=None, current_book_data=None, reading_rates=None):
|
def start_book_load(self, initial_position=None, highlights=None, current_book_data=None, reading_rates=None):
|
||||||
key = (set_book_path.path,)
|
key = (set_book_path.path,)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user