diff --git a/autoload/magit/sign.vim b/autoload/magit/sign.vim index 7a53390921aafefac34b623b5efda53116173d5c..ec02b913b056d2a606b1ea61c4979e1a89cab80b 100644 --- a/autoload/magit/sign.vim +++ b/autoload/magit/sign.vim @@ -82,6 +82,27 @@ function! magit#sign#find_signs(pattern, startline, endline) return found_signs endfunction +function! magit#sign#get_lines(...) + let bufnr = magit#utils#bufnr() + let lines = [] + + redir => signs + silent execute "sign place buffer=" . bufnr + redir END + + for sign_line in filter(split(signs, '\n'), 'v:val =~# "="') + " Typical sign line: line=88 id=1234 name=GitGutterLineAdded + " We assume splitting is faster than a regexp. + let components = split(sign_line) + let id = str2nr(split(components[1], '=')[1]) + if ( index(a:000, id) != -1 ) + let line_number = str2nr(split(components[0], '=')[1]) + call add(lines, line_number) + endif + endfor + return lines +endfunction + " magit#sign#find_stage_signs: helper function to get marked lines for stage " param[in] startline,endline: range of lines " return Dict of marked lines @@ -95,8 +116,8 @@ let s:magit_mark_signs = {'M': 'MagitTBS', 'S': 'MagitBS', 'E': 'MagitBE'} " magit#sign#init: initializer function for signs function! magit#sign#init() execute "sign define " . s:magit_mark_signs.M . " text=S> linehl=Visual" - execute "sign define " . s:magit_mark_signs.S - execute "sign define " . s:magit_mark_signs.E + execute "sign define " . s:magit_mark_signs.S . " text=S\<Char-0xa0>" + execute "sign define " . s:magit_mark_signs.E . " text=\<Char-0xa0>E" endfunction " magit#sign#toggle_signs: toggle marks for range of lines diff --git a/autoload/magit/state.vim b/autoload/magit/state.vim index 27df64089b7776909f9516eb01ad9916ff8e96a8..c3495346e9500652fa8af575811de167525a4dae 100644 --- a/autoload/magit/state.vim +++ b/autoload/magit/state.vim @@ -96,29 +96,48 @@ function! magit#state#file_set_diff(val) dict endif endfunction -function! magit#state#file_put() dict - "if ( self.dirty != 0 ) - if (1) - let bufnr = magit#utils#bufnr() - let self.sign_start = magit#sign#add_sign(line('.'), 'S', bufnr) - put =file.get_filename_header() - if ( self.dir != 0 ) - if ( self.visible == 1 ) - let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr) - return 1 - endif - endif - if ( self.visible == 0 ) - let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr) - return 0 +function! magit#state#file_put(curline) dict + try + let recursive = 0 + if ( self.sign_start != 0 && self.sign_end != 0 ) + let [line_start, line_end] = magit#sign#get_lines( + \ self.sign_start, self.sign_end) + let curline = line_start + else + let curline = a:curline endif - if ( self.exists == 0 ) - echoerr "Error, " . self.filename . " should not exists" + if ( self.dirty != 0 ) + silent! execute 'silent! ' . line_start . ',' . line_end . 'delete _' + let curline = min( [ curline, line('$') ] ) + let bufnr = magit#utils#bufnr() + let self.sign_start = magit#sign#add_sign(curline, 'S', bufnr) + call magit#utils#debug_log(self.filename . ' start ' . curline) + call append(file.get_filename_header()) + if ( self.dir != 0 && self.visible == 1 ) + let line_end = curline + let self.sign_end = magit#sign#add_sign(line_end, 'E', bufnr) + let recursive = 1 + throw 'goto' + endif + + if ( self.visible == 0 ) + let line_end = curline + throw 'goto' + endif + if ( self.exists == 0 ) + echoerr "Error, " . self.filename . " should not exists" + endif + let hunk_lines=self.get_flat_hunks() + let line_end = curline + len(hunk_lines) + call append(curline, hunk_lines) endif - let hunk_lines=self.get_flat_hunks() - silent put =hunk_lines - let self.sign_end = magit#sign#add_sign(line('.'), 'E', bufnr) - endif + catch /^goto$/ + "do nothing + finally + let self.sign_end = magit#sign#add_sign(line_end, 'E', bufnr) + call magit#utils#debug_log(self.filename . ' end ' . line_end) + return [0, line_end+1] + endtry endfunction " s:hunk_template: template for hunk object (nested in s:diff_template) @@ -126,7 +145,6 @@ endfunction let s:hunk_template = { \ 'header': '', \ 'lines': [], -\ 'marks': [], \} " s:diff_template: template for diff object (nested in s:file_template) @@ -290,6 +308,17 @@ function! magit#state#add_file(mode, status, filename, depth) dict call file.set_diff(diff) endfunction +function! magit#state#get_files_lines() dict + let lines = {} + for diff_dict_mode in values(self.dict) + for file in values(diff_dict_mode) + let lines[file.filename] = magit#sign#get_lines( + \ file.sign_start, file.sign_end) + endfor + endfor + return lines +endfunction + " magit#state#update: update self.dict " if a file does not exists anymore (because all its changes have been " committed, deleted, discarded), it is removed from g:mg_diff_dict @@ -373,6 +402,7 @@ let magit#state#state = { \ 'add_file': function("magit#state#add_file"), \ 'set_files_visible': function("magit#state#set_files_visible"), \ 'update': function("magit#state#update"), + \ 'get_files_lines': function("magit#state#get_files_lines"), \ 'dict': { 'staged': {}, 'unstaged': {}}, \ } diff --git a/autoload/magit/utils.vim b/autoload/magit/utils.vim index 6be7df154753667583c371fe83f5179291682185..75c5fdba0b24c685a94738cb26b16170e78e8d18 100644 --- a/autoload/magit/utils.vim +++ b/autoload/magit/utils.vim @@ -134,7 +134,12 @@ endfunction " return: one dimensional list function! magit#utils#flatten(list) let val = [] - for elem in a:list + if ( type(a:list) == type([]) ) + let list = a:list + elseif ( type(a:list) == type({}) ) + let list = items(a:list) + endif + for elem in list if type(elem) == type([]) call extend(val, magit#utils#flatten(elem)) else @@ -173,3 +178,30 @@ endfunction function! magit#utils#bufnr() return s:bufnr endfunction + +function! magit#utils#set_debug() + echom "Log into " . g:magit_log_file + execute "edit " . g:magit_log_file + execute '%delete _' + write! + let g:magit_debug = 1 +endfunction + +function! magit#utils#debug_cmd(cmd) + if ( g:magit_debug != 0 ) + execute "a:cmd" + endif +endfunc + +function! magit#utils#debug_log(message) + if ( g:magit_debug != 0 ) + if ( type(a:message) == type("") ) + let msg = split(a:message, '\n') + elseif ( type(a:message) == type({}) ) + let msg = split(string(a:message), '\n') + else + let msg = a:message + endif + call magit#utils#append_file(g:magit_log_file, msg) + endif +endfunction diff --git a/plugin/magit.vim b/plugin/magit.vim index 317667b02e0d88d7ac720d8c4ce7aa45986d746a..66179923f247fb677cf577498b8a77b002b119a2 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -50,6 +50,10 @@ let g:magit_default_fold_level = get(g:, 'magit_default_fold_level', let g:magit_warning_max_lines = get(g:, 'magit_warning_max_lines', 10000) + +let g:magit_debug = get(g:, 'magit_debug', 1) +let g:magit_log_file = get(g:, 'magit_log_file', '/tmp/vimagit.log') + execute "nnoremap <silent> " . g:magit_show_magit_mapping . " :call magit#show_magit('v')<cr>" " }}} @@ -95,6 +99,8 @@ let s:magit_inline_help = { \], \} +let s:current_line = 1 + " s:mg_get_inline_help_line_nb: this function returns the number of lines of " a given section, or 0 if help is disabled. " param[in] section: section identifier @@ -115,19 +121,33 @@ function! s:mg_section_help(section) endif endfunction +let s:info_sign_start = 0 +let s:info_sign_end = 0 " s:mg_get_info: this function writes in current buffer current git state " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer -function! s:mg_get_info() - silent put ='' - silent put =g:magit_sections.info - silent put =magit#utils#underline(g:magit_sections.info) - silent put ='' - let branch=magit#utils#system("git rev-parse --abbrev-ref HEAD") - let commit=magit#utils#system("git show -s --oneline") - silent put ='Current branch: ' . branch - silent put ='Last commit: ' . commit - silent put ='' +function! s:mg_get_info(curline) + if ( s:info_sign_start == 0 ) + let bufnr = magit#utils#bufnr() + let s:info_sign_start = magit#sign#add_sign(a:curline, 'S', bufnr) + let branch = magit#utils#system("git rev-parse --abbrev-ref HEAD") + let commit = magit#utils#system("git show -s --oneline") + let info_msg = [ + \'', + \g:magit_sections.info, + \magit#utils#underline(g:magit_sections.info), + \'', + \'Current branch: ' . branch, + \'Last commit: ' . commit, + \'', + \] + call append(a:curline, info_msg) + let endline = a:curline + len(info_msg) + let s:info_sign_end = magit#sign#add_sign(endline, 'E', bufnr) + else + let endline = magit#sign#get_lines(s:info_sign_end) + endif + return endline endfunction " s:mg_display_files: display in current buffer files, filtered by some @@ -137,33 +157,54 @@ endfunction " directory) " param[in] depth: current directory depth (only needed for untracked " directory) -function! s:mg_display_files(mode, curdir, depth) +function! s:mg_display_files(mode, curdir, depth, curline) + let nextline = a:curline + 1 + call magit#utils#debug_log(">> display nextline " . nextline) " FIXME: ouch, must store subdirs in more efficient way for filename in sort(keys(s:state.get_files(a:mode))) let file = s:state.get_file(a:mode, filename) + call magit#utils#debug_log("filename " . filename) if ( file.depth != a:depth || filename !~ a:curdir . '.*' ) + call magit#utils#debug_log("!! skip") continue endif - if ( file.put() != 0 ) - call s:mg_display_files(a:mode, filename, a:depth + 1) + call magit#utils#debug_log('before put nextline ' . nextline) + let [recursive, nextline] = file.put(nextline) + call magit#utils#debug_log('after put nextline ' . nextline) + if ( recursive != 0 ) + call magit#utils#debug_log('before recursive nextline ' . nextline) + let nextline = s:mg_display_files(a:mode, filename, a:depth + 1, nextline) + call magit#utils#debug_log('before recursive nextline ' . nextline) endif - put ='' endfor + call magit#utils#debug_log('return nextline ' . nextline) + return nextline endfunction +let s:stage_sign_start = { 'stage': 0, 'unstaged': 0} +let s:stage_sign_end = { 'stage': 0, 'unstaged': 0} " 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) +function! s:mg_get_staged_section(mode, curline) + + if ( s:stage_sign_start[a:mode] == 0 ) + let bufnr = magit#utils#bufnr() + let s:stage_sign_start[a:mode] = magit#sign#add_sign(a:curline, 'S', bufnr) + let stage_msg = [ + \ g:magit_sections[a:mode], + \ magit#utils#underline(g:magit_sections[a:mode]), + \] + call append(a:curline, stage_msg) + let endline = a:curline + len(stage_msg) + let s:stage_sign_end[a:mode] = magit#sign#add_sign(endline, 'E', bufnr) + else + let endline = magit#sign#get_lines(s:stage_sign_end[a:mode]) + endif + return s:mg_display_files(a:mode, '', 0, endline) endfunction " s:mg_get_stashes: this function write in current buffer all stashes @@ -505,7 +546,8 @@ function! magit#update_buffer() " delete buffer silent! execute "silent :%delete _" - call <SID>mg_get_info() + let current_line = 1 + let current_line = <SID>mg_get_info(current_line) call <SID>mg_section_help('global') if ( s:magit_commit_mode != '' ) call <SID>mg_get_commit_section() @@ -522,8 +564,9 @@ function! magit#update_buffer() endif endif - call <SID>mg_get_staged_section('staged') - call <SID>mg_get_staged_section('unstaged') + let current_line = <SID>mg_get_staged_section('staged', current_line) + let current_line = <SID>mg_get_staged_section('unstaged', current_line) + call <SID>mg_get_stashes() call winrestview(l:winview) @@ -812,4 +855,8 @@ endfunction command! Magit call magit#show_magit('v') +command! MagitDebugFilesLines call magit#utils#append_file(g:magit_log_file, magit#utils#flatten(items(s:state.get_files_lines()))) + +command! MagitDebug call magit#utils#set_debug() + " }}}