Skip to content
This repository was archived by the owner on Jul 10, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 83 additions & 131 deletions autoload/ag.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,95 +2,79 @@
"
" Variables required to manage async
let s:job_number = 0
let s:locListCommand = 0
let s:toLocList = 0
let s:args = ''
let s:cwd = getcwd()
let s:data = []
let s:data = ['']
let s:resetData = 1

"-----------------------------------------------------------------------------
" Public API
"-----------------------------------------------------------------------------

function! ag#Ag(cmd, args) abort
let l:ag_executable = get(split(g:ag_prg, ' '), 0)
function! ag#run(cmd, args, cwd) abort
if empty(a:args)
let l:args = [expand('<cword>')]
els
" If no pattern is provided, search for the word under the cursor
let l:args = a:args
end

" Ensure that `ag` is installed
if !executable(l:ag_executable)
echoe "Ag command '" . l:ag_executable . "' was not found. Is the silver searcher installed and on your $PATH?"
return
endif
let s:ag_current_format = g:ag_format
let s:ag_current_prg = g:ag_prg

" If no pattern is provided, search for the word under the cursor
if empty(a:args)
let l:grepargs = expand('<cword>')
" Set the script variables that will later be used by the async callback
if a:cmd =~# '^l'
let s:toLocList = 1
else
let l:grepargs = a:args . join(a:000, ' ')
end
let s:toLocList = 0
endif

if empty(l:grepargs)
echo "Usage: ':Ag {pattern}'. See ':help :Ag' for more information."
return
if a:cmd =~# 'find'
let s:ag_current_format = g:fd_format
let s:ag_current_prg = g:fd_prg
endif

" Format, used to manage column jump
if a:args =~# '-g'
let s:ag_format_backup = g:ag_format
let g:ag_format = '%f'
elseif exists('s:ag_format_backup')
let g:ag_format = s:ag_format_backup
if a:cmd =~# 'findfull'
let s:ag_current_prg = s:ag_current_prg + ['--full-path']
endif

" Set the script variables that will later be used by the async callback
let s:args = l:grepargs
let l:cmd = a:cmd . ' ' . escape(l:grepargs, '|')
if l:cmd =~# '^l'
let s:locListCommand = 1
else
let s:locListCommand = 0
if a:cmd =~ 'glob'
let s:ag_current_prg = s:ag_current_prg + ['--glob=' .. l:args[0]]
let l:args = l:args[1:]
endif

if a:cmd =~# '!$'
let s:ag_current_prg = s:ag_current_prg + ['--hidden']
endif


" Store the backups
let l:grepprg_bak = &grepprg
let l:grepprg_bak = &l:grepprg
let l:grepformat_bak = &grepformat
let l:t_ti_bak = &t_ti
let l:t_te_bak = &t_te

" Try to change all the system variables and run ag in the right folder
try
let &l:grepprg = g:ag_prg
let &grepformat = g:ag_format
set t_ti= " These 2 commands make ag.vim not bleed in terminal
set t_te=
if g:ag_working_path_mode ==? 'r' " Try to find the project root for current buffer
let l:cwd_back = getcwd()
let s:cwd = s:guessProjectRoot()
try
exe 'lcd '.s:cwd
catch
finally
call s:executeCmd(l:grepargs, l:cmd)
exe 'lcd '.l:cwd_back
endtry
else " Someone chose an undefined value or 'c' so we revert to searching in the cwd
call s:executeCmd(l:grepargs, l:cmd)
endif
call s:execAg(s:ag_current_prg, l:args, { 'cwd': a:cwd })
finally
let &l:grepprg = l:grepprg_bak
let &grepformat = l:grepformat_bak
let &t_ti = l:t_ti_bak
let &t_te = l:t_te_bak
endtry
endfunction

" No neovim, when we finally get here we already have the output so run handleOutput
if !has('nvim')
call s:handleOutput()
return
function! ag#Ag(cmd, ...) abort
let l:args = a:000
if g:ag_working_path_mode ==? 'r' " Try to find the project root for current buffer
let l:cwd = s:guessProjectRoot()
else " Someone chose an undefined value or 'c' so we revert to searching in the cwd
let l:cwd = getcwd()
endif
endfunction
call ag#run(a:cmd, l:args, l:cwd)
endf

