Skip to content

Commit

Permalink
Merge pull request #40 from jreybert/next
Browse files Browse the repository at this point in the history
release 1.4.2
  • Loading branch information
jreybert committed Nov 10, 2015
2 parents 0036bef + e20670f commit 19de192
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 92 deletions.
69 changes: 47 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ Take a look at [TL;DR](#tldr) to start using it immediatly.
* [ ] 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: !

More to come:
* Vizualize and checkout branches.
* Make vimagit more efficient for huge repositories, with a lot of diffs.
* Add a push function, taking care if needed about the remote repository and branch.
* Handle commit fixup! and squash!, with a smart git log popup.
* Handle multiple git repositories within one vim session.
* Stage multiple hunks or file by visually selecting them.
* Go through history, cherry-pick changes.
* Vizualize and checkout branches.
* Something is missing? Open an [issue](https://github.com/jreybert/vimagit/issues/new)!

> Why should I use vimagit, there are already plethora git plugins for vim?
Expand Down Expand Up @@ -92,6 +97,18 @@ There are 5 sections:
* only lines starting with a + sign can be modified
* no line can be deleted

### Visual selection

It is possible to stage part of hunk, by different ways:
* By visually selecting some lines, then staging the selection with **S**.
* By marking some lines "to be staged" with **M**, then staging these selected lines with **S**.
* Staging individual lines with **L**.

Visual selection and marked lines have some limitations for the moment:
* It only work for "staging", not for "unstaging".
* Selection/marks must be within a single hunk.
* Marks not within the hunk currently staged are lost during stage process magit buffer refresh.

### Commands

#### magit#show_magit()
Expand All @@ -104,7 +121,7 @@ It takes 3 parameters:
- 'h', curent window is split horizontally, and magit is displayed in
new buffer
- 'c', magit is displayed in current buffer
* show_all_files: define is file diffs are shown by default for this session
* show_all_files: define how file diffs are shown by default for this session
(see [g:magit_default_show_all_files](#gmagit_default_show_all_files))
* foldlevel: set default magit buffer foldlevel for this session
(see [g:magit_default_fold_level](#gmagit_default_fold_level))
Expand All @@ -120,72 +137,72 @@ For each mapping, user can redefine the behavior with its own mapping. Each vari

Following mappings are broadly set, and are applied in all vim buffers.

**\<Leader>M**
##### \<Leader>M
Open Magit buffer

#### Local mappings

Following mappings are set locally, for magit buffer only, in normal mode.

**Enter**,**\<CR\>**
##### Enter,\<CR\>
* All files are folded by default. To see the changes in a file, move cursor to the filename line, and press Enter. You can close the changes display retyping Enter.

**zo,zO**
##### zo,zO
* Typing zo on a file will unhide its diffs.

**zc,zC**
##### zc,zC
* Typing zc on a file will hide its diffs.

**S**
##### 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.
* If some lines in the hunk are selected (using **v**), stage only visual selected lines (only works for staging).
* If some lines in the hunk are marked (using **M**), stage only marked lines (only works for staging).
* 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**
##### 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.

**L**
##### L
* Stage the line under the cursor.

**M**
##### M
* Mark the line under the cursor "to be staged".
* If some lines in the hunk are selected (using **v**), mark selected lines "to be staged".
* To staged marked lines in a hunk, move cursor to this hunk and press **S**.

**DDD**
##### 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.

**CC**
##### 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.

**:w<cr>**
##### :w<cr>
* If in commit section, commit the all staged changes in commit mode previously set.

**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.

**CF**
##### CF
* Amend the staged changes into the previous commit, without modifying previous commit message.

**I**
##### I
* Add the file under the cursor in .gitgnore

**R**
##### R
* Refresh magit buffer

**q**
##### q
* Close the magit buffer

**h**
##### h
* Toggle help showing in magit buffer

### Options
Expand All @@ -206,10 +223,11 @@ To disable chatty inline help in magit buffer (default 1)
#### g:magit_default_show_all_files

When this variable is set to 0, all diff files are hidden by default.
When this variable is set to 1, all diff files are shown by default.
Default value is 0.
When this variable is set to 1, all diff for modified files are shown by default.
When this variable is set to 2, all diff for all files are shown by default.
Default value is 1.
NB: for repository with large number of differences, display may be slow.
> let g:magit_default_show_all_files=[01]
> let g:magit_default_show_all_files=[012]
#### g:magit_default_fold_level

Expand All @@ -220,6 +238,13 @@ When set to 2, filenames and hunks are unfolded.
Default value is 1.
> let g:magit_default_fold_level=[012]
#### g:magit_default_sections

With this variable, the user is able to choose which sections are displayed in magit
buffer, and in which order.
Default value:
> let g:magit_default_sections = ['info', 'global_help', 'commit', 'staged', 'unstaged']
#### g:magit_warning_max_lines

This variable is the maximum number of diff lines that vimagit will display
Expand Down
41 changes: 41 additions & 0 deletions autoload/magit/git.vim
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,47 @@ function! magit#git#git_dir()
return s:magit_git_dir
endfunction

" magit#git#git_diff: helper function to get diff of a file
" nota: when git fail (due to misformated patch for example), an error
" message is raised.
" param[in] filemane: it must be quoted if it contains spaces
" param[in] status: status of the file (see g:magit_git_status_code)
" param[in] mode: can be staged or unstaged
function! magit#git#git_diff(filename, status, mode)
let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
let git_cmd="git diff --no-ext-diff " . staged_flag .
\ "--no-color --patch -- " . dev_null . " "
\ .a:filename
silent let diff_list=magit#utils#systemlist(git_cmd)
if ( empty(diff_list) )
echohl WarningMsg
echom "diff command \"" . diff_cmd . "\" returned nothing"
echohl None
throw 'diff error'
endif
return diff_list
endfunction

" magit#git#git_sub_summary: helper function to get diff of a submodule
" nota: when git fail (due to misformated patch for example), an error
" message is raised.
" param[in] filemane: it must be quoted if it contains spaces
" param[in] mode: can be staged or unstaged
function! magit#git#git_sub_summary(filename, mode)
let staged_flag = ( a:mode == 'staged' ) ? " --cached " : " --files "
let git_cmd="git submodule summary " . staged_flag . " HEAD "
\ .a:filename
silent let diff_list=magit#utils#systemlist(git_cmd)
if ( empty(diff_list) )
echohl WarningMsg
echom "diff command \"" . diff_cmd . "\" returned nothing"
echohl None
throw 'diff error'
endif
return diff_list
endfunction

" magit#git#git_add: helper function to add a whole file
" nota: when git fail (due to misformated patch for example), an error
" message is raised.
Expand Down
86 changes: 68 additions & 18 deletions autoload/magit/state.vim
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ function! magit#state#toggle_file_visible() dict
let self.visible = ( self.visible == 0 ) ? 1 : 0
endfunction

" magit#state#init_file_visible: init file visible status, among several conditions
function! magit#state#init_file_visible() dict
if ( !self.new )
return self.is_visible()
else
if ( self.status == 'M' || b:magit_default_show_all_files > 1 )
call self.set_visible(b:magit_default_show_all_files)
endif
return self.is_visible()
endif
endfunction

" magit#state#is_file_dir: file getter function
" return 1 if current file is a directory, 0 otherwise
function! magit#state#is_file_dir() dict
Expand Down Expand Up @@ -63,14 +75,17 @@ let s:hunk_template = {
" s:diff_template: template for diff object (nested in s:file_template)
" WARNING: this variable must be deepcopy()'ied
let s:diff_template = {
\ 'len': 0,
\ 'header': [],
\ 'hunks': [s:hunk_template],
\}

" s:file_template: template for file object
" WARNING: this variable must be deepcopy()'ied
let s:file_template = {
\ 'new': 1,
\ 'exists': 0,
\ 'visible': 0,
\ 'filename': '',
\ 'status': '',
\ 'empty': 0,
Expand All @@ -82,6 +97,7 @@ let s:file_template = {
\ 'is_dir': function("magit#state#is_file_dir"),
\ 'is_visible': function("magit#state#is_file_visible"),
\ 'set_visible': function("magit#state#set_file_visible"),
\ 'init_visible': function("magit#state#init_file_visible"),
\ 'toggle_visible': function("magit#state#toggle_file_visible"),
\ 'must_be_added': function("magit#state#must_be_added"),
\ 'get_header': function("magit#state#file_get_header"),
Expand All @@ -101,7 +117,6 @@ function! magit#state#get_file(mode, filename, ...) dict
let create = ( a:0 == 1 ) ? a:1 : 0
if ( file_exists == 0 && create == 1 )
let self.dict[a:mode][a:filename] = deepcopy(s:file_template)
let self.dict[a:mode][a:filename].visible = b:magit_default_show_all_files
let self.dict[a:mode][a:filename].filename = a:filename
elseif ( file_exists == 0 && create == 0 )
throw 'file_doesnt_exists'
Expand All @@ -125,42 +140,65 @@ function! magit#state#file_get_filename_header() dict
endif
endfunction

function! magit#state#check_max_lines(file) dict
let total_lines = self.nb_diff_lines + a:file.diff.len
if ( total_lines > g:magit_warning_max_lines && b:magit_warning_max_lines_answered == 0 )
echohl WarningMsg
let ret = input("There are " . total_lines . " diff lines to display. Do you want to display all diffs? y(es) / N(o) : ", "")
echohl None
let b:magit_warning_max_lines_answered = 1
if ( ret !~? '^y\%(e\%(s\)\?\)\?$' )
call a:file.set_visible(0)
let a:file.diff.len = 0
let b:magit_default_show_all_files = 0
return 1
endif
endif
return 0
endfunction

" magit#state#add_file: method to add a file with all its
" properties (filename, exists, status, header and hunks)
" param[in] mode: can be staged or unstaged
" param[in] status: one character status code of the file (AMDRCU?)
" param[in] filename: filename
function! magit#state#add_file(mode, status, filename, depth) dict
let dev_null = ( a:status == '?' ) ? " /dev/null " : " "
let staged_flag = ( a:mode == 'staged' ) ? " --staged " : " "
let diff_cmd="git diff --no-ext-diff " . staged_flag .
\ "--no-color --patch -- " . dev_null . " "
\ . magit#utils#add_quotes(a:filename)
let diff_list=magit#utils#systemlist(diff_cmd)
if ( empty(diff_list) )
echoerr "diff command \"" . diff_cmd . "\" returned nothing"
endif
let file = self.get_file(a:mode, a:filename, 1)
let file.exists = 1

let file.status = a:status
let file.depth = a:depth

" discard previous diff
let file.diff = deepcopy(s:diff_template)

if ( a:status == '?' && getftype(a:filename) == 'link' )
let file.status = 'L'
let file.symlink = resolve(a:filename)
let file.diff.hunks[0].header = 'New symbolic link file'
elseif ( magit#utils#is_submodule(a:filename))
let file.status = 'S'
let file.submodule = 1
if ( !file.is_visible() )
return
endif
let diff_list=magit#git#git_sub_summary(magit#utils#add_quotes(a:filename),
\ a:mode)
let file.diff.len = len(diff_list)

if ( self.check_max_lines(file) != 0 )
return
endif

let file.diff.hunks[0].header = ''
let file.diff.hunks[0].lines = diff_list
if ( file.is_visible() )
let self.nb_diff_lines += len(diff_list)
endif
let self.nb_diff_lines += file.diff.len
elseif ( a:status == '?' && isdirectory(a:filename) == 1 )
let file.status = 'N'
let file.dir = 1
if ( !file.is_visible() )
return
endif
for subfile in magit#utils#ls_all(a:filename)
call self.add_file(a:mode, a:status, subfile, a:depth + 1)
endfor
Expand All @@ -172,14 +210,25 @@ function! magit#state#add_file(mode, status, filename, depth) dict
let file.binary = 1
let file.diff.hunks[0].header = 'Binary file'
else
if ( !file.init_visible() )
return
endif
let line = 0
" match(
while ( line < len(diff_list) && diff_list[line] !~ "^@.*" )
let diff_list=magit#git#git_diff(magit#utils#add_quotes(a:filename),
\ a:status, a:mode)
let file.diff.len = len(diff_list)

if ( self.check_max_lines(file) != 0 )
return
endif

while ( line < file.diff.len && diff_list[line] !~ "^@.*" )
call add(file.diff.header, diff_list[line])
let line += 1
endwhile

if ( line < len(diff_list) )
if ( line < file.diff.len )
let hunk = file.diff.hunks[0]
let hunk.header = diff_list[line]

Expand All @@ -193,10 +242,9 @@ function! magit#state#add_file(mode, status, filename, depth) dict
call add(hunk.lines, diff_line)
endfor
endif
if ( file.is_visible() )
let self.nb_diff_lines += len(diff_list)
endif
let self.nb_diff_lines += file.diff.len
endif

endfunction

" magit#state#update: update self.dict
Expand All @@ -209,6 +257,7 @@ function! magit#state#update() dict
for diff_dict_mode in values(self.dict)
for file in values(diff_dict_mode)
let file.exists = 0
let file.new = 0
" always discard previous diff
let file.diff = deepcopy(s:diff_template)
endfor
Expand Down Expand Up @@ -283,6 +332,7 @@ let magit#state#state = {
\ 'get_files': function("magit#state#get_files"),
\ '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"),
\ 'update': function("magit#state#update"),
\ 'dict': { 'staged': {}, 'unstaged': {}},
\ }
Expand Down
Loading

0 comments on commit 19de192

Please sign in to comment.