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 @@ class Boss(QObject):
if name is not None and getattr(ed, 'syntax', None) == 'html': if name is not None and getattr(ed, 'syntax', None) == 'html':
self.gui.preview.sync_to_editor(name, ed.current_tag()) 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): def goto_style_declaration(self, data):
name = data['name'] name = data['name']
editor = self.edit_file(name, syntax=data['syntax']) editor = self.edit_file(name, syntax=data['syntax'])
@ -1152,12 +1144,13 @@ class Boss(QObject):
editor.data_changed.connect(self.editor_data_changed) editor.data_changed.connect(self.editor_data_changed)
editor.copy_available_state_changed.connect(self.editor_copy_available_state_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_preview_to_editor)
editor.cursor_position_changed.connect(self.sync_live_css_to_editor)
editor.cursor_position_changed.connect(self.update_cursor_position) editor.cursor_position_changed.connect(self.update_cursor_position)
if hasattr(editor, 'word_ignored'): if hasattr(editor, 'word_ignored'):
editor.word_ignored.connect(self.word_ignored) editor.word_ignored.connect(self.word_ignored)
if hasattr(editor, 'link_clicked'): if hasattr(editor, 'link_clicked'):
editor.link_clicked.connect(self.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 data is not None:
if use_template: if use_template:
editor.init_from_template(data) editor.init_from_template(data)
@ -1284,7 +1277,6 @@ class Boss(QObject):
# focused. This is not inefficient since multiple requests # focused. This is not inefficient since multiple requests
# to sync are de-bounced with a 100 msec wait. # to sync are de-bounced with a 100 msec wait.
self.sync_preview_to_editor() self.sync_preview_to_editor()
self.sync_live_css_to_editor()
if name is not None: if name is not None:
self.gui.file_list.mark_name_as_current(name) self.gui.file_list.mark_name_as_current(name)
if ed.has_line_numbers: if ed.has_line_numbers:

View File

@ -20,7 +20,7 @@ class NullSmarts(object):
def verify_for_spellcheck(self, cursor, highlighter): def verify_for_spellcheck(self, cursor, highlighter):
return False return False
def cursor_position_with_sourceline(self, cursor): def cursor_position_with_sourceline(self, cursor, for_position_sync=True):
return None, None return None, None
def goto_sourceline(self, editor, sourceline, tags, attribute=None): def goto_sourceline(self, editor, sourceline, tags, attribute=None):

View File

@ -270,6 +270,10 @@ def set_style_property(tag, property_name, value, editor):
class HTMLSmarts(NullSmarts): class HTMLSmarts(NullSmarts):
def __init__(self, *args, **kwargs):
NullSmarts.__init__(self, *args, **kwargs)
self.last_matched_tag = None
def get_extra_selections(self, editor): def get_extra_selections(self, editor):
ans = [] ans = []
@ -288,7 +292,7 @@ class HTMLSmarts(NullSmarts):
c = editor.textCursor() c = editor.textCursor()
block, offset = c.block(), c.positionInBlock() 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: if tag is not None:
add_tag(tag) add_tag(tag)
tag = find_closing_tag(tag, max_tags=4000) tag = find_closing_tag(tag, max_tags=4000)
@ -391,13 +395,14 @@ class HTMLSmarts(NullSmarts):
return False 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 ''' 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 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 tag. If ``for_position_sync`` is False then the tag
*containing* the cursor is returned instead of the tag just before the *containing* the cursor is returned instead of the tag just before the
cursor. Note that finding the containing tag is relative expensive, so cursor. Note that finding the containing tag is expensive, so
use with care.''' 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() block, offset = cursor.block(), cursor.positionInBlock()
if for_position_sync: if for_position_sync:
nblock, boundary = next_tag_boundary(block, offset, forward=False) nblock, boundary = next_tag_boundary(block, offset, forward=False)
@ -417,6 +422,10 @@ class HTMLSmarts(NullSmarts):
break break
block, offset = block.previous(), sys.maxint block, offset = block.previous(), sys.maxint
else: else:
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) tag = find_closest_containing_tag(block, offset, max_tags=2000)
if tag is None: if tag is None:
return None, None return None, None

View File

@ -132,6 +132,7 @@ class PlainTextEdit(QPlainTextEdit):
class TextEdit(PlainTextEdit): class TextEdit(PlainTextEdit):
link_clicked = pyqtSignal(object) link_clicked = pyqtSignal(object)
smart_highlighting_updated = pyqtSignal()
def __init__(self, parent=None, expected_geometry=(100, 50)): def __init__(self, parent=None, expected_geometry=(100, 50)):
PlainTextEdit.__init__(self, parent) PlainTextEdit.__init__(self, parent)
@ -274,6 +275,7 @@ class TextEdit(PlainTextEdit):
sel.append(self.current_search_mark) sel.append(self.current_search_mark)
if instant and not self.highlighter.has_requests: if instant and not self.highlighter.has_requests:
sel.extend(self.smarts.get_extra_selections(self)) sel.extend(self.smarts.get_extra_selections(self))
self.smart_highlighting_updated.emit()
else: else:
self.smarts_highlight_timer.start() self.smarts_highlight_timer.start()
self.setExtraSelections(sel) self.setExtraSelections(sel)

View File

@ -107,6 +107,7 @@ class Editor(QMainWindow):
cursor_position_changed = pyqtSignal() cursor_position_changed = pyqtSignal()
word_ignored = pyqtSignal(object, object) word_ignored = pyqtSignal(object, object)
link_clicked = pyqtSignal(object) link_clicked = pyqtSignal(object)
smart_highlighting_updated = pyqtSignal()
def __init__(self, syntax, parent=None): def __init__(self, syntax, parent=None):
QMainWindow.__init__(self, parent) QMainWindow.__init__(self, parent)
@ -129,6 +130,7 @@ class Editor(QMainWindow):
self.editor.copyAvailable.connect(self._copy_available) self.editor.copyAvailable.connect(self._copy_available)
self.editor.cursorPositionChanged.connect(self._cursor_position_changed) self.editor.cursorPositionChanged.connect(self._cursor_position_changed)
self.editor.link_clicked.connect(self.link_clicked) self.editor.link_clicked.connect(self.link_clicked)
self.editor.smart_highlighting_updated.connect(self.smart_highlighting_updated)
@dynamic_property @dynamic_property
def current_line(self): def current_line(self):
@ -328,7 +330,7 @@ class Editor(QMainWindow):
self.restore_state() self.restore_state()
def break_cycles(self): 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: try:
getattr(self, x).disconnect() getattr(self, x).disconnect()
except TypeError: except TypeError:
@ -344,6 +346,7 @@ class Editor(QMainWindow):
self.editor.copyAvailable.disconnect() self.editor.copyAvailable.disconnect()
self.editor.cursorPositionChanged.disconnect() self.editor.cursorPositionChanged.disconnect()
self.editor.link_clicked.disconnect() self.editor.link_clicked.disconnect()
self.editor.smart_highlighting_updated.disconnect()
self.editor.setPlainText('') self.editor.setPlainText('')
self.editor.smarts = None self.editor.smarts = None

View File

@ -470,8 +470,8 @@ class LiveCSS(QWidget):
actions['auto-reload-preview'].setEnabled(True) actions['auto-reload-preview'].setEnabled(True)
return QWidget.showEvent(self, ev) return QWidget.showEvent(self, ev)
def sync_to_editor(self, name): def sync_to_editor(self):
self.start_update_timer() self.update_data()
def update_data(self): def update_data(self):
if not self.is_visible or self.preview_is_refreshing: if not self.is_visible or self.preview_is_refreshing: