-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master'
- Loading branch information
Showing
5 changed files
with
354 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
" Constructs a Differ object that is still unbound. To initialize the object | ||
" with data, `Init(from, to)` needs to be invoked on that object. | ||
function! linediff#differ#New(sign_name, sign_number) | ||
let differ = { | ||
\ 'original_buffer': -1, | ||
\ 'diff_buffer': -1, | ||
\ 'filetype': '', | ||
\ 'from': -1, | ||
\ 'to': -1, | ||
\ 'sign_name': a:sign_name, | ||
\ 'sign_number': a:sign_number, | ||
\ 'sign_text': a:sign_number.'-', | ||
\ 'is_blank': 1, | ||
\ 'other_differ': {}, | ||
\ | ||
\ 'Init': function('linediff#differ#Init'), | ||
\ 'IsBlank': function('linediff#differ#IsBlank'), | ||
\ 'Reset': function('linediff#differ#Reset'), | ||
\ 'Lines': function('linediff#differ#Lines'), | ||
\ 'CreateDiffBuffer': function('linediff#differ#CreateDiffBuffer'), | ||
\ 'SetupDiffBuffer': function('linediff#differ#SetupDiffBuffer'), | ||
\ 'CloseDiffBuffer': function('linediff#differ#CloseDiffBuffer'), | ||
\ 'UpdateOriginalBuffer': function('linediff#differ#UpdateOriginalBuffer'), | ||
\ 'PossiblyUpdateOtherDiffer': function('linediff#differ#PossiblyUpdateOtherDiffer'), | ||
\ 'SetupSigns': function('linediff#differ#SetupSigns') | ||
\ } | ||
|
||
exe "sign define ".differ.sign_name." text=".differ.sign_text." texthl=Search" | ||
|
||
return differ | ||
endfunction | ||
|
||
" Sets up the Differ with data from the argument list and from the current | ||
" file. | ||
function! linediff#differ#Init(from, to) dict | ||
let self.original_buffer = bufnr('%') | ||
let self.filetype = &filetype | ||
let self.from = a:from | ||
let self.to = a:to | ||
|
||
call self.SetupSigns() | ||
|
||
let self.is_blank = 0 | ||
endfunction | ||
|
||
" Returns true if the differ is blank, which means not initialized with data. | ||
function! linediff#differ#IsBlank() dict | ||
return self.is_blank | ||
endfunction | ||
|
||
" Resets the differ to the blank state. Invoke `Init(from, to)` on it later to | ||
" make it usable again. | ||
function! linediff#differ#Reset() dict | ||
call self.CloseDiffBuffer() | ||
|
||
let self.original_buffer = -1 | ||
let self.diff_buffer = -1 | ||
let self.filetype = '' | ||
let self.from = -1 | ||
let self.to = -1 | ||
let self.other_differ = {} | ||
|
||
exe "sign unplace ".self.sign_number."1" | ||
exe "sign unplace ".self.sign_number."2" | ||
|
||
let self.is_blank = 1 | ||
endfunction | ||
|
||
" Extracts the relevant lines from the original buffer and returns them as a | ||
" list. | ||
function! linediff#differ#Lines() dict | ||
return getbufline(self.original_buffer, self.from, self.to) | ||
endfunction | ||
|
||
" Creates the buffer used for the diffing and connects it to this differ | ||
" object. | ||
function! linediff#differ#CreateDiffBuffer(edit_command) dict | ||
let lines = self.Lines() | ||
let temp_file = tempname() | ||
|
||
exe a:edit_command . " " . temp_file | ||
call append(0, lines) | ||
normal! Gdd | ||
set nomodified | ||
|
||
let self.diff_buffer = bufnr('%') | ||
call self.SetupDiffBuffer() | ||
|
||
diffthis | ||
endfunction | ||
|
||
" Sets up the temporary buffer's filetype and statusline. | ||
" | ||
" Attempts to leave the current statusline as it is, and simply add the | ||
" relevant information in the place of the current filename. If that fails, | ||
" replaces the whole statusline. | ||
function! linediff#differ#SetupDiffBuffer() dict | ||
let b:differ = self | ||
|
||
let statusline = printf('[%s:%%{b:differ.from}-%%{b:differ.to}]', bufname(self.original_buffer)) | ||
if &statusline =~ '%[fF]' | ||
let statusline = substitute(&statusline, '%[fF]', statusline, '') | ||
endif | ||
exe "setlocal statusline=" . escape(statusline, ' |') | ||
exe "set filetype=" . self.filetype | ||
setlocal bufhidden=hide | ||
|
||
autocmd BufWrite <buffer> silent call b:differ.UpdateOriginalBuffer() | ||
endfunction | ||
|
||
function! linediff#differ#CloseDiffBuffer() dict | ||
if bufexists(self.diff_buffer) | ||
exe "bdelete ".self.diff_buffer | ||
endif | ||
endfunction | ||
|
||
function! linediff#differ#SetupSigns() dict | ||
exe "sign unplace ".self.sign_number."1" | ||
exe "sign unplace ".self.sign_number."2" | ||
|
||
exe printf("sign place %d1 name=%s line=%d buffer=%d", self.sign_number, self.sign_name, self.from, self.original_buffer) | ||
exe printf("sign place %d2 name=%s line=%d buffer=%d", self.sign_number, self.sign_name, self.to, self.original_buffer) | ||
endfunction | ||
|
||
" Updates the original buffer after saving the temporary one. It might also | ||
" update the other differ's data, provided a few conditions are met. See | ||
" linediff#differ#PossiblyUpdateOtherDiffer() for details. | ||
function! linediff#differ#UpdateOriginalBuffer() dict | ||
let new_lines = getbufline('%', 0, '$') | ||
|
||
" Switch to the original buffer, delete the relevant lines, add the new | ||
" ones, switch back to the diff buffer. | ||
call linediff#util#SwitchBuffer(self.original_buffer) | ||
let saved_cursor = getpos('.') | ||
call cursor(self.from, 1) | ||
exe "normal! ".(self.to - self.from + 1)."dd" | ||
call append(self.from - 1, new_lines) | ||
call setpos('.', saved_cursor) | ||
call linediff#util#SwitchBuffer(self.diff_buffer) | ||
|
||
" Keep the difference in lines to know how to update the other differ if | ||
" necessary. | ||
let line_count = self.to - self.from + 1 | ||
let new_line_count = len(new_lines) | ||
|
||
let self.to = self.from + len(new_lines) - 1 | ||
call self.SetupDiffBuffer() | ||
call self.SetupSigns() | ||
|
||
call self.PossiblyUpdateOtherDiffer(new_line_count - line_count) | ||
endfunction | ||
|
||
" If the other differ originates from the same buffer and it's located below | ||
" this one, we need to update its starting and ending lines, since any change | ||
" would result in a line shift. | ||
" | ||
" a:delta is the change in the number of lines. | ||
function! linediff#differ#PossiblyUpdateOtherDiffer(delta) dict | ||
let other = self.other_differ | ||
|
||
if self.original_buffer == other.original_buffer | ||
\ && self.to <= other.from | ||
\ && a:delta != 0 | ||
let other.from = other.from + a:delta | ||
let other.to = other.to + a:delta | ||
|
||
call other.SetupSigns() | ||
endif | ||
endfunction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
" Helper method to change to a certain buffer. | ||
function! linediff#util#SwitchBuffer(bufno) | ||
exe "buffer ".a:bufno | ||
endfunction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
============================================================================== | ||
CONTENTS *linediff* *linediff-contents* | ||
|
||
Installation...........................: |linediff-installation| | ||
Usage..................................: |linediff-usage| | ||
Commands...............................: |linediff-commands| | ||
Internals..............................: |linediff-internals| | ||
Issues.................................: |linediff-issues| | ||
|
||
|
||
============================================================================== | ||
INSTALLATION *linediff-installation* | ||
|
||
There are several ways to install the plugin. The recommended one is by using | ||
Tim Pope's pathogen (http://www.vim.org/scripts/script.php?script_id=2332). In | ||
that case, you can clone the plugin's git repository like so: | ||
> | ||
git clone git://github.com/AndrewRadev/linediff.vim.git ~/.vim/bundle/linediff | ||
< | ||
If your vim configuration is under git version control, you could also set up | ||
the repository as a submodule, which would allow you to update more easily. | ||
The command is (provided you're in ~/.vim): | ||
> | ||
git submodule add git://github.com/AndrewRadev/linediff.vim.git bundle/linediff | ||
< | ||
|
||
Another way is to simply copy all the essential directories inside the ~.vim/ | ||
directory: plugin, autoload, doc. | ||
|
||
============================================================================== | ||
USAGE *linediff-usage* | ||
|
||
The plugin provides a simple command, |:Linediff|, which is used to diff two | ||
separate blocks of text. | ||
|
||
A simple example: | ||
|
||
def one | ||
two | ||
end | ||
|
||
def two | ||
three | ||
end | ||
|
||
If we mark the first three lines, starting from "def one", in visual mode, and | ||
execute the |:Linediff| command, the signs "1-" will be placed at the start | ||
and at the end of the visual mode's range. Doing the same thing on the bottom | ||
half of the code, starting from "def two", will result in the signs "2-" | ||
placed there. After that, a new tab will be opened with the two blocks of code | ||
in vertical splits, diffed against each other. | ||
|
||
The two buffers are temporary, but when any one of them is saved, its original | ||
buffer is updated. Note that this doesn't save the original buffer, just | ||
performs the change. Saving is something you should do later. | ||
|
||
Executing the command |:LinediffReset| will delete the temporary buffers and | ||
remove the signs. | ||
|
||
Executing a new |:Linediff| will do the same as |:LinediffReset|, but will | ||
also initiate a new diff process. | ||
|
||
The statuslines of the two temporary buffers will be changed to contain: | ||
- The original buffer | ||
- The starting line of the selected segment | ||
- The ending line of the selected segment | ||
|
||
If you're using a custom statusline and it contains "%f" (the current file's | ||
name), that token will simply be substituted by the above data. Otherwise, the | ||
entire statusline will be set to a custom one. | ||
|
||
============================================================================== | ||
COMMANDS *linediff-commands* | ||
|
||
*:Linediff* | ||
:Linediff The main interface of the plugin. Needs to be executed on a | ||
range of lines, which will be marked with a sign. On the | ||
selection of the second such range, the command will open a | ||
tab with the two ranges in vertically split windows and | ||
perform a diff on them. Saving one of the two buffers will | ||
automatically update the original buffer the text was taken | ||
from. | ||
|
||
When executed for a third time, a new line diff is | ||
initiated, and the current process is reset, much like the | ||
effect of |LinediffReset| would be. | ||
|
||
|
||
*:LinediffReset* | ||
:LinediffReset Removes the signs denoting the diffed regions and deletes | ||
the temporary buffers, used for the diff. The original | ||
buffers are untouched by this, which means that any updates | ||
to them, performed by the diff process will remain. | ||
|
||
============================================================================== | ||
INTERNALS *linediff-internals* | ||
|
||
When a block of text is diffed with the plugin, a "Differ" object is | ||
initialized with its relevant data. The differ contains information about the | ||
buffer number, filetype, start and end lines of the text, and a few other | ||
things. Almost all functions the plugin uses are scoped to this object in | ||
order to keep the interface simple. They're located under | ||
"autoload/linediff/differ.vim" and should be fairly understandable. | ||
|
||
Functions that are general-purpose utilities are placed in | ||
"autoload/linediff/util.vim". | ||
|
||
The two differ objects that are required for the two diff buffers are linked | ||
to each other out of necessity. If they originate from a single buffer, | ||
updating one would move the lines of the other, so that one would have to be | ||
updated as well. Apart from that, they have no interaction. | ||
|
||
============================================================================== | ||
ISSUES *linediff-issues* | ||
|
||
You shouldn't linediff two pieces of text that overlap. Not that anything | ||
horribly bad will happen, it just won't work as you'd hope to. I don't feel | ||
like it's a very important use case, but if someone requests sensible | ||
behaviour in that case, I should be able to get it working. | ||
|
||
To report any issues or offer suggestions, use the bugtracker of the github | ||
project at http://github.com/AndrewRadev/linediff.vim/issues | ||
|
||
vim:tw=78:sw=4:ft=help:norl: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
if exists("g:loaded_linediff") || &cp | ||
finish | ||
endif | ||
|
||
let g:loaded_linediff = '0.1.1' " version number | ||
let s:keepcpo = &cpo | ||
set cpo&vim | ||
|
||
" Initialized lazily to avoid executing the autoload file before it's really | ||
" needed. | ||
function! s:Init() | ||
if !exists('s:differ_one') | ||
let s:differ_one = linediff#differ#New('linediff_one', 1) | ||
let s:differ_two = linediff#differ#New('linediff_two', 2) | ||
endif | ||
endfunction | ||
|
||
command! -range Linediff call s:Linediff(<line1>, <line2>) | ||
function! s:Linediff(from, to) | ||
call s:Init() | ||
|
||
if s:differ_one.IsBlank() | ||
call s:differ_one.Init(a:from, a:to) | ||
elseif s:differ_two.IsBlank() | ||
call s:differ_two.Init(a:from, a:to) | ||
|
||
call s:PerformDiff(s:differ_one, s:differ_two) | ||
else | ||
call s:differ_one.Reset() | ||
call s:differ_two.Reset() | ||
|
||
call s:Linediff(a:from, a:to) | ||
endif | ||
endfunction | ||
|
||
command! LinediffReset call s:LinediffReset() | ||
function! s:LinediffReset() | ||
call s:differ_one.Reset() | ||
call s:differ_two.Reset() | ||
endfunction | ||
|
||
function! s:PerformDiff(one, two) | ||
call a:one.CreateDiffBuffer("tabedit") | ||
call a:two.CreateDiffBuffer("rightbelow vsplit") | ||
|
||
let a:one.other_differ = a:two | ||
let a:two.other_differ = a:one | ||
endfunction |