77import re
88from collections import defaultdict
99from datetime import datetime
10- from threading import Event , Thread , RLock
1110from queue import Empty , Queue
11+ from threading import Event , RLock , Thread
1212
1313import sublime
1414
15- from .utils import show_password_input
16- from .utils import get_png_dimensions
17-
15+ from .utils import get_cell , get_png_dimensions , show_password_input
1816
1917JUPYTER_PROTOCOL_VERSION = "5.0"
2018
@@ -149,6 +147,7 @@ class IOPubMessageReceiver(MessageReceiver):
149147 def run (self ):
150148 """Run main routine."""
151149 # TODO: log, handle other message types.
150+
152151 while not self .exit .is_set ():
153152 try :
154153 msg = self ._kernel .client .get_iopub_msg (timeout = 1 )
@@ -163,6 +162,9 @@ def run(self):
163162 if msg_type == MSG_TYPE_STATUS :
164163 self ._kernel ._execution_state = content ["execution_state" ]
165164 elif msg_type == MSG_TYPE_EXECUTE_INPUT :
165+ # if code is executed deleted all phantoms in this region
166+ self ._kernel ._clear_phantoms_in_region (region , view )
167+
166168 self ._kernel ._write_text_to_view ("\n \n " )
167169 if sublime .load_settings ("Helium.sublime-settings" ).get (
168170 "output_code"
@@ -191,6 +193,7 @@ def run(self):
191193 self ._kernel ._handle_stream (
192194 content ["name" ], content ["text" ], region , view ,
193195 )
196+
194197 except Empty :
195198 pass
196199 except Exception as ex :
@@ -260,6 +263,7 @@ def __init__(
260263 self ._connection_name = connection_name
261264 self ._execution_state = "unknown"
262265 self ._init_receivers ()
266+ self .phantoms = {}
263267
264268 def __del__ (self ): # noqa
265269 self ._shell_msg_receiver .shutdown ()
@@ -387,7 +391,7 @@ def _handle_stream(
387391 pass
388392
389393 def _write_out_execution_count (self , execution_count ) -> None :
390- self ._write_text_to_view ("\n Out[{}]: " .format (execution_count ))
394+ self ._write_text_to_view ("\n Out[{}]: \n " .format (execution_count ))
391395
392396 def _write_text_to_view (self , text : str ) -> None :
393397 if self ._show_inline_output :
@@ -416,14 +420,18 @@ def _write_inline_html_phantom(
416420 ):
417421 if self ._show_inline_output :
418422 id = HELIUM_FIGURE_PHANTOMS + datetime .now ().isoformat ()
423+
419424 html = TEXT_PHANTOM .format (content = content )
420- view .add_phantom (
425+ int_id = view .add_phantom (
421426 id ,
422427 region ,
423428 html ,
424429 sublime .LAYOUT_BLOCK ,
425- on_navigate = lambda href , id = id : view .erase_phantoms (id ),
430+ on_navigate = lambda href , id = id , view = view : self ._erase_phantom (
431+ id , view = view
432+ ),
426433 )
434+ self .phantoms [id ] = int_id
427435 self ._logger .info ("Created inline phantom {}" .format (html ))
428436
429437 def _write_inline_image_phantom (
@@ -450,20 +458,40 @@ def _write_inline_image_phantom(
450458
451459 html = IMAGE_PHANTOM .format (data = data , width = width , height = height )
452460
453- view .add_phantom (
461+ int_id = view .add_phantom (
454462 id ,
455463 region ,
456464 html ,
457465 sublime .LAYOUT_BLOCK ,
458- on_navigate = lambda href , id = id : view .erase_phantoms (id ),
466+ on_navigate = lambda href , id = id , view = view : self ._erase_phantom (
467+ id , view = view
468+ ),
459469 )
470+ self .phantoms [id ] = int_id
460471 self ._logger .info ("Created inline phantom image" )
461472
473+ def _clear_phantoms_in_region (self , region : sublime .Region , view : sublime .View ):
474+ _ , cell = get_cell (view , region , logger = "" )
475+ remove = [
476+ pid
477+ for pid , int_id in self .phantoms .items ()
478+ if cell .contains (view .query_phantom (int_id )[0 ])
479+ ]
480+
481+ for pid in remove :
482+ self ._erase_phantom (pid , view = view )
483+
484+ def _erase_phantom (self , pid : str , * , view : sublime .View ):
485+ if pid in self .phantoms :
486+ _ = self .phantoms .pop (pid )
487+ view .erase_phantoms (pid )
488+
462489 def _write_mime_data_to_view (
463490 self , mime_data : dict , region : sublime .Region , view : sublime .View
464491 ) -> None :
465492 # Now we use basically text/plain for text type.
466493 # Jupyter kernels often emits html whom minihtml cannot render.
494+
467495 if "text/plain" in mime_data :
468496 content = mime_data ["text/plain" ]
469497 lines = "\n (display data): {content}" .format (content = content )
0 commit comments