vim - How to query the pwd of a terminal buffer? - vim

Assuming I have a terminal buffer open that's cd'ed to ~/foo/bar directory, how can I capture that directory to use in other vimscripts?

#phd's answer helped me find a solution
function s:get_closest_terminal()
" Reference: https://stackoverflow.com/a/27232550/3626104
let l:buffers = sort(tabpagebuflist('%'), 'n')
for l:number in reverse(l:buffers)
let l:type = getbufvar(l:number, '&buftype', '')
if l:type == "terminal"
return l:number
endif
endfor
return -1
endfunction
function s:get_current_directory()
let l:terminal_buffer = s:get_closest_terminal()
if l:terminal_buffer == -1
echoerr "No directory could be found"
return ""
endif
" Example: "hostname#localhost: /home/username"
let l:title = term_gettitle(l:terminal_buffer)
" Example: "/home/username"
return substitute(l:title, "^.*: ", "", "")
endfunction

Related

How to create a directory search and replace with vimscript and fzf

I'm trying to create a directory search and replace function in vimscript using fzf. The place where I block is when trying to use Alt-a fzf binding to select the whole list. I'm not even sure if that is possible given fzf is an external process but I may be wrong.
Here's my current function.
function! CWDSearchAndReplace()
" Try to get word under cursor else prompt user for a word
let wordToReplace = expand("<cword>")
if wordToReplace == ""
call inputsave()
let wordToReplace = input("Replace: ")
call inputrestore()
endif
" Prompt for replacement
call inputsave()
let replacement = input("Replace \"" . wordToReplace . "\" with: ")
call inputrestore()
execute "Ag " . wordToReplace
" =====> Here I'd like to execute Alt-a followed by <CR>
execute "cdo %s//" . replacement . "/gc"
end function
Thanks for your help!
As pointed out by the creator of fzf.vim, there is no need to use fzf here, one can simply use ag.
function! s:ag_to_qf(line)
let parts = split(a:line, ':')
echo parts
return {'filename': parts[0], 'lnum': parts[1], 'col': parts[2],
\ 'text': join(parts[3:], ':')}
endfunction
function! AgToQF(query)
call setqflist(map(systemlist('ag --column '.a:query), 's:ag_to_qf(v:val)'))
endfunction
function! CWDSearchAndReplace()
let wordUnderCursor = expand("<cword>")
call inputsave()
let wordToReplace = input("Replace : ", wordUnderCursor)
call inputrestore()
call inputsave()
let replacement = input("Replace \"" . wordUnderCursor . "\" with: ")
call inputrestore()
call AgToQF(wordUnderCursor)
execute "cdo %s/" . wordToReplace . "/" . replacement ."/gc"
endfunction
nnoremap <leader>r :call FileSearchAndReplace()<CR>

pass vim argument in completefunc

