Configure vimrc based on environment variables - vim

Is it possible to configure vimrc command mapping based on env variables?
For example, I'm using vim-ruby-test plugin which provides the following config:
let g:rubytest_cmd_test = "ruby %p"
I want to set the command differently based on whether i'm running tests using spork or not:
With Spork:
$ TESTDRB=y mvim .
let g:rubytest_cmd_test = "testdrb %p"
Without Spork:
$ mvim .
let g:rubytest_cmd_test = "ruby %p"

if $TESTDRB == 'y'
let g:rubytest_cmd_test = 'ruby %p'
endif
" etc

Related

Vim + latex-suite - modify output file name

I want to create a custom compile rule that takes foo.tex and outputs foo_bar.pdf
I have used the following configurations in my texrc, but I have not found a way to exclude the .tex extension from the output name.
TexLet g:Tex_CompileRule_bar = 'pdflatex -interaction=nonstopmode -file-line-error-style -halt-on-error -jobname=%_bar $*'
Result: foo.tex_bar.pdf
TexLet g:Tex_CompileRule_bar = 'pdflatex -interaction=nonstopmode -file-line-error-style -halt-on-error -jobname=$*_bar $*'
Result: foo.tex_bar.pdf
TexLet g:Tex_CompileRule_bar = 'pdflatex -interaction=nonstopmode -file-line-error-style -halt-on-error -jobname=bar_$ $*'
Result: bar_$.tex
You can use the :r filename modifier after % to remove its extension, before adding the new suffix. Filename modifiers usually work in contexts where % is supported (such as using :! to run an external shell command.)
In your case, -jobname=%:r_bar should do the job.
See :help filename-modifiers for the full list of modifiers and how they work.

Vim -- Double Inclusion Guard

