Use the highlighted matching tags for Live CSS as a performance optimization

This commit is contained in:
Kovid Goyal 2014-08-02 16:48:12 +05:30
parent df15f6120a
commit 6a1f82320d
6 changed files with 25 additions and 19 deletions

View file

@ -1134,14 +1134,6 @@ def sync_preview_to_editor(self):
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 @@ def init_editor(self, name, editor, data=None, use_template=False):
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 @@ def apply_current_editor_state(self):
# 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:

View file

@ -20,7 +20,7 @@ def get_smart_selection(self, editor, update=True):
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):

View file

@ -270,6 +270,10 @@ def css(d):
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 @@ def add_tag(tag):
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 @@ def verify_for_spellcheck(self, cursor, highlighter):
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 @@ def cursor_position_with_sourceline(self, cursor, for_position_sync=True):
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

View file

@ -132,6 +132,7 @@ def event(self, ev):
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 @@ def update_extra_selections(self, instant=True):
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)

View file

@ -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 @@ def __init__(self, syntax, parent=None):
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 @@ def add_action(name, bar):
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 @@ def break_cycles(self):
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

View file

@ -470,8 +470,8 @@ def showEvent(self, ev):
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: