Skip to content

Commit 7fc3f91

Browse files
committed
Allow advanced customization of layout and splits via user-defined callback function
1 parent e7bf0c5 commit 7fc3f91

File tree

3 files changed

+75
-5
lines changed

3 files changed

+75
-5
lines changed

autoload/mergetool.vim

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11

2+
function s:noop(...)
3+
endfunction
4+
25
" Configuration settings
36
let g:mergetool_layout = get(g:, 'mergetool_layout', 'wr')
47
let g:mergetool_prefer_revision = get(g:, 'mergetool_prefer_revision', 'local')
8+
let g:MergetoolSetLayoutCallback = get(g:, 'MergetoolSetLayoutCallback', function('s:noop'))
59

610
" {{{ Public exports
711

@@ -32,6 +36,7 @@ function! mergetool#start() "{{{
3236
let s:mergedfile_name = expand('%')
3337
let s:mergedfile_contents = join(getline(0, "$"), "\n") . "\n"
3438
let s:mergedfile_fileformat = &fileformat
39+
let s:mergedfile_filetype = &filetype
3540

3641
" Detect if we're run as 'git mergetool' by presence of BASE|LOCAL|REMOTE buf names
3742
let s:run_as_git_mergetool = bufnr('BASE') != -1 &&
@@ -128,6 +133,8 @@ function! mergetool#set_layout(layout) " {{{
128133
throw "Unknown layout option: " . a:layout
129134
endif
130135

136+
let splits = []
137+
131138
let abbrevs = {
132139
\ 'b': 'base',
133140
\ 'B': 'BASE',
@@ -164,17 +171,30 @@ function! mergetool#set_layout(layout) " {{{
164171
let is_first_split = 0
165172
endif
166173

167-
" For merged file itself, just load its buffer
168174
if labbr ==? 'm'
175+
" For merged file itself, just load its buffer
169176
execute "buffer " . s:mergedfile_bufnr
170-
continue
177+
else
178+
silent call s:load_revision(abbrevs[labbr])
171179
endif
172180

173-
silent call s:load_revision(abbrevs[labbr])
181+
call add(splits, {
182+
\ 'layout': a:layout,
183+
\ 'split': labbr,
184+
\ 'filetype': s:mergedfile_filetype,
185+
\ 'bufnr': bufnr(''),
186+
\ 'winnr': winnr() })
174187
endfor
175188

176189
let s:current_layout = a:layout
177190
windo diffthis
191+
192+
" Iterate over created splits and fire callback
193+
for l:split in splits
194+
execute "noautocmd " . l:split["winnr"] . "wincmd w"
195+
call g:MergetoolSetLayoutCallback(l:split)
196+
endfor
197+
178198
if s:goto_win_with_merged_file() && exists('l:_winstate')
179199
call winrestview(l:_winstate)
180200
endif
@@ -222,6 +242,7 @@ function! s:load_revision(revision)
222242
put = s:mergedfile_contents | 1delete _
223243
call s:remove_conflict_markers(a:revision)
224244
setlocal nomodifiable readonly buftype=nofile bufhidden=delete nobuflisted
245+
execute "setlocal filetype=" . s:mergedfile_filetype
225246
execute "file " . a:revision
226247
elseif a:revision ==# 'BASE' || a:revision ==# 'REMOTE' || a:revision ==# 'LOCAL'
227248

@@ -234,6 +255,7 @@ function! s:load_revision(revision)
234255
enew
235256
call s:load_revision_from_index(a:revision)
236257
setlocal nomodifiable readonly buftype=nofile bufhidden=delete nobuflisted
258+
execute "setlocal filetype=" . s:mergedfile_filetype
237259
execute "file " . a:revision
238260
endif
239261
else
@@ -311,7 +333,7 @@ endfunction
311333
" Tell if window was found
312334
function! s:goto_win_with_merged_file()
313335
let l:winnr = bufwinnr(s:mergedfile_bufnr)
314-
execute bufwinnr(s:mergedfile_bufnr) "wincmd w"
336+
execute "noautocmd " . bufwinnr(s:mergedfile_bufnr) . "wincmd w"
315337
return l:winnr != -1
316338
endfunction
317339

readme.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ git checkout --conflict=diff3 {file}
9090

9191
- Flexible layouts. You're not limited to default 2-way diff layout. You can use 3-way diff layout, or even setup window of 4 splits. Both horizontal and vertical splits are supported, and mix thereof.
9292
- Toggle between layouts during merge. You can have several layouts and toggle between them during merge. For example, you're using 2-way diff by default, but sometimes you want to quickly recall what's the state of a diff in the `BASE` revision, but don't want to keep 3rd `BASE` split constantly opened.
93+
- Customize layout splits as you like: resize, turn off syntax highlighting, turn off diff mode.
9394
- Choose preferred conflict side. By default `ours` side is picked up. But you can choose `ours`, `theirs` or `base` side of a conflict for `MERGED` file as a default, or work with raw conflict markers.
9495
- Conventional `LOCAL`, `REMOTE`, `BASE` history revisions are available to compare to as well.
9596
- Can be run as a `git mergetool`, or by opening a file with conflict markers from the running Vim instance.
@@ -197,7 +198,6 @@ let g:mergetool_layout = 'mr'
197198
:MergetoolToggleLayout LBR
198199
```
199200

200-
201201
![Switching layouts](./screenshots/toggle_layouts.png)
202202

203203
In addition to commands, you can setup key mappings for your most common layouts:
@@ -206,6 +206,54 @@ In addition to commands, you can setup key mappings for your most common layouts
206206
nnoremap <silent> <leader>mb :call mergetool#toggle_layout('mr,b')<CR>
207207
```
208208

209+
### Advanced layout customization
210+
211+
If you want to further tweak layout or change settings of individual splits, define the callback function, which is called when layout is changed.
212+
213+
Example. When layout is `mr,b`, I want the `base` horizontal split to be pulled of a diff mode and have syntax highlighting enabled. Also, I want it to reduce it's height.
214+
215+
```vim
216+
function s:on_mergetool_set_layout(split)
217+
if a:split["layout"] ==# 'mr,b' && a:split["split"] ==# 'b'
218+
set nodiff
219+
set syntax=on
220+
221+
resize 15
222+
endif
223+
endfunction
224+
225+
let g:MergetoolSetLayoutCallback = function('s:on_mergetool_set_layout')
226+
```
227+
228+
Callback is called for each split in the layout, with a split being passed as a callback argument.
229+
230+
```
231+
{
232+
'layout': 'mb,r', # current layout
233+
'split': 'b', # current split
234+
'filetype': 'javascript', # file type of MERGED file
235+
'bufnr': 2, # buffer number of current split
236+
'winnr': 5 # window number of current split
237+
}
238+
```
239+
240+
Example. I want to turn off syntax and spell checking highlighting for all splits, so it doesn't distracts me from diff highlighting.
241+
242+
243+
```vim
244+
function s:on_mergetool_set_layout(split)
245+
set syntax=off
246+
set nospell
247+
endfunction
248+
249+
let g:MergetoolSetLayoutCallback = function('s:on_mergetool_set_layout')
250+
```
251+
252+
Here's the end result:
253+
254+
![Layout advanced customization](./screenshots/layout_advanced_customization.png)
255+
256+
209257
### Running as a `git mergetool`
210258

211259
`vim-mergetool` can be configured to run as a `git mergetool`. In your `~/.gitconfig`:
409 KB
Loading

0 commit comments

Comments
 (0)