Completed
Push — master ( acd2ba...1adca7 )
by timothy
01:02
created

Text   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
c 5
b 1
f 0
dl 0
loc 111
rs 10
wmc 24

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 3 1
A apply_attribute() 0 14 4
B font_from_style() 0 18 5
A make_font_size() 0 5 2
A unique_int() 0 13 3
A make_name() 0 4 2
A get_pos() 0 3 2
B highlight_pattern() 0 27 4
A get_endcol() 0 7 1
1
import os
2
import tkinter as tk
3
4
5
class TkBlink():
6
    def __init__(self, *args, **kwargs):
7
        super().__init__(*args, **kwargs)
8
        self._blink_timer_id = None
9
        self._blink_status = 'off'
10
        self._blink_time = 500
11
12
13
    def _do_blink(self):
14
        if self._blink_status == 'off':
15
            self._blink_status = 'on'
16
            self.tag_add('cursorblock', self._blink_pos)
17
            self.tag_config('cursorblock',
18
                            background=self._blink_bg,
19
                            foreground=self._blink_fg)
20
        else:
21
            self.tag_delete('cursorblock')
22
            self._blink_status = 'off'
23
24
        self._blink_timer_id = self.after(self._blink_time,
25
                                          self._do_blink)
26
27
28
    def blink_cursor(self, pos, fg, bg):
29
        '''
30
        alternate the background color of the cursorblock tag
31
        self.blink_time = time inbetween blinks
32
        recall the function when pos/fg/bg change
33
        '''
34
        if self._blink_timer_id:
35
            self.after_cancel(self._blink_timer_id)
36
        self._blink_pos = pos
37
        self._blink_bg = bg
38
        self._blink_fg = fg
39
        self._do_blink()
40
41
42
    def stop_blink(self):
43
        '''remove cursor from screen'''
44
        self.after_cancel(self._blink_timer_id)
45
        self.tag_delete('cursorblock')
46
        self._blink_status = 'off'
47
48
49
class Text(TkBlink, tk.Text):
50
    def __init__(self, *args, **kwargs):
51
        super().__init__(*args, **kwargs)
52
        self._added_tags = {}
53
54
55
    def get_pos(self, row=None, col=None, mark=tk.INSERT):
56
        '''returns row and column as an int'''
57
        return (int(x) for x in self.index(mark).split('.'))
58
59
60
    def make_font_size(self, size):
61
        if os.name == 'nt':
62
            return size
63
        else:
64
            return size - 2
65
66
67
    def highlight_pattern(self, pattern, tag, start="1.0",
68
                          end="end", regexp=False):
69
       '''Apply the given tag to all text that matches the
70
       given pattern
71
       If 'regexp' is set to True, pattern will be treated as a
72
       regular expression according to Tcl's regular
73
       expression syntax.
74
       '''
75
       start = self.index(start)
76
       end = self.index(end)
77
       self.mark_set("matchStart", start)
78
       self.mark_set("matchEnd", start)
79
       self.mark_set("searchLimit", end)
80
81
       count = tk.IntVar()
82
       while True:
83
           index = self.search(pattern, "matchEnd","searchLimit",
84
                               count=count, regexp=regexp)
85
           if index == "":
86
               break
87
           # degenerate pattern which matches zero-length strings
88
           if count.get() == 0:
89
               break
90
           self.mark_set("matchStart", index)
91
           self.mark_set("matchEnd", "%s+%sc"
92
                                       % (index, count.get()))
93
           self.tag_add(tag, "matchStart", "matchEnd")
94
95
96
    def get_endcol(self, row):
97
        '''
98
        returns the index of the last char, not the newline char
99
        '''
100
        end_col = int(self.index(
101
                            str(row)+'.end-1c').split('.')[1])
102
        return end_col
103
104
105
    def apply_attribute(self, style, start, end):
106
        # Ensure the attribute name is associated with a tag
107
        # configured with the corresponding attribute format
108
        for name, existing_style in self._added_tags.items():
109
            # Style already exists
110
            if style == existing_style:
111
                break
112
        # Create a new
113
        else:
114
            name = self.make_name(style)
115
            self.font_from_style(name, style)
116
            self._added_tags[name] = style
117
118
        self.tag_add(name, start, end)
119
120
121
    def make_name(self, style):
122
        versions = [int(name[5:]) for name in \
123
                                        self._added_tags.keys()]
124
        return 'nvim_' + str(self.unique_int(versions))
125
126
127
    def font_from_style(self, name, style):
128
        '''configure font attributes'''
129
        # Get base font options
130
        new_font = tk.font.Font(self, self.cget("font"))
131
        for key, value in style.items():
132
            if key == 'size':
133
                if os.name == 'posix':
134
                    new_font.configure(size=int(value)-2)
135
                else:
136
                    new_font.configure(size=value)
137
            else:
138
                try:
139
                    eval('self.tag_configure(name, %s=value)'\
140
                                                        % key)
141
                except tk.TclError:
142
                    eval('new_font.configure(%s=value)' % key)
143
            self.tag_configure(name, font=new_font)
144
        return new_font
145
146
147
    @staticmethod
148
    def unique_int(values):
149
        '''
150
        if a list looks like 3,6
151
        if repeatedly called will return 1,2,4,5,7,8
152
        '''
153
        last = 0
154
        for num in values:
155
            if last not in values:
156
                break
157
            else:
158
                last += 1
159
        return last
160