@@ -90,12 +90,12 @@ def __init__(self, font):
9090 self ._resize_timer_id = None
9191 self ._pressed = None
9292 self ._invalid = None
93- self ._pending = [0 , 0 , 0 ]
9493 self ._reset_cache ()
94+ self ._attr_defs = {}
9595
9696 def start (self , bridge ):
9797 """Start the UI event loop."""
98- bridge .attach (80 , 24 , rgb = True )
98+ bridge .attach (80 , 24 , rgb = True , ext_multigrid = True )
9999 drawing_area = Gtk .DrawingArea ()
100100 drawing_area .connect ('draw' , self ._gtk_draw )
101101 window = Gtk .Window ()
@@ -135,15 +135,15 @@ def schedule_screen_update(self, apply_updates):
135135 """Schedule screen updates to run in the UI event loop."""
136136 def wrapper ():
137137 apply_updates ()
138- self ._flush ()
139138 self ._start_blinking ()
140139 self ._screen_invalid ()
141140 GObject .idle_add (wrapper )
142141
143142 def _screen_invalid (self ):
144143 self ._drawing_area .queue_draw ()
145144
146- def _nvim_resize (self , columns , rows ):
145+ def _nvim_grid_resize (self , grid , columns , rows ):
146+ assert grid == 1
147147 da = self ._drawing_area
148148 # create FontDescription object for the selected font/size
149149 font_str = '{0} {1}' .format (self ._font_name , self ._font_size )
@@ -170,17 +170,12 @@ def _nvim_resize(self, columns, rows):
170170 self ._screen = Screen (columns , rows )
171171 self ._window .resize (pixel_width , pixel_height )
172172
173- def _nvim_clear (self ):
173+ def _nvim_grid_clear (self , grid ):
174174 self ._clear_region (self ._screen .top , self ._screen .bot + 1 ,
175175 self ._screen .left , self ._screen .right + 1 )
176176 self ._screen .clear ()
177177
178- def _nvim_eol_clear (self ):
179- row , col = self ._screen .row , self ._screen .col
180- self ._clear_region (row , row + 1 , col , self ._screen .right + 1 )
181- self ._screen .eol_clear ()
182-
183- def _nvim_cursor_goto (self , row , col ):
178+ def _nvim_grid_cursor_goto (self , grid , row , col ):
184179 self ._screen .cursor_goto (row , col )
185180
186181 def _nvim_busy_start (self ):
@@ -198,18 +193,12 @@ def _nvim_mouse_off(self):
198193 def _nvim_mode_change (self , mode ):
199194 self ._insert_cursor = mode == 'insert'
200195
201- def _nvim_set_scroll_region (self , top , bot , left , right ):
202- self ._screen .set_scroll_region (top , bot , left , right )
203-
204- def _nvim_scroll (self , count ):
205- self ._flush ()
206- top , bot = self ._screen .top , self ._screen .bot + 1
207- left , right = self ._screen .left , self ._screen .right + 1
196+ def _nvim_grid_scroll (self , grid , top , bot , left , right , rows , cols ):
208197 # The diagrams below illustrate what will happen, depending on the
209198 # scroll direction. "=" is used to represent the SR(scroll region)
210199 # boundaries and "-" the moved rectangles. note that dst and src share
211200 # a common region
212- if count > 0 :
201+ if rows > 0 :
213202 # move an rectangle in the SR up, this can happen while scrolling
214203 # down
215204 # +-------------------------+
@@ -221,8 +210,8 @@ def _nvim_scroll(self, count):
221210 # |-------------------------| dst_bot |
222211 # | src (cleared) | |
223212 # +=========================+ src_bot
224- src_top , src_bot = top + count , bot
225- dst_top , dst_bot = top , bot - count
213+ src_top , src_bot = top + rows , bot
214+ dst_top , dst_bot = top , bot - rows
226215 clr_top , clr_bot = dst_bot , src_bot
227216 else :
228217 # move a rectangle in the SR down, this can happen while scrolling
@@ -236,8 +225,8 @@ def _nvim_scroll(self, count):
236225 # |=========================| dst_bot |
237226 # | (clipped below SR) | v
238227 # +-------------------------+
239- src_top , src_bot = top , bot + count
240- dst_top , dst_bot = top - count , bot
228+ src_top , src_bot = top , bot + rows
229+ dst_top , dst_bot = top - rows , bot
241230 clr_top , clr_bot = src_top , dst_top
242231 self ._cairo_surface .flush ()
243232 self ._cairo_context .save ()
@@ -252,33 +241,59 @@ def _nvim_scroll(self, count):
252241 self ._cairo_context .restore ()
253242 # Clear the emptied region
254243 self ._clear_region (clr_top , clr_bot , left , right )
255- self ._screen .scroll (count )
244+ self ._screen .scroll (rows )
256245
257- def _nvim_highlight_set (self , attrs ):
258- self ._attrs = self ._get_pango_attrs (attrs )
246+ def _nvim_hl_attr_define (self , hlid , attr , info ):
247+ self ._attr_defs [hlid ] = attr
248+
249+ def _nvim_grid_line (self , grid , row , col_start , cells ):
250+ assert grid == 1
259251
260- def _nvim_put (self , text ):
261- if self ._screen .row != self ._pending [0 ]:
262- # flush pending text if jumped to a different row
263- self ._flush ()
264- # work around some redraw glitches that can happen
265- self ._redraw_glitch_fix ()
266252 # Update internal screen
267- self ._screen .put (self ._get_pango_text (text ), self ._attrs )
268- self ._pending [1 ] = min (self ._screen .col - 1 , self ._pending [1 ])
269- self ._pending [2 ] = max (self ._screen .col , self ._pending [2 ])
253+ col = col_start
254+ attr = None # will be set in first cell
255+ for cell in cells :
256+ text = cell [0 ]
257+ if len (cell ) > 1 :
258+ hl_id = cell [1 ]
259+ attr = self ._get_pango_attrs (hl_id )
260+ repeat = cell [2 ] if len (cell ) > 2 else 1
261+ for i in range (repeat ):
262+ self ._screen .put (row , col , self ._get_pango_text (text ), attr )
263+ col += 1
264+ col_end = col
265+
266+ # work around some redraw glitches that can happen
267+ col_start , col_end = self ._redraw_glitch_fix (row , col_start , col_end )
268+
269+ self ._cairo_context .save ()
270+ ccol = col_start
271+ buf = []
272+ bold = False
273+ for _ , col , text , attrs in self ._screen .iter (row , row , col_start ,
274+ col_end - 1 ):
275+ newbold = attrs and 'bold' in attrs [0 ]
276+ if newbold != bold or not text :
277+ if buf :
278+ self ._pango_draw (row , ccol , buf )
279+ bold = newbold
280+ buf = [(text , attrs ,)]
281+ ccol = col
282+ else :
283+ buf .append ((text , attrs ,))
284+ if buf :
285+ self ._pango_draw (row , ccol , buf )
286+ self ._cairo_context .restore ()
287+
270288
271289 def _nvim_bell (self ):
272290 self ._window .get_window ().beep ()
273291
274292 def _nvim_visual_bell (self ):
275293 pass
276294
277- def _nvim_update_fg (self , fg ):
295+ def _nvim_default_colors_set (self , fg , bg , sp , cterm_fg , cterm_bg ):
278296 self ._foreground = fg
279- self ._reset_cache ()
280-
281- def _nvim_update_bg (self , bg ):
282297 self ._background = bg
283298 self ._reset_cache ()
284299
@@ -427,7 +442,6 @@ def blink(*args):
427442 blink ()
428443
429444 def _clear_region (self , top , bot , left , right ):
430- self ._flush ()
431445 self ._cairo_context .save ()
432446 self ._mask_region (top , bot , left , right )
433447 r , g , b = _split_color (self ._background )
@@ -453,37 +467,11 @@ def _get_coords(self, row, col):
453467 y = row * self ._cell_pixel_height
454468 return x , y
455469
456- def _flush (self ):
457- row , startcol , endcol = self ._pending
458- self ._pending [0 ] = self ._screen .row
459- self ._pending [1 ] = self ._screen .col
460- self ._pending [2 ] = self ._screen .col
461- if startcol == endcol :
462- return
463- self ._cairo_context .save ()
464- ccol = startcol
465- buf = []
466- bold = False
467- for _ , col , text , attrs in self ._screen .iter (row , row , startcol ,
468- endcol - 1 ):
469- newbold = attrs and 'bold' in attrs [0 ]
470- if newbold != bold or not text :
471- if buf :
472- self ._pango_draw (row , ccol , buf )
473- bold = newbold
474- buf = [(text , attrs ,)]
475- ccol = col
476- else :
477- buf .append ((text , attrs ,))
478- if buf :
479- self ._pango_draw (row , ccol , buf )
480- self ._cairo_context .restore ()
481-
482470 def _pango_draw (self , row , col , data , cr = None , cursor = False ):
483471 markup = []
484472 for text , attrs in data :
485473 if not attrs :
486- attrs = self ._get_pango_attrs (None )
474+ attrs = self ._get_pango_attrs (0 )
487475 attrs = attrs [1 ] if cursor else attrs [0 ]
488476 markup .append ('<span {0}>{1}</span>' .format (attrs , text ))
489477 markup = '' .join (markup )
@@ -508,10 +496,10 @@ def _get_pango_text(self, text):
508496 self ._pango_text_cache [text ] = rv
509497 return rv
510498
511- def _get_pango_attrs (self , attrs ):
512- key = tuple (sorted ((k , v ,) for k , v in (attrs or {}).items ()))
513- rv = self ._pango_attrs_cache .get (key , None )
499+ def _get_pango_attrs (self , hl_id ):
500+ rv = self ._pango_attrs_cache .get (hl_id , None )
514501 if rv is None :
502+ attrs = self ._attr_defs .get (hl_id , {})
515503 fg = self ._foreground if self ._foreground != - 1 else 0
516504 bg = self ._background if self ._background != - 1 else 0xffffff
517505 n = {
@@ -545,36 +533,31 @@ def _get_pango_attrs(self, attrs):
545533 n = ' ' .join (['{0}="{1}"' .format (k , v ) for k , v in n .items ()])
546534 c = ' ' .join (['{0}="{1}"' .format (k , v ) for k , v in c .items ()])
547535 rv = (n , c ,)
548- self ._pango_attrs_cache [key ] = rv
536+ self ._pango_attrs_cache [hl_id ] = rv
549537 return rv
550538
551539 def _reset_cache (self ):
552540 self ._pango_text_cache = {}
553541 self ._pango_attrs_cache = {}
554542
555- def _redraw_glitch_fix (self ):
556- row , col = self ._screen .row , self ._screen .col
557- text , attrs = self ._screen .get_cursor ()
543+ def _redraw_glitch_fix (self , row , col_start , col_end ):
558544 # when updating cells in italic or bold words, the result can become
559545 # messy(characters can be clipped or leave remains when removed). To
560546 # prevent that, always update non empty sequences of cells and the
561547 # surrounding space.
562548 # find the start of the sequence
563- lcol = col - 1
564- while lcol >= 0 :
565- text , _ = self ._screen .get_cell (row , lcol )
566- lcol -= 1
549+ while col_start - 1 >= 0 :
550+ text , _ = self ._screen .get_cell (row , col_start - 1 )
567551 if text == ' ' :
568552 break
569- self . _pending [ 1 ] = min ( lcol + 1 , self . _pending [ 1 ])
553+ col_start -= 1
570554 # find the end of the sequence
571- rcol = col + 1
572- while rcol < self ._screen .columns :
573- text , _ = self ._screen .get_cell (row , rcol )
574- rcol += 1
555+ while col_end < self ._screen .columns :
556+ text , _ = self ._screen .get_cell (row , col_end )
575557 if text == ' ' :
576558 break
577- self ._pending [2 ] = max (rcol , self ._pending [2 ])
559+ col_end += 1
560+ return col_start , col_end
578561
579562
580563def _split_color (n ):
0 commit comments