Id'd like to be able to repeatedly insource my ~/.vimrc.local file (I'm using the sp13-vim distro), but I get error messages in the part of that file when I have Bundle/UnBundle statements. How can I prevent that part to be double executed.
That is, how do I write the following in Vimscript?:
if guard_global_not_defined
define_guard_global
do stuff
endif
The canonical structure is
if !exists('g:didBundle')
let g:didBundle = 1
Bundle ...
...
endif
As bundles are globally scoped, the g: prefix makes it a global guard. You can do the same with other scopes (e.g. b: for buffer-local stuff).
The local_vimrc files I'm using have the following kind of include guards: https://github.com/LucHermitte/Rasende/blob/master/_vimrc_local.vim
The latest templates I'm using are a little bit different (they are meant to support projects having global definitions that need to be set before the local settings (like a project name, where to find sources, build configurations and their related build directories), and local tunings).
When expanded, the result look like this (you certainly don't need everything):
let s:k_version = 42
" Always loaded {{{1
" Buffer-local Definitions {{{1
" Avoid local reinclusion {{{2
if &cp || (exists("b:loaded_tests_lh_vimrc_local")
\ && (b:loaded_tests_lh_vimrc_local >= s:k_version)
\ && !exists('g:force_reload_tests_lh_vimrc_local'))
finish
endif
let b:loaded_tests_lh_vimrc_local = s:k_version
let s:cpo_save=&cpo
set cpo&vim
" ======================[ Project config {{{2
if ! (exists("g:loaded_tests_lh_vimrc_local")
\ && (g:loaded_tests_lh_vimrc_local >= s:k_version)
\ && !exists('g:force_reload_tests_lh_vimrc_local'))
source <sfile>:p:h/_vimrc_local_global_defs.vim
endif
" ======================[ Local settings {{{2
.... <- here go your local settings
"--------------------------------------------------------------------
" Global Definitions {{{1
" Avoid global reinclusion {{{2
if &cp || (exists("g:loaded_tests_lh_vimrc_local")
\ && (g:loaded_tests_lh_vimrc_local >= s:k_version)
\ && !exists('g:force_reload_tests_lh_vimrc_local'))
finish
endif
let g:loaded_tests_lh_vimrc_local = s:k_version
" ======================[ Functions {{{2
.... <- here go some more global stuff like functions
" }}}1
"--------------------------------------------------------------------
let &cpo=s:cpo_save
"====================================================================
" vim600: set fdm=marker:
PS: I found quite odd that you have a local_vimrc at your very $HOME directory. They are meant to be at the root of project trees. And moreover they shall not be loaded by a plugin manager but by a local-vimrc plugin.

Hide text segments in vim for use in external commands

I am trying to create some sort of an ncurses-like menu appearence in vim.
Each line should have two fields: title, command
I read the input from stdin, formatted like: title COMMAND: command
item 1 COMMAND: echo hey
item 2 COMMAND: ls /
item 3 COMMAND: some-other-command
I want to show only the titles, like so:
item 1
item 2
item 3
But then I want to be able to run the command of this line, like so:
:.w !exec $(sed -r 's/COMMAND: (.*)/\1/')
But I haven't been able to hide the "COMMAND: ..." part.
How can I accomplish this?
Is vim not suited for such adventures?
Thank you...
Here is how to accomplish what you originally intended. There are many options but I personally use the Unite plugin.
Install Unite
Add the following in your vimrc too see possibilities:
let g:unite_source_menu_menus = {}
let g:unite_source_menu_menus.filters = {
\'description' : 'Text filters',
\'command_candidates' : [
\ ["Remove empty lines" , 'v/./d'],
\ ["Remove empty lines [v]" , "'<,'>v/./d"],
\ ['Condense empty lines' , '%s/\n\{3,}/\r\r/e'],
\ ['Remove trailing white space' , '%s/\s\+$//' ],
\ ['',''],
\]}
let g:unite_source_menu_menus.git = {
\ 'description' : 'Git commands (Fugitive)',
\ 'command_candidates' : [
\ ['git status (Fugitive) ' , 'Gstatus'],
\ ['git diff (Fugitive) ' , 'Gdiff'],
\ ['git commit (Fugitive) ' , 'Gcommit'],
\ ['git cd (Fugitive) ' , 'Gcd'],
\ ['',''],
\ ['git view file (gitv) ' , 'Gitv!'],
\ ['git view all (gitv) ' , 'Gitv'],
\]}
let g:unite_source_menu_menus.myhelp = {
\'description' : 'Interesting help topics',
\'command_candidates' : [
\ ['Executing shell commands in a window', 'h shell-window'],
\ ['File Searching and **', 'h starstar'],
\ ['Local directory .vimrc', "h 'exrc'"]
\]}
noremap <silent> sm :<C-u>Unite -no-start-insert -quick-match -buffer-name=menu menu<CR>
You can launch menu with sm. You can change menu options and you can execute, edit, bookmark and do other tasks with commands. There is an option to filter items and use fuzzy search engine.
Unite is unbelievable awesome plugin with many other benefits.
Another option is to use Forms plugin.
As for custom solution, this is a fast idea:
Given the file awesome.menu
item 11 COMMAND: echo 'hey'
item 2 COMMAND: !ls /
item 3 COMMAND: version
you can use the following function.
fu! Menu()
let g:menu_bg = synIDattr(hlID('Normal'), 'bg#')
let g:menu_fg = synIDattr(hlID('Normal'), 'fg#')
let g:menu_s = 1
exe 'highlight MyMenu guifg=' g:menu_fg
match MyMenu /COMMAND:.*/
nn <buffer> <space> :let g:menu_s = !g:menu_s<cr>:exe 'highlight MyMenu guifg=' . '<c-r>=g:menu_s ? g:menu_fg : g:menu_bg<cr>'<cr>
nn <buffer> <cr> :exe substitute(getline('.'),'.*COMMAND: ','','g')<cr>
norm <space>
echo 'Menu Loaded'
endf
au BufCreate *.menu call Menu()
If you add above code in your vimrc and then load awesome.menu, your command text will be hidden and you can use "space" to toggle its visibility and "enter" to execute it.
first thing you need to take care is, :exec doesn't support [range] , that is, you cannot :% exec !whatever
If I understood you right, you want to for each line in your example, pick part of the line, the text after COMMAND:, as external shell command, and execute it.
You can try this command:
exec '!'.substitute(getline('.'),'.*COMMAND: ','','g')
To apply it on all your lines, you can consider to use macro, it is pretty easy. Don't put sed in, it doesn't help much.
If you want to first execute the cmd, and then modify the line, remove COMMAND:.. part, you can chain a :s after the exec ...:
exec '!'.substitute(....)|s/COMMAND:.*//

Pass variable to tabnew

I have a variable set like so:
let filename="/tmp/" . system('date +"%Y%m%d"') . ".txt"
How do I open a new buffer using that variable as filename, like tabnew /tmp/20130117.txt
No system call needed, although vim's docs do mention that strftime isn't available on all systems (I assume only some esoteric ones):
if exists('*strftime')
let fn = strftime('/tmp/%Y%m%d')
exe "tabnew" fn
endif
Taking a cue from Vim: How do I chdir to path in a variable, I did:
let $FILENAME="/tmp/" . system('date +"%Y%m%d"')
tabnew $FILENAME
I just need to figure out how to remove the "#" character at the end of the string output of the system function.

VIM: Check if a file is open in current tab? window? (and activate it)

In vim, you can check if a file is open in the current buffer with bufexists. For a short filename (not full path), you can check if it's open using bufexists(bufname('filename')).
Is there any way to check if a file is open in a tab?
My closest workaround is to do something like:
:tabdo if bufnr(bufname('filename')) in tabpagebuflist(): echo "Yes"
However, that's sort of pythonic pseudocode... I'm not sure how to get that to work in vim. My goal is for an external applescript to check if a file is already open and if so go to a line in that file.
Ideally, I'd like to be able to search through different GUI windows too, but I've gathered (e.g. Open vim tab in new (GUI) window?) that working with different GUI windows is very challenging / impossible in VIM.
My impatience and good documentation got the better of me... here's the solution (greatly aided by Check if current tab is empty in vim and Open vim tab in new (GUI) window?). The source is at https://github.com/keflavich/macvim-skim
function! WhichTab(filename)
" Try to determine whether file is open in any tab.
" Return number of tab it's open in
let buffername = bufname(a:filename)
if buffername == ""
return 0
endif
let buffernumber = bufnr(buffername)
" tabdo will loop through pages and leave you on the last one;
" this is to make sure we don't leave the current page
let currenttab = tabpagenr()
let tab_arr = []
tabdo let tab_arr += tabpagebuflist()
" return to current page
exec "tabnext ".currenttab
" Start checking tab numbers for matches
let i = 0
for tnum in tab_arr
let i += 1
echo "tnum: ".tnum." buff: ".buffernumber." i: ".i
if tnum == buffernumber
return i
endif
endfor
endfunction
function! WhichWindow(filename)
" Try to determine whether the file is open in any GVIM *window*
let serverlist = split(serverlist(),"\n")
"let currentserver = ????
for server in serverlist
let remotetabnum = remote_expr(server,
\"WhichTab('".a:filename."')")
if remotetabnum != 0
return server
endif
endfor
endfunction
then use like so:
exec "tabnext ".WhichTab('my_filename')
echo remote_foreground( WhichWindow('my_filename') )
or, from the command line, here's a script to go to a particular line of a file using WhichTab:
#!/bin/bash
file="$1"
line="$2"
for server in `mvim --serverlist`
do
foundfile=`mvim --servername $server --remote-expr "WhichTab('$file')"`
if [[ $foundfile > 0 ]]
then
mvim --servername $server --remote-expr "foreground()"
mvim --servername $server --remote-send ":exec \"tabnext $foundfile\" <CR>"
mvim --servername $server --remote-send ":$line <CR>"
fi
done
I'd reply to keflavich, but I can't yet...
I was working on a similar problem where I wanted to mimic the behavior of gvim --remote-tab-silent when opening files inside of gvim. I found this WhichTab script of yours, but ran into problems when there is more than one window open in any given tab. If you split windows inside of tabs, then you will have more than one buffer returned by tabpagebuflist(), so your method of using the buffer number's position in the List doesn't work. Here's my solution that accounts for that possibility.
" Note: returns a list of tabnos where the buf is found or 0 for none.
" tabnos start at 1, so 0 is always invalid
function! WhichTabNo(bufNo)
let tabNos = []
for tabNo in range(1, tabpagenr("$"))
for bufInTab in tabpagebuflist(tabNo)
if (bufInTab == a:bufNo)
call add(tabNos, tabNo)
endif
endfor
endfor
let numBufsFound = len(tabNos)
return (numBufsFound == 0) ? 0 : tabNos
endfunction
I think I can just return tabNos which will be an empty list that gets evaluated as a scalar 0, but I just learned vimscript and am not that comfortable with the particulars of its dynamic typing behavior yet, so I'm leaving it like that for now.

Resources