function! ag#AgBuffer(cmd, args) abort
function! ag#AgBuffer(...) abort
let l:bufs = filter(range(1, bufnr('$')), 'buflisted(v:val)')
let l:files = []
for buf in l:bufs
Expand All @@ -99,44 +83,29 @@ function! ag#AgBuffer(cmd, args) abort
call add(l:files, l:file)
endif
endfor
call ag#Ag(a:cmd, a:args . ' ' . join(l:files, ' '))

let l:args = a:000 + ["--"] + l:files
call call(function('ag#Ag'), l:args)
endfunction

function! ag#AgFromSearch(cmd, args) abort
let l:search = getreg('/')
" translate vim regular expression to perl regular expression.
let l:search = substitute(l:search,'\(\\<\|\\>\)','\\b','g')
call ag#Ag(a:cmd, '"' . l:search .'" '. a:args)
endfunction

function! ag#AgHelp(cmd,args) abort
let l:args = a:args.' '.s:GetDocLocations()
call ag#Ag(a:cmd,l:args)
endfunction

function! ag#AgFile(cmd, args) abort
let l:args = ' -g ' . a:args
call ag#Ag(a:cmd, l:args)
endfunction

function! ag#AgAdd(cmd, args) abort
function! ag#AgAdd(...) abort
let s:resetData = 0
call ag#Ag(a:cmd, a:args)
call call(function('ag#Ag'), a:000)
endfunction

"-----------------------------------------------------------------------------
" Private API
"-----------------------------------------------------------------------------

function! s:handleOutput() abort
if s:locListCommand
if s:toLocList
let l:match_count = len(getloclist(winnr()))
else
let l:match_count = len(getqflist())
endif

if l:match_count
if s:locListCommand
if s:toLocList
exe g:ag_lhandler
let l:apply_mappings = g:ag_apply_lmappings
let l:matches_window_prefix = 'l' " we're using the location list
Expand All @@ -155,11 +124,11 @@ function! s:handleOutput() abort
redraw! " Regular vim needs some1 to tell it to redraw

if l:apply_mappings
nnoremap <buffer> <silent> h <C-W><CR>:exe 'wincmd ' (&splitbelow ? 'J' : 'K')<CR><C-W>p<C-W>J<C-W>p
nnoremap <buffer> <silent> H <C-W><CR>:exe 'wincmd ' (&splitbelow ? 'J' : 'K')<CR><C-W>p<C-W>J
nnoremap <buffer> <silent> o <CR>
nnoremap <buffer> <silent> f <C-W><CR>:exe 'wincmd ' (&splitbelow ? 'J' : 'K')<CR><C-W>p<C-W>J<C-W>p
" nnoremap <buffer> <silent> H <C-W><CR>:exe 'wincmd ' (&splitbelow ? 'J' : 'K')<CR><C-W>p<C-W>J
" nnoremap <buffer> <silent> o <CR>
nnoremap <buffer> <silent> t <C-W><CR><C-W>T
nnoremap <buffer> <silent> T <C-W><CR><C-W>TgT<C-W><C-W>
" nnoremap <buffer> <silent> T <C-W><CR><C-W>TgT<C-W><C-W>
nnoremap <buffer> <silent> v <C-W><CR>:exe 'wincmd ' (&splitright ? 'L' : 'H')<CR><C-W>p<C-W>J<C-W>p

let l:closecmd = l:matches_window_prefix . 'close'
Expand All @@ -180,104 +149,87 @@ function! s:handleOutput() abort
endif
endfunction

function! s:handleAsyncOutput(job_id, data, event) abort
function! s:handleAsyncOutput(job_id, data, event) abort dict
" Don't care about older async calls that have been killed or replaced
if s:job_number !=# a:job_id
return
end

" Store all the input we get from the shell
if a:event ==# 'stdout'
let s:data = s:data+a:data
let s:data[-1] .= a:data[0]
call extend(s:data, a:data[1:])

" When the program has finished running we parse the data
elseif a:event ==# 'exit'
echom 'Ag search finished'
let l:expandeddata = []
" Expand the path of the result so we can jump to it
for l:result in s:data
if( l:result !~? '^/home/' ) " Only expand when the path is not a full path already
let l:result = s:cwd.'/'.l:result
" At the end we usually have some bogous/empty lines, so skip them
if( l:result =~ '^\s*$')
continue
endif
if( l:result !~? '^/' ) " Only expand when the path is not a full path already
let l:result = self.cwd.'/'.l:result
endif
let l:result = substitute(l:result , '//', '/' ,'g') " Get rid of excess slashes in filename if present
call add(l:expandeddata, l:result)
endfor

