How to fix buffer in a window in vim? - vim

Can I fix a buffer so that the only way to remove it from vim window is closing it?
For instance, I'm using the NERDtree plugin, which displays the filesystem in a vim window. Sometimes I forget to change focus to other window before using the quickfix commands and the erroneus file ends up replacing the file tree. (Not to mention that NERDtree's window default width is only 31)
Edit:
What I'm trying to achieve with this question is to simulate Eclipse's notion of views and editors inside vim. In this terms, NERDTree (and other plugins destined to exclusively display information) would be a view while the other windows would be editors.

This isn't exactly an answer, but if you screw up, Ctrl-^ undoes a change in a buffer's content.

I've written an autocommand that does this. Adding the following to vimrc will prevent NERDtree buffers from being overwritten:
autocmd BufEnter * if bufname("#") =~ "NERD_tree" && bufname("%") !~ "NERD_tree" | b# | endif
The autocommand runs every time a new buffer is opened -- if it detects that the previous buffer was NERDtree and the current buffer is not NERDtree, then it will go back to the NERDtree buffer, essentially 'locking' NERDtree in place.

Related

NERDTree live-preview (like sublime sidebar)

Sublime's sidebar has a cool feature, where I can just press the arrow keys and get a quick glance of what each file looks like in the editor pane. It doesn't actually open the file -- just shows it in the editor pane.
I want to do the same thing with NERDTree in Vim (or Vinegar/netrw, doesn't really matter). I know NERDTree lets me use go to open the file under the cursor while keeping the tree in focus, but (a) that requires two keystrokes, and (b) it creates a new buffer for every file I "preview" like this, so... not much of a preview really.
Is there a way to make NERDTree or Vim emulate this Sublime feature?
Yes, there is. Vim has a feature called "preview window". You can open a file in the preview window with :pedit <filename>. If you want to plug this into NERDTree, you could create a file in the ~/.vim/nerdtree_plugin/ directory, for example "live_preview_mapping.vim", with the following contents:
if exists("g:loaded_nerdree_live_preview_mapping")
finish
endif
let g:loaded_nerdree_live_preview_mapping = 1
call NERDTreeAddKeyMap({
\ 'key': '<up>',
\ 'callback': 'NERDTreeLivePreview',
\ 'quickhelpText': 'preview',
\ })
function! NERDTreeLivePreview()
" Get the path of the item under the cursor if possible:
let current_file = g:NERDTreeFileNode.GetSelected()
if current_file == {}
return
else
exe 'pedit '.current_file.path.str()
endif
endfunction
The first part is simply a load guard, so the file is sourced only once, just boilerplate. The second part adds a keymap using the NERDTree API for the <up> key that calls the given callback function.
The callback function is the meat of the code, but it should be fairly easy to understand -- it takes the node under the cursor, if there is one, and executes a :pedit with the filename.
You can even do this more easily with a simple filetype-specific mapping, something like this:
autocmd FileType nerdtree nnoremap <buffer> <up> :call NERDTreeLivePreview()<cr>
But the former is the approach recommended by the plugin (see :help NERDTreeAPI). If nothing else, this adds a help entry to the ? key for it, and it keeps nerdtree extensions in one place.
For more info on what you can do with the preview window, try :help preview-window. For instance, you can close it with <c-w>z, but you can map that to whatever you'd like, that's not really related to the NERDTree anymore. If you're unhappy with where the window shows up, consider changing the "pedit" to "botright pedit" or "leftabove pedit" or whatever you want. Check the help for :leftabove and take a look at the related commands below.
NERDTree doesn't offer anything automatic out of the box. I like a preview window that hijacks the last active window and allows for opening the buffer there, or to split with the original buffer. This extension does that, and its source code is pretty short.
https://github.com/numEricL/nerdtree-live-preview
With netrw, to preview a file: with the cursor atop a file, press "p".

Slimv - Change REPL Vertical Split

I am using Slimv (version 0.9.13) with Vim (version 7.4). When I compile or run code or do anything that opens the REPL, it always opens in a window above my code, with the height split 50/50. Is it possible to make it open in a smaller window and below my source code by default?
According to the documentation (https://github.com/vim-scripts/slimv.vim/blob/master/doc/slimv.txt#L461) doing the below should make the REPL open in a split below the current window.
let g:slimv_repl_split=2
As for the size of the window, I don't think slimv provides an option for that.
However, I think an autocommand could do the trick.
autocmd BufEnter REPL :20wincmd _
'20' Can be replaced by whatever height you want the window to be, and 'REPL' should be replaced by the name of the REPL buffer. The default value g:slimv_repl_name is 'REPL' so it should work. If you need any more information on the commands used in this solution, you can read these in vim:
:help :autocmd
:help autocmd-events
:help :wincmd

Make vim commands work on initial window like NERDTree, MiniBufExplorer and CtrlP does

I have NERDTree and MiniBufExplorer open at the launch of vim, so I have three windows. Whenever I use the aforementioned plugins the files/buffers are presented in the correct window, which is the initial one. However whenever I use a command such as :e ~/.vimrc the command works on the window which contains the cursor. This means I have to always remember to move the cursor over to the window used for editing. I was wondering if there was a way to have commands work on that window regardless of where the cursor is, or if file buffers would automatically present themselves in that window?
I was looking at a way to have the cursor move over to the right window when : (or some other key I could use) is pressed, but I couldn't figure out a way as there is no way to identify windows (or is there?).
Files, Buffers, and Splits Oh My!
You are asking Vim to change how every single file and buffer command to change to accommodate your plugin choice and workflow. You are going against the vim way here and it will hinder your use of Vim's splits.
First things first is to realize that Vim has no concept of Project drawers, only splits/windows. This means that NerdTree and other plugins go to great lengths to emulate Project Drawer behavior and ultimately fail.
Lets look at problems with using NerdTree and MiniBufExplorer as always open windows:
NerdTree:
Wasted space. How often do you look at your file structure? 10% of the time? Less?
Splits - open up a few split now switch to the bottom right most split via <c-w>b. Open up a file via NerdTree in this window. Did you use <c-w>t to go to the top left most window? Feels like quite a nuance to use so many window commands just to open a file
NerdTree doesn't play well when rearranging splits. Create some splits then do <c-w>J or <c-w>H. See how it messed up your layout
MiniBufExplorer
Scale - MiniBufExplorer just doesn't scale with the number of buffers. I have opened up over a hundred buffers without issue. I can not imagine the waste of space this would cause with MiniBufExplorer
There is little to be gained by seeing all your open buffers all the time. You only need to see them when you are switching to a different buffer
Switching buffers - You can switch buffers just as easily by mapping the :bnext and :bprev commands
More on switching buffers - Moving to the MiniBufExplorer window is tedious and annoy if that is how you want to switch buffers
Rearranging windows - Same as NerdTree
MiniBufExplorer is akin to using Vim's tabs for each file in vim see: Use buffer effectively
The Vim Way
As laid out in the Vimcast post, Oil and vinegar - split windows and the project drawer, Vim prefers to just open a file explorer when you need it then switch away from it when it isn't needed. You can user NerdTree in this fashion too, just forget the alway on file explorer bit. There are other ways of opening files in vim:
Use file completion, via <tab>, with commands like :e and :sp
Use <c-d> instead of <tab> to get a list of completions
:e and :sp commands take globs. e.g. :e *.c and :e foo/**/bar.c
:find and setup 'path' and 'suffix' options
Ctags or cscope to jump to tags
gf will go to a file under the cursor
Look into fuzzy finders like CtrlP or Command-T
Create project specific navigation via Projectile (Rails is a good example of this)
There are plenty of ways to switch buffers in Vim:
:b and :sb take buffer numbers but also names that will complete and glob
Use :ls to see a list of your buffers then use :b to switch directly
<c-6> will go the the previous buffer
Map :bnext and :bprev example [b and ]b are Unimpaired.vim mappings
set hidden make switching buffers easier. Don't worry vim will let you know if you have unwritten buffer before exiting
Once again look into fuzzy finder plugsin like CtrlP and Command-T to switch buffers
Vim is split happy. Make sure you use splits as effectively as you can. There are many split commmands, see :h opening-window. Better yet read the whole :h window help file, there are many treasure in there.
The core of a solution can be found in the NERDTree source via s:Opener._firstUsableWindow, which I then edited some to get the id and include modified buffers:
" Returns the first window ID containing a file buffer
"
" Iterates through window numbers until the last (winnr('$')),
" Skipping special buffer types & preview windows
function! FirstFileWindowID()
let i = 1
while i <= winnr('$')
let bnum = winbufnr(i)
if bnum !=# -1 && getbufvar(bnum, '&buftype') ==# ''
\ && !getwinvar(i, '&previewwindow')
" TODO I don't know what excluding &hidden does in the original,
" but may be desirable for correctness
return win_getid(i)
endif
let i += 1
endwhile
return -1
endfunction
This can then be used with win_execute to target recent file buffers, gaining tab-like behavior with buffers:
"tab movement (ctrl-n for next tab, ctrl-p for previous)
map <c-n> :call win_execute(FirstFileWindowID(), 'bnext')<CR>
map <c-p> :call win_execute(FirstFileWindowID(), 'bprev')<CR>
I use tmux for all my pane management, so while I'm sure leveraging the full range of vim's tab / window / buffer paradigm is best for many, I personally don't use it to is fullest extent.

How to script MacVIM to split windows the way I want

I'm just starting to try MacVIM as a primary text editor after years of using vi only when I was sshing into a remote server. After installing the Janus set of extensions, I launch MacVIM from the Terminal with macvim . to get a listing of the current directory.
When launching MacVIM in this manner, by default I get two windows, a narrow NERDtree window and a buffer window taking up the rest of the space available and the focus being in the NERDtree window. I want to split the non-NERDtree window into either two equal parts or, failing that, create a new window at least 83 columns wide. From the default setup, I would enter <CTRL-W>l:vsplit, and that would do the job.
Of course, I don't want to do that every time, so how do I script it in my .gvimrc (or actually, with Janus, .gvimrc.local) file? I've tried a number of ways to do this all with no success. Attempts have included 80vsplit, and
<C-W>
l
vsplit
I use this in my .vimrc to move the cursor to the content panel when vim starts, you may want to put this in your list of commands to get to the right panel before splitting:
autocmd VimEnter * NERDTree "run nerdtree
autocmd VimEnter * wincmd p "cursor to right

How can I execute a command when a buffer is closed in vim?

Is there something like a close-window-hook in vim/vimscript, so that I can call a function every time a window is closed?
I want to use it for the following scenario:
I use an extra scratch window to display information about the file, and when I close the file I want the scratch window to be closed automatically so that vim exits.
If you have any ideas how to achieve that without a hook that will be just as fine.
edit:
I know about :qa[ll], but I am lazy and only want to type :q or ZZ.
edit2.71828183:
I accepted the autocommand answer as it was closest to the original question, but found another solution in using a preview window instead of a split window. A preview window is automatically closed when the last "normal" window is closed..
autocommands are amazing! I'm pretty sure that in this case, BufLeave will do the job, but you might want BufWinLeave? Have a look at :help autocmd-events for a full list of events.
The other bit you'll care about is: you can have buffer-local autocommands! (:help autocmd-buflocal)
You can define one for the current buffer using au BufLeave <buffer> .... My best guess is that you could run this in whatever command creates the scratch window. You should be able to cache the scratch window's buffer number in a global variable when you open the scratch window, then your autocommand could just delete that buffer (:help :bdelete).
au BufLeave <buffer> bdelete g:scratch_buffer
call CreateScratchWindow()
function CreateScratchWindow() {
...
let g:scratch_buffer = bufnr("")
}
There's also a function winbufnr, for getting buffer numbers by window. You can use either one - just make sure that the scratch window/buffer is current when you use it! (The "" means current window/buffer).
Add a mapping.
:nnoremap :q :qa
then, if you only want to use :q one day, you can just
:qa<backspace>
and normally, you can just
:q<enter>
and get
:qa<enter>
for free.
Ok, not really a new question, but I found it looking for, what I now know, BufWinLeave. However, the scenario the author is describing is something I have in my vimrc with NerdTree, e.g. when the last buffer is closed, I want vim to close the NerdTree "buffer" and then quit.
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTree") && b:NERDTree.isTabTree()) | q | endif
Replace the NERDTree specific stuff with how the scratch buffer is identified.
You can use
:quitall
or
:qall
to close all windows at once.
add a ! if you want to ignore unsaved changes.
:qall!

Resources