Implement navigation to inline style attributes

This commit is contained in:
Kovid Goyal 2014-05-21 08:25:55 +05:30
parent 35d3531bfc
commit 062d38a156
5 changed files with 62 additions and 4 deletions

View File

@ -23,3 +23,5 @@ class NullSmarts(object):
def cursor_position_with_sourceline(self, cursor):
return None, None
def goto_sourceline(self, editor, sourceline, tags, attribute=None):
return False

View File

@ -14,7 +14,7 @@ from PyQt4.Qt import QTextEdit
from calibre import prepare_string_for_xml
from calibre.gui2 import error_dialog
from calibre.gui2.tweak_book.editor.syntax.html import ATTR_NAME, ATTR_END
from calibre.gui2.tweak_book.editor.syntax.html import ATTR_NAME, ATTR_END, ATTR_START, ATTR_VALUE
get_offset = itemgetter(0)
PARAGRAPH_SEPARATOR = '\u2029'
@ -117,6 +117,28 @@ def find_containing_attribute(block, offset):
return boundary.data
return None
def find_attribute_in_tag(block, offset, attr_name):
end_block, boundary = next_tag_boundary(block, offset)
if boundary.is_start:
return None, None
end_offset = boundary.offset
end_pos = (end_block.blockNumber(), end_offset)
current_block, current_offset = block, offset
found_attr = False
while True:
current_block, boundary = next_attr_boundary(current_block, current_offset)
if current_block is None or (current_block.blockNumber(), boundary.offset) > end_pos:
return None, None
current_offset = boundary.offset
if found_attr:
if boundary.type is not ATTR_VALUE or boundary.data is not ATTR_START:
return None, None
return current_block, current_offset
else:
if boundary.type is ATTR_NAME and boundary.data.lower() == attr_name.lower():
found_attr = True
current_offset += 1
def find_closing_tag(tag, max_tags=sys.maxint):
''' Find the closing tag corresponding to the specified tag. To find it we
search for the first closing tag after the specified tag that does not
@ -335,3 +357,29 @@ class HTMLSmarts(NullSmarts):
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
def goto_sourceline(self, editor, sourceline, tags, attribute=None):
''' Move the cursor to the tag identified by sourceline and tags (a
list of tags names on the specified line). If attribute is specified
the cursor will be placed at the start of the attribute value. '''
block = editor.document().findBlockByNumber(sourceline - 1) # blockNumber() is zero based
found_tag = False
if not block.isValid():
return found_tag
c = editor.textCursor()
ud = block.userData()
all_tags = [] if ud is None else [t for t in ud.tags if (t.is_start and not t.closing)]
tag_names = [t.name for t in all_tags]
if tag_names[:len(tags)] == tags:
c.setPosition(block.position() + all_tags[len(tags)-1].offset)
found_tag = True
else:
c.setPosition(block.position())
if found_tag and attribute is not None:
start_offset = c.position() - block.position()
nblock, offset = find_attribute_in_tag(block, start_offset, attribute)
if nblock is not None:
c.setPosition(nblock.position() + offset)
editor.setTextCursor(c)
return found_tag

View File

@ -752,3 +752,6 @@ class TextEdit(PlainTextEdit):
def current_tag(self):
return self.smarts.cursor_position_with_sourceline(self.textCursor())
def goto_sourceline(self, sourceline, tags, attribute=None):
return self.smarts.goto_sourceline(self, sourceline, tags, attribute=attribute)

View File

@ -403,6 +403,9 @@ class Editor(QMainWindow):
m.addAction(actions['multisplit'])
m.exec_(self.editor.mapToGlobal(pos))
def goto_sourceline(self, *args, **kwargs):
return self.editor.goto_sourceline(*args, **kwargs)
def _nuke_word(self, dic, word, locale):
if dic is None:
dictionaries.ignore_word(word, locale)

View File

@ -204,7 +204,7 @@ class Declaration(QWidget):
pos = ev.pos()
if self.hyperlink_rect.contains(pos):
self.emit_hyperlink_activated()
return QWidget.mouseMoveEvent(self, ev)
return QWidget.mousePressEvent(self, ev)
def emit_hyperlink_activated(self):
dt = self.data['type']
@ -316,7 +316,7 @@ class LiveCSS(QWidget):
s.addWidget(la)
self.box = box = Box(self)
box.hyperlink_activated.connect(self.goto_declaration)
box.hyperlink_activated.connect(self.goto_declaration, type=Qt.QueuedConnection)
self.scroll = sc = QScrollArea(self)
sc.setWidget(box)
sc.setWidgetResizable(True)
@ -409,5 +409,7 @@ class LiveCSS(QWidget):
self.update_timer.stop()
def navigate_to_declaration(self, data, editor):
print (data) # TODO: Implement this
if data['type'] == 'inline':
sourceline, tags = data['sourceline_address']
editor.goto_sourceline(sourceline, tags, attribute='style')