| @@ 27-266 (lines=240) @@ | ||
| 24 | range = xrange |
|
| 25 | ||
| 26 | ||
| 27 | class NvimTk(object): |
|
| 28 | ||
| 29 | """Wraps all nvim/tk event handling.""" |
|
| 30 | ||
| 31 | def __init__(self, nvim): |
|
| 32 | """Initialize with a Nvim instance.""" |
|
| 33 | self._nvim = nvim |
|
| 34 | self._attrs = {} |
|
| 35 | self._nvim_updates = deque() |
|
| 36 | self._canvas = None |
|
| 37 | self._fg = '#000000' |
|
| 38 | self._bg = '#ffffff' |
|
| 39 | ||
| 40 | def run(self): |
|
| 41 | """Start the UI.""" |
|
| 42 | self._tk_setup() |
|
| 43 | t = Thread(target=self._nvim_event_loop) |
|
| 44 | t.daemon = True |
|
| 45 | t.start() |
|
| 46 | self._root.mainloop() |
|
| 47 | ||
| 48 | def _tk_setup(self): |
|
| 49 | self._root = Tk() |
|
| 50 | self._root.bind('<<nvim_redraw>>', self._tk_nvim_redraw) |
|
| 51 | self._root.bind('<<nvim_detach>>', self._tk_nvim_detach) |
|
| 52 | self._root.bind('<Key>', self._tk_key) |
|
| 53 | ||
| 54 | def _tk_nvim_redraw(self, *args): |
|
| 55 | update = self._nvim_updates.popleft() |
|
| 56 | for update in update: |
|
| 57 | handler = getattr(self, '_tk_nvim_' + update[0]) |
|
| 58 | for args in update[1:]: |
|
| 59 | handler(*args) |
|
| 60 | ||
| 61 | def _tk_nvim_detach(self, *args): |
|
| 62 | self._root.destroy() |
|
| 63 | ||
| 64 | def _tk_nvim_resize(self, width, height): |
|
| 65 | self._tk_redraw_canvas(width, height) |
|
| 66 | ||
| 67 | def _tk_nvim_clear(self): |
|
| 68 | self._tk_clear_region(0, self._height - 1, 0, self._width - 1) |
|
| 69 | ||
| 70 | def _tk_nvim_eol_clear(self): |
|
| 71 | row, col = (self._cursor_row, self._cursor_col,) |
|
| 72 | self._tk_clear_region(row, row, col, self._scroll_right) |
|
| 73 | ||
| 74 | def _tk_nvim_cursor_goto(self, row, col): |
|
| 75 | self._cursor_row = row |
|
| 76 | self._cursor_col = col |
|
| 77 | ||
| 78 | def _tk_nvim_cursor_on(self): |
|
| 79 | pass |
|
| 80 | ||
| 81 | def _tk_nvim_cursor_off(self): |
|
| 82 | pass |
|
| 83 | ||
| 84 | def _tk_nvim_mouse_on(self): |
|
| 85 | pass |
|
| 86 | ||
| 87 | def _tk_nvim_mouse_off(self): |
|
| 88 | pass |
|
| 89 | ||
| 90 | def _tk_nvim_insert_mode(self): |
|
| 91 | pass |
|
| 92 | ||
| 93 | def _tk_nvim_normal_mode(self): |
|
| 94 | pass |
|
| 95 | ||
| 96 | def _tk_nvim_set_scroll_region(self, top, bot, left, right): |
|
| 97 | self._scroll_top = top |
|
| 98 | self._scroll_bot = bot |
|
| 99 | self._scroll_left = left |
|
| 100 | self._scroll_right = right |
|
| 101 | ||
| 102 | def _tk_nvim_scroll(self, count): |
|
| 103 | top, bot = (self._scroll_top, self._scroll_bot,) |
|
| 104 | left, right = (self._scroll_left, self._scroll_right,) |
|
| 105 | ||
| 106 | if count > 0: |
|
| 107 | destroy_top = top |
|
| 108 | destroy_bot = top + count - 1 |
|
| 109 | move_top = destroy_bot + 1 |
|
| 110 | move_bot = bot |
|
| 111 | fill_top = move_bot + 1 |
|
| 112 | fill_bot = fill_top + count - 1 |
|
| 113 | else: |
|
| 114 | destroy_top = bot + count + 1 |
|
| 115 | destroy_bot = bot |
|
| 116 | move_top = top |
|
| 117 | move_bot = destroy_top - 1 |
|
| 118 | fill_bot = move_top - 1 |
|
| 119 | fill_top = fill_bot + count + 1 |
|
| 120 | ||
| 121 | # destroy items that would be moved outside the scroll region after |
|
| 122 | # scrolling |
|
| 123 | # self._tk_clear_region(destroy_top, destroy_bot, left, right) |
|
| 124 | # self._tk_clear_region(move_top, move_bot, left, right) |
|
| 125 | self._tk_destroy_region(destroy_top, destroy_bot, left, right) |
|
| 126 | self._tk_tag_region('move', move_top, move_bot, left, right) |
|
| 127 | self._canvas.move('move', 0, -count * self._rowsize) |
|
| 128 | self._canvas.dtag('move', 'move') |
|
| 129 | # self._tk_fill_region(fill_top, fill_bot, left, right) |
|
| 130 | ||
| 131 | ||
| 132 | def _tk_nvim_highlight_set(self, attrs): |
|
| 133 | self._attrs = attrs |
|
| 134 | ||
| 135 | def _tk_nvim_put(self, data): |
|
| 136 | # choose a Font instance |
|
| 137 | font = self._fnormal |
|
| 138 | if self._attrs.get('bold', False): |
|
| 139 | font = self._fbold |
|
| 140 | if self._attrs.get('italic', False): |
|
| 141 | font = self._fbolditalic if font == self._fbold else self._fitalic |
|
| 142 | # colors |
|
| 143 | fg = "#{0:0{1}x}".format(self._attrs.get('foreground', self._fg), 6) |
|
| 144 | bg = "#{0:0{1}x}".format(self._attrs.get('background', self._bg), 6) |
|
| 145 | # get the "text" and "rect" which correspond to the current cell |
|
| 146 | x, y = self._tk_get_coords(self._cursor_row, self._cursor_col) |
|
| 147 | items = self._canvas.find_overlapping(x, y, x + 1, y + 1) |
|
| 148 | if len(items) != 2: |
|
| 149 | # caught part the double-width character in the cell to the left, |
|
| 150 | # filter items which dont have the same horizontal coordinate as |
|
| 151 | # "x" |
|
| 152 | predicate = lambda item: self._canvas.coords(item)[0] == x |
|
| 153 | items = filter(predicate, items) |
|
| 154 | # rect has lower id than text, sort to unpack correctly |
|
| 155 | rect, text = sorted(items) |
|
| 156 | self._canvas.itemconfig(text, fill=fg, font=font, text=data or ' ') |
|
| 157 | self._canvas.itemconfig(rect, fill=bg) |
|
| 158 | self._tk_nvim_cursor_goto(self._cursor_row, self._cursor_col + 1) |
|
| 159 | ||
| 160 | def _tk_nvim_bell(self): |
|
| 161 | self._root.bell() |
|
| 162 | ||
| 163 | def _tk_nvim_update_fg(self, fg): |
|
| 164 | self._fg = "#{0:0{1}x}".format(fg, 6) |
|
| 165 | ||
| 166 | def _tk_nvim_update_bg(self, bg): |
|
| 167 | self._bg = "#{0:0{1}x}".format(bg, 6) |
|
| 168 | ||
| 169 | def _tk_redraw_canvas(self, width, height): |
|
| 170 | if self._canvas: |
|
| 171 | self._canvas.destroy() |
|
| 172 | self._fnormal = Font(family='Monospace', size=13) |
|
| 173 | self._fbold = Font(family='Monospace', weight='bold', size=13) |
|
| 174 | self._fitalic = Font(family='Monospace', slant='italic', size=13) |
|
| 175 | self._fbolditalic = Font(family='Monospace', weight='bold', |
|
| 176 | slant='italic', size=13) |
|
| 177 | self._colsize = self._fnormal.measure('A') |
|
| 178 | self._rowsize = self._fnormal.metrics('linespace') |
|
| 179 | self._canvas = Canvas(self._root, width=self._colsize * width, |
|
| 180 | height=self._rowsize * height) |
|
| 181 | self._tk_fill_region(0, height - 1, 0, width - 1) |
|
| 182 | self._cursor_row = 0 |
|
| 183 | self._cursor_col = 0 |
|
| 184 | self._scroll_top = 0 |
|
| 185 | self._scroll_bot = height - 1 |
|
| 186 | self._scroll_left = 0 |
|
| 187 | self._scroll_right = width - 1 |
|
| 188 | self._width, self._height = (width, height,) |
|
| 189 | self._canvas.pack() |
|
| 190 | ||
| 191 | def _tk_fill_region(self, top, bot, left, right): |
|
| 192 | # create columns from right to left so the left columns have a |
|
| 193 | # higher z-index than the right columns. This is required to |
|
| 194 | # properly display characters that cross cell boundary |
|
| 195 | for rownum in range(bot, top - 1, -1): |
|
| 196 | for colnum in range(right, left - 1, -1): |
|
| 197 | x1 = colnum * self._colsize |
|
| 198 | y1 = rownum * self._rowsize |
|
| 199 | x2 = (colnum + 1) * self._colsize |
|
| 200 | y2 = (rownum + 1) * self._rowsize |
|
| 201 | # for each cell, create two items: The rectangle is used for |
|
| 202 | # filling background and the text is for cell contents. |
|
| 203 | self._canvas.create_rectangle(x1, y1, x2, y2, |
|
| 204 | fill=self._bg, width=0) |
|
| 205 | self._canvas.create_text(x1, y1, anchor='nw', |
|
| 206 | font=self._fnormal, width=1, |
|
| 207 | fill=self._fg, text=' ') |
|
| 208 | ||
| 209 | def _tk_clear_region(self, top, bot, left, right): |
|
| 210 | self._tk_tag_region('clear', top, bot, left, right) |
|
| 211 | self._canvas.itemconfig('clear', fill=self._bg) |
|
| 212 | self._canvas.dtag('clear', 'clear') |
|
| 213 | ||
| 214 | def _tk_destroy_region(self, top, bot, left, right): |
|
| 215 | self._tk_tag_region('destroy', top, bot, left, right) |
|
| 216 | self._canvas.delete('destroy') |
|
| 217 | self._canvas.dtag('destroy', 'destroy') |
|
| 218 | ||
| 219 | def _tk_tag_region(self, tag, top, bot, left, right): |
|
| 220 | x1, y1 = self._tk_get_coords(top, left) |
|
| 221 | x2, y2 = self._tk_get_coords(bot, right) |
|
| 222 | self._canvas.addtag_overlapping(tag, x1, y1, x2 + 1, y2 + 1) |
|
| 223 | ||
| 224 | def _tk_get_coords(self, row, col): |
|
| 225 | x = col * self._colsize |
|
| 226 | y = row * self._rowsize |
|
| 227 | return x, y |
|
| 228 | ||
| 229 | def _tk_key(self, event): |
|
| 230 | if 0xffe1 <= event.keysym_num <= 0xffee: |
|
| 231 | # this is a modifier key, ignore. Source: |
|
| 232 | # https://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm |
|
| 233 | return |
|
| 234 | # Translate to Nvim representation of keys |
|
| 235 | send = [] |
|
| 236 | if event.state & 0x1: |
|
| 237 | send.append('S') |
|
| 238 | if event.state & 0x4: |
|
| 239 | send.append('C') |
|
| 240 | if event.state & (0x8 | 0x80): |
|
| 241 | send.append('A') |
|
| 242 | special = len(send) > 0 |
|
| 243 | key = event.char |
|
| 244 | if _is_invalid_key(key): |
|
| 245 | special = True |
|
| 246 | key = event.keysym |
|
| 247 | send.append(SPECIAL_KEYS.get(key, key)) |
|
| 248 | send = '-'.join(send) |
|
| 249 | if special: |
|
| 250 | send = '<' + send + '>' |
|
| 251 | nvim = self._nvim |
|
| 252 | nvim.session.threadsafe_call(lambda: nvim.input(send)) |
|
| 253 | ||
| 254 | def _nvim_event_loop(self): |
|
| 255 | self._nvim.session.run(self._nvim_request, |
|
| 256 | self._nvim_notification, |
|
| 257 | lambda: self._nvim.attach_ui(80, 24)) |
|
| 258 | self._root.event_generate('<<nvim_detach>>', when='tail') |
|
| 259 | ||
| 260 | def _nvim_request(self, method, args): |
|
| 261 | raise Exception('This UI does not implement any methods') |
|
| 262 | ||
| 263 | def _nvim_notification(self, method, args): |
|
| 264 | if method == 'redraw': |
|
| 265 | self._nvim_updates.append(args) |
|
| 266 | self._root.event_generate('<<nvim_redraw>>', when='tail') |
|
| 267 | ||
| 268 | ||
| 269 | def _is_invalid_key(c): |
|
| @@ 26-264 (lines=239) @@ | ||
| 23 | range = xrange |
|
| 24 | ||
| 25 | ||
| 26 | class NvimTk(object): |
|
| 27 | ||
| 28 | """Wraps all nvim/tk event handling.""" |
|
| 29 | ||
| 30 | def __init__(self, nvim): |
|
| 31 | """Initialize with a Nvim instance.""" |
|
| 32 | self._nvim = nvim |
|
| 33 | self._attrs = {} |
|
| 34 | self._nvim_updates = deque() |
|
| 35 | self._canvas = None |
|
| 36 | self._fg = '#000000' |
|
| 37 | self._bg = '#ffffff' |
|
| 38 | ||
| 39 | def run(self): |
|
| 40 | """Start the UI.""" |
|
| 41 | self._tk_setup() |
|
| 42 | t = Thread(target=self._nvim_event_loop) |
|
| 43 | t.daemon = True |
|
| 44 | t.start() |
|
| 45 | self._root.mainloop() |
|
| 46 | ||
| 47 | def _tk_setup(self): |
|
| 48 | self._root = Tk() |
|
| 49 | self._root.bind('<<nvim_redraw>>', self._tk_nvim_redraw) |
|
| 50 | self._root.bind('<<nvim_detach>>', self._tk_nvim_detach) |
|
| 51 | self._root.bind('<Key>', self._tk_key) |
|
| 52 | ||
| 53 | def _tk_nvim_redraw(self, *args): |
|
| 54 | update = self._nvim_updates.popleft() |
|
| 55 | for update in update: |
|
| 56 | handler = getattr(self, '_tk_nvim_' + update[0]) |
|
| 57 | for args in update[1:]: |
|
| 58 | handler(*args) |
|
| 59 | ||
| 60 | def _tk_nvim_detach(self, *args): |
|
| 61 | self._root.destroy() |
|
| 62 | ||
| 63 | def _tk_nvim_resize(self, width, height): |
|
| 64 | self._tk_redraw_canvas(width, height) |
|
| 65 | ||
| 66 | def _tk_nvim_clear(self): |
|
| 67 | self._tk_clear_region(0, self._height - 1, 0, self._width - 1) |
|
| 68 | ||
| 69 | def _tk_nvim_eol_clear(self): |
|
| 70 | row, col = (self._cursor_row, self._cursor_col,) |
|
| 71 | self._tk_clear_region(row, row, col, self._scroll_right) |
|
| 72 | ||
| 73 | def _tk_nvim_cursor_goto(self, row, col): |
|
| 74 | self._cursor_row = row |
|
| 75 | self._cursor_col = col |
|
| 76 | ||
| 77 | def _tk_nvim_cursor_on(self): |
|
| 78 | pass |
|
| 79 | ||
| 80 | def _tk_nvim_cursor_off(self): |
|
| 81 | pass |
|
| 82 | ||
| 83 | def _tk_nvim_mouse_on(self): |
|
| 84 | pass |
|
| 85 | ||
| 86 | def _tk_nvim_mouse_off(self): |
|
| 87 | pass |
|
| 88 | ||
| 89 | def _tk_nvim_insert_mode(self): |
|
| 90 | pass |
|
| 91 | ||
| 92 | def _tk_nvim_normal_mode(self): |
|
| 93 | pass |
|
| 94 | ||
| 95 | def _tk_nvim_set_scroll_region(self, top, bot, left, right): |
|
| 96 | self._scroll_top = top |
|
| 97 | self._scroll_bot = bot |
|
| 98 | self._scroll_left = left |
|
| 99 | self._scroll_right = right |
|
| 100 | ||
| 101 | def _tk_nvim_scroll(self, count): |
|
| 102 | top, bot = (self._scroll_top, self._scroll_bot,) |
|
| 103 | left, right = (self._scroll_left, self._scroll_right,) |
|
| 104 | ||
| 105 | if count > 0: |
|
| 106 | destroy_top = top |
|
| 107 | destroy_bot = top + count - 1 |
|
| 108 | move_top = destroy_bot + 1 |
|
| 109 | move_bot = bot |
|
| 110 | fill_top = move_bot + 1 |
|
| 111 | fill_bot = fill_top + count - 1 |
|
| 112 | else: |
|
| 113 | destroy_top = bot + count + 1 |
|
| 114 | destroy_bot = bot |
|
| 115 | move_top = top |
|
| 116 | move_bot = destroy_top - 1 |
|
| 117 | fill_bot = move_top - 1 |
|
| 118 | fill_top = fill_bot + count + 1 |
|
| 119 | ||
| 120 | # destroy items that would be moved outside the scroll region after |
|
| 121 | # scrolling |
|
| 122 | # self._tk_clear_region(destroy_top, destroy_bot, left, right) |
|
| 123 | # self._tk_clear_region(move_top, move_bot, left, right) |
|
| 124 | self._tk_destroy_region(destroy_top, destroy_bot, left, right) |
|
| 125 | self._tk_tag_region('move', move_top, move_bot, left, right) |
|
| 126 | self._canvas.move('move', 0, -count * self._rowsize) |
|
| 127 | self._canvas.dtag('move', 'move') |
|
| 128 | # self._tk_fill_region(fill_top, fill_bot, left, right) |
|
| 129 | ||
| 130 | def _tk_nvim_highlight_set(self, attrs): |
|
| 131 | self._attrs = attrs |
|
| 132 | ||
| 133 | def _tk_nvim_put(self, data): |
|
| 134 | # choose a Font instance |
|
| 135 | font = self._fnormal |
|
| 136 | if self._attrs.get('bold', False): |
|
| 137 | font = self._fbold |
|
| 138 | if self._attrs.get('italic', False): |
|
| 139 | font = self._fbolditalic if font == self._fbold else self._fitalic |
|
| 140 | # colors |
|
| 141 | fg = "#{0:0{1}x}".format(self._attrs.get('foreground', self._fg), 6) |
|
| 142 | bg = "#{0:0{1}x}".format(self._attrs.get('background', self._bg), 6) |
|
| 143 | # get the "text" and "rect" which correspond to the current cell |
|
| 144 | x, y = self._tk_get_coords(self._cursor_row, self._cursor_col) |
|
| 145 | items = self._canvas.find_overlapping(x, y, x + 1, y + 1) |
|
| 146 | if len(items) != 2: |
|
| 147 | # caught part the double-width character in the cell to the left, |
|
| 148 | # filter items which dont have the same horizontal coordinate as |
|
| 149 | # "x" |
|
| 150 | predicate = lambda item: self._canvas.coords(item)[0] == x |
|
| 151 | items = filter(predicate, items) |
|
| 152 | # rect has lower id than text, sort to unpack correctly |
|
| 153 | rect, text = sorted(items) |
|
| 154 | self._canvas.itemconfig(text, fill=fg, font=font, text=data or ' ') |
|
| 155 | self._canvas.itemconfig(rect, fill=bg) |
|
| 156 | self._tk_nvim_cursor_goto(self._cursor_row, self._cursor_col + 1) |
|
| 157 | ||
| 158 | def _tk_nvim_bell(self): |
|
| 159 | self._root.bell() |
|
| 160 | ||
| 161 | def _tk_nvim_update_fg(self, fg): |
|
| 162 | self._fg = "#{0:0{1}x}".format(fg, 6) |
|
| 163 | ||
| 164 | def _tk_nvim_update_bg(self, bg): |
|
| 165 | self._bg = "#{0:0{1}x}".format(bg, 6) |
|
| 166 | ||
| 167 | def _tk_redraw_canvas(self, width, height): |
|
| 168 | if self._canvas: |
|
| 169 | self._canvas.destroy() |
|
| 170 | self._fnormal = Font(family='Monospace', size=13) |
|
| 171 | self._fbold = Font(family='Monospace', weight='bold', size=13) |
|
| 172 | self._fitalic = Font(family='Monospace', slant='italic', size=13) |
|
| 173 | self._fbolditalic = Font(family='Monospace', weight='bold', |
|
| 174 | slant='italic', size=13) |
|
| 175 | self._colsize = self._fnormal.measure('A') |
|
| 176 | self._rowsize = self._fnormal.metrics('linespace') |
|
| 177 | self._canvas = Canvas(self._root, width=self._colsize * width, |
|
| 178 | height=self._rowsize * height) |
|
| 179 | self._tk_fill_region(0, height - 1, 0, width - 1) |
|
| 180 | self._cursor_row = 0 |
|
| 181 | self._cursor_col = 0 |
|
| 182 | self._scroll_top = 0 |
|
| 183 | self._scroll_bot = height - 1 |
|
| 184 | self._scroll_left = 0 |
|
| 185 | self._scroll_right = width - 1 |
|
| 186 | self._width, self._height = (width, height,) |
|
| 187 | self._canvas.pack() |
|
| 188 | ||
| 189 | def _tk_fill_region(self, top, bot, left, right): |
|
| 190 | # create columns from right to left so the left columns have a |
|
| 191 | # higher z-index than the right columns. This is required to |
|
| 192 | # properly display characters that cross cell boundary |
|
| 193 | for rownum in range(bot, top - 1, -1): |
|
| 194 | for colnum in range(right, left - 1, -1): |
|
| 195 | x1 = colnum * self._colsize |
|
| 196 | y1 = rownum * self._rowsize |
|
| 197 | x2 = (colnum + 1) * self._colsize |
|
| 198 | y2 = (rownum + 1) * self._rowsize |
|
| 199 | # for each cell, create two items: The rectangle is used for |
|
| 200 | # filling background and the text is for cell contents. |
|
| 201 | self._canvas.create_rectangle(x1, y1, x2, y2, |
|
| 202 | fill=self._background, width=0) |
|
| 203 | self._canvas.create_text(x1, y1, anchor='nw', |
|
| 204 | font=self._fnormal, width=1, |
|
| 205 | fill=self._foreground, text=' ') |
|
| 206 | ||
| 207 | def _tk_clear_region(self, top, bot, left, right): |
|
| 208 | self._tk_tag_region('clear', top, bot, left, right) |
|
| 209 | self._canvas.itemconfig('clear', fill=self._bg) |
|
| 210 | self._canvas.dtag('clear', 'clear') |
|
| 211 | ||
| 212 | def _tk_destroy_region(self, top, bot, left, right): |
|
| 213 | self._tk_tag_region('destroy', top, bot, left, right) |
|
| 214 | self._canvas.delete('destroy') |
|
| 215 | self._canvas.dtag('destroy', 'destroy') |
|
| 216 | ||
| 217 | def _tk_tag_region(self, tag, top, bot, left, right): |
|
| 218 | x1, y1 = self._tk_get_coords(top, left) |
|
| 219 | x2, y2 = self._tk_get_coords(bot, right) |
|
| 220 | self._canvas.addtag_overlapping(tag, x1, y1, x2 + 1, y2 + 1) |
|
| 221 | ||
| 222 | def _tk_get_coords(self, row, col): |
|
| 223 | x = col * self._colsize |
|
| 224 | y = row * self._rowsize |
|
| 225 | return x, y |
|
| 226 | ||
| 227 | def _tk_key(self, event): |
|
| 228 | if 0xffe1 <= event.keysym_num <= 0xffee: |
|
| 229 | # this is a modifier key, ignore. Source: |
|
| 230 | # https://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm |
|
| 231 | return |
|
| 232 | # Translate to Nvim representation of keys |
|
| 233 | send = [] |
|
| 234 | if event.state & 0x1: |
|
| 235 | send.append('S') |
|
| 236 | if event.state & 0x4: |
|
| 237 | send.append('C') |
|
| 238 | if event.state & (0x8 | 0x80): |
|
| 239 | send.append('A') |
|
| 240 | special = len(send) > 0 |
|
| 241 | key = event.char |
|
| 242 | if _is_invalid_key(key): |
|
| 243 | special = True |
|
| 244 | key = event.keysym |
|
| 245 | send.append(SPECIAL_KEYS.get(key, key)) |
|
| 246 | send = '-'.join(send) |
|
| 247 | if special: |
|
| 248 | send = '<' + send + '>' |
|
| 249 | nvim = self._nvim |
|
| 250 | nvim.session.threadsafe_call(lambda: nvim.input(send)) |
|
| 251 | ||
| 252 | def _nvim_event_loop(self): |
|
| 253 | self._nvim.session.run(self._nvim_request, |
|
| 254 | self._nvim_notification, |
|
| 255 | lambda: self._nvim.attach_ui(80, 24)) |
|
| 256 | self._root.event_generate('<<nvim_detach>>', when='tail') |
|
| 257 | ||
| 258 | def _nvim_request(self, method, args): |
|
| 259 | raise Exception('This UI does not implement any methods') |
|
| 260 | ||
| 261 | def _nvim_notification(self, method, args): |
|
| 262 | if method == 'redraw': |
|
| 263 | self._nvim_updates.append(args) |
|
| 264 | self._root.event_generate('<<nvim_redraw>>', when='tail') |
|
| 265 | ||
| 266 | ||
| 267 | def _is_invalid_key(c): |
|