mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement navigation to inline style attributes
This commit is contained in:
parent
35d3531bfc
commit
062d38a156
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user