1010
1111from .settings import TrailingSpacesSettings
1212from os .path import isfile
13+ from typing import Dict , List , Literal , Tuple , Union , cast
1314import codecs
1415import difflib
1516import re
1617import sublime
1718import sublime_plugin
1819
1920# dictionary of currently active view ids and last visible regions
20- active_views = {}
21+ active_views : Dict [ int , sublime . Region ] = {}
2122current_highlight_color = ''
2223on_disk = None
2324# Highlight color as defined in settings. Plugin mutates that setting when disabled so
2728settings = TrailingSpacesSettings ()
2829
2930
30- def plugin_loaded ():
31+ def plugin_loaded () -> None :
3132 global current_highlight_color , INITIAL_HIGHLIGHT_COLOR
3233
3334 settings .load ()
@@ -44,7 +45,7 @@ def plugin_loaded():
4445# Private: Makes sure all timers are stopped.
4546#
4647# Returns nothing.
47- def plugin_unloaded ():
48+ def plugin_unloaded () -> None :
4849 global on_disk
4950
5051 # clear all active views to kill all timeouts
@@ -59,8 +60,8 @@ def plugin_unloaded():
5960# regex - the regex pattern to search for
6061#
6162# Returns all matching trailing regions within regions.
62- def view_find_all_in_regions (view , regions , regex ) :
63- found = []
63+ def view_find_all_in_regions (view : sublime . View , regions : List [ sublime . Region ] , regex : str ) -> List [ sublime . Region ] :
64+ found : List [ sublime . Region ] = []
6465
6566 # find all matches in the region's text
6667 for region in regions :
@@ -81,15 +82,17 @@ def view_find_all_in_regions(view, regions, regex):
8182#
8283# Returns both the list of regions which map to trailing spaces and the list of
8384# regions which are to be highlighted, as a list [matched, highlightable].
84- def find_trailing_spaces (view , scan_only_visible = True ):
85+ def find_trailing_spaces (
86+ view : sublime .View , scan_only_visible : bool = True
87+ ) -> Tuple [List [sublime .Region ], List [sublime .Region ]]:
8588 include_empty_lines = settings .include_empty_lines
8689 include_current_line = settings .include_current_line
8790 regexp = settings .regexp + "$"
8891
8992 if not include_empty_lines :
9093 regexp = "(?<=\\ S)%s$" % regexp
9194
92- trailing_regions = []
95+ trailing_regions : List [ sublime . Region ] = []
9396
9497 non_visible_highlighting = settings .non_visible_highlighting
9598
@@ -114,13 +117,13 @@ def find_trailing_spaces(view, scan_only_visible=True):
114117 sel = view .sel ()
115118
116119 if include_current_line or len (sel ) == 0 :
117- return [ trailing_regions , trailing_regions ]
120+ return ( trailing_regions , trailing_regions )
118121 else :
119122 selection_lines = [view .line (region .b ) for region in sel ]
120123 # find all matches in the current line and exclude them from highlighting
121124 selection_offenders = view_find_all_in_regions (view , selection_lines , regexp )
122125 highlightable = [r for r in trailing_regions if r not in selection_offenders ]
123- return [ trailing_regions , highlightable ]
126+ return ( trailing_regions , highlightable )
124127
125128
126129# Private: Find the freaking trailing spaces in the view and flags them as such!
@@ -132,7 +135,7 @@ def find_trailing_spaces(view, scan_only_visible=True):
132135# view - the view, you know
133136#
134137# Returns nothing.
135- def match_trailing_spaces (view ) :
138+ def match_trailing_spaces (view : sublime . View ) -> None :
136139 # Silently pass ignored views.
137140 if ignore_view (view ):
138141 return
@@ -150,14 +153,14 @@ def match_trailing_spaces(view):
150153# view - the view to check.
151154#
152155# Returns True if the view should be ignored, False otherwise.
153- def ignore_view (view ) :
156+ def ignore_view (view : sublime . View ) -> bool :
154157 if view .is_scratch ():
155158 return True
156159
157160 view_settings = view .settings ()
158161 view_syntax = view_settings .get ('syntax' )
159162
160- if not view_syntax or view_settings .get ('is_widget' ):
163+ if not isinstance ( view_syntax , str ) or view_settings .get ('is_widget' ):
161164 return False
162165
163166 for syntax_ignore in settings .syntax_ignore :
@@ -172,7 +175,7 @@ def ignore_view(view):
172175# view - the view, you know
173176#
174177# Returns True or False.
175- def max_size_exceeded (view ) :
178+ def max_size_exceeded (view : sublime . View ) -> bool :
176179 return view .size () > settings .file_max_size
177180
178181
@@ -184,7 +187,7 @@ def max_size_exceeded(view):
184187# regions - regions qualified as trailing spaces
185188#
186189# Returns nothing.
187- def highlight_trailing_spaces_regions (view , regions ) :
190+ def highlight_trailing_spaces_regions (view : sublime . View , regions : List [ sublime . Region ]) -> None :
188191 view .erase_regions (HIGHLIGHT_REGION_KEY )
189192 if regions :
190193 view .add_regions (HIGHLIGHT_REGION_KEY , regions , current_highlight_color or "" , "" , sublime .HIDE_ON_MINIMAP )
@@ -197,7 +200,7 @@ def highlight_trailing_spaces_regions(view, regions):
197200# view - the view, you know
198201#
199202# Returns True (highlighting was turned on) or False (turned off).
200- def toggle_highlighting (view ) :
203+ def toggle_highlighting (view : sublime . View ) -> Literal [ 'disabled!' , 'off' , 'on' ] :
201204 global current_highlight_color
202205
203206 # If the scope is that of an invisible, there is nothing to toggle.
@@ -223,7 +226,7 @@ def toggle_highlighting(view):
223226# window - the window, you know
224227#
225228# Returns nothing.
226- def clear_trailing_spaces_highlight (window ) :
229+ def clear_trailing_spaces_highlight (window : sublime . Window ) -> None :
227230 for view in window .views ():
228231 view .erase_regions ('TrailingSpacesMatchedRegions' )
229232
@@ -241,7 +244,7 @@ def clear_trailing_spaces_highlight(window):
241244# new - a buffer of lines, as in "new version"
242245#
243246# Returns the list of edited line numbers.
244- def modified_lines_as_numbers (old , new ) :
247+ def modified_lines_as_numbers (old : List [ str ] , new : List [ str ]) -> Union [ Literal [ False ], List [ int ]] :
245248 d = difflib .Differ ()
246249 diffs = d .compare (old , new )
247250
@@ -251,7 +254,7 @@ def modified_lines_as_numbers(old, new):
251254 # - the line is only in b: it qualifies as an edited line!
252255 # Starting from -1 as ST2 is internally 0-based for lines.
253256 lineNum = - 1
254- edited_lines = []
257+ edited_lines : List [ int ] = []
255258 for line in diffs :
256259 code = line [:2 ]
257260 # those lines with "? " are not real! watch out!
@@ -268,7 +271,7 @@ def modified_lines_as_numbers(old, new):
268271# view - the view, you know
269272#
270273# Returns the list of regions matching dirty lines.
271- def get_modified_lines (view ) :
274+ def get_modified_lines (view : sublime . View ) -> List [ sublime . Region ] :
272275 on_buffer = view .substr (sublime .Region (0 , view .size ())).splitlines ()
273276 lines = []
274277 line_numbers = modified_lines_as_numbers (on_disk or [], on_buffer )
@@ -286,7 +289,7 @@ def get_modified_lines(view):
286289# view - the view, you know
287290#
288291# Returns a list of regions to be deleted.
289- def find_regions_to_delete (view ) :
292+ def find_regions_to_delete (view : sublime . View ) -> List [ sublime . Region ] :
290293 (regions , highlightable ) = find_trailing_spaces (view , scan_only_visible = False )
291294
292295 # Filtering is required in case triming is restricted to dirty regions only.
@@ -295,7 +298,7 @@ def find_regions_to_delete(view):
295298
296299 # If there are no dirty lines, don't do nothing.
297300 if not modified_lines :
298- return
301+ return []
299302
300303 # Super-private: filters trailing spaces regions to dirty lines only.
301304 #
@@ -314,9 +317,9 @@ def find_regions_to_delete(view):
314317 # we can re-create and store a Region for the relevant trailing spaces boundaries.
315318 #
316319 # Returns the filtered list of trailing spaces regions for the modified lines set.
317- def only_those_with_trailing_spaces ():
318- regions_by_begin = {}
319- matches = []
320+ def only_those_with_trailing_spaces () -> List [ sublime . Region ] :
321+ regions_by_begin : Dict [ sublime . Point , Tuple [ sublime . Point , sublime . Point ]] = {}
322+ matches : List [ sublime . Region ] = []
320323 for region in regions :
321324 begin = view .line (region ).begin ()
322325 regions_by_begin [begin ] = (region .begin (), region .end ())
@@ -339,7 +342,7 @@ def only_those_with_trailing_spaces():
339342# edit - the Edit object spawned by the deletion command
340343#
341344# Returns the number of deleted regions.
342- def delete_trailing_regions (view , edit ) :
345+ def delete_trailing_regions (view : sublime . View , edit : sublime . Edit ) -> int :
343346 regions = find_regions_to_delete (view )
344347
345348 if regions :
@@ -355,8 +358,11 @@ def delete_trailing_regions(view, edit):
355358
356359# Public: Toggles the highlighting on or off.
357360class ToggleTrailingSpacesCommand (sublime_plugin .WindowCommand ):
358- def run (self ):
361+ def run (self ) -> None :
359362 view = self .window .active_view ()
363+ if not view :
364+ return
365+
360366 if max_size_exceeded (view ):
361367 sublime .status_message ("File is too big, trailing spaces handling disabled." )
362368 return
@@ -366,13 +372,13 @@ def run(self):
366372 settings .save ()
367373 sublime .status_message ('Highlighting of trailing spaces is %s' % state )
368374
369- def is_checked (self ):
375+ def is_checked (self ) -> bool :
370376 return current_highlight_color != ""
371377
372378
373379# Public: Toggles "Modified Lines Only" mode on or off.
374380class ToggleTrailingSpacesModifiedLinesOnlyCommand (sublime_plugin .WindowCommand ):
375- def run (self ):
381+ def run (self ) -> None :
376382 was_on = settings .modified_lines_only
377383 settings .modified_lines_only = not was_on
378384 settings .save ()
@@ -381,22 +387,22 @@ def run(self):
381387 else "Let's trim trailing spaces only on modified lines"
382388 sublime .status_message (message )
383389
384- def is_checked (self ):
390+ def is_checked (self ) -> bool :
385391 return settings .modified_lines_only
386392
387393
388394# Public: Matches and highlights trailing spaces on key events, according to the
389395# current settings.
390396class TrailingSpacesListener (sublime_plugin .EventListener ):
391- def on_modified_async (self , view ) :
397+ def on_modified_async (self , view : sublime . View ) -> None :
392398 if settings .enabled :
393399 match_trailing_spaces (view )
394400
395- def on_selection_modified_async (self , view ) :
401+ def on_selection_modified_async (self , view : sublime . View ) -> None :
396402 if settings .enabled :
397403 match_trailing_spaces (view )
398404
399- def on_activated_async (self , view ) :
405+ def on_activated_async (self , view : sublime . View ) -> None :
400406 if settings .modified_lines_only :
401407 self .freeze_last_version (view )
402408
@@ -409,18 +415,18 @@ def on_activated_async(self, view):
409415 active_views [view .id ()] = view .visible_region ()
410416 self .update_on_region_change (view )
411417
412- def on_pre_save (self , view ) :
418+ def on_pre_save (self , view : sublime . View ) -> None :
413419 if settings .modified_lines_only :
414420 self .freeze_last_version (view )
415421
416422 if settings .trim_on_save :
417423 view .run_command ("delete_trailing_spaces" )
418424
419- def on_close (self , view ) :
425+ def on_close (self , view : sublime . View ) -> None :
420426 # untrack
421427 active_views .pop (view .id (), None )
422428
423- def update_on_region_change (self , view ) :
429+ def update_on_region_change (self , view : sublime . View ) -> None :
424430 # remove views not currently visible
425431 if not self .is_view_visible (view ):
426432 active_views .pop (view .id (), None )
@@ -441,7 +447,7 @@ def update_on_region_change(self, view):
441447 # Anyway, let's cache the persisted version of the document's buffer for
442448 # later use on specific event, so that we always have a decent version of
443449 # "what's on the disk" to work with.
444- def freeze_last_version (self , view ) :
450+ def freeze_last_version (self , view : sublime . View ) -> None :
445451 global on_disk
446452
447453 file_name = view .file_name ()
@@ -451,7 +457,7 @@ def freeze_last_version(self, view):
451457 encoding = view .encoding ()
452458
453459 if encoding == "Undefined" :
454- encoding = view .settings ().get ("default_encoding" , "UTF-8" )
460+ encoding = cast ( str , view .settings ().get ("default_encoding" , "UTF-8" ) )
455461
456462 if encoding == "Hexadecimal" : # not supported?
457463 on_disk = None
@@ -463,7 +469,7 @@ def freeze_last_version(self, view):
463469 with codecs .open (file_name , "r" , encoding ) as f :
464470 on_disk = f .read ().splitlines ()
465471
466- def is_view_visible (self , view ) :
472+ def is_view_visible (self , view : sublime . View ) -> bool :
467473 window = view .window ()
468474 if not window :
469475 return False
@@ -497,7 +503,7 @@ def is_view_visible(self, view):
497503
498504# Public: Deletes the trailing spaces.
499505class DeleteTrailingSpacesCommand (sublime_plugin .TextCommand ):
500- def run (self , edit ) :
506+ def run (self , edit : sublime . Edit ) -> None :
501507 if max_size_exceeded (self .view ):
502508 sublime .status_message ("File is too big, trailing spaces handling disabled." )
503509 return
@@ -516,7 +522,7 @@ def run(self, edit):
516522
517523 sublime .status_message (message )
518524
519- def save (self , view ) :
525+ def save (self , view : sublime . View ) -> None :
520526 if view .file_name () is None :
521527 view .run_command ('prompt_save_as' )
522528 else :
0 commit comments