Pass variable to tabnew - vim

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.

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 script about concating a variable and a const string

I'm writing a function in my ~/.vimrc file, but I got a problem.
I want to concat a variable and a const string, so I do this like below:
let linux_version=system('uname -r')
let host_kernel_dir= "/lib/modules/" . linux_version . "/build"
echo host_kernel_dir
I wanted result is /lib/modules/4.8.0-52-generic/build, but I got this result
"/lib/modules/4.8.0-52-generic
/build "
So it seems a \n was added. So how to get rid of this \n?
This removes newlines from the system output
let linux_version = substitute(system('uname -r'), '\n\+$', '', '')
system() result must be chomped (for those who have known perl), I use the following:
function! lh#os#system(cmd)
return system(a:cmd)[:-2]
endfunction
Another solution using /proc pseudo filesystem:
let linux_version=readfile('/proc/sys/kernel/osrelease')[0]

Escaping "%" in Vim when shelling out, so it's not expanded to filename?

Say I have this vimscript as "/tmp/example.vim":
let g:input = "START; % END"
exec("! clear && echo " . shellescape(g:input))
If I open that file and run it with :so %, the output will be
START; /tmp/example.vim END
because the "%" is expanded to the buffer name. I want the output to be
START; % END
I can use the generic escape() method to escape percent signs in particular. This works:
let g:input = "START; % END"
exec("! clear && echo " . escape(shellescape(g:input), "%"))
But is that really the best way? I'm sure there're more characters I should escape. Is there a specific escape function for this purpose? Or a better way to shell out?
For use with the :! command, you need to pass the optional {special} argument to shellescape():
When the {special} argument is present and it's a non-zero
Number or a non-empty String (|non-zero-arg|), then special
items such as !, %, # and <cword> will be preceded by
a backslash. This backslash will be removed again by the |:!|
command.
:exec("! clear && echo " . shellescape(g:input, 1))
You need to properly escape the '%'. So it should be:
let g:input = "START; \\% END"
This seems to do it:
let g:input = "START; % END"
echo system("echo " . shellescape(g:input))
It should be noted I don't really care about the output; I'll use this with silent in a larger script.

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.

How to get a list of files that match some pattern?

How to get a list of files that match some pattern if filenames may contain \n character?
Update: I want solution in pure vimscript, so that it will depend on nothing but vim.
Update2:
Expected output of glob function
Consider the following script:
:!touch /test ; mkdir /test$'\n' ; touch /test$'\n'/test
:echo glob('/**/test')
/test
/test
/test
That is the output of glob function. I want it be the following:
:echo NewGlob('/**/test')
['/test', '/test
/test']
you may try using ls with -b option. check the man page
:echo split( glob("pattern", '.'), "\r")
If you want the pattern to match files containing \n exclusively, use "*\n*".
EDIT:
I see, the character you use in the filename is the same as the one used by glob() to distinguish results. As a consequence, we can't rely of glob().
ghostdog74 gave a good answer then:
:echo split( system('ls -1bd test*'), "\n")
Of course, this is not portable. But I do not really call this the general case -- I never see this kind of names. If glob() cannot handle this general case, then glob() must be fixed.
May be you can try with embedded python or ruby as arnold suggested. But that isn't portable either.
Try this python program. It will match files like abc\n1, abc\n2abc etc.
#!/usr/bin/env python
import os, re
dirlist = os.listdir('.')
pattern = 'abc\n\\d'
for fname in dirlist:
if re.search(pattern, fname):
print fname.replace('\n', '\\n')
It will replace line end ('\n') characters with "\n" string for clarity.
I finally had to write the following function that returns just the same results as python's os.listdir:
function s:globdir(directory, ...)
return split(glob(escape(a:directory.g:os#pathSeparator, '`*[]\').
\ get(a:000, 0, '*')),
\"\n", 1)
endfunction
function s:GetDirContents(directory)
let dirlist = s:globdir(a:directory)+s:globdir(a:directory, '.*')
let nlnum=len(split(a:directory, "\n", 1))-1
let r=[]
let i=0
let addfragment=""
for directory in dirlist
if i<nlnum
let i+=1
let addfragment=directory."\n"
continue
else
let directory=addfragment.directory
let i=0
let addfragment=""
endif
let tail=fnamemodify(directory, ':t')
if tail==#'.' || tail==#'..'
continue
endif
if directory[0]!=#'/'
let r[-1].="\n".directory
else
call add(r, tail)
endif
endfor
return r
endfunction

Resources