Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Commit e8aa5be

Browse files
committed
make the gui use grid_line representation
1 parent ff3ccc7 commit e8aa5be

File tree

2 files changed

+69
-87
lines changed

2 files changed

+69
-87
lines changed

neovim_gui/gtk_ui.py

Lines changed: 67 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,14 @@ def __init__(self, font):
9191
self._resize_timer_id = None
9292
self._pressed = None
9393
self._invalid = None
94-
self._pending = [0, 0, 0]
9594
self._reset_cache()
95+
self._attr_defs = {}
9696

9797
def start(self, bridge):
9898
"""Start the UI event loop."""
9999
debug_ext_env = os.environ.get("NVIM_PYTHON_UI_DEBUG_EXT", "")
100100
extra_exts = {x:True for x in debug_ext_env.split(",") if x}
101-
bridge.attach(80, 24, rgb=True, **extra_exts)
101+
bridge.attach(80, 24, rgb=True, ext_newgrid=True, **extra_exts)
102102
drawing_area = Gtk.DrawingArea()
103103
drawing_area.connect('draw', self._gtk_draw)
104104
window = Gtk.Window()
@@ -138,15 +138,15 @@ def schedule_screen_update(self, apply_updates):
138138
"""Schedule screen updates to run in the UI event loop."""
139139
def wrapper():
140140
apply_updates()
141-
self._flush()
142141
self._start_blinking()
143142
self._screen_invalid()
144143
GObject.idle_add(wrapper)
145144

146145
def _screen_invalid(self):
147146
self._drawing_area.queue_draw()
148147

149-
def _nvim_resize(self, columns, rows):
148+
def _nvim_grid_resize(self, grid, columns, rows):
149+
assert grid == 1
150150
da = self._drawing_area
151151
# create FontDescription object for the selected font/size
152152
font_str = '{0} {1}'.format(self._font_name, self._font_size)
@@ -173,17 +173,12 @@ def _nvim_resize(self, columns, rows):
173173
self._screen = Screen(columns, rows)
174174
self._window.resize(pixel_width, pixel_height)
175175

176-
def _nvim_clear(self):
176+
def _nvim_grid_clear(self, grid):
177177
self._clear_region(self._screen.top, self._screen.bot + 1,
178178
self._screen.left, self._screen.right + 1)
179179
self._screen.clear()
180180

181-
def _nvim_eol_clear(self):
182-
row, col = self._screen.row, self._screen.col
183-
self._clear_region(row, row + 1, col, self._screen.right + 1)
184-
self._screen.eol_clear()
185-
186-
def _nvim_cursor_goto(self, row, col):
181+
def _nvim_grid_cursor_goto(self, grid, row, col):
187182
self._screen.cursor_goto(row, col)
188183

189184
def _nvim_busy_start(self):
@@ -201,18 +196,12 @@ def _nvim_mouse_off(self):
201196
def _nvim_mode_change(self, mode):
202197
self._insert_cursor = mode == 'insert'
203198

204-
def _nvim_set_scroll_region(self, top, bot, left, right):
205-
self._screen.set_scroll_region(top, bot, left, right)
206-
207-
def _nvim_scroll(self, count):
208-
self._flush()
209-
top, bot = self._screen.top, self._screen.bot + 1
210-
left, right = self._screen.left, self._screen.right + 1
199+
def _nvim_grid_scroll(self, grid, top, bot, left, right, rows, cols):
211200
# The diagrams below illustrate what will happen, depending on the
212201
# scroll direction. "=" is used to represent the SR(scroll region)
213202
# boundaries and "-" the moved rectangles. note that dst and src share
214203
# a common region
215-
if count > 0:
204+
if rows > 0:
216205
# move an rectangle in the SR up, this can happen while scrolling
217206
# down
218207
# +-------------------------+
@@ -224,8 +213,8 @@ def _nvim_scroll(self, count):
224213
# |-------------------------| dst_bot |
225214
# | src (cleared) | |
226215
# +=========================+ src_bot
227-
src_top, src_bot = top + count, bot
228-
dst_top, dst_bot = top, bot - count
216+
src_top, src_bot = top + rows, bot
217+
dst_top, dst_bot = top, bot - rows
229218
clr_top, clr_bot = dst_bot, src_bot
230219
else:
231220
# move a rectangle in the SR down, this can happen while scrolling
@@ -239,8 +228,8 @@ def _nvim_scroll(self, count):
239228
# |=========================| dst_bot |
240229
# | (clipped below SR) | v
241230
# +-------------------------+
242-
src_top, src_bot = top, bot + count
243-
dst_top, dst_bot = top - count, bot
231+
src_top, src_bot = top, bot + rows
232+
dst_top, dst_bot = top - rows, bot
244233
clr_top, clr_bot = src_top, dst_top
245234
self._cairo_surface.flush()
246235
self._cairo_context.save()
@@ -255,33 +244,59 @@ def _nvim_scroll(self, count):
255244
self._cairo_context.restore()
256245
# Clear the emptied region
257246
self._clear_region(clr_top, clr_bot, left, right)
258-
self._screen.scroll(count)
247+
self._screen.scroll(rows)
259248

