~ubuntu-branches/debian/sid/calibre/sid

« back to all changes in this revision

Viewing changes to src/calibre/gui2/tweak_book/diff/highlight.py

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-02-27 07:48:06 UTC
  • mto: This revision was merged to the branch mainline in revision 74.
  • Revision ID: package-import@ubuntu.com-20140227074806-64wdebb3ptosxhhx
Tags: upstream-1.25.0+dfsg
ImportĀ upstreamĀ versionĀ 1.25.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# vim:fileencoding=utf-8
 
3
from __future__ import (unicode_literals, division, absolute_import,
 
4
                        print_function)
 
5
 
 
6
__license__ = 'GPL v3'
 
7
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
 
8
 
 
9
import os
 
10
 
 
11
from PyQt4.Qt import QTextDocument, QTextCursor, QTextCharFormat, QPlainTextDocumentLayout
 
12
 
 
13
from calibre.gui2.tweak_book import tprefs
 
14
from calibre.gui2.tweak_book.editor.text import get_highlighter as calibre_highlighter, SyntaxHighlighter
 
15
from calibre.gui2.tweak_book.editor.themes import THEMES, default_theme, highlight_to_char_format
 
16
 
 
17
def get_theme():
 
18
    theme = THEMES.get(tprefs['editor_theme'], None)
 
19
    if theme is None:
 
20
        theme = THEMES[default_theme()]
 
21
    return theme
 
22
 
 
23
NULL_FMT = QTextCharFormat()
 
24
 
 
25
class QtHighlighter(QTextDocument):
 
26
 
 
27
    def __init__(self, parent, text, hlclass):
 
28
        QTextDocument.__init__(self, parent)
 
29
        self.l = QPlainTextDocumentLayout(self)
 
30
        self.setDocumentLayout(self.l)
 
31
        self.highlighter = hlclass(self)
 
32
        self.highlighter.apply_theme(get_theme())
 
33
        self.highlighter.setDocument(self)
 
34
        self.setPlainText(text)
 
35
 
 
36
    def copy_lines(self, lo, hi, cursor):
 
37
        ''' Copy specified lines from the syntax highlighted buffer into the
 
38
        destination cursor, preserving all formatting created by the syntax
 
39
        highlighter. '''
 
40
        num = hi - lo
 
41
        if num > 0:
 
42
            block = self.findBlockByNumber(lo)
 
43
            while num > 0:
 
44
                num -= 1
 
45
                cursor.insertText(block.text())
 
46
                dest_block = cursor.block()
 
47
                c = QTextCursor(dest_block)
 
48
                for af in block.layout().additionalFormats():
 
49
                    start = dest_block.position() + af.start
 
50
                    c.setPosition(start), c.setPosition(start + af.length, c.KeepAnchor)
 
51
                    c.setCharFormat(af.format)
 
52
                cursor.insertBlock()
 
53
                cursor.setCharFormat(NULL_FMT)
 
54
                block = block.next()
 
55
 
 
56
class NullHighlighter(object):
 
57
 
 
58
    def __init__(self, text):
 
59
        self.lines = text.splitlines()
 
60
 
 
61
    def copy_lines(self, lo, hi, cursor):
 
62
        for i in xrange(lo, hi):
 
63
            cursor.insertText(self.lines[i])
 
64
            cursor.insertBlock()
 
65
 
 
66
def pygments_lexer(filename):
 
67
    try:
 
68
        from pygments.lexers import get_lexer_for_filename
 
69
        from pygments.util import ClassNotFound
 
70
    except ImportError:
 
71
        return None
 
72
    glff = lambda n: get_lexer_for_filename(n, stripnl=False)
 
73
    try:
 
74
        return glff(filename)
 
75
    except ClassNotFound:
 
76
        if filename.lower().endswith('.recipe'):
 
77
            return glff('a.py')
 
78
        return None
 
79
 
 
80
_pyg_map = None
 
81
def pygments_map():
 
82
    global _pyg_map
 
83
    if _pyg_map is None:
 
84
        from pygments.token import Token
 
85
        _pyg_map = {
 
86
            Token: None,
 
87
            Token.Comment: 'Comment',
 
88
            Token.Comment.Preproc: 'PreProc',
 
89
            Token.String: 'String',
 
90
            Token.Number: 'Number',
 
91
            Token.Keyword.Type: 'Type',
 
92
            Token.Keyword: 'Keyword',
 
93
            Token.Name.Builtin: 'Identifier',
 
94
            Token.Operator: 'Statement',
 
95
            Token.Name.Function: 'Function',
 
96
            Token.Literal: 'Constant',
 
97
            Token.Error: 'Error',
 
98
        }
 
99
    return _pyg_map
 
100
 
 
101
def format_for_token(theme, cache, token):
 
102
    try:
 
103
        return cache[token]
 
104
    except KeyError:
 
105
        pass
 
106
    pmap = pygments_map()
 
107
    while token is not None:
 
108
        try:
 
109
            name = pmap[token]
 
110
        except KeyError:
 
111
            token = token.parent
 
112
            continue
 
113
        cache[token] = ans = theme[name]
 
114
        return ans
 
115
    cache[token] = ans = NULL_FMT
 
116
    return ans
 
117
 
 
118
class PygmentsHighlighter(object):
 
119
 
 
120
    def __init__(self, text, lexer):
 
121
        theme, cache = get_theme(), {}
 
122
        theme = {k:highlight_to_char_format(v) for k, v in theme.iteritems()}
 
123
        theme[None] = NULL_FMT
 
124
        def fmt(token):
 
125
            return format_for_token(theme, cache, token)
 
126
 
 
127
        from pygments import lex
 
128
        lines = self.lines = [[]]
 
129
        current_line = lines[0]
 
130
        for token, val in lex(text, lexer):
 
131
            for v in val.splitlines(True):
 
132
                current_line.append((fmt(token), v))
 
133
                if v[-1] in '\n\r':
 
134
                    lines.append([])
 
135
                    current_line = lines[-1]
 
136
                    continue
 
137
 
 
138
    def copy_lines(self, lo, hi, cursor):
 
139
        for i in xrange(lo, hi):
 
140
            for fmt, text in self.lines[i]:
 
141
                cursor.insertText(text, fmt)
 
142
            cursor.setCharFormat(NULL_FMT)
 
143
 
 
144
def get_highlighter(parent, text, syntax):
 
145
    hlclass = calibre_highlighter(syntax)
 
146
    if hlclass is SyntaxHighlighter:
 
147
        filename = os.path.basename(parent.headers[-1][1])
 
148
        lexer = pygments_lexer(filename)
 
149
        if lexer is None:
 
150
            return NullHighlighter(text)
 
151
        return PygmentsHighlighter(text, lexer)
 
152
    return QtHighlighter(parent, text, hlclass)