<s> import re <EOL> from functools import partial <EOL> import sublime <EOL> from sublime_plugin import WindowCommand , TextCommand , EventListener <EOL> from . util import find_view_by_settings , get_setting <EOL> from . cmd import GitCmd <EOL> from . helpers import GitDiffHelper , GitErrorHelper , GitStatusHelper <EOL> RE_DIFF_HEAD = re . compile ( r'<STR_LIT>' ) <EOL> GIT_DIFF_TITLE = '<STR_LIT>' <EOL> GIT_DIFF_TITLE_PREFIX = GIT_DIFF_TITLE + '<STR_LIT>' <EOL> GIT_DIFF_CACHED_TITLE = '<STR_LIT>' <EOL> GIT_DIFF_CACHED_TITLE_PREFIX = GIT_DIFF_CACHED_TITLE + '<STR_LIT>' <EOL> GIT_DIFF_CLEAN = "<STR_LIT>" <EOL> GIT_DIFF_CLEAN_CACHED = "<STR_LIT>" <EOL> GIT_DIFF_VIEW_SYNTAX = '<STR_LIT>' <EOL> GIT_DIFF_UNSTAGE_ERROR = "<STR_LIT>" <EOL> GIT_DIFF_STAGE_ERROR = "<STR_LIT>" <EOL> class GitDiffCommand ( WindowCommand , GitCmd ) : <EOL> """<STR_LIT>""" <EOL> def run ( self , repo = None , path = None , cached = False ) : <EOL> repo = repo or self . get_repo ( ) <EOL> if not repo : <EOL> return <EOL> path = path or repo <EOL> title = self . get_view_title ( path , cached ) <EOL> git_view = '<STR_LIT>' % ( '<STR_LIT>' if cached else '<STR_LIT>' ) <EOL> view = find_view_by_settings ( self . window , git_view = git_view , git_repo = repo , git_diff_path = path ) <EOL> if not view : <EOL> view = self . window . new_file ( ) <EOL> view . set_name ( title ) <EOL> view . set_syntax_file ( GIT_DIFF_VIEW_SYNTAX ) <EOL> view . set_scratch ( True ) <EOL> view . set_read_only ( True ) <EOL> view . settings ( ) . set ( '<STR_LIT>' , git_view ) <EOL> view . settings ( ) . set ( '<STR_LIT>' , repo ) <EOL> view . settings ( ) . set ( '<STR_LIT>' , path ) <EOL> view . settings ( ) . set ( '<STR_LIT>' , cached ) <EOL> view . settings ( ) . set ( '<STR_LIT>' , <NUM_LIT:3> ) <EOL> self . window . focus_view ( view ) <EOL> view . run_command ( '<STR_LIT>' , { '<STR_LIT:path>' : path , '<STR_LIT>' : cached , '<STR_LIT>' : True } ) <EOL> def get_view_title ( self , path = None , cached = False ) : <EOL> if cached : <EOL> return GIT_DIFF_CACHED_TITLE_PREFIX + path if path else GIT_DIFF_CACHED_TITLE <EOL> else : <EOL> return GIT_DIFF_TITLE_PREFIX + path if path else GIT_DIFF_TITLE <EOL> class GitDiffCachedCommand ( GitDiffCommand ) : <EOL> """<STR_LIT>""" <EOL> def run ( self , path = None ) : <EOL> super ( GitDiffCachedCommand , self ) . run ( path = path , cached = True ) <EOL> class GitDiffCurrentFileCommand ( GitCmd , GitStatusHelper , TextCommand ) : <EOL> """<STR_LIT>""" <EOL> def run ( self , edit , cached = False ) : <EOL> filename = self . view . file_name ( ) <EOL> if not filename : <EOL> sublime . error_message ( '<STR_LIT>' ) <EOL> return <EOL> repo = self . get_repo ( ) <EOL> if not repo : <EOL> return <EOL> in_git = self . file_in_git ( repo , filename ) <EOL> if not in_git : <EOL> sublime . error_message ( '<STR_LIT>' % filename . replace ( repo , '<STR_LIT>' ) . lstrip ( '<STR_LIT:/>' ) ) <EOL> return <EOL> self . view . window ( ) . run_command ( '<STR_LIT>' , { '<STR_LIT>' : repo , '<STR_LIT:path>' : filename , '<STR_LIT>' : cached } ) <EOL> class GitDiffCachedCurrentFileCommand ( GitDiffCurrentFileCommand ) : <EOL> """<STR_LIT>""" <EOL> def run ( self , edit ) : <EOL> super ( GitDiffCachedCurrentFileCommand , self ) . run ( edit , cached = True ) <EOL> class GitDiffTextCmd ( GitCmd , GitDiffHelper ) : <EOL> def move_to_point ( self , point ) : <EOL> self . view . sel ( ) . clear ( ) <EOL> self . view . sel ( ) . add ( sublime . Region ( point ) ) <EOL> if not self . view . visible_region ( ) . contains ( point ) : <EOL> view = self . view <EOL> sublime . set_timeout ( partial ( view . show , point , True ) , <NUM_LIT:50> ) <EOL> def parse_diff ( self ) : <EOL> sections = [ ] <EOL> state = None <EOL> prev_file = None <EOL> current_file = { } <EOL> current_hunks = [ ] <EOL> prev_hunk = None <EOL> current_hunk = None <EOL> for line in self . view . lines ( sublime . Region ( <NUM_LIT:0> , self . view . size ( ) ) ) : <EOL> linetext = self . view . substr ( line ) <EOL> if linetext . startswith ( '<STR_LIT>' ) : <EOL> state = '<STR_LIT>' <EOL> if prev_file != line : <EOL> if prev_file is not None : <EOL> if current_hunk : <EOL> current_hunks . append ( current_hunk ) <EOL> sections . append ( ( current_file , current_hunks ) ) <EOL> prev_file = line <EOL> prev_hunk = None <EOL> current_file = line <EOL> current_hunks = [ ] <EOL> elif state == '<STR_LIT>' and RE_DIFF_HEAD . match ( linetext ) : <EOL> current_file = current_file . cover ( line ) <EOL> elif linetext . startswith ( '<STR_LIT>' ) : <EOL> state = '<STR_LIT>' <EOL> if prev_hunk != line : <EOL> if prev_hunk is not None : <EOL> current_hunks . append ( current_hunk ) <EOL> prev_hunk = line <EOL> current_hunk = line <EOL> elif state == '<STR_LIT>' and linetext [ <NUM_LIT:0> ] in ( '<STR_LIT:U+0020>' , '<STR_LIT:->' , '<STR_LIT:+>' ) : <EOL> current_hunk = current_hunk . cover ( line ) <EOL> elif state == '<STR_LIT>' : <EOL> current_file = current_file . cover ( line ) <EOL> if current_file and current_hunk : <EOL> current_hunks . append ( current_hunk ) <EOL> sections . append ( ( current_file , current_hunks ) ) <EOL> return sections <EOL> def build_lookup ( self , parsed_diff ) : <EOL> lookup = [ ] <EOL> for header , hunks in parsed_diff : <EOL> for h in hunks : <EOL> lookup . append ( ( h , header ) ) <EOL> return lookup <EOL> def get_hunks_from_selection ( self , selection ) : <EOL> if not selection : <EOL> return None <EOL> diffspec = self . parse_diff ( ) <EOL> lookup = self . build_lookup ( diffspec ) <EOL> hunks = { } <EOL> for s in selection : <EOL> for hunk , header in lookup : <EOL> if s . intersects ( hunk ) or hunk . contains ( s ) or ( s . begin ( ) == self . view . size ( ) and hunk . contains ( s . begin ( ) - <NUM_LIT:1> ) ) : <EOL> hunks . setdefault ( ( header . begin ( ) , header . end ( ) ) , [ ] ) . append ( hunk ) <EOL> return hunks <EOL> def create_patch ( self , selected_hunks ) : <EOL> patch = [ ] <EOL> for ( hstart , hend ) , hunks in selected_hunks . items ( ) : <EOL> header = sublime . Region ( hstart , hend ) <EOL> for head in self . view . lines ( header ) : <EOL> headline = self . view . substr ( head ) <EOL> if headline . startswith ( '<STR_LIT>' ) or headline . startswith ( '<STR_LIT>' ) : <EOL> patch . append ( "<STR_LIT>" % headline . strip ( ) ) <EOL> else : <EOL> patch . append ( "<STR_LIT>" % headline ) <EOL> for h in hunks : <EOL> patch . append ( self . view . substr ( self . view . full_line ( h ) ) ) <EOL> return "<STR_LIT>" . join ( patch ) <EOL> class GitDiffRefreshCommand ( TextCommand , GitDiffTextCmd ) : <EOL> def is_visible ( self ) : <EOL> return False <EOL> def run ( self , edit , path = None , cached = False , run_move = False ) : <EOL> path = path if path else self . view . settings ( ) . get ( '<STR_LIT>' ) <EOL> cached = cached if cached else self . view . settings ( ) . get ( '<STR_LIT>' ) <EOL> unified = self . view . settings ( ) . get ( '<STR_LIT>' , <NUM_LIT:3> ) <EOL> repo = self . view . settings ( ) . get ( '<STR_LIT>' ) <EOL> if path is None or cached is None : <EOL> return <EOL> point = self . view . sel ( ) [ <NUM_LIT:0> ] . begin ( ) if self . view . sel ( ) else <NUM_LIT:0> <EOL> row , col = self . view . rowcol ( point ) <EOL> diff = self . get_diff ( repo , path , cached , unified = unified ) <EOL> clean = False <EOL> if not diff : <EOL> diff = GIT_DIFF_CLEAN_CACHED if cached else GIT_DIFF_CLEAN <EOL> clean = True <EOL> self . view . settings ( ) . set ( '<STR_LIT>' , clean ) <EOL> self . view . set_read_only ( False ) <EOL> self . view . replace ( edit , sublime . Region ( <NUM_LIT:0> , self . view . size ( ) ) , diff ) <EOL> self . view . set_read_only ( True ) <EOL> if run_move : <EOL> self . view . run_command ( '<STR_LIT>' ) <EOL> else : <EOL> row_begin = self . view . text_point ( row , <NUM_LIT:0> ) <EOL> line = self . view . line ( row_begin ) <EOL> point = self . view . text_point ( row , min ( col , ( line . end ( ) - line . begin ( ) ) ) ) <EOL> self . move_to_point ( point ) <EOL> class GitDiffEventListener ( EventListener ) : <EOL> def on_activated ( self , view ) : <EOL> if view . settings ( ) . get ( '<STR_LIT>' ) in ( '<STR_LIT>' , '<STR_LIT>' ) and get_setting ( '<STR_LIT>' , True ) : <EOL> view . run_command ( '<STR_LIT>' ) <EOL> class GitDiffChangeHunkSizeCommand ( TextCommand ) : <EOL> def is_visible ( self ) : <EOL> return False <EOL> def run ( self , edit , action = '<STR_LIT>' ) : <EOL> unified = self . view . settings ( ) . get ( '<STR_LIT>' , <NUM_LIT:3> ) <EOL> if action == '<STR_LIT>' : <EOL> self . view . settings ( ) . set ( '<STR_LIT>' , unified + <NUM_LIT:1> ) <EOL> else : <EOL> self . view . settings ( ) . set ( '<STR_LIT>' , max ( <NUM_LIT:1> , unified - <NUM_LIT:1> ) ) <EOL> self . view . run_command ( '<STR_LIT>' ) <EOL> class GitDiffMoveCommand ( TextCommand , GitDiffTextCmd ) : <EOL> def is_visible ( self ) : <EOL> return False <EOL> def run ( self , edit , item = '<STR_LIT>' , which = <NUM_LIT:0> , start = None ) : <EOL> if self . view . settings ( ) . get ( '<STR_LIT>' ) is True : <EOL> return <EOL> if item not in ( '<STR_LIT>' , '<STR_LIT:file>' ) : <EOL> return <EOL> try : <EOL> which = int ( which ) <EOL> except ValueError : <EOL> if which not in ( '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ) : <EOL> return <EOL> if start is not None : <EOL> start = int ( start ) <EOL> elif self . view . sel ( ) : <EOL> start = self . view . sel ( ) [ <NUM_LIT:0> ] . begin ( ) <EOL> else : <EOL> start = <NUM_LIT:0> <EOL> file_lookup = self . parse_diff ( ) <EOL> hunk_lookup = self . build_lookup ( file_lookup ) <EOL> if not hunk_lookup : <EOL> return <EOL> goto = None <EOL> if which == '<STR_LIT>' : <EOL> goto , _ = hunk_lookup [ <NUM_LIT:0> ] <EOL> elif which == '<STR_LIT>' : <EOL> goto , _ = hunk_lookup [ - <NUM_LIT:1> ] <EOL> elif which == '<STR_LIT>' : <EOL> if item == '<STR_LIT>' : <EOL> next_hunks = [ ( h , f ) for h , f in hunk_lookup if h . begin ( ) > start ] <EOL> goto , _ = next_hunks [ <NUM_LIT:0> ] if next_hunks else hunk_lookup [ - <NUM_LIT:1> ] <EOL> else : <EOL> next_files = [ ( f , h ) for f , h in file_lookup if f . begin ( ) > start ] <EOL> goto , _ = next_files [ <NUM_LIT:0> ] if next_files else file_lookup [ - <NUM_LIT:1> ] <EOL> elif which == '<STR_LIT>' : <EOL> if item == '<STR_LIT>' : <EOL> prev_hunks = [ ( h , f ) for h , f in hunk_lookup if h . end ( ) < start ] <EOL> goto , _ = prev_hunks [ - <NUM_LIT:1> ] if prev_hunks else hunk_lookup [ <NUM_LIT:0> ] <EOL> else : <EOL> prev_files = [ ( f , h ) for f , h in file_lookup if h [ - <NUM_LIT:1> ] . end ( ) < start ] <EOL> goto , _ = prev_files [ - <NUM_LIT:1> ] if prev_files else file_lookup [ <NUM_LIT:0> ] <EOL> else : <EOL> if item == '<STR_LIT>' : <EOL> goto , _ = hunk_lookup [ max ( <NUM_LIT:0> , which ) ] if which < len ( hunk_lookup ) else hunk_lookup [ - <NUM_LIT:1> ] <EOL> else : <EOL> goto , _ = file_lookup [ max ( <NUM_LIT:0> , which ) ] if which < len ( file_lookup ) else file_lookup [ - <NUM_LIT:1> ] <EOL> if goto : <EOL> self . move_to_point ( goto . begin ( ) ) <EOL> class GitDiffStageUnstageHunkCommand ( GitDiffTextCmd , GitErrorHelper , TextCommand ) : <EOL> def is_visible ( self ) : <EOL> return False <EOL> def run ( self , edit , reverse = False ) : <EOL> repo = self . view . settings ( ) . get ( '<STR_LIT>' ) <EOL> if self . view . settings ( ) . get ( '<STR_LIT>' ) is not reverse : <EOL> if reverse : <EOL> sublime . error_message ( GIT_DIFF_UNSTAGE_ERROR ) <EOL> else : <EOL> sublime . error_message ( GIT_DIFF_STAGE_ERROR ) <EOL> return <EOL> if self . view . settings ( ) . get ( '<STR_LIT>' ) is True : <EOL> return <EOL> hunks = self . get_hunks_from_selection ( self . view . sel ( ) ) <EOL> if hunks : <EOL> patch = self . create_patch ( hunks ) <EOL> cmd = [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' if reverse else None , '<STR_LIT:->' ] <EOL> exit , stdout , stderr = self . git ( cmd , stdin = patch , cwd = repo ) <EOL> if exit != <NUM_LIT:0> : <EOL> sublime . error_message ( self . format_error_message ( stderr ) ) <EOL> self . view . run_command ( '<STR_LIT>' ) </s>
