<s> import sublime , sublime_plugin <EOL> def advance_to_first_non_white_space_on_line ( view , pt ) : <EOL> while True : <EOL> c = view . substr ( sublime . Region ( pt , pt + <NUM_LIT:1> ) ) <EOL> if c == "<STR_LIT:U+0020>" or c == "<STR_LIT:\t>" : <EOL> pt += <NUM_LIT:1> <EOL> else : <EOL> break <EOL> return pt <EOL> def has_non_white_space_on_line ( view , pt ) : <EOL> while True : <EOL> c = view . substr ( sublime . Region ( pt , pt + <NUM_LIT:1> ) ) <EOL> if c == "<STR_LIT:U+0020>" or c == "<STR_LIT:\t>" : <EOL> pt += <NUM_LIT:1> <EOL> else : <EOL> return c != "<STR_LIT:\n>" <EOL> def build_comment_data ( view , pt ) : <EOL> shell_vars = view . meta_info ( "<STR_LIT>" , pt ) <EOL> if not shell_vars : <EOL> return ( [ ] , [ ] ) <EOL> all_vars = { } <EOL> for v in shell_vars : <EOL> if '<STR_LIT:name>' in v and '<STR_LIT:value>' in v : <EOL> all_vars [ v [ '<STR_LIT:name>' ] ] = v [ '<STR_LIT:value>' ] <EOL> line_comments = [ ] <EOL> block_comments = [ ] <EOL> suffixes = [ "<STR_LIT>" ] + [ "<STR_LIT:_>" + str ( i ) for i in xrange ( <NUM_LIT:1> , <NUM_LIT:10> ) ] <EOL> for suffix in suffixes : <EOL> start = all_vars . setdefault ( "<STR_LIT>" + suffix ) <EOL> end = all_vars . setdefault ( "<STR_LIT>" + suffix ) <EOL> mode = all_vars . setdefault ( "<STR_LIT>" + suffix ) <EOL> disable_indent = all_vars . setdefault ( "<STR_LIT>" + suffix ) <EOL> if start and end : <EOL> block_comments . append ( ( start , end , disable_indent == '<STR_LIT:yes>' ) ) <EOL> block_comments . append ( ( start . strip ( ) , end . strip ( ) , disable_indent == '<STR_LIT:yes>' ) ) <EOL> elif start : <EOL> line_comments . append ( ( start , disable_indent == '<STR_LIT:yes>' ) ) <EOL> line_comments . append ( ( start . strip ( ) , disable_indent == '<STR_LIT:yes>' ) ) <EOL> return ( line_comments , block_comments ) <EOL> class ToggleCommentCommand ( sublime_plugin . TextCommand ) : <EOL> def remove_block_comment ( self , view , edit , comment_data , region ) : <EOL> ( line_comments , block_comments ) = comment_data <EOL> whole_region = view . extract_scope ( region . begin ( ) + region . size ( ) / <NUM_LIT:2> ) <EOL> for c in block_comments : <EOL> ( start , end , disable_indent ) = c <EOL> start_region = sublime . Region ( whole_region . begin ( ) , <EOL> whole_region . begin ( ) + len ( start ) ) <EOL> end_region = sublime . Region ( whole_region . end ( ) - len ( end ) , <EOL> whole_region . end ( ) ) <EOL> if view . substr ( start_region ) == start and view . substr ( end_region ) == end : <EOL> view . erase ( edit , start_region ) <EOL> end_region = sublime . Region ( <EOL> end_region . begin ( ) - start_region . size ( ) , <EOL> end_region . end ( ) - start_region . size ( ) ) <EOL> view . erase ( edit , end_region ) <EOL> return True <EOL> return False <EOL> def remove_line_comment ( self , view , edit , comment_data , region ) : <EOL> ( line_comments , block_comments ) = comment_data <EOL> found_line_comment = False <EOL> start_positions = [ advance_to_first_non_white_space_on_line ( view , r . begin ( ) ) <EOL> for r in view . lines ( region ) ] <EOL> start_positions . reverse ( ) <EOL> for pos in start_positions : <EOL> for c in line_comments : <EOL> ( start , disable_indent ) = c <EOL> comment_region = sublime . Region ( pos , <EOL> pos + len ( start ) ) <EOL> if view . substr ( comment_region ) == start : <EOL> view . erase ( edit , comment_region ) <EOL> found_line_comment = True <EOL> break <EOL> return found_line_comment <EOL> def is_entirely_line_commented ( self , view , comment_data , region ) : <EOL> ( line_comments , block_comments ) = comment_data <EOL> start_positions = [ advance_to_first_non_white_space_on_line ( view , r . begin ( ) ) <EOL> for r in view . lines ( region ) ] <EOL> start_positions = filter ( lambda p : has_non_white_space_on_line ( view , p ) , <EOL> start_positions ) <EOL> if len ( start_positions ) == <NUM_LIT:0> : <EOL> return False <EOL> for pos in start_positions : <EOL> found_line_comment = False <EOL> for c in line_comments : <EOL> ( start , disable_indent ) = c <EOL> comment_region = sublime . Region ( pos , <EOL> pos + len ( start ) ) <EOL> if view . substr ( comment_region ) == start : <EOL> found_line_comment = True <EOL> if not found_line_comment : <EOL> return False <EOL> return True <EOL> def block_comment_region ( self , view , edit , block_comment_data , region ) : <EOL> ( start , end , disable_indent ) = block_comment_data <EOL> if region . empty ( ) : <EOL> view . replace ( edit , sublime . Region ( region . end ( ) ) , '<STR_LIT:x>' ) <EOL> view . insert ( edit , region . end ( ) + <NUM_LIT:1> , end ) <EOL> view . replace ( edit , sublime . Region ( region . end ( ) , region . end ( ) + <NUM_LIT:1> ) , '<STR_LIT>' ) <EOL> view . insert ( edit , region . begin ( ) , start ) <EOL> else : <EOL> view . insert ( edit , region . end ( ) , end ) <EOL> view . insert ( edit , region . begin ( ) , start ) <EOL> def line_comment_region ( self , view , edit , line_comment_data , region ) : <EOL> ( start , disable_indent ) = line_comment_data <EOL> start_positions = [ r . begin ( ) for r in view . lines ( region ) ] <EOL> start_positions . reverse ( ) <EOL> non_empty_start_positions = filter ( lambda p : has_non_white_space_on_line ( view , p ) , <EOL> start_positions ) <EOL> if len ( non_empty_start_positions ) != <NUM_LIT:0> : <EOL> start_positions = non_empty_start_positions <EOL> if not disable_indent : <EOL> min_indent = None <EOL> for pos in start_positions : <EOL> indent = advance_to_first_non_white_space_on_line ( view , pos ) - pos <EOL> if min_indent == None or indent < min_indent : <EOL> min_indent = indent <EOL> if min_indent != None and min_indent > <NUM_LIT:0> : <EOL> start_positions = [ r + min_indent for r in start_positions ] <EOL> for pos in start_positions : <EOL> view . insert ( edit , pos , start ) <EOL> def add_comment ( self , view , edit , comment_data , prefer_block , region ) : <EOL> ( line_comments , block_comments ) = comment_data <EOL> if len ( line_comments ) == <NUM_LIT:0> and len ( block_comments ) == <NUM_LIT:0> : <EOL> return <EOL> if len ( block_comments ) == <NUM_LIT:0> : <EOL> prefer_block = False <EOL> if len ( line_comments ) == <NUM_LIT:0> : <EOL> prefer_block = True <EOL> if region . empty ( ) : <EOL> if prefer_block : <EOL> self . block_comment_region ( view , edit , block_comments [ <NUM_LIT:0> ] , region ) <EOL> else : <EOL> self . line_comment_region ( view , edit , line_comments [ <NUM_LIT:0> ] , region ) <EOL> else : <EOL> if prefer_block : <EOL> self . block_comment_region ( view , edit , block_comments [ <NUM_LIT:0> ] , region ) <EOL> else : <EOL> self . line_comment_region ( view , edit , line_comments [ <NUM_LIT:0> ] , region ) <EOL> def run ( self , edit , block = False ) : <EOL> for region in self . view . sel ( ) : <EOL> comment_data = build_comment_data ( self . view , region . begin ( ) ) <EOL> if ( region . end ( ) != self . view . size ( ) and <EOL> build_comment_data ( self . view , region . end ( ) ) != comment_data ) : <EOL> continue <EOL> if self . remove_block_comment ( self . view , edit , comment_data , region ) : <EOL> continue <EOL> if self . is_entirely_line_commented ( self . view , comment_data , region ) : <EOL> self . remove_line_comment ( self . view , edit , comment_data , region ) <EOL> continue <EOL> has_line_comment = len ( comment_data [ <NUM_LIT:0> ] ) > <NUM_LIT:0> <EOL> if not has_line_comment and not block and region . empty ( ) : <EOL> line = self . view . line ( region . a ) <EOL> line = sublime . Region ( <EOL> advance_to_first_non_white_space_on_line ( self . view , line . a ) , <EOL> line . b ) <EOL> if self . remove_block_comment ( self . view , edit , comment_data , line ) : <EOL> continue <EOL> self . add_comment ( self . view , edit , comment_data , block , line ) <EOL> continue <EOL> self . add_comment ( self . view , edit , comment_data , block , region ) </s>
