diff --git a/.travis.yml b/.travis.yml index 5df2b12d11f6938cc6a1b8aa04594f4fc03c93ae..660befcb77d8e3608b7da434ad45c5faf381c272 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,28 +1,70 @@ language: vim -sudo: false +branches: + only: + - master + - next os: - linux - osx env: - matrix: - - TEST_SUB_PATH=./ - - TEST_SUB_PATH=books/templates/ + - VIM_VERSION=normal + - VIM_VERSION=last + - VIM_VERSION=neovim + - VIM_VERSION=macvim matrix: - allow_failures: + exclude: - os: osx + env: VIM_VERSION=last +# neovim build fails with homebrew +# Error: undefined method `desc' for Neovim:Class + - os: osx + env: VIM_VERSION=neovim + - os: linux + env: VIM_VERSION=macvim + +install: + - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then + if [ "$VIM_VERSION" = 'neovim' ]; then + brew tap neovim/neovim && + brew tap --repair && + brew install --HEAD neovim; + elif [ "$VIM_VERSION" = 'macvim' ]; then + brew install macvim; + elif [ "$VIM_VERSION" = 'normal' ]; then + echo "use normal vim"; + else + echo "VIM_VERSION is not set"; + exit 1; + fi + elif [ "$TRAVIS_OS_NAME" = 'linux' ]; then + if [ "$VIM_VERSION" = 'last' ]; then + sudo add-apt-repository -y ppa:fcwu-tw/ppa && + sudo apt-get -qq update && + sudo apt-get -qq -f install && + sudo apt-get -qq install vim; + elif [ "$VIM_VERSION" = 'neovim' ]; then + sudo add-apt-repository -y ppa:neovim-ppa/unstable && + sudo apt-get -qq update && + sudo apt-get -qq -f install && + sudo apt-get -qq install neovim; + elif [ "$VIM_VERSION" = 'normal' ]; then + echo "use normal vim"; + else + echo "VIM_VERSION is not set"; + exit 1; + fi + fi before_script: - git clone https://github.com/jreybert/djooks - git clone https://github.com/junegunn/vader.vim script: - - ./test/run.sh . vader.vim djooks - -install: true + - ./test/run.sh . vader.vim djooks $VIM_VERSION after_success: - ./test/merge.sh diff --git a/README.md b/README.md index 986b807f3949234a15a0048d37cc142847a359b1..9a0fa59d4662ba0e4a27d584c16b8c6759fe49bd 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,13 @@ More to come: ## Usage -IMPORTANT: mappings can have different meanings regarding the cursor position. +**:Magit** +The main magical command, showing vimagit buffer. ### Sections: +IMPORTANT: mappings can have different meanings regarding the cursor position. + There are 3 sections: * Commit message: this section appears in commit mode (see below). It contains the message to be commited. @@ -60,38 +63,43 @@ There are 3 sections: These mappings work in normal mode. They can be redefined. - S if cursor is in a hunk, stage/unstage hunk at - cursor position - if cursor is in diff header, stage/unstage whole file - at cursor position - When cursor is in "Unstaged changes" section, it will - stage the hunk/file. - On the other side, when cursor is in "Staged changes" - section, it will unstage hunk/file. - F stage/unstage the whole file at cursor position - When cursor is in "Unstaged changes" section, it will - stage the file. - On the other side, when cursor is in "Staged changes" - section, it will unstage file. - DDD if cursor is in a hunk, discard hunk at cursor position - if cursor is in diff header, discard whole file at - cursor position - When cursor is in "Unstaged changes" section, it will - discard the hunk/file. - R refresh vimagit buffer - C,CC,:w<cr> 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 - 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 - CF amend the staged changes into the previous commit, - without modifying previous commit message - I add the file under the cursor in .gitgnore +**S** + * If cursor is in a hunk, stage/unstage hunk at cursor position. + * If cursor is in diff header, stage/unstage whole file at cursor position. + * When cursor is in "Unstaged changes" section, it will stage the hunk/file. + * On the other side, when cursor is in "Staged changes" section, it will unstage hunk/file. + +**F** + * Stage/unstage the whole file at cursor position. + * When cursor is in "Unstaged changes" section, it will stage the file. + * On the other side, when cursor is in "Staged changes" section, it will unstage file. + +**DDD** + * If cursor is in a hunk, discard hunk at cursor position. + * If cursor is in diff header, discard whole file at cursor position. + * Only works in "Unstaged changes" section. + +**C** +**CC** +**:w<cr>** + * 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. + +**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. + +**CF** + * Amend the staged changes into the previous commit, without modifying previous commit message. + +**I** + * Add the file under the cursor in .gitgnore + +**R** + * Refresh vimagit buffer + +**h** + * Toggle help showing in magit buffer ## Installation diff --git a/TODO.md b/TODO.md index 113a56887213d8f6f734d56b6ff34189cc93ee06..10020b6c096ff4854458d3f4edd2c5b466e01a9c 100644 --- a/TODO.md +++ b/TODO.md @@ -4,4 +4,3 @@ * fix new empty file staging * add tests * add tutorial -* fix new/renamed file diff: it gives an absolute pathname, which is wrong fir diff diff --git a/common/magit_common.vim b/common/magit_common.vim index d183399dc5819b23a98a9930a4932ef6bc2cb04a..88528436a8786a5bac154e1b397834986991da36 100644 --- a/common/magit_common.vim +++ b/common/magit_common.vim @@ -2,6 +2,7 @@ " These are used to beautify the magit buffer and to help for some block " selection let g:magit_sections = { + \ 'info': 'Info', \ 'staged': 'Staged changes', \ 'unstaged': 'Unstaged changes', \ 'commit_start': 'Commit message', diff --git a/doc/vimagit.txt b/doc/vimagit.txt index 9c71080ac1b6f54e38e3d7dec6fedaa25a9bb035..14dcbab39ab11678e553ee5f6a8e2486a38a70aa 100644 --- a/doc/vimagit.txt +++ b/doc/vimagit.txt @@ -11,19 +11,18 @@ Plugin Homepage: <https://github.com/jreybert/vimagit> ----- ~ =============================================================================== -CONTENTS *vimagitContents* +CONTENTS *vimagit-contents* - 1. Introduction ................. |vimagitIntroduction| - 2. Installation ................. |vimagitInstallation| - 3. Usage ........................ |vimagitUsage| - 4. Commands ..................... |vimagitCommands| - 5. Customization ................ |vimagitCustomization| - 6. FAQ .......................... |vimagitFAQ| + 1. Introduction ................. |vimagit-introduction| + 2. Installation ................. |vimagit-installation| + 3. Usage ........................ |vimagit-usage| + 4. Commands ..................... |vimagit-commands| + 5. Customization ................ |vimagit-customization| + 6. FAQ .......................... |vimagit-FAQ| =============================================================================== -1. INTRODUCTION *vimagitIntroduction* - *vimagit* +1. INTRODUCTION *vimagit-introduction* vimagit is a plugin which try to mimic the fantastic magit emacs plugin. If you already know the original plugin, give it a try. If you never have heard about @@ -31,7 +30,7 @@ magit (or maybe emacs), this is IMO the most efficient way to stage hunks and craft nice commits. =============================================================================== -2. INSTALLATION *vimagitInstallation* +2. INSTALLATION *vimagit-installation* The plugin hierarchy tree respects the vim plugin standard. It is compatible with pathogen (and most probably vundle). @@ -43,18 +42,23 @@ To install: < =============================================================================== -3. USAGE *vimagitUsage* +3. USAGE *vimagit-usage* In a git'ed source directory, once you have some unstaged work, simply type with :Magit , and here is the magic. A new window appears, with all the diffs and new files in your directory. =============================================================================== -4. COMMANDS *vimagitCommands* +4. COMMANDS *vimagit-commands* -IMPORTANT: mappings can have different meanings regarding the cursor position. -Sections: + *:Magit* *magit#show_magit('v')* + :Magit the main magical command, showing vimagit buffer + +Sections: *vimagit-sections* +--------- + +IMPORTANT: mappings can have different meanings regarding the cursor position. There are 3 sections: * Commit message: this section appears in commit mode (see below). It @@ -65,45 +69,60 @@ There are 3 sections: files/hunks. * Stash list: this section contains all stahes. -These mappings work in normal mode. - - S if cursor is in a hunk, stage/unstage hunk at - cursor position - if cursor is in diff header, stage/unstage whole file - at cursor position - When cursor is in "Unstaged changes" section, it will - stage the hunk/file. - On the other side, when cursor is in "Staged changes" - section, it will unstage hunk/file. - F stage/unstage the whole file at cursor position - When cursor is in "Unstaged changes" section, it will - stage the file. - On the other side, when cursor is in "Staged changes" - section, it will unstage file. - DDD if cursor is in a hunk, discard hunk at cursor position - if cursor is in diff header, discard whole file at - cursor position - When cursor is in "Unstaged changes" section, it will - discard the hunk/file. - R refresh vimagit buffer - C,CC,:w<cr> 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 - 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 - CF amend the staged changes into the previous commit, - without modifying previous commit message - I add the file under the cursor in .gitgnore +These mappings work in normal mode. *vimagit-mappings* + + *vimagit-S* *magit#stage_hunk()* + S If cursor is in a hunk, stage/unstage hunk at cursor position. + If cursor is in diff header, stage/unstage whole file at cursor + position. + When cursor is in "Unstaged changes" section, it will stage the + hunk/file. + On the other side, when cursor is in "Staged changes" section, it + will unstage hunk/file. + + *vimagit-F* *magit#stage_file()* + F Stage/unstage the whole file at cursor position. + When cursor is in "Unstaged changes" section, it will stage the + file. + On the other side, when cursor is in "Staged changes" section, it + will unstage file. + + + *vimagit-DDD* *magit#discard_hunk()* + DDD If cursor is in a hunk, discard hunk at cursor position. + If cursor is in diff header, discard whole file at cursor + position. + Only works in "Unstaged changes" section. + + *vimagit-C* *vimagit-CC* *vimagit-:w<cr>* *magit#commit_command('CC')* + C,CC, If not in commit section, set commit mode to "New commit" and show + :w<cr> "Commit message" section with brand new commit message. + If in commit section, commit the all staged changes in commit mode + previously set. + + *vimagit-CA* *magit#commit_command('CA')* + 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')* + CF Amend the staged changes into the previous commit, without + modifying previous commit message + + *vimagit-I* *magit#ignore_file()* + I Add the file under the cursor in .gitgnore + + *vimagit-R* *magit#update_buffer()* + R Refresh vimagit buffer. + + *vimagit-h* *magit#toggle_help()* + h Toggle help showing in magit buffer =============================================================================== -5. CUSTOMISATION *vimagitCustomization* +5. CUSTOMISATION *vimagit-customization* =============================================================================== -6. FAQ *vimagitFAQ* +6. FAQ *vimagit-FAQ* diff --git a/plugin/magit.vim b/plugin/magit.vim index 07def374546275d75a4f80beb59c706c31ce4dd5..490d8e262c8d0256382756ffdcfc193a9b2a3c78 100644 --- a/plugin/magit.vim +++ b/plugin/magit.vim @@ -4,14 +4,18 @@ if exists('g:loaded_magit') || !executable('git') || &cp finish endif let g:loaded_magit = 1 + " Initialisation {{{ " FIXME: find if there is a minimum vim version required " if v:version < 703 " endif +" source common file. variables in common file are shared with plugin and +" syntax files execute 'source ' . resolve(expand('<sfile>:p:h')) . '/../common/magit_common.vim' +" g:magit_unstaged_buffer_name: vim buffer name for vimagit let g:magit_unstaged_buffer_name = "magit-playground" " s:set: helper function to set user definable variable @@ -53,13 +57,13 @@ call s:set('g:magit_show_help', 1) " FIXME: it won't work when playing with multiple git directories wihtin one " vim session let s:magit_top_dir='' -" magit#top_dir: return the absolute path of current git worktree +" s:mg_top_dir: return the absolute path of current git worktree " return top directory -function! magit#top_dir() +function! s:mg_top_dir() if ( s:magit_top_dir == '' ) - let s:magit_top_dir=magit#strip(system("git rev-parse --show-toplevel")) . "/" + let s:magit_top_dir=<SID>mg_strip(system("git rev-parse --show-toplevel")) . "/" if ( v:shell_error != 0 ) - echoerr "Git error: " . top_dir + echoerr "Git error: " . s:magit_top_dir endif endif return s:magit_top_dir @@ -70,13 +74,13 @@ endfunction " FIXME: it won't work when playing with multiple git directories wihtin one " vim session let s:magit_git_dir='' -" magit#git_dir: return the absolute path of current git worktree +" s:mg_git_dir: return the absolute path of current git worktree " return git directory -function! magit#git_dir() +function! s:mg_git_dir() if ( s:magit_git_dir == '' ) - let s:magit_git_dir=magit#strip(system("git rev-parse --git-dir")) . "/" + let s:magit_git_dir=<SID>mg_strip(system("git rev-parse --git-dir")) . "/" if ( v:shell_error != 0 ) - echoerr "Git error: " . git_dir + echoerr "Git error: " . s:magit_git_dir endif endif return s:magit_git_dir @@ -86,16 +90,16 @@ endfunction " 'cd' otherwise let s:magit_cd_cmd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd ' -" magit#system: wrapper for system, which only takes String as input in vim, +" s:mg_system: wrapper for system, which only takes String as input in vim, " although it can take String or List input in neovim. " INFO: temporarly change pwd to git top directory, then restore to previous " pwd at the end of function " param[in] ...: command + optional args " return: command output as a string -function! magit#system(...) +function! s:mg_system(...) let dir = getcwd() try - execute s:magit_cd_cmd . magit#top_dir() + execute s:magit_cd_cmd . <SID>mg_top_dir() " List as system() input is since v7.4.247, it is safe to check " systemlist, which is sine v7.4.248 if exists('*systemlist') @@ -119,62 +123,71 @@ function! magit#system(...) endtry endfunction -" magit#systemlist: wrapper for systemlist, which only exists in neovim for +" s:mg_systemlist: wrapper for systemlist, which only exists in neovim for " the moment. " INFO: temporarly change pwd to git top directory, then restore to previous " pwd at the end of function " param[in] ...: command + optional args to execute, args can be List or String " return: command output as a list -function! magit#systemlist(...) +function! s:mg_systemlist(...) let dir = getcwd() try - execute s:magit_cd_cmd . magit#top_dir() + execute s:magit_cd_cmd . <SID>mg_top_dir() " systemlist since v7.4.248 if exists('*systemlist') return call('systemlist', a:000) else - return split(call('magit#system', a:000), '\n') + return split(call('<SID>mg_system', a:000), '\n') endif finally execute s:magit_cd_cmd . dir endtry endfunction -" magit#underline: helper function to underline a string +" s:mg_underline: helper function to underline a string " param[in] title: string to underline " return a string composed of strlen(title) '=' -function! magit#underline(title) +function! s:mg_underline(title) return substitute(a:title, ".", "=", "g") endfunction -" magit#strip: helper function to strip a string +" s:mg_strip: helper function to strip a string " WARNING: it only works with monoline string " param[in] string: string to strip " return: stripped string -function! magit#strip(string) +function! s:mg_strip(string) return substitute(a:string, '^\s*\(.\{-}\)\s*\n\=$', '\1', '') endfunction -" magit#join_list: helper function to concatente a list of strings with newlines +" s:mg_join_list: helper function to concatente a list of strings with newlines " param[in] list: List to to concat " return: concatenated list -function! magit#join_list(list) +function! s:mg_join_list(list) return join(a:list, "\n") . "\n" endfunction -" magit#append_file: helper function to append to a file +" s:mg_append_file: helper function to append to a file " Version working with file *possibly* containing trailing newline " param[in] file: filename to append " param[in] lines: List of lines to append -function! magit#append_file(file, lines) - let fcontents=readfile(a:file, 'b') +function! s:mg_append_file(file, lines) + let fcontents=[] + if ( filereadable(a:file) ) + let fcontents=readfile(a:file, 'b') + endif if !empty(fcontents) && empty(fcontents[-1]) call remove(fcontents, -1) endif call writefile(fcontents+a:lines, a:file, 'b') endfunction -function! magit#get_diff(mode) +" s:mg_get_diff: this function write in current buffer all file names and +" related diffs for a given mode +" filename are prefixed in git status ('new: ' , 'modified: ', ...) +" WARNING: this function writes in file, it should only be called through +" protected functions like magit#update_buffer +" param[in] mode: can be 'staged' or 'unstaged' +function! s:mg_get_diff(mode) let staged_flag="" if ( a:mode == 'staged' ) @@ -184,7 +197,7 @@ function! magit#get_diff(mode) let status_position=1 endif - let status_list=magit#systemlist("git status --porcelain") + let status_list=<SID>mg_systemlist("git status --porcelain") for file_status_line in status_list let file_status=file_status_line[status_position] let file_name=substitute(file_status_line, '.. \(.*\)$', '\1', '') @@ -204,7 +217,7 @@ function! magit#get_diff(mode) let file_name='"' . file_name . '"' endif let diff_cmd="git diff --no-ext-diff " . staged_flag . "--no-color --patch -- " . dev_null . " " . file_name - let diff_list=magit#systemlist(diff_cmd) + let diff_list=<SID>mg_systemlist(diff_cmd) if ( empty(diff_list) ) echoerr "diff command \"" . diff_cmd . "\" returned nothing" endif @@ -214,6 +227,7 @@ function! magit#get_diff(mode) endfor endfunction +" s:magit_inline_help: Dict containing inline help for each section let s:magit_inline_help = { \ 'staged': [ \'S if cursor in diff header, unstage file', @@ -235,7 +249,9 @@ let s:magit_inline_help = { \' commit message', \'R refresh magit buffer', \'h toggle help showing in magit buffer', -\'To disable this help by default, add "let g:magit_show_help=0" to .vimrc', +\'', +\'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': [ \'C CC commit all staged changes with commit mode previously set (normal or', @@ -243,49 +259,73 @@ let s:magit_inline_help = { \], \} -function! magit#get_inline_help_line_nb(section) +" 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 +" return number of lines +function! s:mg_get_inline_help_line_nb(section) return ( g:magit_show_help == 1 ) ? \ len(s:magit_inline_help[a:section]) : 0 endfunction -function! magit#section_help(section) +" s:mg_section_help: this function writes in current buffer the inline help +" for a given section, it does nothing if inline help is disabled. +" WARNING: this function writes in file, it should only be called through +" protected functions like magit#update_buffer +" param[in] section: section identifier +function! s:mg_section_help(section) if ( g:magit_show_help == 1 ) silent put =s:magit_inline_help[a:section] endif endfunction -" magit#get_staged: this function writes in current buffer all staged files +" 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 =<SID>mg_underline(g:magit_sections['info']) + silent put ='' + let branch=<SID>mg_system("git rev-parse --abbrev-ref HEAD") + let commit=<SID>mg_system("git show -s --oneline") + silent put ='Current branch: ' . branch + silent put ='Last commit: ' . commit + silent put ='' +endfunction + +" s:mg_get_staged: this function writes in current buffer all staged files " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer -function! magit#get_staged() +function! s:mg_get_staged() silent put ='' silent put =g:magit_sections['staged'] - call magit#section_help('staged') - silent put =magit#underline(g:magit_sections['staged']) + call <SID>mg_section_help('staged') + silent put =<SID>mg_underline(g:magit_sections['staged']) silent put ='' - call magit#get_diff('staged') + call <SID>mg_get_diff('staged') endfunction -" magit#get_unstaged: this function writes in current buffer all unstaged +" s:mg_get_unstaged: this function writes in current buffer all unstaged " and untracked files " WARNING: this function writes in file, it should only be called through " protected functions like magit#update_buffer -function! magit#get_unstaged() +function! s:mg_get_unstaged() silent put ='' silent put =g:magit_sections['unstaged'] - call magit#section_help('unstaged') - silent put =magit#underline(g:magit_sections['unstaged']) + call <SID>mg_section_help('unstaged') + silent put =<SID>mg_underline(g:magit_sections['unstaged']) silent put ='' - call magit#get_diff('unstaged') + call <SID>mg_get_diff('unstaged') endfunction -" magit#get_stashes: this function write in current buffer all stashes +" 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 -function! magit#get_stashes() - silent! let stash_list=magit#systemlist("git stash list") +function! s:mg_get_stashes() + silent! let stash_list=<SID>mg_systemlist("git stash list") if ( v:shell_error != 0 ) echoerr "Git error: " . stash_list endif @@ -293,7 +333,7 @@ function! magit#get_stashes() if (!empty(stash_list)) silent put ='' silent put =g:magit_sections['stash'] - silent put =magit#underline(g:magit_sections['stash']) + silent put =<SID>mg_underline(g:magit_sections['stash']) silent put ='' for stash in stash_list @@ -312,14 +352,14 @@ endfunction " 'CF': fixup commit mode, it should not be a global state mode let s:magit_commit_mode='' -" magit#get_commit_section: this function writes in current buffer the commit +" 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 " 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 " 'CC': prepare a brand new commit message " 'CA': get the last commit message -function! magit#get_commit_section() +function! s:mg_get_commit_section() let commit_mode_str="" if ( s:magit_commit_mode == 'CC' ) let commit_mode_str="normal" @@ -329,26 +369,28 @@ function! magit#get_commit_section() silent put ='' silent put =g:magit_sections['commit_start'] silent put ='Commit mode: '.commit_mode_str - call magit#section_help('commit') - silent put =magit#underline(g:magit_sections['commit_start']) + call <SID>mg_section_help('commit') + silent put =<SID>mg_underline(g:magit_sections['commit_start']) silent put ='' - let git_dir=magit#git_dir() + let git_dir=<SID>mg_git_dir() " refresh the COMMIT_EDITMSG file if ( s:magit_commit_mode == 'CC' ) - silent! call magit#system("GIT_EDITOR=/bin/false git commit -e 2> /dev/null") + silent! call <SID>mg_system("GIT_EDITOR=/bin/false git commit -e 2> /dev/null") elseif ( s:magit_commit_mode == 'CA' ) - silent! call magit#system("GIT_EDITOR=/bin/false git commit --amend -e 2> /dev/null") + silent! call <SID>mg_system("GIT_EDITOR=/bin/false git commit --amend -e 2> /dev/null") + endif + if ( filereadable(git_dir . 'COMMIT_EDITMSG') ) + let comment_char=<SID>mg_comment_char() + let commit_msg=<SID>mg_join_list(filter(readfile(git_dir . 'COMMIT_EDITMSG'), 'v:val !~ "^' . comment_char . '"')) + put =commit_msg endif - let comment_char=magit#comment_char() - let commit_msg=magit#join_list(filter(readfile(git_dir . 'COMMIT_EDITMSG'), 'v:val !~ "^' . comment_char . '"')) - put =commit_msg put =g:magit_sections['commit_end'] endfunction -" magit#comment_char: this function gets the commentChar from git config -function! magit#comment_char() - silent! let git_result=magit#strip(magit#system("git config --get core.commentChar")) +" s:mg_comment_char: this function gets the commentChar from git config +function! s:mg_comment_char() + silent! let git_result=<SID>mg_strip(<SID>mg_system("git config --get core.commentChar")) if ( v:shell_error != 0 ) return '#' else @@ -356,7 +398,7 @@ function! magit#comment_char() endif endfunction -" magit#search_block: helper function, to get a block of text, giving a start +" s:mg_search_block: helper function, to get a block of text, giving a start " and multiple end pattern " a "pattern parameter" is a List: " @[0]: end pattern regex @@ -372,17 +414,15 @@ endfunction " return: a list. " @[0]: return status " @[1]: List of selected block lines -function! magit#search_block(start_pattern, end_pattern, upper_limit_pattern) +function! s:mg_search_block(start_pattern, end_pattern, upper_limit_pattern) let l:winview = winsaveview() let upper_limit=0 if ( a:upper_limit_pattern != "" ) - let upper_limit=search(a:upper_limit_pattern, "bnW") + let upper_limit=search(a:upper_limit_pattern, "cbnW") endif - " important if backward regex is at the beginning of the current line - call cursor(0, 100) - let start=search(a:start_pattern[0], "bW") + let start=search(a:start_pattern[0], "cbW") if ( start == 0 ) call winrestview(l:winview) return [1, ""] @@ -413,7 +453,7 @@ function! magit#search_block(start_pattern, end_pattern, upper_limit_pattern) return [0, lines] endfunction -" magit#git_commit: commit staged stuff with message prepared in commit section +" s:mg_git_commit: commit staged stuff with message prepared in commit section " param[in] mode: mode to commit " 'CF': don't use commit section, just amend previous commit with staged " stuff, without modifying message @@ -422,39 +462,38 @@ endfunction " 'CA': commit staged stuff with message in commit section amending last " commit " return no -function! magit#git_commit(mode) +function! s:mg_git_commit(mode) if ( a:mode == 'CF' ) - silent let git_result=magit#system("git commit --amend -C HEAD") + silent let git_result=<SID>mg_system("git commit --amend -C HEAD") 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 + magit#get_inline_help_line_nb('commit') - let [ret, commit_msg]=magit#search_block( + let commit_jump_line = 3 + <SID>mg_get_inline_help_line_nb('commit') + let [ret, commit_msg]=<SID>mg_search_block( \ [commit_section_pat_start, commit_jump_line], \ [ [commit_section_pat_end, -1] ], "") let amend_flag="" if ( a:mode == 'CA' ) let amend_flag=" --amend " endif - silent! let git_result=magit#system("git commit " . amend_flag . " --file - ", commit_msg) + silent! let git_result=<SID>mg_system("git commit " . amend_flag . " --file - ", commit_msg) endif if ( v:shell_error != 0 ) echoerr "Git error: " . git_result endif endfunction -" magit#select_file: select the whole diff file, relative to the current +" s:mg_select_file: select the whole diff file, relative to the current " cursor position " nota: if the cursor is not in a diff file when the function is called, this " function will fail " return: a List " @[0]: return value " @[1]: List of lines containing the patch for the whole file -function! magit#select_file() - return magit#search_block( - \ [g:magit_diff_re, 0], - \ [ [g:magit_diff_re, -1], - \ [g:magit_file_re, -1], +function! s:mg_select_file() + return <SID>mg_search_block( + \ [g:magit_file_re, 1], + \ [ [g:magit_file_re, -1], \ [g:magit_stash_re, -1], \ [g:magit_section_re, -2], \ [g:magit_bin_re, 0], @@ -463,65 +502,69 @@ function! magit#select_file() \ "") endfunction -" magit#select_file_header: select the upper diff header, relative to the current +" s:mg_select_file_header: select the upper diff header, relative to the current " cursor position " nota: if the cursor is not in a diff file when the function is called, this " function will fail " return: a List " @[0]: return value " @[1]: List of lines containing the diff header -function! magit#select_file_header() - return magit#search_block( - \ [g:magit_diff_re, 0], +function! s:mg_select_file_header() + return <SID>mg_search_block( + \ [g:magit_file_re, 1], \ [ [g:magit_hunk_re, -1] ], \ "") endfunction -" magit#select_hunk: select a hunk, from the current cursor position +" s:mg_select_hunk: select a hunk, from the current cursor position " nota: if the cursor is not in a hunk when the function is called, this " function will fail " return: a List " @[0]: return value " @[1]: List of lines containing the hunk -function! magit#select_hunk() - return magit#search_block( +function! s:mg_select_hunk() + return <SID>mg_search_block( \ [g:magit_hunk_re, 0], \ [ [g:magit_hunk_re, -1], - \ [g:magit_diff_re, -1], \ [g:magit_file_re, -1], \ [g:magit_stash_re, -1], \ [g:magit_section_re, -2], \ [g:magit_eof_re, 0 ] \ ], - \ g:magit_diff_re) + \ g:magit_file_re) endfunction -" magit#git_apply: helper function to stage a selection +" s:mg_git_apply: helper function to stage a selection " nota: when git fail (due to misformated patch for example), an error " message is raised. " param[in] selection: the text to stage. It must be a patch, i.e. a diff " header plus one or more hunks " return: no -function! magit#git_apply(selection) +function! s:mg_git_apply(selection) let selection = a:selection if ( selection[-1] !~ '^\s*$' ) let selection += [ '' ] endif - silent let git_result=magit#system("git apply --cached -", selection) + " when passing List to system as input, there are some rare and + " difficultly reproductable cases failing because of whitespaces + let tmp=tempname() + call writefile(selection, tmp) + silent let git_result=<SID>mg_system("git apply --cached - < " . tmp) if ( v:shell_error != 0 ) echoerr "Git error: " . git_result echoerr "Tried to aply this" echoerr string(a:selection) endif + call delete(tmp) endfunction -" magit#git_unapply: helper function to unstage a selection +" s:mg_git_unapply: helper function to unstage a selection " nota: when git fail (due to misformated patch for example), an error " message is raised. " param[in] selection: the text to stage. It must be a patch, i.e. a diff " header plus one or more hunks " return: no -function! magit#git_unapply(selection, mode) +function! s:mg_git_unapply(selection, mode) let cached_flag='' if ( a:mode == 'staged' ) let cached_flag=' --cached ' @@ -530,14 +573,26 @@ function! magit#git_unapply(selection, mode) if ( selection[-1] !~ '^\s*$' ) let selection += [ '' ] endif - silent let git_result=magit#system("git apply " . cached_flag . " --reverse - ", selection) + " when passing List to system as input, there are some rare and + " difficultly reproductable cases failing because of whitespaces + let tmp=tempname() + call writefile(selection, tmp) + silent let git_result=<SID>mg_system("git apply " . cached_flag . " --reverse - < " . tmp) if ( v:shell_error != 0 ) echoerr "Git error: " . git_result echoerr "Tried to unaply this" echoerr string(a:selection) endif + call delete(tmp) endfunction +" s:mg_get_section: helper function to get the current section, according to +" cursor position +" return: string of the current section, without decoration +function! s:mg_get_section() + let section_line=search(g:magit_section_re, "bnW") + return getline(section_line) +endfunction " }}} " {{{ User functions and commands @@ -561,26 +616,28 @@ function! magit#update_buffer() let l:winview = winsaveview() silent! %d - call magit#section_help('global') + call <SID>mg_get_info() + call <SID>mg_section_help('global') if ( s:magit_commit_mode != '' ) - call magit#get_commit_section() + call <SID>mg_get_commit_section() endif - call magit#get_staged() - call magit#get_unstaged() - call magit#get_stashes() + call <SID>mg_get_staged() + call <SID>mg_get_unstaged() + call <SID>mg_get_stashes() call winrestview(l:winview) if ( s:magit_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+magit#get_inline_help_line_nb('commit'), 0) + silent! call cursor(section_line+3+<SID>mg_get_inline_help_line_nb('commit'), 0) endif set filetype=magit endfunction +" magit#toggle_help: toggle inline help showing in magit buffer function! magit#toggle_help() let g:magit_show_help = ( g:magit_show_help == 0 ) ? 1 : 0 call magit#update_buffer() @@ -589,7 +646,7 @@ endfunction " magit#show_magit: prepare and show magit buffer " it also set local mappings to magit buffer function! magit#show_magit(orientation) - if ( magit#strip(system("git rev-parse --is-inside-work-tree")) != 'true' ) + if ( <SID>mg_strip(system("git rev-parse --is-inside-work-tree")) != 'true' ) echoerr "Magit must be started from a git repository" return endif @@ -622,40 +679,32 @@ function! magit#show_magit(orientation) execute "normal! gg" endfunction -" magit#get_section: helper function to get the current section, according to -" cursor position -" return: string of the current section, without decoration -function! magit#get_section() - let section_line=search(g:magit_section_re, "bnW") - return getline(section_line) -endfunction - " magit#stage_hunk: this function stage a single hunk, from the current " cursor position " INFO: in unstaged section, it stages the hunk, and in staged section, it " unstages the hunk " return: no function! magit#stage_hunk() - let [ret, header] = magit#select_file_header() + let [ret, header] = <SID>mg_select_file_header() if ( ret != 0 ) echoerr "Can't find diff header" return endif - let [ret, hunk] = magit#select_hunk() + let [ret, hunk] = <SID>mg_select_hunk() if ( ret == 0 ) let selection = header + hunk else - let [ret, selection] = magit#select_file() + let [ret, selection] = <SID>mg_select_file() if ( ret != 0 ) echoerr "Can't find diff header" return endif endif - let section=magit#get_section() + let section=<SID>mg_get_section() if ( section == g:magit_sections['unstaged'] ) - call magit#git_apply(selection) + call <SID>mg_git_apply(selection) elseif ( section == g:magit_sections['staged'] ) - call magit#git_unapply(selection, 'staged') + call <SID>mg_git_unapply(selection, 'staged') else echoerr "Must be in \"" . \ g:magit_sections['staged'] . "\" or \"" . @@ -670,16 +719,16 @@ endfunction " unstages the file " return: no function! magit#stage_file() - let [ret, selection] = magit#select_file() + let [ret, selection] = <SID>mg_select_file() if ( ret != 0 ) echoerr "Not in a file region" return endif - let section=magit#get_section() + let section=<SID>mg_get_section() if ( section == g:magit_sections['unstaged'] ) - call magit#git_apply(selection) + call <SID>mg_git_apply(selection) elseif ( section == g:magit_sections['staged'] ) - call magit#git_unapply(selection, 'staged') + call <SID>mg_git_unapply(selection, 'staged') else echoerr "Must be in \"" . \ g:magit_sections['staged'] . "\" or \"" . @@ -693,24 +742,24 @@ endfunction " INFO: only works in unstaged section " return: no function! magit#discard_hunk() - let [ret, header] = magit#select_file_header() + let [ret, header] = <SID>mg_select_file_header() if ( ret != 0 ) echoerr "Can't find diff header" return endif - let [ret, hunk] = magit#select_hunk() + let [ret, hunk] = <SID>mg_select_hunk() if ( ret == 0 ) let selection = header + hunk else - let [ret, selection] = magit#select_file() + let [ret, selection] = <SID>mg_select_file() if ( ret != 0 ) echoerr "Can't find diff header" return endif endif - let section=magit#get_section() + let section=<SID>mg_get_section() if ( section == g:magit_sections['unstaged'] ) - call magit#git_unapply(selection, 'unstaged') + call <SID>mg_git_unapply(selection, 'unstaged') else echoerr "Must be in \"" . \ g:magit_sections['unstaged'] . "\" section" @@ -721,7 +770,7 @@ endfunction " magit#ignore_file: this function add the file under cursor to .gitignore " FIXME: git diff adds some strange characters to end of line function! magit#ignore_file() - let [ret, selection] = magit#select_file() + let [ret, selection] = <SID>mg_select_file() if ( ret != 0 ) echoerr "Not in a file region" return @@ -729,7 +778,7 @@ function! magit#ignore_file() let ignore_file="" for line in selection if ( match(line, "^+++ ") != -1 ) - let ignore_file=magit#strip(substitute(line, '^+++ ./\(.*\)$', '\1', '')) + let ignore_file=<SID>mg_strip(substitute(line, '^+++ ./\(.*\)$', '\1', '')) break endif endfor @@ -737,7 +786,7 @@ function! magit#ignore_file() echoerr "Can not find file to ignore" return endif - call magit#append_file(magit#top_dir() . ".gitignore", [ ignore_file ] ) + call <SID>mg_append_file(<SID>mg_top_dir() . ".gitignore", [ ignore_file ] ) call magit#update_buffer() endfunction @@ -748,9 +797,9 @@ endfunction " 'CA'/'CF': if in commit section mode, call magit#git_commit, else just set " global state variable s:magit_commit_mode, function! magit#commit_command(mode) - let section=magit#get_section() + let section=<SID>mg_get_section() if ( a:mode == 'CF' ) - call magit#git_commit(a:mode) + call <SID>mg_git_commit(a:mode) else if ( section == g:magit_sections['commit_start'] ) if ( s:magit_commit_mode == '' ) @@ -759,7 +808,7 @@ function! magit#commit_command(mode) 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 magit#git_commit(s:magit_commit_mode) + call <SID>mg_git_commit(s:magit_commit_mode) let s:magit_commit_mode='' else let s:magit_commit_mode=a:mode diff --git a/test/addFile.vader b/test/addFile.vader index af02e2f47669d24f94147569bffdc01fd6020b03..a26f58c10207635636c207c33e275fef0304f019 100644 --- a/test/addFile.vader +++ b/test/addFile.vader @@ -1,14 +1,154 @@ Include: setup.inc -# add test -Execute (Add file): +Execute (Stage untracked file with magit#stage_file at file header): call Cd_test_sub() Magit - /untracked: bootstrap + call Search_file('unstaged') + call Cursor_position() + call magit#stage_file() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff) + +Execute (Unstage file with magit#stage_file at file header): + call Cd_test_sub() + Magit + call Search_file('staged') + call Cursor_position() + call magit#stage_file() + call Cd_test() + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_file): + call Cd_test_sub() + Magit + call Search_file('unstaged') + call Move_relative(+1) + call Cursor_position() + call magit#stage_file() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff) + +Execute (Unstage file with magit#stage_file): + call Cd_test_sub() + Magit + call Search_file('staged') call Move_relative(+1) + call Cursor_position() call magit#stage_file() call Cd_test() - let diff=Git_diff('staged', 'bootstrap') - call Expect_diff(g:test_dir . 'addFile_bootstrap.expect', diff) + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_hunk at file header): + call Cd_test_sub() + Magit + call Search_file('unstaged') + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff) + +Execute (Unstage file with magit#stage_hunk at file header): + call Cd_test_sub() + Magit + call Search_file('staged') + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_hunk on diff header): + call Cd_test_sub() + Magit + call Search_file('unstaged') + call Move_relative(+1) + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff) + +Execute (Unstage file with magit#stage_hunk on diff header): + call Cd_test_sub() + Magit + call Search_file('staged') + call Move_relative(+1) + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_hunk on start hunk): + call Cd_test_sub() + Magit + call Search_file('unstaged') + /^@@ + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_hunk_diff.expect', diff) + +Execute (Unstage file with magit#stage_hunk on diff header): + call Cd_test_sub() + Magit + call Search_file('staged') + /^@@ + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_hunk on end hunk): + call Cd_test_sub() + Magit + call Search_file('unstaged') + /^@@ + call Move_relative(+3) + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_hunk_diff.expect', diff) + +Execute (Unstage file with magit#stage_hunk on diff header): + call Cd_test_sub() + Magit + call Search_file('staged') + /^@@ + call Move_relative(+3) + call Cursor_position() + call magit#stage_hunk() + call Cd_test() + let diff=Git_status(Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_unstaged_status.expect', diff) + +Execute (Stage untracked file with magit#stage_file at file header): + call Cd_test_sub() + Magit + call Search_file('unstaged') + call Cursor_position() + call magit#stage_file() + call Cd_test() + let diff=Git_diff('staged', Get_filename()) + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_file_diff.expect', diff) + +Execute (Commit file): + call Cd_test_sub() + Magit + call magit#commit_command('CC') + put =['Add bootstrap file', '', 'Some description text', 'On multiple lines', '', 'With blanks'] + call magit#commit_command('CC') + call Cd_test() + let commit_msg=Git_commit_msg('HEAD') + call Expect_diff(g:test_script_dir . 'addFile/addFile_' . Get_safe_filename() . '_commit.expect', commit_msg) + Include: cleanup.inc diff --git a/test/addFile/addFile_books_models_py_commit.expect b/test/addFile/addFile_books_models_py_commit.expect new file mode 100644 index 0000000000000000000000000000000000000000..7fc69eebb7b482d390025f25c3b1d03ed7c2df75 --- /dev/null +++ b/test/addFile/addFile_books_models_py_commit.expect @@ -0,0 +1,62 @@ +Add bootstrap fileAdd bootstrap file + +Some description text +On multiple lines + +With blanks + + +diff --git books/models.py books/models.py +--- books/models.py ++++ books/models.py +@@ -1,5 +1,9 @@ + from django.db import models + ++import urllib2 as urllib ++from PIL import Image ++import io ++ + import isbn_search + + class User(models.Model): +@@ -20,20 +24,26 @@ class BookManager(models.Manager): + eisbn = product.eisbn, + author = product.author, + title = product.title, +- edition = product.edition ++ edition = product.edition, + ) ++ if product.cover_url is not '': ++ cover_img_bin = urllib.urlopen(product.cover_url) ++ cover_img_file = Image.open(io.BytesIO(cover_img_bin.read())) ++ book.cover_img.save("cover.jpg", cover_img_file) + return book + ++def upload_path(book, filename): ++ return 'covers/%s/%s' % (book.isbn, filename) ++ + class Book(models.Model): + isbn = models.CharField(max_length=10, unique=True) +- eisbn = models.CharField(max_length=13, blank=True) ++ eisbn = models.CharField(max_length=13, blank=True, null=True) + title = models.CharField(max_length=200) + author = models.CharField(max_length=200) +- edition = models.CharField(max_length=200, blank=True) +- cover = models.ImageField(upload_to='covers', blank=True) ++ edition = models.CharField(max_length=200, blank=True, null=True) ++ cover_img = models.ImageField(upload_to=upload_path) + def __unicode__(self): + return u'[%s] "%s" by %s' % (self.isbn, self.title, self.author,) +- + objects = BookManager() + + +@@ -47,7 +57,7 @@ class Book_copy(models.Model): + class Borrowing(models.Model): + book_copy = models.ForeignKey(Book_copy) + borrower = models.ForeignKey(User) +- borrow_date = models.DateTimeField('date published') ++ date = models.DateTimeField(auto_now_add=True) + def __unicode__(self): + return u'%s loaned by %s since %s' % (self.book_copy.book, self.borrower, self.borrow_date,) + diff --git a/test/addFile/addFile_books_models_py_file_diff.expect b/test/addFile/addFile_books_models_py_file_diff.expect new file mode 100644 index 0000000000000000000000000000000000000000..78c9eb694492d1b406b7f891742d69b11d13883b --- /dev/null +++ b/test/addFile/addFile_books_models_py_file_diff.expect @@ -0,0 +1,54 @@ +diff --git books/models.py books/models.py +--- books/models.py ++++ books/models.py +@@ -1,5 +1,9 @@ + from django.db import models + ++import urllib2 as urllib ++from PIL import Image ++import io ++ + import isbn_search + + class User(models.Model): +@@ -20,20 +24,26 @@ class BookManager(models.Manager): + eisbn = product.eisbn, + author = product.author, + title = product.title, +- edition = product.edition ++ edition = product.edition, + ) ++ if product.cover_url is not '': ++ cover_img_bin = urllib.urlopen(product.cover_url) ++ cover_img_file = Image.open(io.BytesIO(cover_img_bin.read())) ++ book.cover_img.save("cover.jpg", cover_img_file) + return book + ++def upload_path(book, filename): ++ return 'covers/%s/%s' % (book.isbn, filename) ++ + class Book(models.Model): + isbn = models.CharField(max_length=10, unique=True) +- eisbn = models.CharField(max_length=13, blank=True) ++ eisbn = models.CharField(max_length=13, blank=True, null=True) + title = models.CharField(max_length=200) + author = models.CharField(max_length=200) +- edition = models.CharField(max_length=200, blank=True) +- cover = models.ImageField(upload_to='covers', blank=True) ++ edition = models.CharField(max_length=200, blank=True, null=True) ++ cover_img = models.ImageField(upload_to=upload_path) + def __unicode__(self): + return u'[%s] "%s" by %s' % (self.isbn, self.title, self.author,) +- + objects = BookManager() + + +@@ -47,7 +57,7 @@ class Book_copy(models.Model): + class Borrowing(models.Model): + book_copy = models.ForeignKey(Book_copy) + borrower = models.ForeignKey(User) +- borrow_date = models.DateTimeField('date published') ++ date = models.DateTimeField(auto_now_add=True) + def __unicode__(self): + return u'%s loaned by %s since %s' % (self.book_copy.book, self.borrower, self.borrow_date,) + diff --git a/test/addFile/addFile_books_models_py_hunk_diff.expect b/test/addFile/addFile_books_models_py_hunk_diff.expect new file mode 100644 index 0000000000000000000000000000000000000000..4d9138a938c57a7b32e49aa6e00289063c97ab00 --- /dev/null +++ b/test/addFile/addFile_books_models_py_hunk_diff.expect @@ -0,0 +1,13 @@ +diff --git books/models.py books/models.py +--- books/models.py ++++ books/models.py +@@ -1,5 +1,9 @@ + from django.db import models + ++import urllib2 as urllib ++from PIL import Image ++import io ++ + import isbn_search + + class User(models.Model): diff --git a/test/addFile/addFile_books_models_py_unstaged_status.expect b/test/addFile/addFile_books_models_py_unstaged_status.expect new file mode 100644 index 0000000000000000000000000000000000000000..419e4688776dc934c2a0b47cbef082044814aae4 --- /dev/null +++ b/test/addFile/addFile_books_models_py_unstaged_status.expect @@ -0,0 +1 @@ + M books/models.py diff --git a/test/addFile/addFile_bootstrap_commit.expect b/test/addFile/addFile_bootstrap_commit.expect new file mode 100644 index 0000000000000000000000000000000000000000..7056a6d61aac4a7983514e51ac2c6427e31950e0 --- /dev/null +++ b/test/addFile/addFile_bootstrap_commit.expect @@ -0,0 +1,16 @@ +Add bootstrap fileAdd bootstrap file + +Some description text +On multiple lines + +With blanks + + +diff --git bootstrap bootstrap +new file mode 100755 +--- /dev/null ++++ bootstrap +@@ -0,0 +1,3 @@ ++pip install --user python-amazon-simple-product-api django ++python manage.py migrate ++python manage.py makemigrations books diff --git a/test/addFile_bootstrap.expect b/test/addFile/addFile_bootstrap_file_diff.expect similarity index 100% rename from test/addFile_bootstrap.expect rename to test/addFile/addFile_bootstrap_file_diff.expect diff --git a/test/addFile/addFile_bootstrap_hunk_diff.expect b/test/addFile/addFile_bootstrap_hunk_diff.expect new file mode 100644 index 0000000000000000000000000000000000000000..76e066c4387ad7187987eb805fae4a31d177c8e3 --- /dev/null +++ b/test/addFile/addFile_bootstrap_hunk_diff.expect @@ -0,0 +1,8 @@ +diff --git bootstrap bootstrap +new file mode 100755 +--- /dev/null ++++ bootstrap +@@ -0,0 +1,3 @@ ++pip install --user python-amazon-simple-product-api django ++python manage.py migrate ++python manage.py makemigrations books diff --git a/test/addFile/addFile_bootstrap_unstaged_status.expect b/test/addFile/addFile_bootstrap_unstaged_status.expect new file mode 100644 index 0000000000000000000000000000000000000000..b4b587b9dec49ff2da0c517e2a5cb1020a090921 --- /dev/null +++ b/test/addFile/addFile_bootstrap_unstaged_status.expect @@ -0,0 +1 @@ +?? bootstrap diff --git a/test/ignoreFile.vader b/test/ignoreFile.vader new file mode 100644 index 0000000000000000000000000000000000000000..8287d314bfccf3f3accfefefd65790c5e06b21d8 --- /dev/null +++ b/test/ignoreFile.vader @@ -0,0 +1,20 @@ +Include: setup.inc + +Execute (Ignore untracked file): + call Cd_test_sub() + Magit + call Search_file('unstaged') + call Cursor_position() + call magit#ignore_file() + call Cd_test() + let diff=Git_diff('unstaged', '.gitignore') + call Expect_diff(g:test_script_dir . 'ignoreFile/ignoreFile_' . Get_safe_filename() . '_ignore_diff.expect', diff) + call magit#update_buffer() + Assert (Search_file('unstaged') == 0), $VIMAGIT_TEST_FILENAME . 'should be ignored' + call search('^modified: .gitignore$') + call magit#discard_hunk() + call magit#update_buffer() + Assert (Search_file('unstaged') != 0), $VIMAGIT_TEST_FILENAME . 'should not be ignored anymore' + + +Include: cleanup.inc diff --git a/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect b/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect new file mode 100644 index 0000000000000000000000000000000000000000..ac7158716e5ea0e44d80c4a6d5a691c89a081258 --- /dev/null +++ b/test/ignoreFile/ignoreFile_bootstrap_ignore_diff.expect @@ -0,0 +1,9 @@ +diff --git .gitignore .gitignore +--- .gitignore ++++ .gitignore +@@ -1,3 +1,4 @@ + *.py[co] + /db.sqlite3 + /books.cfg ++bootstrap +\ No newline at end of file diff --git a/test/run.sh b/test/run.sh index 96d7578bd927b89e7dfefc9f9f27aa9dfbb3ae9a..24a2d162fbf7fc0be84192fae681ca2cff52ac6e 100755 --- a/test/run.sh +++ b/test/run.sh @@ -1,7 +1,7 @@ set -xe -if [[ $# -ne 3 ]]; then - echo "Usage $0 VIMAGIT_PATH VADER_PATH TEST_PATH" +if [[ $# -ne 4 ]]; then + echo "Usage $0 VIMAGIT_PATH VADER_PATH TEST_PATH VIM_VERSION" exit 1 fi @@ -12,21 +12,55 @@ python -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1]) export VIMAGIT_PATH=$(prealpath $1) export VADER_PATH=$(prealpath $2) export TEST_PATH=$(prealpath $3) -export TEST_SUB_PATH=$(prealpath $TEST_PATH/$TEST_SUB_PATH) +export VIM_VERSION=$4 -if [[ ! ( -d $VIMAGIT_PATH && -d $VADER_PATH && -d $TEST_PATH && -d $TEST_SUB_PATH) ]]; then - echo "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH' '$TEST_SUB_PATH'" +if [[ ! ( -d $VIMAGIT_PATH && -d $VADER_PATH && -d $TEST_PATH ) ]]; then + echo "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH'" exit 1 fi +pushd $TEST_PATH +git config --local user.email 'tester@vimagit.org' +git config --local user.name 'vimagit tester' export TEST_HEAD_SHA1='6efcd49' +popd -vim -Nu <(cat << EOF -filetype off -set rtp-=~/.vim -set rtp-=~/.vim/after -set rtp+=$VIMAGIT_PATH -set rtp+=$VADER_PATH -filetype plugin indent on -syntax enable -EOF) -c "Vader! $VIMAGIT_PATH/test/*" +if [ "$VIM_VERSION" = 'neovim' ]; then + VIM=nvim +elif [ "$VIM_VERSION" = 'macvim' ]; then + VIM=mvim +else + VIM=vim +fi + +echo 'Vim version' +$VIM --version + +source $VIMAGIT_PATH/test/test.config + +for script in ${!test_scripts[@]}; do + + for filename in ${test_scripts[$script]}; do + for test_path in ${test_paths[@]}; do + export TEST_SUB_PATH=$(prealpath $TEST_PATH/$test_path) + export VIMAGIT_TEST_FILENAME=$filename + + for i in 1 0; do + export VIMAGIT_TEST_FROM_EOL=$i + + echo "Test $script with $filename from path $TEST_SUB_PATH and from $([ $i -eq 1 ] && echo "end" || echo "start") of line" + + $VIM -Nu <(cat << EOF + filetype off + set rtp-=~/.vim + set rtp-=~/.vim/after + set rtp+=$VIMAGIT_PATH + set rtp+=$VADER_PATH + filetype plugin indent on + syntax enable +EOF) -c "Vader! $VIMAGIT_PATH/test/$script" + + done + done + done +done diff --git a/test/setup.inc b/test/setup.inc index b9a8785bd90ba51655af7aa64dc726ba98e97304..fa73d19e98955ada5fb534eb1ac313fa4a6e6d56 100644 --- a/test/setup.inc +++ b/test/setup.inc @@ -1,5 +1,5 @@ Execute (setup): source $VIMAGIT_PATH/test/utils.vim - cd $TEST_PATH + call Cd_test() call system("git reset " . $TEST_HEAD_SHA1 . "~1") - cd $TEST_SUB_PATH + call Cd_test_sub() diff --git a/test/test.config b/test/test.config new file mode 100644 index 0000000000000000000000000000000000000000..f6c49aa2bfb1fd80185e7bd7f0c755caaf2032b9 --- /dev/null +++ b/test/test.config @@ -0,0 +1,2 @@ +declare -a test_paths=(./ ./books/templates/) +declare -A test_scripts=( [addFile.vader]='bootstrap books/models.py' [ignoreFile.vader]='bootstrap' ) diff --git a/test/utils.vim b/test/utils.vim index c8f54f78a05458f31bbed3846b0ca640c0c10cd2..410d7f56c8f80d4e503fc8ec4073c0419e7b0fbb 100644 --- a/test/utils.vim +++ b/test/utils.vim @@ -1,42 +1,137 @@ -if ( ! ( exists("$VIMAGIT_PATH") && exists("$VADER_PATH") && exists("$TEST_PATH") ) -\ && ( ! ( isdirectory("$VIMAGIT_PATH") && isdirectory("$VADER_PATH") && isdirectory("$TEST_PATH") ) ) ) - echoerr "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH'" +"This file contains utility functions for tests, and wrapper around +"environment variables. Env var are the way found to run the same test with +"different configurations. + +" These environment variables must be exported from bash +" $VIMAGIT_PATH: vimagit plugin root path +" $VADER_PATH: vader plugin root path +" $TEST_PATH: git dir used for test root path +" $TEST_SUB_PATH: git dir used for test subdir path (we want to test vimagit commands from subdirs) +" $VIMAGIT_TEST_FILENAME: filename we test (stage/unstage/ignore...) +" $VIMAGIT_TEST_FROM_EOL: change cursor initial position before a command test see Cursor_position() +" Optionals +" $VIMAGIT_CRAFT_EXPECT: see Is_crafting() and Expect_diff() +if ( ! ( exists("$VIMAGIT_PATH") && exists("$VADER_PATH") && exists("$TEST_PATH") && exists("$TEST_SUB_PATH") ) +\ && ( ! ( isdirectory("$VIMAGIT_PATH") && isdirectory("$VADER_PATH") && isdirectory("$TEST_PATH") && isdirectory("$TEST_PATH"."/"."$TEST_SUB_PATH")) ) ) + echoerr "can't access to one of them '$VIMAGIT_PATH' '$VADER_PATH' '$TEST_PATH' '$TEST_SUB_PATH'" +endif + +if ( ! ( exists('$VIMAGIT_TEST_FILENAME') ) ) + echoerr "env VIMAGIT_TEST_FILENAME is not set" endif -let g:test_dir = $VIMAGIT_PATH . '/test/' +" directory containing test scripts and golden files +let g:test_script_dir = $VIMAGIT_PATH . '/test/' +" regex to discard sha1 lines in diff, commit, ... git messages +" we don't want them because they change at each run, we can't put them in +" golden files +let g:index_regex = "\"^index [[:xdigit:]]\\{7\\}\\.\\.[[:xdigit:]]\\{7\\}\"" + +" this method is used to generate gold files +" when envvar VIMAGIT_CRAFT_EXPECT is set, we don't check diff with gold +" files, we create them. +function! Is_crafting() + return exists("$VIMAGIT_CRAFT_EXPECT") ? $VIMAGIT_CRAFT_EXPECT : 0 +endfunction + +" helper function to move cursor few lines up or down function! Move_relative(nb_lines) call cursor(line('.') + a:nb_lines, 0) endfunction +" wrapper to execute command, echoerr'ing complete message in case of error +function! Git_cmd(...) + let ret=call('system', a:000) + if ( v:shell_error != 0 ) + echoerr "Error:\ncommand:\n" . join(a:000, "\n") . "\nret:\n" . ret + endif + return ret +endfunction + +" helper function to get a commit message (without sha1) +function! Git_commit_msg(sha1) + let commit_cmd="git show --src-prefix='' --dst-prefix='' --format='%s%B' " . a:sha1 . + \ " | \\grep -v " . g:index_regex + return Git_cmd(commit_cmd) +endfunction + +" helper function to get status of a given file +function! Git_status(file) + call Cd_test() + let status_cmd="git status --porcelain -- " . a:file + let status=Git_cmd(status_cmd) + call Cd_test_sub() + return status +endfunction + +" helper function to get the diff of a file, in staged or unstaged mode function! Git_diff(state, file) let staged_flag = ( a:state == 'staged' ) ? ' --staged ' : '' let diff_cmd="git diff --no-color --no-ext-diff --src-prefix='' --dst-prefix='' " . \ staged_flag . " -- " . a:file . - \ " | \\grep -v \"^index [[:xdigit:]]\\{7\\}\\.\\.[[:xdigit:]]\\{7\\}\"" - let diff=system(diff_cmd) - if ( v:shell_error != 0 ) - echoerr "git diff: " . diff - endif - return diff + \ " | \\grep -v " . g:index_regex + return Git_cmd(diff_cmd) endfunction +" helper function to: +" - check if output is conform to gold file if VIMAGIT_CRAFT_EXPECT == 0 +" - generate gold file with output if VIMAGIT_CRAFT_EXPECT == 0 function! Expect_diff(gold_file, test_diff) - let diff=system("diff " . a:gold_file . " - ", a:test_diff) - if ( v:shell_error != 0 ) - echoerr "diff: " . diff + if ( Is_crafting() == 0 ) + let diff_cmd="diff " . a:gold_file . " - " + let diff=system(diff_cmd, a:test_diff) + if ( v:shell_error != 0 ) + echoerr "diff: " . diff + echoerr "diffcmd: " . diff_cmd + endif + return v:shell_error + else + let ret=writefile(split(a:test_diff, '\n'), a:gold_file, "w") + if ( ret != 0 ) + echoerr 'Error while writing ' . a:gold_file + endif + endif +endfunction + +" we want to test every magit command with cursor at the begenning and at the +" end of the line before calling the command +function! Cursor_position() + if ( exists("$VIMAGIT_TEST_FROM_EOL") ? $VIMAGIT_TEST_FROM_EOL : 0 ) + call cursor(0, virtcol('$')) + else + call cursor(0, 1) endif - return v:shell_error endfunction +" set cwd to vimagit path function! Cd_vimagit() cd $VIMAGIT_PATH endfunction +" set cwd to git test directory root function! Cd_test() cd $TEST_PATH endfunction +" set cwd to git test directory subdir (see $TEST_SUB_PATH) function! Cd_test_sub() cd $TEST_SUB_PATH endfunction + +" search a file header in magit buffer, for example 'added: bootstrap', move +" the cursor and return the line +function! Search_file(mode) + call search(substitute(a:mode, '.*', '\u\0', '') . ' changes') + return search("^.*: " . $VIMAGIT_TEST_FILENAME) +endfunction + +" get the filename we curently test +function! Get_filename() + return $VIMAGIT_TEST_FILENAME +endfunction + +" get a safe to use string of filename we curently test (for golden files) +function! Get_safe_filename() + return substitute($VIMAGIT_TEST_FILENAME, '[/.]', '_', 'g') +endfunction