commands.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. local Job = require('plenary.job')
  2. function make(opts)
  3. local makeprg = vim.bo.makeprg
  4. local errorformat = vim.bo.errorformat
  5. if makeprg == '' then
  6. return
  7. end
  8. -- escape special characters in args
  9. args = string.gsub(opts.args or '', '%%', '%%%%')
  10. -- substitute $*
  11. makeprg, _ = string.gsub(makeprg, '%$%*', args);
  12. -- expand
  13. makeprg = vim.fn.expandcmd(makeprg)
  14. local function on_exit(job, retval)
  15. local result = {}
  16. vim.list_extend(result, job:result())
  17. vim.list_extend(result, job:stderr_result())
  18. vim.notify(string.format(
  19. ':!%s\n%s\n\nshell returned %d',
  20. makeprg,
  21. table.concat(result, '\n'),
  22. retval
  23. ))
  24. vim.fn.setqflist({}, ' ', {
  25. title = makeprg,
  26. lines = result,
  27. efm = errorformat,
  28. })
  29. vim.api.nvim_exec_autocmds('QuickFixCmdPost', {})
  30. if #result > 0 then
  31. vim.cmd('copen')
  32. end
  33. end
  34. Job:new({
  35. command = 'sh',
  36. args = { '-c', makeprg },
  37. on_exit = vim.schedule_wrap(on_exit),
  38. }):start()
  39. end
  40. vim.api.nvim_create_user_command('Make', make, {
  41. nargs = '*',
  42. complete = 'file',
  43. })
  44. function ensure_log_buffer(bufname)
  45. for _, buf in ipairs(vim.api.nvim_list_bufs()) do
  46. if vim.api.nvim_buf_is_loaded(buf) and vim.api.nvim_buf_get_name(buf) == bufname then
  47. vim.bo[buf].modifiable = true
  48. vim.api.nvim_buf_set_lines(buf, 0, -1, true, {})
  49. vim.bo[buf].modifiable = false
  50. return buf
  51. end
  52. end
  53. local bufnr = vim.api.nvim_create_buf(true, true)
  54. vim.api.nvim_buf_set_name(bufnr, bufname)
  55. vim.bo[bufnr].filetype = 'git'
  56. vim.bo[bufnr].buftype = 'nofile'
  57. vim.bo[bufnr].bufhidden = 'hide'
  58. vim.bo[bufnr].swapfile = false
  59. vim.bo[bufnr].modifiable = false
  60. vim.api.nvim_win_set_buf(0, bufnr)
  61. -- avoid ui thrashing
  62. vim.opt_local.number = false
  63. vim.opt_local.relativenumber = false
  64. -- add fugitive mappings
  65. vim.fn['fugitive#MapJumps']()
  66. return bufnr
  67. end
  68. function git_lg(opts)
  69. local argstr = ''
  70. if #opts.args > 0 then
  71. argstr = ' ' .. opts.args
  72. end
  73. -- we want a pseudo fqdn so that it's not considered relative to the current
  74. -- directory
  75. local bufname = 'cmd://git//lg' .. argstr
  76. local bufnr = ensure_log_buffer(bufname)
  77. local job
  78. -- there are custom syntax highlights for --graph and --pretty
  79. local args = {
  80. 'log',
  81. '--abbrev-commit',
  82. '--graph',
  83. '--pretty=%h %d %s (%cr) <%an>',
  84. }
  85. vim.list_extend(args, opts.fargs)
  86. local stdout_lines = {}
  87. local stderr_lines = {}
  88. local first = true
  89. local append_to_buf = vim.schedule_wrap(function(lines)
  90. -- stop appending and terminate the job if the buffer is closed
  91. if not vim.api.nvim_buf_is_loaded(bufnr) then
  92. job:shutdown(0, 0)
  93. return
  94. end
  95. -- the first append should replace the first line, succeeding appends
  96. -- should append to the end
  97. local start = -1
  98. if first then
  99. start = 0
  100. first = false
  101. end
  102. vim.bo[bufnr].modifiable = true
  103. vim.api.nvim_buf_set_lines(bufnr, start, -1, true, lines)
  104. vim.bo[bufnr].modifiable = false
  105. end)
  106. local function on_stdout(error, data)
  107. if data == nil then
  108. return
  109. end
  110. -- we get called for every line of output so buffer the lines to avoid too
  111. -- much overhead
  112. table.insert(stdout_lines, data)
  113. if #stdout_lines > 100 then
  114. local done = stdout_lines
  115. stdout_lines = {}
  116. append_to_buf(done)
  117. end
  118. end
  119. local function on_exit(job, retval)
  120. append_to_buf(stdout_lines)
  121. if retval ~= 0 then
  122. vim.schedule(function()
  123. vim.notify(string.format(
  124. ':%s\n%s\n\nreturned %d',
  125. 'GLg' .. argstr,
  126. table.concat(stderr_lines, '\n'),
  127. retval
  128. ))
  129. end)
  130. end
  131. end
  132. job = Job:new({
  133. command = 'git',
  134. args = args,
  135. enable_recording = false,
  136. on_stdout = on_stdout,
  137. on_stderr = function(error, data)
  138. if data == nil then
  139. return
  140. end
  141. table.insert(stderr_lines, data)
  142. end,
  143. on_exit = on_exit,
  144. })
  145. job:start()
  146. end
  147. vim.api.nvim_create_user_command('GLg', git_lg, {
  148. nargs = '*',
  149. complete = vim.fn['fugitive#LogComplete'],
  150. })