if len(l:expandeddata) " Only if we actually find something
let l:errorformat_bak = &errorformat
let &errorformat = s:ag_current_format

" The last element is always bogus for some reason
let l:expandeddata = l:expandeddata[0:-2]

if s:locListCommand
if s:toLocList
" Add to location list
lgete l:expandeddata
else
" Add to quickfix list
cgete l:expandeddata
endif
let &errorformat = l:errorformat_bak
call s:handleOutput()
else
echom 'No matches for "'.s:args.'"'
endif
endif
endfunction

function! s:executeCmd(grepargs, cmd) abort
if !has('nvim')
silent! execute a:cmd
return
endif

" Stop older running ag jobs if any
function! s:execAg(prg, args, opts) abort
try
call jobstop(s:job_number)
catch
endtry

" Clear all of the old captures
if s:resetData
let s:data = []
let s:data = ['']
endif
let s:resetData = 1

" All types of exiting the job should be directed to handleAsyncOutput
let s:callbacks = {
\ 'on_stdout': function('s:handleAsyncOutput'),
\ 'on_stderr': function('s:handleAsyncOutput'),
\ 'on_exit': function('s:handleAsyncOutput')
\ }

let l:splitargs = split(a:grepargs)
let l:grepargs = ''
"Make sure we shellescape arguments separately and expand the ~ in a string
for l:splitarg in l:splitargs
if l:splitarg !~? '^-'
let l:grepargs = l:grepargs.' '.shellescape(substitute(l:splitarg,'^\~',$HOME, ''))
else
let l:grepargs = l:grepargs.' '.l:splitarg
endif
endfor
let l:opts = {
\ 'on_stdout': function('s:handleAsyncOutput'),
\ 'on_stderr': function('s:handleAsyncOutput'),
\ 'on_exit': function('s:handleAsyncOutput')
\ }

" Construct the command string send to job shell -
" cd [directory]; ag --vimgrep [extra flags] '[value]' '[optional directory]'
let l:agcmd = 'cd '.s:cwd.'; '.g:ag_prg . ' ' . l:grepargs

echom 'Ag search started'
let s:job_number = jobstart(['sh', '-c', l:agcmd], extend({'shell': 'shell 1'}, s:callbacks))
endfunction

let l:args = copy(a:args)
let l:idx = index(l:args, "--")
if l:idx >= 0
call remove(l:args, l:idx)
else
call add(l:args, "./")
endif
let l:cmd = a:prg + l:args
let s:args = join(l:args, " ")

function! s:GetDocLocations() abort
let dp = ''
for p in split(&runtimepath,',')
let p = p.'doc/'
if isdirectory(p)
let dp = p.'*.txt '.dp
endif
endfor
return dp
echom 'Ag search started (' . join(l:cmd, " ") . ')'
let s:job_number = jobstart(l:cmd, extend(l:opts, a:opts))
endfunction


" Called from within a list window, preserves its height after shuffling vsplit.
" The parameter indicates whether list was opened as copen or lopen.
function! s:PreviewVertical(opencmd) abort
Expand Down
45 changes: 45 additions & 0 deletions lua/agvim/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
-- > package.loaded[ 'agvim' ] = nil
-- > x = require("agvim")
-- > x.get_file("abc|")
-- abc|
-- lua agvim = require("agvim")
-- call v:lua.agvim.as_args()

local function get_fname(entry)
local idx = string.find(entry, "|")
if idx == nil then
return nil
end
return string.sub(entry, 1, idx-1)
end

local function extract_files(lines)
local seen = {}
local files = {}
local n = 1
for _, v in ipairs(lines) do
local fn = get_fname(v)
if fn and not seen[fn] then
seen[fn] = true
files[n] = fn
n = n+1
end
end
return files
end

local function as_args()
local bufnr = vim.api.nvim_get_current_buf()
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
local files = extract_files(lines)

for i,v in ipairs(files) do
files[i] = vim.api.nvim_call_function("fnameescape",{v})
end
vim.api.nvim_command("close")
vim.api.nvim_command("args " .. table.concat(files, " "))
end

return {
as_args = as_args
}
Loading