I am writing a vimscript that uses completefunc as:
" GetComp: Menu and Sunroutine Completion {{{1
function! GetComp(arg, findstart, base)
if a:findstart
" locate the start of the word
let line = getline('.')
let start = col('.') - 1
while start > 0 && line[start - 1] =~ '\a'
let start -= 1
endwhile
return start
else
echomsg '**** completing' a:base
python << EOF
import vim
import os
flsts = [' ']
path = "."
for dirs, subdirs, files in os.walk(path):
for tfile in files:
if tfile.endswith(('f90', 'F90', 'f', 'F')):
ofile = open(dirs+'/'+tfile)
for line in ofile:
if line.lower().strip().startswith(vim.eval("a:arg")):
modname = line.split()[1]
flsts.append(modname)
vim.command("let flstsI = %s"%flsts)
EOF
if eval("a:arg") = "module"
for m in ["ieee_arithmatic", "ieee_exceptions", "ieee_features", "iso_c_bindings", "iso_fortran_env", "omp_lib", "omp_lib_kinds"]
if m =~ "^" . a:base
call add(flstsI, m)
endif
endfor
elseif eval("a:arg") = "subroutine"
for m in ["alarm()", "date_and_time()", "backtrace", "c_f_procpointer()", "chdir()", "chmod()", "co_broadcast()", "get_command()", "get_command_argument()", "get_environment_variable()", "mvbits()", "random_number()", "random_seed()"]
if m =~ "^" . a:base
call add(flstsI, m)
endif
endfor
endif
return flstsI
endif
endfunction
I will call it for 2 different argument as:
inoremap <leader>call call <C-o>:set completefunc=GetComp("subroutine", findstart, base)<CR><C-x><C-u>
inoremap <leader>use use <C-o>:set completefunc=GetComp("module", findstart, base)<CR><C-x><C-u>
But trying so, gives error: Unknown function GetComp(
I don't know how to call them.
If I don't use arg, then, using this reply, I can call this perfectly.
Kindly help.
You'll have to attach a context to your completion. If you look closely at my message on vi.se, you'll see a framework that permits to bind data to a user-completion. From there in your mapping, it just becomes a question of which context to attach.
A simplified way would be to execute a (preparation) function from the mappings and have the function set script global variables that will be used in your completion function.

Vim not setting `tex` filetype on startup

I noticed that if I open a non-existent HTML file with Vim, the filetype is set automatically to html:
$ vim foobar.html
:set filetype # --> filetype=html
On the other hand, the same does not happen with TeX. If I create a non-existent file the filetype is plaintext, and I have to save the file and reopen it to have it correctly set:
$ vim blabla.tex
:set filetype # --> filetype=plaintext
I also tried with Python, C, VimL, Javascript files and the filetype is always set right away. I don't know why this does not happen with TeX files.
The only thing I can think might interfere is vim-latex. Could that be possible? If so, how do I fix this problem?
If it might be of help, here is my not so long .vimrc file.
Vim uses a giant heuristic to determine plaintex vs other variations of tex.
If you look in $VIMRUNTIME/filetype.vim you will find the following function
" Choose context, plaintex, or tex (LaTeX) based on these rules:
" 1. Check the first line of the file for "%&<format>".
" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
func! s:FTtex()
let firstline = getline(1)
if firstline =~ '^%&\s*\a\+'
let format = tolower(matchstr(firstline, '\a\+'))
let format = substitute(format, 'pdf', '', '')
if format == 'tex'
let format = 'plain'
endif
else
" Default value, may be changed later:
let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
" Save position, go to the top of the file, find first non-comment line.
let save_cursor = getpos('.')
call cursor(1,1)
let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
\ 'cnp', firstNC + 1000)
if kwline == 1 " lpat matched
let format = 'latex'
elseif kwline == 2 " cpat matched
let format = 'context'
endif " If neither matched, keep default set above.
" let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
" let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
" if cline > 0
" let format = 'context'
" endif
" if lline > 0 && (cline == 0 || cline > lline)
" let format = 'tex'
" endif
endif " firstNC
call setpos('.', save_cursor)
endif " firstline =~ '^%&\s*\a\+'
" Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
if format == 'plain'
setf plaintex
elseif format == 'context'
setf context
else " probably LaTeX
setf tex
endif
return
endfunc
This function determines which flavor of tex to use. If you look at it you can see that default value is taken from g:tex_flavor (if it exists, defaults to plain). If you set this variable to tex (in you vimrc), vim will default to the tex filetype.
let g:tex_flavor = 'tex'
There is a way to automate the process you're doing manually.
Adding autocmd BufRead,BufNewFile *.tex set filetype=tex to your .vimrc file will set tex filetype for each tex file, once you open them in vim.

Unexpected behavior of Vim IDE(winmanager, minibufexpl, neerdtree, taglist)