260-
def _nvim_highlight_set(self, attrs):
261-
self._attrs = self._get_pango_attrs(attrs)
249+
def _nvim_hl_attr_define(self, hlid, attr, cterm_attr, info):
250+
self._attr_defs[hlid] = attr
251+
252+
def _nvim_grid_line(self, grid, row, col_start, cells):
253+
assert grid == 1
262254

263-
def _nvim_put(self, text):
264-
if self._screen.row != self._pending[0]:
265-
# flush pending text if jumped to a different row
266-
self._flush()
267-
# work around some redraw glitches that can happen
268-
self._redraw_glitch_fix()
269255
# Update internal screen
270-
self._screen.put(self._get_pango_text(text), self._attrs)
271-
self._pending[1] = min(self._screen.col - 1, self._pending[1])
272-
self._pending[2] = max(self._screen.col, self._pending[2])
256+
col = col_start
257+
attr = None # will be set in first cell
258+
for cell in cells:
259+
text = cell[0]
260+
if len(cell) > 1:
261+
hl_id = cell[1]
262+
attr = self._get_pango_attrs(hl_id)
263+
repeat = cell[2] if len(cell) > 2 else 1
264+
for i in range(repeat):
265+
self._screen.put(row, col, self._get_pango_text(text), attr)
266+
col += 1
267+
col_end = col
268+
269+
# work around some redraw glitches that can happen
270+
col_start, col_end = self._redraw_glitch_fix(row, col_start, col_end)
271+
272+
self._cairo_context.save()
273+
ccol = col_start
274+
buf = []
275+
bold = False
276+
for _, col, text, attrs in self._screen.iter(row, row, col_start,
277+
col_end - 1):
278+
newbold = attrs and 'bold' in attrs[0]
279+
if newbold != bold or not text:
280+
if buf:
281+
self._pango_draw(row, ccol, buf)
282+
bold = newbold
283+
buf = [(text, attrs,)]
284+
ccol = col
285+
else:
286+
buf.append((text, attrs,))
287+
if buf:
288+
self._pango_draw(row, ccol, buf)
289+
self._cairo_context.restore()
290+
273291

274292
def _nvim_bell(self):
275293
self._window.get_window().beep()
276294

277295
def _nvim_visual_bell(self):
278296
pass
279297

280-
def _nvim_update_fg(self, fg):
298+
def _nvim_default_colors_set(self, fg, bg, sp, cterm_fg, cterm_bg):
281299
self._foreground = fg
282-
self._reset_cache()
283-
284-
def _nvim_update_bg(self, bg):
285300
self._background = bg
286301
self._reset_cache()
287302

@@ -430,7 +445,6 @@ def blink(*args):
430445
blink()
431446

432447
def _clear_region(self, top, bot, left, right):
433-
self._flush()
434448
self._cairo_context.save()
435449
self._mask_region(top, bot, left, right)
436450
r, g, b = _split_color(self._background)
@@ -456,37 +470,11 @@ def _get_coords(self, row, col):
456470
y = row * self._cell_pixel_height
457471
return x, y
458472

