@@ -139,6 +139,14 @@ function! clang_format#is_invalid() abort
139
139
let s: version = v
140
140
endif
141
141
142
+ if g: clang_format #auto_format_git_diff &&
143
+ \ ! exists (' s:git_available' )
144
+ if ! executable (g: clang_format #git)
145
+ return 1
146
+ endif
147
+ let s: git_available = 1
148
+ endif
149
+
142
150
return 0
143
151
endfunction
144
152
@@ -184,6 +192,7 @@ let g:clang_format#extra_args = s:getg('clang_format#extra_args', "")
184
192
if type (g: clang_format #extra_args) == type ([])
185
193
let g: clang_format #extra_args = join (g: clang_format #extra_args, " " )
186
194
endif
195
+ let g: clang_format #git = s: getg (' clang_format#git' , ' git' )
187
196
188
197
let g: clang_format #code_style = s: getg (' clang_format#code_style' , ' google' )
189
198
let g: clang_format #style_options = s: getg (' clang_format#style_options' , {})
@@ -193,6 +202,8 @@ let g:clang_format#detect_style_file = s:getg('clang_format#detect_style_file',
193
202
let g: clang_format #enable_fallback_style = s: getg (' clang_format#enable_fallback_style' , 1 )
194
203
195
204
let g: clang_format #auto_format = s: getg (' clang_format#auto_format' , 0 )
205
+ let g: clang_format #auto_format_git_diff = s: get (' clang_format#auto_format_git_diff' , 0 )
206
+ let g: clang_format #auto_format_git_diff_fallback = s: get (' clang_format#auto_format_git_diff_fallback' , ' file' )
196
207
let g: clang_format #auto_format_on_insert_leave = s: getg (' clang_format#auto_format_on_insert_leave' , 0 )
197
208
let g: clang_format #auto_formatexpr = s: getg (' clang_format#auto_formatexpr' , 0 )
198
209
" }}}
@@ -203,8 +214,11 @@ function! s:detect_style_file() abort
203
214
return findfile (' .clang-format' , dirname.' ;' ) != ' ' || findfile (' _clang-format' , dirname.' ;' ) != ' '
204
215
endfunction
205
216
206
- function ! clang_format#format (line1, line2) abort
207
- let args = printf (' -lines=%d:%d' , a: line1 , a: line2 )
217
+ function ! clang_format#format (ranges ) abort
218
+ let args = ' '
219
+ for range in a: ranges
220
+ let args .= printf (' -lines=%d:%d' , range [0 ], range [1 ])
221
+ endfor
208
222
if ! (g: clang_format #detect_style_file && s: detect_style_file ())
209
223
if g: clang_format #enable_fallback_style
210
224
let args .= ' ' . s: shellescape (printf (' -style=%s' , s: make_style_options ())) . ' '
@@ -226,11 +240,11 @@ endfunction
226
240
" }}}
227
241
228
242
" replace buffer {{{
229
- function ! clang_format#replace (line1, line2 , ... ) abort
243
+ function ! clang_format#replace (ranges , ... ) abort
230
244
call s: verify_command ()
231
245
232
246
let pos_save = a: 0 >= 1 ? a: 1 : getpos (' .' )
233
- let formatted = clang_format#format (a: line1 , a: line2 )
247
+ let formatted = clang_format#format (a: ranges )
234
248
if ! s: success (formatted)
235
249
call s: error_message (formatted)
236
250
return
@@ -256,7 +270,7 @@ function! s:format_inserted_area() abort
256
270
let pos = getpos (' .' )
257
271
" When in the same buffer
258
272
if &modified && ! empty (s: pos_on_insertenter ) && s: pos_on_insertenter [0 ] == pos[0 ]
259
- call clang_format#replace (s: pos_on_insertenter [1 ], line (' .' ))
273
+ call clang_format#replace ([[ s: pos_on_insertenter [1 ], line (' .' )]] )
260
274
let s: pos_on_insertenter = []
261
275
endif
262
276
endfunction
@@ -291,6 +305,65 @@ endfunction
291
305
function ! clang_format#disable_auto_format () abort
292
306
let g: clang_format #auto_format = 0
293
307
endfunction
308
+ " s:chdir will change the directory respecting
309
+ " local/tab-local/global directory settings.
310
+ function ! s: chdir (dir )
311
+ " This is a dirty hack to fix tcd breakages on neovim.
312
+ " Future work should be based on nvim API.
313
+ if exists (' :tcd' )
314
+ let chdir = haslocaldir () ? ' lcd' : haslocaldir (-1 , 0 ) ? ' tcd' : ' cd'
315
+ else
316
+ let chdir = exists (' *haslocaldir' ) && haslocaldir () ? ' lcd' : ' cd'
317
+ endif
318
+ execute chdir fnameescape (a: dir )
319
+ endfunction
320
+
321
+ " s:strip: helper function to strip a string
322
+ function ! s: strip (string )
323
+ return substitute (a: string , ' ^\s*\(.\{-}\)\s*\n\=$' , ' \1' , ' ' )
324
+ endfunction
325
+
326
+ function ! clang_format#do_auto_format_git_diff ()
327
+ let dir = getcwd ()
328
+ let cur_file = expand (" %:p" )
329
+ let cur_file_path = isdirectory (cur_file) ? cur_file : fnamemodify (cur_file, " :h" )
330
+ try
331
+ call s: chdir (cur_file_path)
332
+ let top_dir= s: strip (system (
333
+ \ g: clang_format #git." rev-parse --show-toplevel" ))
334
+ call s: chdir (top_dir)
335
+ let cur_file = s: system (
336
+ \ g: clang_format #git." ls-files --error-unmatch " .cur_file)
337
+ let source = join (getline (1 , ' $' ), " \n " )
338
+ let ranges = s: system (
339
+ \ ' diff <(' .g: clang_format #git.' show :' .cur_file.' ) - '
340
+ \ ' --old-group-format="" --unchanged-group-format="" '
341
+ \ ' --new-group-format="%dF-%dL%c'' \\012'' " '
342
+ \ ' --changed-group-format="%dF-%dL%c'' \\012'' "' ,
343
+ \ source )
344
+ let ranges = split (ranges , ' \n' )
345
+ let ranges = map (ranges , " split(v:val, '-')" )
346
+ call clang_format#replace (ranges )
347
+ catch
348
+ " not in a git dir, or not a tracked file
349
+ return 1
350
+ finally
351
+ call s: chdir (dir )
352
+ endtry
353
+ return 0
354
+ endfunction
355
+
356
+ function ! clang_format#do_auto_format ()
357
+ if g: clang_format #auto_format_git_diff
358
+ let ret = clang_format#do_auto_format_git_diff ()
359
+ if ret == 0 ||
360
+ \ g: clang_format #auto_format_git_diff_fallback != ' file'
361
+ return
362
+ endif
363
+ endif
364
+ call clang_format#replace ([[1 , line (' $' )]])
365
+ endfunction
366
+
294
367
" }}}
295
368
let &cpo = s: save_cpo
296
369
unlet s: save_cpo
0 commit comments