From 6a1f82320dd27af2b5aa3eeaf614b2af8f9452cd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 2 Aug 2014 16:48:12 +0530 Subject: [PATCH] Use the highlighted matching tags for Live CSS as a performance optimization --- src/calibre/gui2/tweak_book/boss.py | 12 ++---------- .../gui2/tweak_book/editor/smart/__init__.py | 2 +- .../gui2/tweak_book/editor/smart/html.py | 19 ++++++++++++++----- src/calibre/gui2/tweak_book/editor/text.py | 2 ++ src/calibre/gui2/tweak_book/editor/widget.py | 5 ++++- src/calibre/gui2/tweak_book/live_css.py | 4 ++-- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 1ab19cf9d0..e60f4b7b2f 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -1134,14 +1134,6 @@ class Boss(QObject): if name is not None and getattr(ed, 'syntax', None) == 'html': self.gui.preview.sync_to_editor(name, ed.current_tag()) - def sync_live_css_to_editor(self): - ' Sync the Live CSS panel to the current cursor position in the current editor ' - ed = self.gui.central.current_editor - if ed is not None: - name = editor_name(ed) - if name is not None and getattr(ed, 'syntax', None) == 'html': - self.gui.live_css.sync_to_editor(name) - def goto_style_declaration(self, data): name = data['name'] editor = self.edit_file(name, syntax=data['syntax']) @@ -1152,12 +1144,13 @@ class Boss(QObject): editor.data_changed.connect(self.editor_data_changed) editor.copy_available_state_changed.connect(self.editor_copy_available_state_changed) editor.cursor_position_changed.connect(self.sync_preview_to_editor) - editor.cursor_position_changed.connect(self.sync_live_css_to_editor) editor.cursor_position_changed.connect(self.update_cursor_position) if hasattr(editor, 'word_ignored'): editor.word_ignored.connect(self.word_ignored) if hasattr(editor, 'link_clicked'): editor.link_clicked.connect(self.editor_link_clicked) + if getattr(editor, 'syntax', None) == 'html': + editor.smart_highlighting_updated.connect(self.gui.live_css.sync_to_editor) if data is not None: if use_template: editor.init_from_template(data) @@ -1284,7 +1277,6 @@ class Boss(QObject): # focused. This is not inefficient since multiple requests # to sync are de-bounced with a 100 msec wait. self.sync_preview_to_editor() - self.sync_live_css_to_editor() if name is not None: self.gui.file_list.mark_name_as_current(name) if ed.has_line_numbers: diff --git a/src/calibre/gui2/tweak_book/editor/smart/__init__.py b/src/calibre/gui2/tweak_book/editor/smart/__init__.py index 471fac2358..135ac12e52 100644 --- a/src/calibre/gui2/tweak_book/editor/smart/__init__.py +++ b/src/calibre/gui2/tweak_book/editor/smart/__init__.py @@ -20,7 +20,7 @@ class NullSmarts(object): def verify_for_spellcheck(self, cursor, highlighter): return False - def cursor_position_with_sourceline(self, cursor): + def cursor_position_with_sourceline(self, cursor, for_position_sync=True): return None, None def goto_sourceline(self, editor, sourceline, tags, attribute=None): diff --git a/src/calibre/gui2/tweak_book/editor/smart/html.py b/src/calibre/gui2/tweak_book/editor/smart/html.py index 015b00db8f..97c6b9ade4 100644 --- a/src/calibre/gui2/tweak_book/editor/smart/html.py +++ b/src/calibre/gui2/tweak_book/editor/smart/html.py @@ -270,6 +270,10 @@ def set_style_property(tag, property_name, value, editor): class HTMLSmarts(NullSmarts): + def __init__(self, *args, **kwargs): + NullSmarts.__init__(self, *args, **kwargs) + self.last_matched_tag = None + def get_extra_selections(self, editor): ans = [] @@ -288,7 +292,7 @@ class HTMLSmarts(NullSmarts): c = editor.textCursor() block, offset = c.block(), c.positionInBlock() - tag = find_closest_containing_tag(block, offset, max_tags=2000) + tag = self.last_matched_tag = find_closest_containing_tag(block, offset, max_tags=2000) if tag is not None: add_tag(tag) tag = find_closing_tag(tag, max_tags=4000) @@ -391,13 +395,14 @@ class HTMLSmarts(NullSmarts): return False - def cursor_position_with_sourceline(self, cursor, for_position_sync=True): + def cursor_position_with_sourceline(self, cursor, for_position_sync=True, use_matched_tag=True): ''' Return the tag just before the current cursor as a source line number and a list of tags defined on that line upto and including the containing tag. If ``for_position_sync`` is False then the tag *containing* the cursor is returned instead of the tag just before the - cursor. Note that finding the containing tag is relative expensive, so - use with care.''' + cursor. Note that finding the containing tag is expensive, so + use with care. As an optimization, the last tag matched by + get_extra_selections is used, unless use_matched_tag is False. ''' block, offset = cursor.block(), cursor.positionInBlock() if for_position_sync: nblock, boundary = next_tag_boundary(block, offset, forward=False) @@ -417,7 +422,11 @@ class HTMLSmarts(NullSmarts): break block, offset = block.previous(), sys.maxint else: - tag = find_closest_containing_tag(block, offset, max_tags=2000) + tag = None + if use_matched_tag: + tag = self.last_matched_tag + if tag is None: + tag = find_closest_containing_tag(block, offset, max_tags=2000) if tag is None: return None, None start_block, start_offset = tag.start_block, tag.start_offset diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index 16bcc5d57b..a6812cdb78 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -132,6 +132,7 @@ class PlainTextEdit(QPlainTextEdit): class TextEdit(PlainTextEdit): link_clicked = pyqtSignal(object) + smart_highlighting_updated = pyqtSignal() def __init__(self, parent=None, expected_geometry=(100, 50)): PlainTextEdit.__init__(self, parent) @@ -274,6 +275,7 @@ class TextEdit(PlainTextEdit): sel.append(self.current_search_mark) if instant and not self.highlighter.has_requests: sel.extend(self.smarts.get_extra_selections(self)) + self.smart_highlighting_updated.emit() else: self.smarts_highlight_timer.start() self.setExtraSelections(sel) diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index e9603efb7d..081dba6a01 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -107,6 +107,7 @@ class Editor(QMainWindow): cursor_position_changed = pyqtSignal() word_ignored = pyqtSignal(object, object) link_clicked = pyqtSignal(object) + smart_highlighting_updated = pyqtSignal() def __init__(self, syntax, parent=None): QMainWindow.__init__(self, parent) @@ -129,6 +130,7 @@ class Editor(QMainWindow): self.editor.copyAvailable.connect(self._copy_available) self.editor.cursorPositionChanged.connect(self._cursor_position_changed) self.editor.link_clicked.connect(self.link_clicked) + self.editor.smart_highlighting_updated.connect(self.smart_highlighting_updated) @dynamic_property def current_line(self): @@ -328,7 +330,7 @@ class Editor(QMainWindow): self.restore_state() def break_cycles(self): - for x in ('modification_state_changed', 'word_ignored', 'link_clicked'): + for x in ('modification_state_changed', 'word_ignored', 'link_clicked', 'smart_highlighting_updated'): try: getattr(self, x).disconnect() except TypeError: @@ -344,6 +346,7 @@ class Editor(QMainWindow): self.editor.copyAvailable.disconnect() self.editor.cursorPositionChanged.disconnect() self.editor.link_clicked.disconnect() + self.editor.smart_highlighting_updated.disconnect() self.editor.setPlainText('') self.editor.smarts = None diff --git a/src/calibre/gui2/tweak_book/live_css.py b/src/calibre/gui2/tweak_book/live_css.py index 5a31af5068..a6e758f69b 100644 --- a/src/calibre/gui2/tweak_book/live_css.py +++ b/src/calibre/gui2/tweak_book/live_css.py @@ -470,8 +470,8 @@ class LiveCSS(QWidget): actions['auto-reload-preview'].setEnabled(True) return QWidget.showEvent(self, ev) - def sync_to_editor(self, name): - self.start_update_timer() + def sync_to_editor(self): + self.update_data() def update_data(self): if not self.is_visible or self.preview_is_refreshing: