mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-03 19:17:02 -05: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