mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Implement navigation to rules defined in stylesheets
This commit is contained in:
parent
d993534dfc
commit
4febe3c455
@ -25,3 +25,6 @@ class NullSmarts(object):
|
||||
|
||||
def goto_sourceline(self, editor, sourceline, tags, attribute=None):
|
||||
return False
|
||||
|
||||
def get_inner_HTML(self, editor):
|
||||
return None
|
||||
|
31
src/calibre/gui2/tweak_book/editor/smart/css.py
Normal file
31
src/calibre/gui2/tweak_book/editor/smart/css.py
Normal file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from calibre.gui2.tweak_book.editor.smart import NullSmarts
|
||||
|
||||
def find_rule(raw, rule_address):
|
||||
import tinycss
|
||||
parser = tinycss.make_parser()
|
||||
sheet = parser.parse_stylesheet(raw)
|
||||
rules = sheet.rules
|
||||
ans = None, None
|
||||
while rule_address:
|
||||
try:
|
||||
r = rules[rule_address[0]]
|
||||
except IndexError:
|
||||
return None, None
|
||||
else:
|
||||
ans = r.line, r.column
|
||||
rule_address = rule_address[1:]
|
||||
if rule_address:
|
||||
rules = getattr(r, 'rules', ())
|
||||
return ans
|
||||
|
||||
class CSSSmarts(NullSmarts):
|
||||
pass
|
||||
|
@ -383,3 +383,27 @@ class HTMLSmarts(NullSmarts):
|
||||
editor.setTextCursor(c)
|
||||
return found_tag
|
||||
|
||||
def get_inner_HTML(self, editor):
|
||||
''' Select the inner HTML of the current tag. Return a cursor with the
|
||||
inner HTML selected or None. '''
|
||||
c = editor.textCursor()
|
||||
block = c.block()
|
||||
offset = c.position() - block.position()
|
||||
nblock, boundary = next_tag_boundary(block, offset)
|
||||
if boundary.is_start:
|
||||
# We are within the contents of a tag already
|
||||
tag = find_closest_containing_tag(block, offset)
|
||||
else:
|
||||
# We are inside a tag definition < | >
|
||||
if boundary.self_closing:
|
||||
return None # self closing tags have no inner html
|
||||
tag = find_closest_containing_tag(nblock, boundary.offset + 1)
|
||||
if tag is None:
|
||||
return None
|
||||
ctag = find_closing_tag(tag)
|
||||
if ctag is None:
|
||||
return None
|
||||
c.setPosition(tag.end_block.position() + tag.end_offset + 1)
|
||||
c.setPosition(ctag.start_block.position() + ctag.start_offset, c.KeepAnchor)
|
||||
return c
|
||||
|
||||
|
@ -25,6 +25,7 @@ from calibre.gui2.tweak_book.editor.syntax.html import HTMLHighlighter, XMLHighl
|
||||
from calibre.gui2.tweak_book.editor.syntax.css import CSSHighlighter
|
||||
from calibre.gui2.tweak_book.editor.smart import NullSmarts
|
||||
from calibre.gui2.tweak_book.editor.smart.html import HTMLSmarts
|
||||
from calibre.gui2.tweak_book.editor.smart.css import CSSSmarts
|
||||
from calibre.spell.break_iterator import index_of
|
||||
from calibre.utils.icu import safe_chr, string_length
|
||||
|
||||
@ -211,7 +212,7 @@ class TextEdit(PlainTextEdit):
|
||||
self.highlighter = get_highlighter(syntax)()
|
||||
self.highlighter.apply_theme(self.theme)
|
||||
self.highlighter.set_document(self.document())
|
||||
sclass = {'html':HTMLSmarts, 'xml':HTMLSmarts}.get(syntax, None)
|
||||
sclass = {'html':HTMLSmarts, 'xml':HTMLSmarts, 'css':CSSSmarts}.get(syntax, None)
|
||||
if sclass is not None:
|
||||
self.smarts = sclass(self)
|
||||
self.setPlainText(unicodedata.normalize('NFC', text))
|
||||
@ -755,3 +756,31 @@ class TextEdit(PlainTextEdit):
|
||||
def goto_sourceline(self, sourceline, tags, attribute=None):
|
||||
return self.smarts.goto_sourceline(self, sourceline, tags, attribute=attribute)
|
||||
|
||||
def get_tag_contents(self):
|
||||
c = self.smarts.get_inner_HTML(self)
|
||||
if c is not None:
|
||||
return self.selected_text_from_cursor(c)
|
||||
|
||||
def goto_css_rule(self, rule_address, sourceline_address=None):
|
||||
from calibre.gui2.tweak_book.editor.smart.css import find_rule
|
||||
block = None
|
||||
if self.syntax == 'css':
|
||||
raw = unicode(self.toPlainText())
|
||||
line, col = find_rule(raw, rule_address)
|
||||
if line is not None:
|
||||
block = self.document().findBlockByNumber(line - 1)
|
||||
elif sourceline_address is not None:
|
||||
sourceline, tags = sourceline_address
|
||||
if self.goto_sourceline(sourceline, tags):
|
||||
c = self.textCursor()
|
||||
c.setPosition(c.position() + 1)
|
||||
self.setTextCursor(c)
|
||||
raw = self.get_tag_contents()
|
||||
line, col = find_rule(raw, rule_address)
|
||||
if line is not None:
|
||||
block = self.document().findBlockByNumber(c.blockNumber() + line - 1)
|
||||
|
||||
if block is not None and block.isValid():
|
||||
c = self.textCursor()
|
||||
c.setPosition(block.position() + col)
|
||||
self.setTextCursor(c)
|
||||
|
@ -406,6 +406,12 @@ class Editor(QMainWindow):
|
||||
def goto_sourceline(self, *args, **kwargs):
|
||||
return self.editor.goto_sourceline(*args, **kwargs)
|
||||
|
||||
def goto_css_rule(self, *args, **kwargs):
|
||||
return self.editor.goto_css_rule(*args, **kwargs)
|
||||
|
||||
def get_tag_contents(self, *args, **kwargs):
|
||||
return self.editor.get_tag_contents(*args, **kwargs)
|
||||
|
||||
def _nuke_word(self, dic, word, locale):
|
||||
if dic is None:
|
||||
dictionaries.ignore_word(word, locale)
|
||||
|
@ -412,4 +412,8 @@ class LiveCSS(QWidget):
|
||||
if data['type'] == 'inline':
|
||||
sourceline, tags = data['sourceline_address']
|
||||
editor.goto_sourceline(sourceline, tags, attribute='style')
|
||||
elif data['type'] == 'sheet':
|
||||
editor.goto_css_rule(data['rule_address'])
|
||||
elif data['type'] == 'elem':
|
||||
editor.goto_css_rule(data['rule_address'], sourceline_address=data['sourceline_address'])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user