VIM: Open separate help/hint/text file automatically in a vsplit - vim

I have the following problem, or lets say idea, with vim. When I am writing latex documents I want automatically open a file ~/.vim/latex_hints, where I collected some hints, shortcuts, workarounds,..., in vsplit on the right side. The hint file should be loaded read only and automatically closing when I close the latex document.
After a few experiments I added the following commands to my vimrc:
function Handletexfile()
setlocal cc=80
setlocal wrap
setlocal textwidth=80
belowright vsplit +setl\ ro\ nomodifiable ~/.vim/latex_hints
endfunction
autocmd BufRead,BufNewFile *.tex call Handletexfile()
and
function Handletexfileexit()
let tablist = []
call extend(tablist, tabpagebuflist(tabpagenr()))
for b in tablist
echo b . " ". bufname(b)
if bufname(b) =~ "vim/.*_hints"
echo "Close buffer..". b
execute "bdelete! ".b
endif
endfor
endfunction
autocmd BufWinLeave *.* call Handletexfileexit()
When I open a tex file, my hint file is displayed on the right side as read only and not modifiable. But when I close using :q or :wq the buffers open in the current tab are listed and the one matching to the hint file is selected by the if statement. But I get the following output
1 abstract.tex
2 ~/.vim/latex_hints
Close buffer..2
and my vim crashes with an segfault.

The first part of your requirement translates pretty straightforward into Vimscript:
autocmd BufWinEnter <buffer> belowright vsplit +setl\ ro ~/.vim/latex_hints
Put this into ~/.vim/after/ftplugin/tex.vim, or prepend :autocmd FileType tex to the above command.
The latter part is more complex; on BufWinLeave, you'd have to check all other windows for the opened cheat file with bufwinnr(), go to it (:wincmd w), and :close it.

As an alternative use the preview window with your hint file. The preview window gives you some advantages:
It is small and out of the way
Can close it easily via <c-w>z from any other window
Can jump to the preview window from any window easily via <c-w>P (jump back via <c-w>p)
You can do this via the :pedit command. For example:
autocmd BufWinEnter <buffer> pedit +setl\ ro ~/.vim/latex_hints
Personally I feel like it would be better to create command or mapping to open your hints files as you may eventually out grow the file as time goes on. I would also set the 'bufhidden' to wipe and un-list the buffer with 'nobuflisted'.
You may also want to look into getting a nice snippet plugin.

Related

How to delete a buffer when the window is closed?

