Skip to content

Commit

Permalink
plugin/magit.vim: handle directories recursively (fix #10)
Browse files Browse the repository at this point in the history
  • Loading branch information
jreybert committed Oct 19, 2015
1 parent 3ab04b2 commit e8b6928
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 78 deletions.
142 changes: 77 additions & 65 deletions autoload/magit/state.vim
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ function! magit#state#is_file_visible(section, filename) dict
\ ( self.dict[a:section][a:filename].visible == 1 ) )
endfunction

function! magit#state#is_dir(section, filename) dict
return ( has_key(self.dict[a:section], a:filename) &&
\ ( self.dict[a:section][a:filename].dir != 0 ) )
endfunction

function! magit#state#get_files(mode) dict
return self.dict[a:mode]
endfunction
Expand All @@ -28,6 +33,7 @@ let s:file_template = {
\ 'exists': 0,
\ 'status': '',
\ 'empty': 0,
\ 'dir': 0,
\ 'binary': 0,
\ 'symlink': '',
\ 'diff': s:diff_template,
Expand Down Expand Up @@ -87,60 +93,60 @@ endfunction
" param[in] mode: can be staged or unstaged
" param[in] status: one character status code of the file (AMDRCU?)
" param[in] filename: filename
function! magit#state#add_file(mode, status, filename) dict
let dir = getcwd()
try
call magit#utils#lcd(magit#utils#top_dir())
let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
let diff_cmd="git diff --no-ext-diff " . staged_flag .
\ "--no-color --patch -- " . dev_null . " "
\ . magit#utils#add_quotes(a:filename)
let diff_list=magit#utils#systemlist(diff_cmd)
if ( empty(diff_list) )
echoerr "diff command \"" . diff_cmd . "\" returned nothing"
endif
let diff_dict_file = self.get_file(a:mode, a:filename, 1)
let diff_dict_file.exists = 1
let diff_dict_file.status = a:status
if ( a:status == '?' && getftype(a:filename) == 'link' )
let diff_dict_file.symlink = resolve(a:filename)
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'New symbolic link file'
elseif ( a:status == '?' && getfsize(a:filename) == 0 )
let diff_dict_file.empty = 1
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'New empty file'
elseif ( match(system("file --mime " .
\ magit#utils#add_quotes(a:filename)),
\ a:filename . ".*charset=binary") != -1 )
let diff_dict_file.binary = 1
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'Binary file'
else
let line = 0
" match(
while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
call add(diff_dict_file.diff.header, diff_list[line])
let line += 1
endwhile

let hunk = diff_dict_file.diff.hunks[0]
let hunk.header = diff_list[line]

for diff_line in diff_list[line+1 : -1]
if ( diff_line =~ "^@.*" )
let hunk = deepcopy(s:hunk_template)
call add(diff_dict_file.diff.hunks, hunk)
let hunk.header = diff_line
continue
endif
call add(hunk.lines, diff_line)
endfor
endif
finally
call magit#utils#lcd(dir)
endtry
function! magit#state#add_file(mode, status, filename, depth) dict
let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
let diff_cmd="git diff --no-ext-diff " . staged_flag .
\ "--no-color --patch -- " . dev_null . " "
\ . magit#utils#add_quotes(a:filename)
let diff_list=magit#utils#systemlist(diff_cmd)
if ( empty(diff_list) )
echoerr "diff command \"" . diff_cmd . "\" returned nothing"
endif
let diff_dict_file = self.get_file(a:mode, a:filename, 1)
let diff_dict_file.exists = 1
let diff_dict_file.status = a:status
let diff_dict_file.depth = a:depth
if ( a:status == '?' && getftype(a:filename) == 'link' )
let diff_dict_file.symlink = resolve(a:filename)
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'New symbolic link file'
elseif ( a:status == '?' && isdirectory(a:filename) == 1 )
let diff_dict_file.dir = 1
for subfile in split(globpath(a:filename, '\(.[^.]*\|*\)'), '\n')
call self.add_file(a:mode, a:status, subfile, a:depth + 1)
endfor
elseif ( a:status == '?' && getfsize(a:filename) == 0 )
let diff_dict_file.empty = 1
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'New empty file'
elseif ( match(system("file --mime " .
\ magit#utils#add_quotes(a:filename)),
\ a:filename . ".*charset=binary") != -1 )
let diff_dict_file.binary = 1
call add(diff_dict_file.diff.header, 'no header')
let diff_dict_file.diff.hunks[0].header = 'Binary file'
else
let line = 0
" match(
while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
call add(diff_dict_file.diff.header, diff_list[line])
let line += 1
endwhile

let hunk = diff_dict_file.diff.hunks[0]
let hunk.header = diff_list[line]

for diff_line in diff_list[line+1 : -1]
if ( diff_line =~ "^@.*" )
let hunk = deepcopy(s:hunk_template)
call add(diff_dict_file.diff.hunks, hunk)
let hunk.header = diff_line
continue
endif
call add(hunk.lines, diff_line)
endfor
endif
endfunction

" magit#state#update: update self.dict
Expand All @@ -157,19 +163,24 @@ function! magit#state#update() dict
endfor
endfor

for [mode, diff_dict_mode] in items(self.dict)

let status_list = magit#git#get_status()
for file_status in status_list
let status=file_status[mode]
let dir = getcwd()
try
call magit#utils#lcd(magit#utils#top_dir())
for [mode, diff_dict_mode] in items(self.dict)
let status_list = magit#git#get_status()
for file_status in status_list
let status=file_status[mode]

" untracked code apperas in staged column, we skip it
if ( status == ' ' || ( ( mode == 'staged' ) && status == '?' ) )
continue
endif
call self.add_file(mode, status, file_status.filename)
" untracked code apperas in staged column, we skip it
if ( status == ' ' || ( ( mode == 'staged' ) && status == '?' ) )
continue
endif
call self.add_file(mode, status, file_status.filename, 0)
endfor
endfor
endfor
finally
call magit#utils#lcd(dir)
endtry

" remove files that have changed their mode or been committed/deleted/discarded...
for diff_dict_mode in values(self.dict)
Expand Down Expand Up @@ -202,6 +213,7 @@ let magit#state#state = {
\ 'get_hunks': function("magit#state#get_hunks"),
\ 'get_flat_hunks': function("magit#state#get_flat_hunks"),
\ 'add_file': function("magit#state#add_file"),
\ 'is_dir': function("magit#state#is_dir"),
\ 'is_file_visible': function("magit#state#is_file_visible"),
\ 'update': function("magit#state#update"),
\ 'dict': { 'staged': {}, 'unstaged': {}},
Expand Down
1 change: 1 addition & 0 deletions common/magit_common.vim
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let g:magit_git_status_code = {
\ '!': 'ignored',
\ 'E': 'empty',
\ 'L': 'symlink',
\ 'N': 'new dir',
\ }

" Regular expressions used to select blocks
Expand Down
43 changes: 30 additions & 13 deletions plugin/magit.vim
Original file line number Diff line number Diff line change
Expand Up @@ -140,24 +140,23 @@ function! s:mg_get_info()
silent put =''
endfunction

function! s:mg_display_files(mode, curdir, depth)

" s:mg_get_staged_section: this function writes in current buffer all staged
" or unstaged files, using s:state.dict information
" WARNING: this function writes in file, it should only be called through
" protected functions like magit#update_buffer
" param[in] mode: 'staged' or 'unstaged'
function! s:mg_get_staged_section(mode)
put =''
put =g:magit_sections[a:mode]
call <SID>mg_section_help(a:mode)
put =magit#utils#underline(g:magit_sections[a:mode])
put =''

" FIXME: ouch, must store subdirs in more efficient way
for [ filename, file_props ] in items(s:state.get_files(a:mode))
if ( file_props.depth != a:depth || filename !~ a:curdir . '.*' )
continue
endif
if ( file_props.empty == 1 )
put =g:magit_git_status_code.E . ': ' . filename
elseif ( file_props.symlink != '' )
put =g:magit_git_status_code.L . ': ' . filename . ' -> ' . file_props.symlink
elseif ( file_props.dir != 0 )
put =g:magit_git_status_code.N . ': ' . filename
if ( file_props.visible == 1 )
call s:mg_display_files(a:mode, filename, a:depth + 1)
continue
endif
else
put =g:magit_git_status_code[file_props.status] . ': ' . filename
endif
Expand All @@ -177,6 +176,20 @@ function! s:mg_get_staged_section(mode)
endfor
endfunction

" s:mg_get_staged_section: this function writes in current buffer all staged
" or unstaged files, using s:state.dict information
" WARNING: this function writes in file, it should only be called through
" protected functions like magit#update_buffer
" param[in] mode: 'staged' or 'unstaged'
function! s:mg_get_staged_section(mode)
put =''
put =g:magit_sections[a:mode]
call <SID>mg_section_help(a:mode)
put =magit#utils#underline(g:magit_sections[a:mode])
put =''
call s:mg_display_files(a:mode, '', 0)
endfunction

" s:mg_get_stashes: this function write in current buffer all stashes
" WARNING: this function writes in file, it should only be called through
" protected functions like magit#update_buffer
Expand Down Expand Up @@ -663,7 +676,8 @@ function! s:mg_select_closed_file()
let list = matchlist(getline("."), g:magit_file_re)
let filename = list[2]
let section=<SID>mg_get_section()
if ( s:state.is_file_visible(section, filename) == 0 )
if ( s:state.is_file_visible(section, filename) == 0 ||
\ s:state.is_dir(section, filename) == 1 )
let selection = s:state.get_flat_hunks(section, filename)
return selection
endif
Expand All @@ -687,6 +701,7 @@ function! magit#stage_block(selection, discard) abort
if ( section == 'unstaged' )
if ( file.empty == 1 ||
\ file.symlink != '' ||
\ file.dir != 0 ||
\ file.binary == 1 )
call magit#utils#system('git add ' .
\ magit#utils#add_quotes(filename))
Expand All @@ -696,6 +711,7 @@ function! magit#stage_block(selection, discard) abort
elseif ( section == 'staged' )
if ( file.empty == 1 ||
\ file.symlink != '' ||
\ file.dir != 0 ||
\ file.binary == 1 )
call magit#utils#system('git reset ' .
\ magit#utils#add_quotes(filename))
Expand All @@ -711,6 +727,7 @@ function! magit#stage_block(selection, discard) abort
if ( section == 'unstaged' )
if ( file.empty == 1 ||
\ file.symlink != '' ||
\ file.dir != 0 ||
\ file.binary == 1 )
call delete(filename)
else
Expand Down

0 comments on commit e8b6928

Please sign in to comment.