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):
|
def cursor_position_with_sourceline(self, cursor):
|
||||||
return None, None
|
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 import prepare_string_for_xml
|
||||||
from calibre.gui2 import error_dialog
|
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)
|
get_offset = itemgetter(0)
|
||||||
PARAGRAPH_SEPARATOR = '\u2029'
|
PARAGRAPH_SEPARATOR = '\u2029'
|
||||||
@ -117,6 +117,28 @@ def find_containing_attribute(block, offset):
|
|||||||
return boundary.data
|
return boundary.data
|
||||||
return None
|
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):
|
def find_closing_tag(tag, max_tags=sys.maxint):
|
||||||
''' Find the closing tag corresponding to the specified tag. To find it we
|
''' 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
|
search for the first closing tag after the specified tag that does not
|
||||||
@ -335,3 +357,29 @@ class HTMLSmarts(NullSmarts):
|
|||||||
return None, 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)]
|
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
|
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):
|
def current_tag(self):
|
||||||
return self.smarts.cursor_position_with_sourceline(self.textCursor())
|
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.addAction(actions['multisplit'])
|
||||||
m.exec_(self.editor.mapToGlobal(pos))
|
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):
|
def _nuke_word(self, dic, word, locale):
|
||||||
if dic is None:
|
if dic is None:
|
||||||
dictionaries.ignore_word(word, locale)
|
dictionaries.ignore_word(word, locale)
|
||||||
|
@ -204,7 +204,7 @@ class Declaration(QWidget):
|
|||||||
pos = ev.pos()
|
pos = ev.pos()
|
||||||
if self.hyperlink_rect.contains(pos):
|
if self.hyperlink_rect.contains(pos):
|
||||||
self.emit_hyperlink_activated()
|
self.emit_hyperlink_activated()
|
||||||
return QWidget.mouseMoveEvent(self, ev)
|
return QWidget.mousePressEvent(self, ev)
|
||||||
|
|
||||||
def emit_hyperlink_activated(self):
|
def emit_hyperlink_activated(self):
|
||||||
dt = self.data['type']
|
dt = self.data['type']
|
||||||
@ -316,7 +316,7 @@ class LiveCSS(QWidget):
|
|||||||
s.addWidget(la)
|
s.addWidget(la)
|
||||||
|
|
||||||
self.box = box = Box(self)
|
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)
|
self.scroll = sc = QScrollArea(self)
|
||||||
sc.setWidget(box)
|
sc.setWidget(box)
|
||||||
sc.setWidgetResizable(True)
|
sc.setWidgetResizable(True)
|
||||||
@ -409,5 +409,7 @@ class LiveCSS(QWidget):
|
|||||||
self.update_timer.stop()
|
self.update_timer.stop()
|
||||||
|
|
||||||
def navigate_to_declaration(self, data, editor):
|
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