When I have a new temporary buffer/window and I just do :q, it quits the window but do not clean the buffer. When I quit Vim, it will always popup and tell me there is No write since last change for buffer [No Name].
I have the option for hidden and bufhidden
set hidden
set bufhidden=wipe
It closes the window without warning, but still popup when closing the whole Vim program.
I tried to add an autocmd:
au BufLeave * bw
It works when I quit a window, but will clean the buffer when I want to just open a new window/tab (as it does not distinguish switch window and close window). I also tried BufWinLeave and WinLeave, I did not achieve what I need.
I came up with something like:
function! OnBufHidden()
if expand("<afile>") == ""
execute ":bw! " . expand("<abuf>")
endif
endf
set hidden
autocmd BufHidden * call OnBufHidden()
It should work but it does not. The execute is executed because I tried with some echo inside, but not sure why bw! is not executed.
You can create a scratch buffer in a vertical scratch window with this command:
command! SC vnew | setlocal nobuflisted buftype=nofile bufhidden=wipe noswapfile
With :set bufhidden=wipe, the buffer's contents are lost without confirmation, but only if it is hidden (e.g. via :hide) first; :set hidden doesn't do this, it just enables hiding. If you use :q and the buffer is still visible, you'll get the confirmation.
To get what you want, also :setlocal buftype=nofile (as in #romainl's answer). Then, you'll never get a confirmation.

How can I automatically evaluate a script and put the results into an existing window after saving in Vim?

My ideal scenario would be to have Vim split into two windows - first containing the script (python) that I am currently working on and the other showing the result of evaluating that script. This is what I have so far:
:autocmd BufWritePost *.py redir #p | execute 'silent w !python -' | redir END
When saving the script, the contents of the script is piped to the python command, the output of that command is stored in register p. What is the best way to get p into a new/empty buffer displayed in the other window?
Some things I have tried is blast | normal! "pp | bfirst (blast: new/empty buffer, bfirst: buffer containing python script) but this seems to leave me in the "output" buffer and for whatever reason I lose syntax highlighting and need to flip back and forth between the buffers to get it back. I would really like to do this all in place and avoid generating a temp dump file where I pipe the output of running the script and would prefer to avoid using any other external tools to "watch" the python script file and do something when it changes.
My approach was to use the preview window. This allows you to always move to the correct window no matter how many windows you have. It also allows you to "ignore" the fact that the preview window is open when you want to exit vim (you can just do :q rather than :qa for instance).
autocmd BufWritePost *.py call OutputWindow("python")
autocmd BufWritePost *.rb call OutputWindow("ruby")
function OutputWindow(executable)
let filename=expand('%:p')
" move to preview window and create one if it doesn't
" yet exist
silent! wincmd P
if ! &previewwindow
" use 'new' instead of 'vnew' for a horizontal split
vnew
set previewwindow
endif
execute "%d|silent 0r!" . a:executable . " " . filename
wincmd p
endfunction
There may be a less verbose way to accomplish this but it appears to work pretty well as is.

How to set the default to unfolded when you open a file?

In my .vimrc I've put set foldmethod=syntax to enable folding of methods etc. However, I don't like the default that everytime I open a file, the whole thing is folded. Is there a way to enable foldmethod, yet have files unfolded when I open them?
set foldlevel=99
should open all folds, regardless of method used for folding. With foldlevel=0 all folded, foldlevel=1 only somes, ... higher numbers will close fewer folds.
You can put this in your .vimrc:
au BufRead * normal zR
It declares an automatic command (au), triggered when a buffer is read (BufRead), matching all files (*) and executes the zR (opens all folds) command in normal mode.
set nofoldenable
Adding this to your .vimrc will temporarily disable folding when you open the file, but folds can still be restored with zc
In .vimrc add an autocmd for BufWinEnter to open all folds automatically like this:
autocmd BufWinEnter * silent! :%foldopen!
That tell vim to execute the silent :%foldopen! after opening BunWinEnter event (see :h BufWinEnter). The silent %foldopen! will execute foldopen on the whole buffer thanks to the % and will open all folds recursively because of the !. Any eventual error message will be suppressed by silent. (You could get error messages like E490: No fold found if the buffer actually didn't contain any fold yet)
Note: You could use BufRead instead of BufWinEnter but then if the file has a modeline that enables the folding that will override this autocmd. I mean BufRead autocmds run before the modeline is processed and BufWinEnter will run them after. I find the later to be more useful
You can add
set foldlevelstart=99
to your .vimrc file, and it will start editing any new file with all folds open.
If you want a way to have it display unfolded as soon as it is opened, you can use set foldlevelstart=99 as a lot of answers explained.
But, if you just want to see them unfolded, you can just press zi and it will unfold everything. Another, zi will close them back.
You could map it to keys to enable it.
For example,
nmap ,f :set foldmethod=syntax<CR>
Then while in normal mode hit the ",f" key combination
You can open unfolded file when you put set nofoldenable into your .vimrc file.
autocmd BufReadPost * silent! :%foldopen!
This worked best for me. After a buffer gets opened all folds are opened. This opens them to the correct level.
The set foldenable method was not good, because if I choose to close one fold level, it enabled folding again, and folded every thing to 0 level, instead of just going down one level on the one I activated.

How can I reuse the same Vim window/buffer for command output, like the :help window?

Though I'm no Vim expert, I've been scratching an itch by working on a rough Vim equivalent of TextMate's ⌘R functionality to run Ruby code from a buffer and display the output.
The script currently just opens a new window (split) with :new and puts the output there. If you run it multiple times, it opens multiple windows. Ideally, I'd like it to reuse the same window within each tab page, much like :help does.
I've looked but haven't found a way to achieve this. Any pointers?
You can create a scratch buffer with a name, so that on subsequent calls you can check to see if that buffer is already open (and if so reuse it) or you need a new one. Something like this:
function! Output()
let winnr = bufwinnr('^_output$')
if ( winnr >= 0 )
execute winnr . 'wincmd w'
execute 'normal ggdG'
else
new _output
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
endif
silent! r! ls
endfunction
I guess you could do it manually.
For Example:
:e test1.txt (or use any existing buffer)
:vs (or :new or :sp)
:b <tab> (keep pressing tab until test1.txt comes up. or use the buff no)
You may want to use the quickfix window so you can also jump to errors. If you get a ruby compiler vim plugin, you can run :make to run your code. You should see output and errors in the quickfix (:copen).

How to map keys in vim differently for different kinds of buffers

The problem i am facing is that i have mapped some keys and mouse events for seraching in vim while editing a file. But those mappings impact the functionality if the quickfix buffer.
I was wondering if it is possible to map keys depending on the buffer in which they are used.
EDIT - I am adding more info for this question
Let us consider a scenario. I want to map <C-F4> to close a buffer/window. Now this behavior could depend on a number of things.
If i am editing a buffer it should just close that buffer without changing the layout of the windows. I am using buffkil plugin for this.
It does not depend on extension of file but on the type of buffer. I saw in vim documentation that there are unlisted and listed buffer. So if it is listed buffer it should close using bufkill commands.
If it is not a listed buffer it should use <c-w>c command to close buffer and changing the window layout.
I am new at writing vim functions/scripts, can someone help me getting started on this
function KillBuffer()
if &buflisted
" bufkill command here
else
execute "normal! \<C-w>c"
endif
endfunction
noremap <C-F4> :call KillBuffer()<CR>
Put this in your .vimrc
Or, if you want to handle quickfix window as unlisted buffers (in my Vim it is listed):
function KillBuffer()
if &buflisted && !&filetype=="qf"
" bufkill command here
else
execute "normal! \<C-w>c"
endif
endfunction
noremap <C-F4> :call KillBuffer()<CR>
According to the manual, you could replace execute "normal! \<C-w>c" with simpler close! in the above scripts.
You can create filetype specific settings. First, in your vimrc file, make sure filetype plugins are enabled by adding
filet plugin on
Then make a filetype specific plugin. Under Unix create a file called ~/.vim/after/ftplugin/[file-type-name].vim and put your mapping in there. In Windows the directory is $HOME/vimfiles/after/ftplugin. The [file-type-name] is the type detected by Vim, sometimes the same as the filename extension, e.g c.vim, python.vim, etc. Vim can tell you what the type is after you open the file if you enter
:echo &ft
You can intercept certain types of files loading and assign buffer specific mappings.
au! BufRead *.ext call <SID>init_hotkeys()
function s:init_hotkeys()
nnoremap <buffer> <CR> :Action<CR>
endfunction
To map complex logic on the hotkey you can use write something like this in your vimrc, or even better - put the following to the closebuffer.vim file inside your vim plugin directory
function s:close_buffer()
if &buflisted
" your command here from the killbuf plugin
echo "Listed Buffer"
else
wincmd c
" or
" normal <c-w>c
endif
endfunction
nnoremap <C-F4> :call <SID>close_buffer()<CR>
I use this in my vimrc to insert an empty line above or below the current line using only return and shift-return (as opposed to o<Esc> or O<Esc>) without interfering with the open file behaviour you want in the quickfix list.
" Use enter to insert newlines in normal mode, but not in quickfix
function! s:insert_line(direction)
if &buftype == "quickfix"
execute "normal! \<Enter>"
else
if a:direction == 'below'
execute "normal! o\<Esc>"
else
execute "normal! O\<Esc>"
endif
endif
endfunction
nmap <Enter> :call <SID>insert_line('below')<CR>
nmap <S-Enter> :call <SID>insert_line('above')<CR>
Hopefully someone else will find this useful.

Resources