@@ -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
583566def _split_color (n ):
0 commit comments