Почему: bd # удаляет текущий буфер, если альтернативного буфера не существует?

9

Вот как я воспроизвожу поведение, которое наблюдаю.

Сначала я ввожу эту команду:

echo aaaaa > a
vim a

В Vim я ввожу эти команды:

:ls
:e #
:echo bufname('#')

Вот вывод трех вышеупомянутых команд:

:ls
  1 %a   "a"                            line 1

:e #
E194: No alternate file name to substitute for '#'

:echo bufname('#')

Команда bufname('#')не производит вывод.

Теперь я ввожу эту команду:

:bd #

Текущий буфер удаляется и заменяется буфером «[No Name]»:

:ls
  2 %a   "[No Name]"                    line 1

Я ожидал получить E194ошибку при выполнении :bd #. Почему вместо этого удаляется текущий буфер?

Я использую VIM - Vi IMproved 8.0.

Одинокий ученик
источник
1
Это интересный момент. Вы можете упомянуть в своем вопросе, что это также случай NVIM v0.3.0-dev, я проверил.
Клаус
@LoneLearner Я действительно не ответил на это из-за награды, но если вы собираетесь предложить один, было бы неплохо, если бы вы наградили его за достойный ответ ... увы, вы не вошли в почти неделя и период щедрости закончился ...
Уровень B
1
@BLayer Извините, я забыл назначить награду. Вы написали фантастический ответ. Как только у меня будет достаточно очков на этом сайте Stack Exchange, я начну еще одну награду за этот вопрос и присужду вам награду. Я надеюсь, что это исправит мою ошибку. Спасибо за отличный ответ, который вы написали.
Одинокий ученик
@LoneLearner Эй, пожалуйста, не беспокойтесь. Я ценю ваш комментарий. Не беспокойся о награде. Как я уже говорил, речь шла не о пунктах. Я просто хотел предупредить вас, когда вы в следующий раз получите награду. Положите точки отсюда к этому. Ура!
Слой

Ответы:

7

Доказательство

Поскольку нет альтернативного файла, вы на самом деле просто запускаете обычный старый файл :bd, удаляя текущий буфер ... попробуйте без него, #и вы увидите, что результат будет таким же. Подобное происходит и с :buffer, :sbufferпо крайней мере, парой других команд, которые принимают #в качестве аргумента: они молча ведут себя так, как будто не было передано никаких аргументов.

В том же ключе, если вы попробуете :bunload #вы получите эту ошибку: E90: Cannot unload last buffer. Запустите :bunloadбез аргументов и, опять же, вы получите тот же результат.

Документы

Таким образом, у нас есть свидетельство того, что #его заменяют словом «ничего» (вероятно, пустой строкой). Куда мы отправимся отсюда? Некоторое время я копался в файлах справки, пытаясь найти упоминание об этом поведении. Там не было ничего явно, но :h cmdline-linesговорит (прокрутите страницу вниз или две) ...

Когда символ «%» или «#» используется там, где ожидается имя файла, они расширяются до текущего и альтернативного имени файла.

Я прочитал , что , как Вим ввод #через expand()функцию (т.е. expand('#')) или , по крайней мере , тот же исходный код используется там.

:h expand() говорит:

Разверните .. специальные ключевые слова. .. Когда используется «%» или «#», а текущее или альтернативное имя файла не определено, используется пустая строка.

Звучит знакомо.

Код

Теперь ни одно из вышеперечисленного не является окончательным или дает представление о том, почему? так что я потратил немного времени на копание ... на этот раз в коде. Мой C очень ржавый, и у меня не установлено никаких хороших инструментов, но мне удалось найти функцию, которая выполняет некоторые настройки для :bdeleteвызываемого do_bufdel(). Это посылает аргументы командной строки, через buflist_findpat()которые, если #встречается, возвращает значение curwin->w_alt_fnum. Это «номер буфера» альтернативного буфера ... который не может быть положительным значением в нашем сценарии. (Там нет проверки, является ли файл alt действительным / существует до того, как это возвращаемое значение выбрано.)

Отклонение в do_bufdel()проверке выполняется для этого возвращаемого значения для номера буфера меньше 0, и в этом случае цикл обработки параметров прерывается. Это привело бы к тому, что в основной :bdeleteкод не были бы переданы никакие параметры ... что соответствует моим ранним представлениям.

Что дальше?

Кажется, он работает так, как задумано, и я не увидел ничего похожего на явную ошибку. Возможно, грех упущения, хотя ... угловой случай, который был упущен из виду и поэтому не имеет изящного обращения. Но только разработчики, написавшие это, знают наверняка. Таким образом, последний шаг - попытаться получить их вклад. Как сказал Кристиан Б., спросить в списке vim-dev - это путь.

(Обратите внимание , что buflist_findpat()это функция полезности , поэтому он не будет требовать натяжки предположить , что :bunload, :bufferи т.д. использует это тоже ... что бы объяснить их общее поведение по отношению к #.)

B слой
источник
Я думаю, что еще одна функция для проверки того, существует ли расширенный буфер или нет, будет работать. Вы уверены, что это должно было быть задумано? Я думаю, что это должно быть указано как ошибка.
Клаус
Я думаю, что ваши исследования верны. Кстати, я не думаю, что это на самом деле ошибка.
Кристиан Брабандт
Я просто перефразировал свой вывод ... это не похоже на серьезную ошибку. OTOH, если кто-то думает об этом, можно сделать вывод, что это требует лучшей обработки. Наверное, только разработчик знает наверняка.
B Layer
Да, можно спросить в списке Vim-Dev, чтобы убедиться.
Кристиан Брабандт