Привет, коллеги! Такую задачу, наверное, решал каждый программист-вимер: как сделать так, чтобы видеть имя процедуры, в теле которой в данный момент находится курсор. Во всяком случае, я встречал в интернете несколько раз такие решения.
Для языков типа Си это довольно мудрёно, поскольку опознать функцию не так-то просто; с другой стороны, Вим и сам помогает чем может. Я же пишу в основном на Фортране, и мне чуть легче. Далее - мой вариант.
Я сначала я попробовал симулировать действия вручную: поставить метку в позиции курсора через :mark, произвести поиск, запомнить найденное имя, вернуться... Но, во-первых, экран заметно дергается, во-вторых, подтормаживает, а в-третьих, возврат происходит со смещением строк на экране, что раздражает. Должно быть всё незаметно.
Что же. Сначала создаем функцию, которая просто ищет вверх слово subroutine или function:
function! SubName()
let lineN=search('^\s*subroutine\|^\s*\%(pure\|elemental\|recursive\)\{1}\s*function', 'bnW')
if lineN==0
return '--'
endif
let line=getline(lineN)
let m=matchlist(line, '^.\{-}\%(tine\|tion\)\s\+\(\w\+\)')
if len(m)<1
return '---'
endif
let name=m[1]
return name
endfunction
Сначала мы ищем заголовок процедуры функцией search. Она ищет от позиции курсора по указанному регулярному выражению, которое имеет вид
^\s*subroutine\|^\s*\%(pure\|elemental\|recursive\)\{0,1}\s*function
и состоит из двух альтернатив, разделенных символом \|
Первая альтернатива - это "начало строки, пробелы и слово subroutine", вторая тоже "начало строки и пробелы", затем незахватывающие скобки \%(...\) указывают три альтернативы, которых должно быть не более одной (квантификатор \{0,1}).
Можно и усложнять, я специально выбрал простой вариант. Не атомная станция, чай.
Второй аргумент функции содержит флаги, настраивающие поведение. Первый флаг b предписывает вести поиск назад, вверх по тексту. Второй, n, велит не смещать позицию курсора. Третий, W, запрещает переход в конец файла, если выше по тексту искомое не нашлось.
Функция возвращает номер строки, в которой нашлось совпадение, или нуль, если не нашлось. В последнем случае мы возвращаем строку '--' и выходим.
Извлекаем строку по номеру функцией getline.
Ищем в ней имя процедуры функцией matchlist: по выражению
^.\{-}\%(tine\|tion\)\s\+\(\w\+\)
От начала строки (^) может идти что угодно (.) в любом количестве, но чем меньше, тем лучше (\{-}), а затем либо tine, либо tion в незахватывающих скобках \%(...\), после которых пробелы (один или более, \+) и искомое имя (\w\+, то есть словные символы, один или более), уловленное скобками \(...\)
Мы получим список, в котором под номером 0 пойдет всё совпадение, а под номером 1 содержимое скобок. Либо это пустой список, если совпадение не нашлось (это возможно, если текст не на фортране, и после слова function идет что-то не то). В этом случае мы вернем строку '---'
Если же совпадение нашлось, мы его и вернем.
Разумеется, функцию можно сократить и оптимизировать. Я осознанно написал подробно и понятно.
Теперь нам надо, чтобы эта функция вызывалась при каждом смещении курсора. Можно отловить и каждое нажатие на клавишу, но есть способ лучше: строка информации. Всё равно имя функции будем отображать там. Итак:
:setlocal statusline+=\ [IN:%{SubName()}]
Запись += означает, что надо к строке добавить некоторый текст (потом можете убрать через -= и это очень полезно, если в функции допущены ошибки). Пробел экранирован слешем. Квадратные скобки - только для красоты. Поле %{имя_функции()} просто заменяется на результат функции, то есть на найденное имя или строку -- или ---. Последнее позволяет, например, понять, что допущена опечатка в заголовке.
В основном, это будет работать правильно. Вы будете всегда знать, в теле какой функции находится курсор. Это бывает очень полезно!
Но помните, что разработка не учитывает вообще всех нюансов! Если у вас подпрограмма с атрибутом PURE, то функция собьётся, например. Если вы ниже последней процедуры в файле, или в комментариях выше курсора есть слово function. Да мало ли! Не делайте резких движений, основываясь на её показаниях! Это помощь, а не руководство к действию.
Можно настроить распознавание типа файла так, чтобы эта возможность включалась только для файлов на Фортране. Описанную выше функцию надо поместить в файл ~/.vim.ftdetect/fortran.vim (или другой путь из runtimepath) и добавить туда ещё автокоманды, например такие:
au BufRead,BufEnter *.f90 set statusline-=\ %{SubName()} | set statusline+=\ %{SubName()}
au BufLeave *.f90 set statusline-=\ %{SubName()}
Первая будет реагировать на чтение файла или просто вход в буфер и она сначала попробует убрать из строки информации имя функции, а потом добавит. Это позволит избежать удвоения. При выходе из окна (вторая автокоманда) данное поле будет убираться. В итоге для других файлов может отработать своя функция.
Для других языков функция будет, естественно, другая. И для вашего любимого языка сделать такое несложно, используйте мою наработку как образец. В принципе, можно попробовать сделать единую функцию, которая будет работать для всех языков сразу...
И прежде потестируйте функцию через :echo SubName() А потом уже пробуйте строку информации. Потому что если что-то не так, починить можно, но неподготовленного человека вал сообщений об ошибках может и напугать.
Удачи, коллеги!