My environment is vim with winmanager, minibufexpl, neerdtree and taglist. Now I have a problem, when I open more than one file(also the minibufexpl has two file names), and there are four windows(neerdtree window, taglist window, minibufexpl windows and opened file window). Then I use :q to quit one file, but the opened file is colsed also. I think the correct behavior is to move to the next file.
You probably want to close the buffer instead. That can also close the window, however, which may or may not be what you want.
This plugin should help with that:
http://vim.wikia.com/wiki/Deleting_a_buffer_without_closing_the_window
I additionally have this mapped in my .vimrc so I can just do a <leader>bd to close the buffer.
Edit in response to comments from OP:
Here is the code for the plugin from the link I pasted in:
" Delete buffer while keeping window layout (don't close buffer's windows).
" Version 2008-11-18 from http://vim.wikia.com/wiki/VimTip165
if v:version < 700 || exists('loaded_bclose') || &cp
finish
endif
let loaded_bclose = 1
if !exists('bclose_multiple')
let bclose_multiple = 1
endif
" Display an error message.
function! s:Warn(msg)
echohl ErrorMsg
echomsg a:msg
echohl NONE
endfunction
" Command ':Bclose' executes ':bd' to delete buffer in current window.
" The window will show the alternate buffer (Ctrl-^) if it exists,
" or the previous buffer (:bp), or a blank buffer if no previous.
" Command ':Bclose!' is the same, but executes ':bd!' (discard changes).
" An optional argument can specify which buffer to close (name or number).
function! s:Bclose(bang, buffer)
if empty(a:buffer)
let btarget = bufnr('%')
elseif a:buffer =~ '^\d\+$'
let btarget = bufnr(str2nr(a:buffer))
else
let btarget = bufnr(a:buffer)
endif
if btarget < 0
call s:Warn('No matching buffer for '.a:buffer)
return
endif
if empty(a:bang) && getbufvar(btarget, '&modified')
call s:Warn('No write since last change for buffer '.btarget.' (use :Bclose!)')
return
endif
" Numbers of windows that view target buffer which we will delete.
let wnums = filter(range(1, winnr('$')), 'winbufnr(v:val) == btarget')
if !g:bclose_multiple && len(wnums) > 1
call s:Warn('Buffer is in multiple windows (use ":let bclose_multiple=1")')
return
endif
let wcurrent = winnr()
for w in wnums
execute w.'wincmd w'
let prevbuf = bufnr('#')
if prevbuf > 0 && buflisted(prevbuf) && prevbuf != w
buffer #
else
bprevious
endif
if btarget == bufnr('%')
" Numbers of listed buffers which are not the target to be deleted.
let blisted = filter(range(1, bufnr('$')), 'buflisted(v:val) && v:val != btarget')
" Listed, not target, and not displayed.
let bhidden = filter(copy(blisted), 'bufwinnr(v:val) < 0')
" Take the first buffer, if any (could be more intelligent).
let bjump = (bhidden + blisted + [-1])[0]
if bjump > 0
execute 'buffer '.bjump
else
execute 'enew'.a:bang
endif
endif
endfor
execute 'bdelete'.a:bang.' '.btarget
execute wcurrent.'wincmd w'
endfunction
command! -bang -complete=buffer -nargs=? Bclose call s:Bclose('<bang>', '<args>')
nnoremap <silent> <Leader>bd :Bclose<CR>

How to make gvim main window not quit when I type `:q` or `:qa`?

Instead I want it to close the files and open the default No Name buffer. I sometimes accidentally close the last file and I have to restart gvim and cd to the proper directory.
put it in your $MYVIMRC
function! NumberOfWindows()
let i = 1
while winbufnr(i) != -1
let i = i+1
endwhile
return i - 1
endfunction
function! DonotQuitLastWindow()
if NumberOfWindows() != 1
let v:errmsg = ""
silent! quit
if v:errmsg != ""
"echohl ErrorMsg | echomsg v:errmsg | echohl NONE
"echoerr v:errmsg
echohl ErrorMsg | echo v:errmsg | echohl NONE
endif
else
echohl Error | echo "Can't quit the last window..." | echohl None
endif
endfunction
if has("gui_running")
cnoreabbrev <expr> q getcmdtype() == ":" && getcmdline() == 'q' ? 'call DonotQuitLastWindow()' : 'q'
cnoreabbrev <expr> qa getcmdtype() == ":" && getcmdline() == 'qa' ? 'call DonotQuitLastWindow()' : 'qa'
endif
If you use the :close command instead, that command won't close the last window.
Why don't you use
:bd
to close the buffer (after you saved the latest changes)?

Resources