Pull to refresh

Vim :bw, :bd, :bun, :quit, :close. Что со всем этим делать?

Reading time3 min
Views10K
Vim имеет множество команд для закрытия чего угодно и в каких угодно сочетаниях, но чего он не умеет так это закрывать все одной командой. Человеку который начал использовать Vim недавно, это может показаться довольно странным. Попробуем разобраться, как исправить эту ситуацию.


Когда я впервые познакомился с Vim у меня глаза разбежались от обилия способов
закрытия фaйлов, окон и самого редактора. Вот перечень команд удаления(закрытия)
буферов и окон(в квадратных скобках указаны полные названия команд):

  • :bd[elete] — удалить буфер. На самом деле просто делает буфер невидимым, но
    оставляет его в памяти.
  • :bw[ipeout] — полностью стирает(wipeout) буфер из памяти
  • :bun[load] — удаляет буфер из памяти, но оставляет его в списке буферов.
    Бесполезная команда, кроме тех случаев когда у Вас либо
    гигантских размеров файл либо чрезвычайно мало оперативной памяти.
  • :close — закрыть текущий сплит. Буфер не удаляется
  • :q[uit] — чисто теоретически команда должна закрывать Vim, на практике все немного сложнее


Я настоятельно рекомендую установить в .vimrc опцию set confirm, это позволит
избежать надоедливых сообщений об ошибке при попытке закрыть(удалить) буфер с
не сохраненными изменениями. Вместо ошибки будет появляться подтверждение
закрытия не сохраненного файла.

Для закрытия файла в традиционном смысле(для любого другого редактора)
подходит команда :bw, но к сожалению все команды по работе с буферами
обладают отвратительным свойством закрывать то окно в котором, в данный момент
они отображаются(естественно, если это не единственное окно на экране).
Данная проблема проблема решается установкой плагина bufkill.vim и использованием команды
:BW(:BD, :BUN) вместо :bw(:bd, :bun).

Команда :q должна закрывать Vim, но ее поведение зависит от ситуации и далеко не
интуитивно. Для закрытия окна используется команда :close, но закрыть с её
помощью последнее окно Вы не сможете. Также нельзя закрыть Vim с помощью
команд удаления буфера(даже если буфер последний).
По итогу пустой буфер невозможно удалить, последнее окно
нельзя закрыть и работа с несколькими файлами превращается в игру «угадай какую
команду нужно использовать сейчас — :bw, :BW, :q или :close». После
прочесывания форумов, мне пришлось изобретать велосипед, потому
как нужный мне я так и не нашел. Что мне было нужно так это привычный(по другим
редакторам) и интуитивный способ быстро закрывать файлы, окна и сам Vim.

Первая проблема — определиться с алгоритмом «привычного» способа производить все
вышеописанное. Путем проб и ошибок алгоритм стал вот таким:



На первый взгляд немного сложно, но когда начинаешь использовать — все встает на
свои места. Конечно это не панацея — окна(не буферы) по прежнему необходимо закрывать
с помощью :close.

Вот так выглядит реализация:

function! CountListedBuffers() 
  let cnt = 0 
  for nr in range(1,bufnr("$")) 
	if buflisted(nr) 
	  let cnt += 1 
	endif 
  endfor 
  return cnt 
endfunction 

function! SmartExit()
	let s:BufferToKill = bufnr('%')
	let s:EmptyBuffer = 0

	if bufname('%') == '' && ! &modified && &modifiable
		if &buftype == 'nofile' && &swapfile == 0
			" Is scratch buffer, not empty
		else
			let s:EmptyBuffer = 1
		endif
	endif

	" Get a list of all windows which have this buffer loaded
	let s:WindowListWithBufferLoaded = []
	let i = 1
	let buf = winbufnr(i)
	while buf != -1
		if buf == s:BufferToKill
			let s:WindowListWithBufferLoaded += [i]
		endif
		let i = i + 1
		let buf = winbufnr(i)
	endwhile

	" Check that the buffer is last
	if(CountListedBuffers() < 2)
		let s:LastBuffer = 1
	else
		let s:LastBuffer = 0
	endif

	if s:LastBuffer
		if len(s:WindowListWithBufferLoaded) > 1
			execute "close"
		else
			if ! s:EmptyBuffer
				execute "bw | bw"
			else
				execute "q"
			endif
		endif
	else
		let g:BufKillActionWhenBufferDisplayedInAnotherWindow="kill"
		execute "BW"
		let g:BufKillActionWhenBufferDisplayedInAnotherWindow="confirm"
	endif
endfunction


Для работы необходим установленный bufkill.vim.

В итоге мой меппинг для «закрытия всего и вся» выглядит так:

" «Умное» закрытие
nmap qq :call SmartExit()" Закрыть окно, но не удалять буфер
nmap qw <C-W>c

qq используется мною гораздо чаще, она делает именно то, что в моём понимании
должна была бы делать :q, но почему то не делает.

Закрытие

Итог


Vim'ом я пользуюсь с недавних пор, но у меня сложилось впечатление
что писать подобные костыли и велосипеды мне придется еще не раз! Но что уж
греха таить — это чрезвычайно увлекательно. Надеюсь данный мини-плагин или
информация из этой статьи кому-то пригодится.

P.S. Не холивара ради, но как с этим обстоят дела у Emacs?

P.P.S. Вкладками(табами) я не пользуюсь, мне вполне хватает сплитов в пределах одного экрана,
а проблем при работе с буферами они не решают, только добавляют.
Tags:
Hubs:
+20
Comments39

Articles

Change theme settings