diff --git a/src/calibre/gui2/tweak_book/editor/smart/html.py b/src/calibre/gui2/tweak_book/editor/smart/html.py index a204cfef85..3a36aaec0e 100644 --- a/src/calibre/gui2/tweak_book/editor/smart/html.py +++ b/src/calibre/gui2/tweak_book/editor/smart/html.py @@ -384,12 +384,14 @@ class HTMLSmarts(NullSmarts): return False - def cursor_position_with_sourceline(self, cursor): - ''' Return the tag containing the current cursor as a source line + def cursor_position_with_sourceline(self, cursor, for_position_sync=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. ''' + containing tag. If ``for_position_sync`` is False then the tag + *containing* the cursor is returned instead of the tag just before the + cursor. ''' block = cursor.block() - offset = cursor.position() - block.position() + offset = cursor.positionInBlock() nblock, boundary = next_tag_boundary(block, offset, forward=False) if boundary is None: return None, None @@ -412,8 +414,52 @@ class HTMLSmarts(NullSmarts): ud = start_block.userData() if ud is None: return None, None - all_tags = [t.name for t in ud.tags if (t.is_start and not t.closing and t.offset <= start_offset)] - return sourceline, all_tags + if for_position_sync: + return sourceline, [ + t.name for t in ud.tags if (t.is_start and not t.closing and t.offset <= start_offset)] + # We discard self-closing as well as tags that are both opened and + # closed from the end of the list of tags as we want the tag that + # contains the cursor, not the last tag before the cursor + class Tag(object): + __slots__ = 'name', 'is_closed' + def __init__(self, name, is_closed): + self.name = name + self.is_closed = is_closed + def __repr__(self): + return '<%s%s>' % (self.name, ('/' if self.is_closed else '')) + + if cursor.block().blockNumber() == start_block.blockNumber(): + offset = cursor.positionInBlock() + tag_stack = [] + in_tag = None + for t in ud.tags: + if t.offset < offset: + if t.is_start: + if t.closing: + # + if in_tag is not None: + tag_stack.append(Tag(in_tag, t.self_closing)) + in_tag = None + + all_tags = [] + found_open = False + for tag in reversed(tag_stack): + if not tag.is_closed: + found_open = True + if found_open: + all_tags.append(tag.name) + + return sourceline, list(reversed(all_tags)) def goto_sourceline(self, editor, sourceline, tags, attribute=None): ''' Move the cursor to the tag identified by sourceline and tags (a diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index 6da5919a31..16bcc5d57b 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -790,8 +790,8 @@ class TextEdit(PlainTextEdit): if hasattr(self.smarts, 'rename_block_tag'): self.smarts.rename_block_tag(self, new_name) - def current_tag(self): - return self.smarts.cursor_position_with_sourceline(self.textCursor()) + def current_tag(self, for_position_sync=True): + return self.smarts.cursor_position_with_sourceline(self.textCursor(), for_position_sync=for_position_sync) def goto_sourceline(self, sourceline, tags, attribute=None): return self.smarts.goto_sourceline(self, sourceline, tags, attribute=attribute) diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index fdc899cc9a..e9603efb7d 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -138,8 +138,8 @@ class Editor(QMainWindow): self.editor.go_to_line(val) return property(fget=fget, fset=fset) - def current_tag(self): - return self.editor.current_tag() + def current_tag(self, for_position_sync=True): + return self.editor.current_tag(for_position_sync=for_position_sync) @property def number_of_lines(self): diff --git a/src/calibre/gui2/tweak_book/live_css.py b/src/calibre/gui2/tweak_book/live_css.py index 08a547efed..5a31af5068 100644 --- a/src/calibre/gui2/tweak_book/live_css.py +++ b/src/calibre/gui2/tweak_book/live_css.py @@ -481,7 +481,7 @@ class LiveCSS(QWidget): if self.update_timer.isActive() or (ed is None and editor_name is not None): return QTimer.singleShot(100, self.update_data) if ed is not None: - sourceline, tags = ed.current_tag() + sourceline, tags = ed.current_tag(for_position_sync=False) if self.refresh_needed or self.now_showing != (editor_name, sourceline, tags): self.show_data(editor_name, sourceline, tags)