utility.vim 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. let s:file = ''
  2. let s:using_xolox_shell = -1
  3. let s:exit_code = 0
  4. let s:fish = &shell =~# 'fish'
  5. function! gitgutter#utility#warn(message)
  6. echohl WarningMsg
  7. echo 'vim-gitgutter: ' . a:message
  8. echohl None
  9. let v:warningmsg = a:message
  10. endfunction
  11. " Returns truthy when the buffer's file should be processed; and falsey when it shouldn't.
  12. " This function does not and should not make any system calls.
  13. function! gitgutter#utility#is_active()
  14. return g:gitgutter_enabled && gitgutter#utility#exists_file() && gitgutter#utility#not_git_dir() && !gitgutter#utility#help_file()
  15. endfunction
  16. function! gitgutter#utility#not_git_dir()
  17. return gitgutter#utility#full_path_to_directory_of_file() !~ '[/\\]\.git\($\|[/\\]\)'
  18. endfunction
  19. function! gitgutter#utility#help_file()
  20. return getbufvar(s:bufnr, '&filetype') ==# 'help' && getbufvar(s:bufnr, '&buftype') ==# 'help'
  21. endfunction
  22. " A replacement for the built-in `shellescape(arg)`.
  23. "
  24. " Recent versions of Vim handle shell escaping pretty well. However older
  25. " versions aren't as good. This attempts to do the right thing.
  26. "
  27. " See:
  28. " https://github.com/tpope/vim-fugitive/blob/8f0b8edfbd246c0026b7a2388e1d883d579ac7f6/plugin/fugitive.vim#L29-L37
  29. function! gitgutter#utility#shellescape(arg)
  30. if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
  31. return a:arg
  32. elseif &shell =~# 'cmd' || gitgutter#utility#using_xolox_shell()
  33. return '"' . substitute(substitute(a:arg, '"', '""', 'g'), '%', '"%"', 'g') . '"'
  34. else
  35. return shellescape(a:arg)
  36. endif
  37. endfunction
  38. function! gitgutter#utility#set_buffer(bufnr)
  39. let s:bufnr = a:bufnr
  40. let s:file = resolve(bufname(a:bufnr))
  41. endfunction
  42. function! gitgutter#utility#bufnr()
  43. return s:bufnr
  44. endfunction
  45. function! gitgutter#utility#file()
  46. return s:file
  47. endfunction
  48. function! gitgutter#utility#filename()
  49. return fnamemodify(s:file, ':t')
  50. endfunction
  51. function! gitgutter#utility#extension()
  52. return fnamemodify(s:file, ':e')
  53. endfunction
  54. function! gitgutter#utility#full_path_to_directory_of_file()
  55. return fnamemodify(s:file, ':p:h')
  56. endfunction
  57. function! gitgutter#utility#directory_of_file()
  58. return fnamemodify(s:file, ':h')
  59. endfunction
  60. function! gitgutter#utility#exists_file()
  61. return filereadable(s:file)
  62. endfunction
  63. function! gitgutter#utility#has_unsaved_changes()
  64. return getbufvar(s:bufnr, "&mod")
  65. endfunction
  66. function! gitgutter#utility#has_fresh_changes()
  67. return getbufvar(s:bufnr, 'changedtick') != getbufvar(s:bufnr, 'gitgutter_last_tick')
  68. endfunction
  69. function! gitgutter#utility#save_last_seen_change()
  70. call setbufvar(s:bufnr, 'gitgutter_last_tick', getbufvar(s:bufnr, 'changedtick'))
  71. endfunction
  72. function! gitgutter#utility#shell_error()
  73. return gitgutter#utility#using_xolox_shell() ? s:exit_code : v:shell_error
  74. endfunction
  75. function! gitgutter#utility#using_xolox_shell()
  76. if s:using_xolox_shell == -1
  77. if !g:gitgutter_avoid_cmd_prompt_on_windows
  78. let s:using_xolox_shell = 0
  79. " Although xolox/vim-shell works on both windows and unix we only want to use
  80. " it on windows.
  81. elseif has('win32') || has('win64') || has('win32unix')
  82. let s:using_xolox_shell = exists('g:xolox#misc#version') && exists('g:xolox#shell#version')
  83. else
  84. let s:using_xolox_shell = 0
  85. endif
  86. endif
  87. return s:using_xolox_shell
  88. endfunction
  89. function! gitgutter#utility#system(cmd, ...)
  90. if gitgutter#utility#using_xolox_shell()
  91. let options = {'command': a:cmd, 'check': 0}
  92. if a:0 > 0
  93. let options['stdin'] = a:1
  94. endif
  95. let ret = xolox#misc#os#exec(options)
  96. let output = join(ret.stdout, "\n")
  97. let s:exit_code = ret.exit_code
  98. else
  99. silent let output = (a:0 == 0) ? system(a:cmd) : system(a:cmd, a:1)
  100. endif
  101. return output
  102. endfunction
  103. function! gitgutter#utility#file_relative_to_repo_root()
  104. let file_path_relative_to_repo_root = getbufvar(s:bufnr, 'gitgutter_repo_relative_path')
  105. if empty(file_path_relative_to_repo_root)
  106. let dir_path_relative_to_repo_root = gitgutter#utility#system(gitgutter#utility#command_in_directory_of_file('git rev-parse --show-prefix'))
  107. let dir_path_relative_to_repo_root = gitgutter#utility#strip_trailing_new_line(dir_path_relative_to_repo_root)
  108. let file_path_relative_to_repo_root = dir_path_relative_to_repo_root . gitgutter#utility#filename()
  109. call setbufvar(s:bufnr, 'gitgutter_repo_relative_path', file_path_relative_to_repo_root)
  110. endif
  111. return file_path_relative_to_repo_root
  112. endfunction
  113. function! gitgutter#utility#command_in_directory_of_file(cmd)
  114. return 'cd '.gitgutter#utility#shellescape(gitgutter#utility#directory_of_file()) . (s:fish ? '; and ' : ' && ') . a:cmd
  115. endfunction
  116. function! gitgutter#utility#highlight_name_for_change(text)
  117. if a:text ==# 'added'
  118. return 'GitGutterLineAdded'
  119. elseif a:text ==# 'removed'
  120. return 'GitGutterLineRemoved'
  121. elseif a:text ==# 'removed_first_line'
  122. return 'GitGutterLineRemovedFirstLine'
  123. elseif a:text ==# 'modified'
  124. return 'GitGutterLineModified'
  125. elseif a:text ==# 'modified_removed'
  126. return 'GitGutterLineModifiedRemoved'
  127. endif
  128. endfunction
  129. function! gitgutter#utility#strip_trailing_new_line(line)
  130. return substitute(a:line, '\n$', '', '')
  131. endfunction