Vim: замена строки при сохранении и выходе - PullRequest
0 голосов
/ 27 ноября 2018

В моем vimrc у меня есть эта автокоманда на данный момент:

autocmd Bufwritepre,filewritepre *.py exe ":silent! 1," . 20 . "g/Last Modified :.*/s/Last Modified :.*/Last Modified : " .strftime("%Y-%m-%d %H:%M:%S %z(%Z)")

По сути, заменяет определенную строку в моем заголовке.Он записывает дату последней модификации в заголовок файла.

Работает, но раздражает, так как срабатывает каждый раз, когда я сохраняю файл.Я хотел бы вызвать его только тогда, когда я сохраняю и оставляю файл.

Из этого вопроса: Событие autocmd для выполнения команды: wq - vimscript?

Iполучил что-то вроде:

:autocmd BufWritePost *.py :autocmd VimLeave *.py :! exe ":silent! 1," . 20 . "g/Last Modified :.*/s/Last Modified :.*/Last Modified : " .strftime("%Y-%m-%d %H:%M:%S %z(%Z)")

Это не работает и при выходе из Vim я получаю сообщение об ошибке.Возможно, потому что подстановка строк была первоначально сделана «внутренне» с помощью команд vim, а теперь я пытаюсь сделать это с помощью команд bash?

Не могли бы вы помочь мне решить эту проблему, пожалуйста?

РЕДАКТИРОВАТЬ:

Вот как выглядит мой заголовок:

#!/usr/bin/python
# coding: utf-8

"""
------------------------------------------------------------------------------
* Creation Date : 2018-11-27 14:55:00 +0100(CET)

* Last Modified : 2018-11-27 15:52:57 +0100(CET)

* Created By : JPFrancoia https://github.com/JPFrancoia

* Description :
------------------------------------------------------------------------------
"""

Ответы [ 2 ]

0 голосов
/ 27 ноября 2018

Вы можете попробовать следующий код:

augroup monitor_python_change
    au!
    au QuitPre *.py call s:update_timestamp('now', 'on_QuitPre')
    au BufWritePre,FileWritePre *.py call s:update_timestamp('later', 'on_BufLeave')
augroup END

fu! s:update_timestamp(when, on_what) abort
    if a:when is# 'now'
        sil! au! update_timestamp
        sil! aug! update_timestamp
        if a:on_what is# 'on_QuitPre' && !&l:modified
            return
        endif
        sil! 1/Last Modified : \zs.*/s//\=strftime('%Y-%m-%d %H:%M:%S %z(%Z)')/
    else
        augroup update_timestamp
            au!
            au BufLeave * call s:update_timestamp('now', 'on_BufLeave')
        augroup END
    endif
endfu

Если код не обновляет вашу временную метку, вам может потребоваться изменить команду подстановки:

"      ┌ pattern used in the next substitution command (`//` = last used pattern)
"      ├───────────────────┐
sil! 1/Last Modified : \zs.*/s//\=strftime("%Y-%m-%d %H:%M:%S %z(%Z)")/
"    ├──────────────────────┘
"    └ range of the substitution command
"      (after the first line of the buffer,
"       look for the next line containing `Last Modified : `)

Возможно, замените еешаблон и / или его диапазон.

Если код иногда обновляет вашу временную метку, а это не так, вам может потребоваться изменить условие внутри s:update_timestamp():

if a:on_what is# 'on_QuitPre' && !&l:modified
    return
endif

Текущийусловие препятствует выполнению подстановки, когда функция вызывается из QuitPre (a:on_what is# 'on_QuitPre'), а буфер не изменяется (!&l:modified).

0 голосов
/ 27 ноября 2018

Проблема

Проблема здесь в том, что, хотя такие события, как BufWritePre, всегда запускаются, когда текущий буфер активен (как вы сейчас выполняете :write), такие события, как VimLeave запускаются (или, скорее, могут, в зависимости от того, как вы выходите из Vim), выходить за пределы области действия текущего буфера.Вы могли бы отредактировать несколько файлов (Python или других) во вкладках, в списке аргументов, в разделенных окнах и т. Д. На VimLeave вам придется снова найти все эти буферы и явно перебрать их;механизм :autocmd не сделает этого за вас.

Лучшим триггером будет BufUnload или BufDelete, так как он срабатывает один раз для каждого буфера.Однако даже при наличии сложностей, как объясняет :help BufUnload:

ПРИМЕЧАНИЕ. При выполнении этой автокоманды текущий буфер % может отличаться от буфера, который выгружается<afile>.Не переключайтесь на другой буфер или окно, это вызовет проблемы!

Хотя невозможно :write другой буфер без переключения на него, вы можете очень хорошо выйти из других буферов (например, через :[N]bdelete или :qall).Поскольку вам не разрешено переключаться на затронутый (умирающий) буфер, использование :substitute исключено.Вы можете использовать нижний уровень readfile() и writefile(), с указанием спецификаций буфера, полученных через expand('<afile>:p'), и манипуляций через substitute().Или выполните манипуляции с отметкой времени вне Vim с помощью system() и внешней команды оболочки.

Обсуждение

Как видите, переключение с обновлений при каждом сохранении на обновлениетолько после выхода из Vim / буфер звучит просто, но его очень сложно реализовать (все сделано правильно - вы можете что-то запутать, если, например, редактируете только один файл в сеансе Vim).Я бы предпочел остаться с оригинальным дизайном и работать над «раздражающей» частью.С надежной реализацией (которая, например, не загромождает текущий шаблон поиска и вид окна, как это делает ваше простое решение), это очень естественно, и многие люди используют такую ​​функциональность.Фактически, вы можете использовать мой плагин AutoAdapt или любой из альтернатив, перечисленных на его странице плагина (или другие плагины, о которых я не знал, найденные на vim.org , илив другом месте).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...