459-
def _flush(self):
460-
row, startcol, endcol = self._pending
461-
self._pending[0] = self._screen.row
462-
self._pending[1] = self._screen.col
463-
self._pending[2] = self._screen.col
464-
if startcol == endcol:
465-
return
466-
self._cairo_context.save()
467-
ccol = startcol
468-
buf = []
469-
bold = False
470-
for _, col, text, attrs in self._screen.iter(row, row, startcol,
471-
endcol - 1):
472-
newbold = attrs and 'bold' in attrs[0]
473-
if newbold != bold or not text:
474-
if buf:
475-
self._pango_draw(row, ccol, buf)
476-
bold = newbold
477-
buf = [(text, attrs,)]
478-
ccol = col
479-
else:
480-
buf.append((text, attrs,))
481-
if buf:
482-
self._pango_draw(row, ccol, buf)
483-
self._cairo_context.restore()
484-
485473
def _pango_draw(self, row, col, data, cr=None, cursor=False):
486474
markup = []
487475
for text, attrs in data:
488476
if not attrs:
489-
attrs = self._get_pango_attrs(None)
477+
attrs = self._get_pango_attrs(0)
490478
attrs = attrs[1] if cursor else attrs[0]
491479
markup.append('<span {0}>{1}</span>'.format(attrs, text))
492480
markup = ''.join(markup)
@@ -511,10 +499,10 @@ def _get_pango_text(self, text):
511499
self._pango_text_cache[text] = rv
512500
return rv
513501

514-
def _get_pango_attrs(self, attrs):
515-
key = tuple(sorted((k, v,) for k, v in (attrs or {}).items()))
516-
rv = self._pango_attrs_cache.get(key, None)
502+
def _get_pango_attrs(self, hl_id):
503+
rv = self._pango_attrs_cache.get(hl_id, None)
517504
if rv is None:
505+
attrs = self._attr_defs.get(hl_id, {})
518506
fg = self._foreground if self._foreground != -1 else 0
519507
bg = self._background if self._background != -1 else 0xffffff
520508
n = {
@@ -548,36 +536,31 @@ def _get_pango_attrs(self, attrs):
548536
n = ' '.join(['{0}="{1}"'.format(k, v) for k, v in n.items()])
549537
c = ' '.join(['{0}="{1}"'.format(k, v) for k, v in c.items()])
550538
rv = (n, c,)
551-
self._pango_attrs_cache[key] = rv
539+
self._pango_attrs_cache[hl_id] = rv
552540
return rv
553541

554542
def _reset_cache(self):
555543
self._pango_text_cache = {}
556544
self._pango_attrs_cache = {}
557545

558-
def _redraw_glitch_fix(self):
559-
row, col = self._screen.row, self._screen.col
560-
text, attrs = self._screen.get_cursor()
546+
def _redraw_glitch_fix(self, row, col_start, col_end):
561547
# when updating cells in italic or bold words, the result can become
562548
# messy(characters can be clipped or leave remains when removed). To
563549
# prevent that, always update non empty sequences of cells and the
564550
# surrounding space.
565551
# find the start of the sequence
566-
lcol = col - 1
567-
while lcol >= 0:
568-
text, _ = self._screen.get_cell(row, lcol)
569-
lcol -= 1
552+
while col_start-1 >= 0:
553+
text, _ = self._screen.get_cell(row, col_start-1)
570554
if text == ' ':
571555
break
572-
self._pending[1] = min(lcol + 1, self._pending[1])
556+
col_start -= 1
573557
# find the end of the sequence
574-
rcol = col + 1
575-
while rcol < self._screen.columns:
576-
text, _ = self._screen.get_cell(row, rcol)
577-
rcol += 1
558+
while col_end < self._screen.columns:
559+
text, _ = self._screen.get_cell(row, col_end)
578560
if text == ' ':
579561
break
580-
self._pending[2] = max(rcol, self._pending[2])
562+
col_end += 1
563+
return col_start, col_end
581564

582565

583566
def _split_color(n):

neovim_gui/screen.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,10 @@ def scroll(self, count):
8888
for row in range(stop, stop + count, step):
8989
self._clear_region(row, row, left, right)
9090

91-
def put(self, text, attrs):
91+
def put(self, row, col, text, attrs):
9292
"""Put character on virtual cursor position."""
93-
cell = self._cells[self.row][self.col]
93+
cell = self._cells[row][col]
9494
cell.set(text, attrs)
95-
self.cursor_goto(self.row, self.col + 1)
9695

9796
def get_cell(self, row, col):
9897
"""Get text, attrs at row, col."""

0 commit comments

Comments
 (0)