From d387cac87186d72de45e366db3d5ba501ddd74da Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 16 Apr 2017 11:04:56 +0530 Subject: [PATCH] Edit Book: Add keyboard shortcuts to jumpt to opening and closing tags (Ctrl+{ and Ctrl+}) --- manual/edit.rst | 9 ++++++++ .../gui2/tweak_book/editor/smarts/html.py | 21 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/manual/edit.rst b/manual/edit.rst index a34b4e0761..5eb9357855 100644 --- a/manual/edit.rst +++ b/manual/edit.rst @@ -837,3 +837,12 @@ text. The editor allows you to insert a snippet with only a few key strokes. The snippets are very powerful, with many features, such as placeholders you can jump between, automatic mirroring of repeated text and so on. For more information, see :doc:`snippets`. + + +Matching tags +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When editing HTML or XML files, the closest tag containing the current cursor +position is automatically highlighted. You can jump to either the opening tag +or the closing tag using the keyboard shortcuts, :kbd:`Ctrl+{` and +:kbd:`Ctrl+}`. diff --git a/src/calibre/gui2/tweak_book/editor/smarts/html.py b/src/calibre/gui2/tweak_book/editor/smarts/html.py index ec35285687..e571f1472b 100644 --- a/src/calibre/gui2/tweak_book/editor/smarts/html.py +++ b/src/calibre/gui2/tweak_book/editor/smarts/html.py @@ -311,7 +311,7 @@ class Smarts(NullSmarts): Smarts.self_closing_pat = re.compile(r'/\s*>') Smarts.complete_attr_pat = re.compile(r'''([a-zA-Z0-9_-]+)\s*=\s*(?:'([^']*)|"([^"]*))$''') NullSmarts.__init__(self, *args, **kwargs) - self.last_matched_tag = None + self.last_matched_tag = self.last_matched_closing_tag = None def get_extra_selections(self, editor): ans = [] @@ -332,13 +332,24 @@ class Smarts(NullSmarts): c = editor.textCursor() block, offset = c.block(), c.positionInBlock() tag = self.last_matched_tag = find_closest_containing_tag(block, offset, max_tags=2000) + self.last_matched_closing_tag = None if tag is not None: add_tag(tag) - tag = find_closing_tag(tag, max_tags=4000) + tag = self.last_matched_closing_tag = find_closing_tag(tag, max_tags=4000) if tag is not None: add_tag(tag) return ans + def jump_to_enclosing_tag(self, editor, start=True): + editor.highlighter.join() + tag = self.last_matched_tag if start else self.last_matched_closing_tag + if tag is None: + return False + c = editor.textCursor() + c.setPosition(tag.start_block.position() + tag.start_offset + (1 if start else 2)) + editor.setTextCursor(c) + return True + def rename_block_tag(self, editor, new_name): editor.highlighter.join() c = editor.textCursor() @@ -621,6 +632,12 @@ class Smarts(NullSmarts): if key == Qt.Key_Backspace and smart_backspace(editor, ev): return True + if key in (Qt.Key_BraceLeft, Qt.Key_BraceRight): + mods = ev.modifiers() + if int(mods & Qt.ControlModifier): + if self.jump_to_enclosing_tag(editor, key == Qt.Key_BraceLeft): + return True + return False def replace_possible_entity(self, editor):