diff --git a/Changelog b/Changelog index ba0149b..d5c9d7f 100644 --- a/Changelog +++ b/Changelog @@ -1,16 +1,118 @@ +Release 1.5.0 +============= + +Features +-------- + +* vimagit is now able to handle multiple git repositories (fix #44,#34,#29). +* add mappings N and P to jump to next and previous hunk (fix #25). +* reorder magit display: display modified files first. +* disable inline help by default (fix #46). It is always possible to switch + inline help display with 'h', or with g:magit_show_help +* rework magit buffer color syntax. +* display commit mode in Info section. +* rename magit buffer, now named after git repository path, e.g. + magit:///path/to/git/repo/ +* add MagitOnly command. It can be used to craft a bash alias like: + alias magit='vim -c MagitOnly' + +Fixes +----- + +* safe and smart handling of quit command (fix #41,#43). + * close vimagit window if there is another window. + * switch to alternate buffer if any. + * close vim if magit buffer the only buffer. +* disable ':w' mapping, which was not safe. This feature will be re inserted + with a safer method later. + +Release 1.4.2 +============= + +Enhancements +------------ + +* smarter way to handle magit buffer: + * improve some internal mechanisms, which should improve performances for + huge repositories + * by default, do not show untracked/deleted/added/renamed files diffs (ref + #28) + * see g:magit_default_show_all_files new behavior +* add g:magit_default_sections to let user choose which sections are displayed + (fix #37) user can now choose which sections to display, and in which order + +Bug fixes +--------- + +* magit buffer become empty after switching to other window and back (#35) +* remove warning when opening magit buffer +* check that magit buffer exists before removing it (refs #39) + +Release 1.4.1 +============= + +Fixes +----- + +* fix add binary file (fixes #27) +* fix some display problem (Unstaged changes may not be highlighted) +* fix reset and discard for binary files + +Features +-------- + +* git works in a clean environment, without any configuration + +Release 1.4 +=========== + +This is a major step for vimagit. It should now contain all primary command +needed for staging. Then, this release should be the real 1.0 version. + +Features +-------- + +* Stage parts of hunk (fixes #8 and #19) + * select some with v, then stage your selection with S + * stage a single line with L + * mark lines (can be non contiguous) with M, then stage marked lines in + the hunk with S +* Stage single files in new directories (fixes #10) +* New options (fixes #18) + * g:magit_default_show_all_files to define if file diffs are shown or not + at magit buffer opening. + * If magit buffer contains more than g:magit_warning_max_lines (default + 10000) lines to display, user is asked if he wants to display all + these lines. + * g:magit_default_fold_level to define foldlevel of magit buffer. + * These options can be overriden with new magit#show_magit() parameters + (allowing user to define its own mappings/commands) +* File display is now sorted. +* Show submodule diffs (fixes #12) + +Fixes +----- + +No bugs have been reported since release 1.3. + Release 1.3 =========== Features -------- -* hide file diffs: to hide/unhide diffs for a file, move the cursor to the filename and press (Enter). It allows vimagit to be fast when there is a lot of diffs in a repository. +* hide file diffs: to hide/unhide diffs for a file, move the cursor to the + filename and press (Enter). It allows vimagit to be fast when there is a + lot of diffs in a repository. * zo, zO, zc, zC mappings on a filename hide/unhide file diffs. -* modify hunk before staging: in the Magit buffer, it is possible to modify a hunk before staging it. Only '+' lines can be modified. No lines can be deleted or added for the moment. (fixes #9). +* modify hunk before staging: in the Magit buffer, it is possible to modify a + hunk before staging it. Only '+' lines can be modified. No lines can be + deleted or added for the moment. (fixes #9). * handle new empty files and new symlink (fix #11). * handle binary files (fix #13). * stage/unstage/ignore/discard a file with cursor on the filename. -* add global mapping M to open magit buffer (it can be overwritten with g:magit_show_magit_mapping). +* add global mapping M to open magit buffer (it can be overwritten + with g:magit_show_magit_mapping). * remove 'C' default mapping. Fixes @@ -25,7 +127,8 @@ Release 1.2 Fixes ----- -* read COMMIT_EDITMSG only if exists (commit command failed for fresh new git directory) +* read COMMIT_EDITMSG only if exists (commit command failed for fresh new git + directory) * fix issue of some rare hunk staging (because of some whitespaces) Features @@ -40,8 +143,10 @@ Release 1.1 Fixes ----- -* add wrappers to system and systemlist, when vim doesn't support system with List (available since vim v7.4.248) -* fix git diff failing when cwd is not in top dir (it ends with an empty Magit buffer) +* add wrappers to system and systemlist, when vim doesn't support system with + List (available since vim v7.4.248) +* fix git diff failing when cwd is not in top dir (it ends with an empty Magit + buffer) * ensure to not use external diff if any * Check commentChar from git config diff --git a/README.md b/README.md index 26e365b..7530b95 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ Take a look at [TL;DR](#tldr) to start using it immediatly. * [x] Stage part of hunks, by visual select, lines or selecting bunch of lines with marks. * [x] Start to write the commit message in one key press, commit also in one key press. * [x] Modify in line the content just before staging it. -* [x] Visualize stashes. Apply, pop, drop are on going. +* [x] Move easily through hunks. +* [x] Handle multiple git repositories within one vim instance. * [x] Add file to .gitignore file. * [ ] Chase all corner cases. Please remember that vimagit is at an early development stage. If you try vimagit and nothing is working, please don't throw it, fill an [issue](https://github.com/jreybert/vimagit/issues/new) on github :heart: ! @@ -34,6 +35,7 @@ More to come: * Handle multiple git repositories within one vim session. * Stage multiple hunks or file by visually selecting them. * Go through history, cherry-pick changes. +* Handle stash: add, pop, apply, drop... * Vizualize and checkout branches. * Something is missing? Open an [issue](https://github.com/jreybert/vimagit/issues/new)! @@ -60,12 +62,15 @@ This is the minimal required set of command you must know to start playing with #### :Magit -Open magit buffer. +Open magit buffer (see [details](#magitshow_magit)). #### Enter,\ All files diffs are hidden by default. To inspect changes in a file, move cursor to the filename line, and press 'Enter' in Normal mode. Diffs are displayed below the file name. +#### N +* Jump to next hunk with **N**. + #### S * Modify a file, for example foo.c, in your repository. @@ -115,7 +120,9 @@ Visual selection and marked lines have some limitations for the moment: #### magit#show_magit() -Function to open magit buffer. +Function to open magit buffer. This buffer will handle the git repository including focused file. +It is possible to handle multiple git repositories within one vim instance. + It takes 3 parameters: * orientation (mandatory): it can be - 'v', curent window is split vertically, and magit is displayed in new @@ -129,7 +136,12 @@ It takes 3 parameters: (see [g:magit_default_fold_level](#gmagit_default_fold_level)) #### :Magit - * open magit buffer. +Open magit buffer in a vertical split (see [details](magitshow_magit)). + +#### :MagitOnly +Open magit buffer in current window (see [details](magitshow_magit)). + +You can create a bash alias like magit="vim -c MagitOnly" ### Mappings @@ -181,6 +193,9 @@ Following mappings are set locally, for magit buffer only, in normal mode. * If cursor is in diff header, discard whole file at cursor position. * Only works in "Unstaged changes" section. +##### N,P + * Move to **N**ext or **P**revious hunk. + ##### CC * If not in commit section, set commit mode to "New commit" and show "Commit message" section with brand new commit message. * If in commit section, commit the all staged changes in commit mode previously set. diff --git a/autoload/magit/git.vim b/autoload/magit/git.vim index 0f54775..b009105 100644 --- a/autoload/magit/git.vim +++ b/autoload/magit/git.vim @@ -19,39 +19,65 @@ function! magit#git#get_status() return file_list endfunction -" s:magit_top_dir: top directory of git tree -" it is evaluated only once -" FIXME: it won't work when playing with multiple git directories wihtin one -" vim session -let s:magit_top_dir='' -" magit#git#top_dir: return the absolute path of current git worktree -" return top directory -function! magit#git#top_dir() - if ( s:magit_top_dir == '' ) - let s:magit_top_dir=magit#utils#strip( - \ system(s:git_cmd . " rev-parse --show-toplevel")) . "/" +" magit#git#is_work_tree: this function check that path passed as parameter is +" inside a git work tree +" param[in] path: path to check +" return: top work tree path if in a work tree, empty string otherwise +function! magit#git#is_work_tree(path) + let dir = getcwd() + try + call magit#utils#lcd(a:path) + let top_dir=magit#utils#strip( + \ system(s:git_cmd . " rev-parse --show-toplevel")) . "/" + if ( v:shell_error != 0 ) + return '' + endif + return top_dir + finally + call magit#utils#lcd(dir) + endtry +endfunction + +" magit#git#set_top_dir: this function set b:magit_top_dir and b:magit_git_dir +" according to a path +" param[in] path: path to set. This path must be in a git repository work tree +function! magit#git#set_top_dir(path) + let dir = getcwd() + try + call magit#utils#lcd(a:path) + let top_dir=magit#utils#strip( + \ system(s:git_cmd . " rev-parse --show-toplevel")) . "/" + if ( v:shell_error != 0 ) + throw "magit: git-show-toplevel error: " . top_dir + endif + let git_dir=magit#utils#strip(system(s:git_cmd . " rev-parse --git-dir")) . "/" if ( v:shell_error != 0 ) - echoerr "Git error: " . s:magit_top_dir + throw "magit: git-git-dir error: " . git_dir endif + let b:magit_top_dir=top_dir + let b:magit_git_dir=git_dir + finally + call magit#utils#lcd(dir) + endtry +endfunction + +" magit#git#top_dir: return the absolute path of current git worktree for the +" current magit buffer +" return top directory +function! magit#git#top_dir() + if ( !exists("b:magit_top_dir") ) + throw 'top_dir_not_set' endif - return s:magit_top_dir + return b:magit_top_dir endfunction -" s:magit_git_dir: git directory -" it is evaluated only once -" FIXME: it won't work when playing with multiple git directories wihtin one -" vim session -let s:magit_git_dir='' " magit#git#git_dir: return the absolute path of current git worktree " return git directory function! magit#git#git_dir() - if ( s:magit_git_dir == '' ) - let s:magit_git_dir=magit#utils#strip(system(s:git_cmd . " rev-parse --git-dir")) . "/" - if ( v:shell_error != 0 ) - echoerr "Git error: " . s:magit_git_dir - endif + if ( !exists("b:magit_git_dir") ) + throw 'git_dir_not_set' endif - return s:magit_git_dir + return b:magit_git_dir endfunction " magit#git#git_diff: helper function to get diff of a file diff --git a/autoload/magit/sign.vim b/autoload/magit/sign.vim index 7a53390..097e0c8 100644 --- a/autoload/magit/sign.vim +++ b/autoload/magit/sign.vim @@ -12,8 +12,6 @@ let s:dummy_sign_id = s:first_sign_id - 1 " Remove-all-signs optimisation requires Vim 7.3.596+. let s:supports_star = v:version > 703 || (v:version == 703 && has("patch596")) -let s:bufnr = bufnr(g:magit_buffer_name) - function! magit#sign#remove_all(...) if ( a:0 == 1 ) let pattern = a:1 diff --git a/autoload/magit/state.vim b/autoload/magit/state.vim index 1be452b..4f2cbb4 100644 --- a/autoload/magit/state.vim +++ b/autoload/magit/state.vim @@ -304,13 +304,31 @@ function! magit#state#set_files_visible(is_visible) dict endfor endfunction -" magit#state#get_files: global dict getter function +" magit#state#get_files: global dict file objects getter function " param[in] mode: mode to select, can be 'staged' or 'unstaged' -" return all files belonging to mode +" return list of file objects belonging to mode function! magit#state#get_files(mode) dict return self.dict[a:mode] endfunction +" magit#state#get_filenames: global dict filenames getter function +" param[in] mode: mode to select, can be 'staged' or 'unstaged' +" return ordered list of filename strings belonging to mode, modified files +" first +function! magit#state#get_filenames(mode) dict + let modified = [] + let others = [] + for filename in sort(keys(self.dict[a:mode])) + let file = self.get_file(a:mode, filename) + if ( file.status == 'M' ) + call add(modified, filename) + else + call add(others, filename) + endif + endfor + return modified + others +endfunction + " dict: structure containing all diffs " It is formatted as follow @@ -330,6 +348,7 @@ let magit#state#state = { \ 'nb_diff_lines': 0, \ 'get_file': function("magit#state#get_file"), \ 'get_files': function("magit#state#get_files"), + \ 'get_filenames': function("magit#state#get_filenames"), \ 'add_file': function("magit#state#add_file"), \ 'set_files_visible': function("magit#state#set_files_visible"), \ 'check_max_lines': function("magit#state#check_max_lines"), diff --git a/common/magit_common.vim b/common/magit_common.vim index 7773b0d..718bb45 100644 --- a/common/magit_common.vim +++ b/common/magit_common.vim @@ -10,6 +10,13 @@ let g:magit_sections = { \ 'stash': 'Stash list' \ } +let g:magit_section_info = { + \ 'cur_repo': 'Current repository', + \ 'cur_branch': 'Current branch', + \ 'cur_commit': 'Last commit', + \ 'commit_mode': 'Commit mode', + \ } + let g:magit_git_status_code = { \ 'M': 'modified', \ 'A': 'added', @@ -25,6 +32,11 @@ let g:magit_git_status_code = { \ 'S': 'submodule', \ } +let g:magit_commit_mode = { + \ 'CC': 'normal', + \ 'CA': 'amend', + \ } + " Regular expressions used to select blocks let g:magit_file_re = '^\(' for status_code in values(g:magit_git_status_code) diff --git a/doc/vimagit.txt b/doc/vimagit.txt index 863267e..7a4ba8f 100644 --- a/doc/vimagit.txt +++ b/doc/vimagit.txt @@ -50,7 +50,7 @@ with vimagit. See |vimagit-commands| for a complete description. :Magit ----------- -Open magit buffer. +Open magit buffer (see |magit#show_magit()|) Enter ----------- @@ -59,6 +59,11 @@ All files diffs are hidden by default. To inspect changes in a file, move cursor to the filename line, and press 'Enter' in Normal mode. Diffs are displayed below the file name. + N +----------- + +* Jump to next hunk with N. + S ----------- @@ -126,7 +131,11 @@ Visual selection and marked lines have some limitations for the moment: COMMANDS *vimagit-commands* *magit#show_magit()* -Function to open magit buffer. +Function to open magit buffer. This buffer will handle the git repository +including focused file. +It is possible to handle multiple git repositories within one vim instance. +Each git repository will have its own buffer. + It takes 3 parameters: * orientation (mandatory): it can be - 'v', curent window is split vertically, and magit is displayed in new @@ -139,8 +148,12 @@ It takes 3 parameters: * foldlevel: set default magit buffer foldlevel for this session (see |vimagit-g:magit_default_fold_level|) - *:Magit* *magit#show_magit('v')* - :Magit open magit buffer + *:Magit* + :Magit open magit buffer in a vertical split (see |magit#show_magit()|) + + *:MagitOnly* + :MagitOnly open magit buffer in current window (see |magit#show_magit()|) +You can create a bash alias like magit="vim -c MagitOnly" MAPPINGS *vimagit-mappings* @@ -219,6 +232,10 @@ Following mappings are set locally, for magit buffer only, in normal mode. position. Only works in "Unstaged changes" section. + *vimagit-N* *magit#jump_hunk()* + *vimagit-P* + N,P Move to Next or Previous hunk. + *vimagit-CC* *magit#commit_command('CC')* *vimagit-g:magit_commit_mapping* CC If not in commit section, set commit mode to "New commit" and show @@ -226,23 +243,23 @@ Following mappings are set locally, for magit buffer only, in normal mode. If in commit section, commit the all staged changes in commit mode previously set. - *vimagit-CA* *magit#commit_command('CA')* + *vimagit-CA* *magit#commit_command('CA')* *vimagit-g:magit_commit_amend_mapping* CA If not in commit section, set commit mode to "Amend commit" and show "Commit message" section with previous commit message. If in commit section, commit the staged changes in commit mode previously set. - *vimagit-CF* *magit#commit_command('CF')* + *vimagit-CF* *magit#commit_command('CF')* *vimagit-g:magit_commit_fixup_mapping* CF Amend the staged changes into the previous commit, without modifying previous commit message - *vimagit-I* *magit#ignore_file()* + *vimagit-I* *magit#ignore_file()* *vimagit-g:magit_ignore_mapping* I Add the file under the cursor in .gitgnore - *vimagit-R* *magit#update_buffer()* + *vimagit-R* *magit#update_buffer()* *vimagit-g:magit_reload_mapping* R Refresh magit buffer. @@ -250,7 +267,7 @@ Following mappings are set locally, for magit buffer only, in normal mode. *vimagit-g:magit_close_mapping* q close magit buffer. - *vimagit-h* *magit#toggle_help()* + *vimagit-h* *magit#toggle_help()* *vimagit-g:magit_toggle_help_mapping* h Toggle help showing in magit buffer diff --git a/plugin/magit.vim b/plugin/magit.vim index 46dc088..c50ccf4 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -15,11 +15,6 @@ let g:loaded_magit = 1 " syntax files execute 'source ' . resolve(expand(':p:h')) . '/../common/magit_common.vim' -" g:magit_buffer_name: vim buffer name for vimagit -let g:magit_buffer_name = "magit-playground" - -let s:state = deepcopy(magit#state#state) - " these mappings are broadly applied, for all vim buffers let g:magit_show_magit_mapping = get(g:, 'magit_show_magit_mapping', 'M' ) @@ -41,9 +36,11 @@ let g:magit_folding_toggle_mapping = get(g:, 'magit_folding_toggle_mapping', let g:magit_folding_open_mapping = get(g:, 'magit_folding_open_mapping', [ 'zo', 'zO' ]) let g:magit_folding_close_mapping = get(g:, 'magit_folding_close_mapping', [ 'zc', 'zC' ]) +let g:magit_jump_next_hunk = get(g:, 'magit_jump_next_hunk', 'N') +let g:magit_jump_prev_hunk = get(g:, 'magit_jump_prev_hunk', 'P') " user options let g:magit_enabled = get(g:, 'magit_enabled', 1) -let g:magit_show_help = get(g:, 'magit_show_help', 1) +let g:magit_show_help = get(g:, 'magit_show_help', 0) let g:magit_default_show_all_files = get(g:, 'magit_default_show_all_files', 1) let g:magit_default_fold_level = get(g:, 'magit_default_fold_level', 1) let g:magit_default_sections = get(g:, 'magit_default_sections', ['info', 'global_help', 'commit', 'staged', 'unstaged']) @@ -85,12 +82,9 @@ let s:magit_inline_help = { \'R refresh magit buffer', \'q close magit buffer', \'h toggle help showing in magit buffer', -\'', -\'To disable inline default appearance, add "let g:magit_show_help=0" to .vimrc', -\'You will still be able to toggle inline help with h', \], \ 'commit': [ -\'CC,:w commit all staged changes with commit mode previously set (normal or', +\'CC commit all staged changes with commit mode previously set (normal or', \' amend) with message written in this section', \], \} @@ -125,9 +119,15 @@ function! s:mg_get_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 =g:magit_section_info.cur_repo . ': ' . magit#git#top_dir() + silent put =g:magit_section_info.cur_branch . ': ' . branch + silent put =g:magit_section_info.cur_commit . ': ' . commit + if ( b:magit_current_commit_mode != '' ) + silent put =g:magit_section_info.commit_mode . ': ' + \ . g:magit_commit_mode[b:magit_current_commit_mode] + endif silent put ='' + silent put ='Press h to display help' endfunction " s:mg_display_files: display in current buffer files, filtered by some @@ -140,8 +140,8 @@ endfunction function! s:mg_display_files(mode, curdir, depth) " 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, 0) + for filename in b:state.get_filenames(a:mode) + let file = b:state.get_file(a:mode, filename, 0) if ( file.depth != a:depth || filename !~ a:curdir . '.*' ) continue endif @@ -175,7 +175,7 @@ function! s:mg_display_files(mode, curdir, depth) endfunction " s:mg_get_staged_section: this function writes in current buffer all staged -" or unstaged files, using s:state.dict information +" or unstaged files, using b: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' @@ -211,41 +211,27 @@ function! s:mg_get_stashes() endif endfunction -" s:magit_commit_mode: global variable which states in which commit mode we are -" values are: -" '': not in commit mode -" 'CC': normal commit mode, next commit command will create a new commit -" 'CA': amend commit mode, next commit command will ament current commit -" 'CF': fixup commit mode, it should not be a global state mode -let s:magit_commit_mode='' " s:mg_get_commit_section: this function writes in current buffer the commit -" section. It is a commit message, depending on s:magit_commit_mode +" section. It is a commit message, depending on b:magit_current_commit_mode " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer -" param[in] s:magit_commit_mode: this function uses global commit mode +" param[in] b:magit_current_commit_mode: this function uses global commit mode " 'CC': prepare a brand new commit message " 'CA': get the last commit message function! s:mg_get_commit_section() - if ( s:magit_commit_mode != '' ) - let commit_mode_str="" - if ( s:magit_commit_mode == 'CC' ) - let commit_mode_str="normal" - elseif ( s:magit_commit_mode == 'CA' ) - let commit_mode_str="amend" - endif + if ( b:magit_current_commit_mode != '' ) silent put ='' silent put =g:magit_sections.commit_start - silent put ='Commit mode: '.commit_mode_str call mg_section_help('commit') silent put =magit#utils#underline(g:magit_sections.commit_start) silent put ='' let git_dir=magit#git#git_dir() " refresh the COMMIT_EDITMSG file - if ( s:magit_commit_mode == 'CC' ) + if ( b:magit_current_commit_mode == 'CC' ) silent! call magit#utils#system("GIT_EDITOR=/bin/false git commit -e 2> /dev/null") - elseif ( s:magit_commit_mode == 'CA' ) + elseif ( b:magit_current_commit_mode == 'CA' ) silent! call magit#utils#system("GIT_EDITOR=/bin/false git commit --amend -e 2> /dev/null") endif if ( filereadable(git_dir . 'COMMIT_EDITMSG') ) @@ -326,7 +312,7 @@ function! s:mg_git_commit(mode) abort else let commit_section_pat_start='^'.g:magit_sections.commit_start.'$' let commit_section_pat_end='^'.g:magit_sections.commit_end.'$' - let commit_jump_line = 3 + mg_get_inline_help_line_nb('commit') + let commit_jump_line = 2 + mg_get_inline_help_line_nb('commit') let [start, end] = mg_search_block( \ [commit_section_pat_start, commit_jump_line], \ [ [commit_section_pat_end, -1] ], "") @@ -397,7 +383,7 @@ function! s:mg_create_diff_from_select(select_lines) endif let section=mg_get_section() let filename=mg_get_filename() - let hunks = s:state.get_file(section, filename).get_hunks() + let hunks = b:state.get_file(section, filename).get_hunks() for hunk in hunks if ( hunk.header == getline(starthunk) ) let current_hunk = hunk @@ -495,7 +481,7 @@ function! magit#open_close_folding(...) let section=mg_get_section() " if first param is set, force visible to this value " else, toggle value - let file = s:state.get_file(section, filename, 0) + let file = b:state.get_file(section, filename, 0) if ( a:0 == 1 ) call file.set_visible(a:1) else @@ -522,8 +508,9 @@ let s:mg_display_functions = { " 4. fills with unstage stuff " 5. restore window state function! magit#update_buffer() - if ( @% != g:magit_buffer_name ) - echoerr "Not in magit buffer " . g:magit_buffer_name . " but in " . @% + let buffer_name=bufname("%") + if ( buffer_name !~ 'magit://.*' ) + echoerr "Not in magit buffer but in " . buffer_name return endif " FIXME: find a way to save folding state. According to help, this won't @@ -539,7 +526,7 @@ function! magit#update_buffer() " delete buffer silent! execute "silent :%delete _" - call s:state.update() + call b:state.update() for section in g:magit_default_sections try @@ -555,10 +542,10 @@ function! magit#update_buffer() call winrestview(l:winview) - if ( s:magit_commit_mode != '' ) + if ( b:magit_current_commit_mode != '' ) let commit_section_pat_start='^'.g:magit_sections.commit_start.'$' silent! let section_line=search(commit_section_pat_start, "w") - silent! call cursor(section_line+3+mg_get_inline_help_line_nb('commit'), 0) + silent! call cursor(section_line+2+mg_get_inline_help_line_nb('commit'), 0) endif set filetype=magit @@ -578,20 +565,57 @@ endfunction " 'h': horizontal split " 'c': current buffer (should be used when opening vim in vimagit mode function! magit#show_magit(display, ...) - if ( magit#utils#strip(system("git rev-parse --is-inside-work-tree")) != 'true' ) - echoerr "Magit must be started from a git repository" - return + if ( &filetype == 'netrw' ) + let cur_file_path = b:netrw_curdir + else + let cur_file = expand("%:p") + let cur_file_path = isdirectory(cur_file) ? cur_file : fnamemodify(cur_file, ":h") endif + + let git_dir='' + let try_paths = [ cur_file_path, getcwd() ] + for path in try_paths + let git_dir=magit#git#is_work_tree(path) + if ( git_dir != '' ) + break + endif + endfor + + if ( git_dir == '' ) + echohl ErrorMsg + echom "magit can not find any git repository" + echom "make sure that current opened file or vim current directory points to a git repository" + echom "search paths:" + for path in try_paths + echom path + endfor + echohl None + throw 'magit_not_in_git_repo' + endif + + let buffer_name='magit://' . git_dir + if ( a:display == 'v' ) - vnew + silent execute "vnew " . buffer_name elseif ( a:display == 'h' ) - new + silent execute "new " . buffer_name elseif ( a:display == 'c' ) - enew + if ( !bufexists(buffer_name) ) + if ( bufname("%") == "" ) + keepalt enew + else + enew + endif + execute "file " . buffer_name + endif else throw 'parameter_error' endif + silent execute "buffer " . buffer_name + + call magit#git#set_top_dir(git_dir) + let b:magit_default_show_all_files = g:magit_default_show_all_files let b:magit_default_fold_level = g:magit_default_fold_level let b:magit_warning_max_lines_answered = 0 @@ -603,20 +627,25 @@ function! magit#show_magit(display, ...) let b:magit_default_fold_level = a:2 endif - if ( bufexists(g:magit_buffer_name) ) - silent! execute "bdelete " . g:magit_buffer_name - endif - silent! execute "file " . g:magit_buffer_name - setlocal buftype=nofile setlocal bufhidden=hide setlocal noswapfile setlocal foldmethod=syntax + setlocal nobuflisted let &l:foldlevel = b:magit_default_fold_level setlocal filetype=magit "setlocal readonly - call magit#utils#setbufnr(bufnr(g:magit_buffer_name)) + let b:state = deepcopy(g:magit#state#state) + " s:magit_commit_mode: global variable which states in which commit mode we are + " values are: + " '': not in commit mode + " 'CC': normal commit mode, next commit command will create a new commit + " 'CA': amend commit mode, next commit command will ament current commit + " 'CF': fixup commit mode, it should not be a global state mode + let b:magit_current_commit_mode='' + + call magit#utils#setbufnr(bufnr(buffer_name)) call magit#sign#init() execute "nnoremap " . g:magit_stage_file_mapping . " :call magit#stage_file()" @@ -635,7 +664,10 @@ function! magit#show_magit(display, ...) execute "nnoremap " . g:magit_mark_line_mapping . " :call magit#mark_vselect()" execute "xnoremap " . g:magit_mark_line_mapping . " :call magit#mark_vselect()" - + + execute "nnoremap " . g:magit_jump_next_hunk . " :call magit#jump_hunk('N')" + execute "nnoremap " . g:magit_jump_prev_hunk . " :call magit#jump_hunk('P')" + for mapping in g:magit_folding_toggle_mapping " trick to pass '' in a mapping command without being interpreted let func_arg = ( mapping ==? "" ) ? '+' : mapping @@ -670,7 +702,7 @@ function! s:mg_stage_closed_file(discard) let filename = list[2] let section=mg_get_section() - let file = s:state.get_file(section, filename) + let file = b:state.get_file(section, filename) if ( file.is_visible() == 0 || \ file.is_dir() == 1 ) if ( a:discard == 0 ) @@ -707,9 +739,9 @@ endfunction function! magit#stage_block(selection, discard) abort let section=mg_get_section() let filename=mg_get_filename() - let header = s:state.get_file(section, filename).get_header() + let header = b:state.get_file(section, filename).get_header() - let file = s:state.get_file(section, filename, 0) + let file = b:state.get_file(section, filename, 0) if ( a:discard == 0 ) if ( section == 'unstaged' ) if ( file.must_be_added() ) @@ -864,30 +896,53 @@ endfunction " magit#commit_command: entry function for commit mode " INFO: it has a different effect if current section is commit section or not " param[in] mode: commit mode -" 'CF': do not set global s:magit_commit_mode, directly call magit#git_commit +" 'CF': do not set global b:magit_current_commit_mode, directly call magit#git_commit " 'CA'/'CF': if in commit section mode, call magit#git_commit, else just set -" global state variable s:magit_commit_mode, +" global state variable b:magit_current_commit_mode, function! magit#commit_command(mode) if ( a:mode == 'CF' ) call mg_git_commit(a:mode) else let section=mg_get_section() if ( section == 'commit_start' ) - if ( s:magit_commit_mode == '' ) + if ( b:magit_current_commit_mode == '' ) echoerr "Error, commit section should not be enabled" return endif " when we do commit, it is prefered ot commit the way we prepared it " (.i.e normal or amend), whatever we commit with CC or CA. - call mg_git_commit(s:magit_commit_mode) - let s:magit_commit_mode='' + call mg_git_commit(b:magit_current_commit_mode) + let b:magit_current_commit_mode='' else - let s:magit_commit_mode=a:mode + let b:magit_current_commit_mode=a:mode endif endif call magit#update_buffer() endfunction +" magit#jump_hunk: function to jump among hunks +" it closes the current fold (if any), jump to next hunk and unfold it +" param[in] dir: can be 'N' (for next) or 'P' (for previous) +function! magit#jump_hunk(dir) + let back = ( a:dir == 'P' ) ? 'b' : '' + let line = search("^@@ ", back . 'wn') + if ( line != 0 ) + try + foldclose + catch /^Vim\%((\a\+)\)\=:E490/ + endtry + call cursor(line, 0) + try + foldopen + catch /^Vim\%((\a\+)\)\=:E490/ + echohl WarningMsg + echom "Warning: you should have jumped on a folded hunk" + echohl None + endtry + endif +endfunction + command! Magit call magit#show_magit('v') +command! MagitOnly call magit#show_magit('c') " }}} diff --git a/syntax/magit.vim b/syntax/magit.vim index e33e322..904d8d3 100644 --- a/syntax/magit.vim +++ b/syntax/magit.vim @@ -9,14 +9,8 @@ syn sync minlines=50 syn include @diff syntax/diff.vim -execute 'syn match titleEntry "' . g:magit_section_re . '" contains=titleSign' -if has("conceal") - syn match titleSign contained "\%(&@\|@&\)" conceal -else - syn match titleSign contained "\%(&@\|@&\)" -endif -hi def link titleEntry String -hi def link titleSign Ignore +execute 'syn match titleEntry "' . g:magit_section_re . '\n=\+"' +hi def link titleEntry Comment execute 'syn match stashEntry "' . g:magit_stash_re . '"' hi def link stashEntry String @@ -36,4 +30,23 @@ execute 'syn region gitHunk start=/' . \ g:magit_hunk_re . '/ end=/\%(' . g:magit_end_diff_re . '\|' . g:magit_hunk_re \ '\)\@=/ contains=@diff fold' +execute 'syn region gitInfo start=/^' . g:magit_sections.info . '$/ end=/' . + \ g:magit_section_re . '/' + +execute 'syn region gitInfoRepo start=/^' . g:magit_section_info.cur_repo . + \ ':\s*.*/hs=s+20 end=/$/ oneline' +highlight default link gitInfoRepo Directory +execute 'syn region gitInfoBranch start=/^' . g:magit_section_info.cur_branch . + \ ':\s*.*/hs=s+20 end=/$/ oneline' +highlight default link gitInfoBranch Identifier +execute 'syn region gitCommitMode start=/^' . g:magit_section_info.commit_mode . + \ ':\s*.*/hs=s+20 end=/$/ oneline' +highlight default link gitCommitMode Special + +execute 'syn region gitInfoCommit start=/^' . g:magit_section_info.cur_commit . + \ ':\s*\(.*\)/ end=/$/ contains=infoSha1 oneline' +syntax match infoSha1 containedin=gitInfoCommit "\x\{7}" +highlight default link infoSha1 Identifier + + let b:current_syntax = "magit"