АффигительноБольшойТекстовыйФайл4 - Тэги

Jan 27, 2009 00:03

О Большом Текстовом Файле проговорился совершенно случайно, зато теперь ни разу не жалею. Очень благодарен человекам (сэру ollycat, без вопросов которого я бы не взялся за эти заметки - в особенности), за их мнения и примечания. Почему-то всегда лучше работается, когда есть с кем обсудить эту работу. Вопрос с тэгами, поднятый d7s, я решил вчера благодаря паре часов свободного времени и прочищенным свежим воздухом и бадминтоном мозгам :) Заодно, к своему удовольствию разобрался со встроенным в Vim скриптовым языком, до которого ни как не доходили руки.

Чего мне хотелось? Меню, которое бы выводило список тэгов и проставляло бы их в тексте автоматом. Тэг напомню выглядит как отмеченное крылышками =слово=, с завершающим тэгом ==. Некоторое время я обдумывал где хранить такое добро, перепробовал несколько разных вариантов. Потом понял, что в принципе хватит отдельного файлика tag.txt и некоторой "особой виммерской магии". Еще час вдумчивого перелистывания мануала и родился такой вот скрипт.

" автодополнение по табу ---------------------------------------------------

function Snipping_close()
     execute "q"
endfunction

function Snipping()
   if bufname("%") == "tag.txt"
       if strpart(getline('.'), 0, 1) != '='
          normal yy
          execute "q"
          normal p
          normal $
       else
          normal yy
          execute "q"
          normal p
          normal o==
          normal O
       endif
   else
      execute "vsplit tag.txt"
      map   :call Snipping()
      map   :call Snipping_close()
   endif
endfunction

map :call Snipping()

" автодополнение по табу ---------------------------------------------------

Который был добавлен в vimrc. В принципе еще еще хорошо немного допилить, но сейчас он вполне функционален.

* Как это работает с точки зрения пользователя?

Исходная позиция:




1. По Ctrl+Tab открывается боковое окно-меню в котором появляется список тэгов. Если пользователь передумал что-то вставлять - он нажимает Ctrl+Tab еще раз и окошко просто закрывается.




2. Пользователь становится курсором на нужный тэг и жмет Enter.

3. Боковое окно-меню закрывается и в текст добавляется нужный тэг.




4. Если тэг начинается крылышками - он добавляется в текст в виде:

=тэг=

==

5. Если тэг не начинается крылышками - он добавляется в текст "как есть". Предусмотрел это, потому, что оказалось что очень удобно так копировать в текст заготовки для заголовков и прочих спецзнаков.

* Как это работает с точки зрения алгоритма?

map ... завязывает соответствующий хоткей на функцию Snipping(). Дальше я все рассматриваю "задом наперед" - потому, что этого требовала логика программы. Сначала надо было объявить функцию, потом завязывать ее на хоткей.

При вызове функция Snipping() получает название буфера (функция bufname("%") - возвращает название текущего открытого файла - %) и исходя их него проверяет где был нажат хоткей - в основном окне или в окошке-меню (в этом случае название текущего файла будет "tag.txt").

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

Если это не файл "tag.txt" - выполняется ветка else - execute "vsplit tag.txt" эквивалентно :vsplit tag.txt - то есть делается вертикальный сплит и в нем открывается файл с тэгами.

Дальше идет интересный нюанс. Если в синтаксисе map указан ключ - то привязка хоткеев к действию будет распространятся только на текущий буффер. То есть следующие две строки меняют правила игры для открытого tag.txt и только внутри него.

map :call Snipping() - переназначает Enter на вызов функции Snipping() (то есть теперь Enter будет работать не как "Ввод", а как вызов Snipping())

map :call Snipping_close() - переназначает сочетание Ctrl+Tab на вызов функции Snipping_close() Сама эта функция, раз уж я ее упомянул, просто закрывает tag.txt - execute "q" эквивалентно :q

Еще раз напомню - обе эти привязки действуют только внутри tag.txt и как только мы его покинем все вернется на круги своя - Enter снова станет "Вводом".

Если имя файла, в котором была вызвана функция Snipping() - "tag.txt" - переходим ко второй ветке алгоритма. Следует скопировать тэг в основной текст и закрыть окно.

Сначала проверяется, что это за тэг был выбран - начинается он на '=' или нет.

strpart({src}, {start}[, {len}]) возвращает кусочек строки src, начинающийся с символа (байта) номер start (первый символ строки имеет номер 0) и длиной в len.

getline('.') возвращает текущую ('.') строку.

Функция strpart(getline('.'), 0, 1) берет первый символ строки тэга, а if проверяет равен ли он "=" (в строке - крылатый тэг или что-то другое).

Если тэг не крылатый - он просто копируется (normal yy - это просто - yy основного режима - копирование строки), окно закрывается (execute "q" - :q), тэг вставляется в основной файл и курсор передвигается в конец строки тэга (чтобы сразу можно было начинать писать).

Если тэг крылатый - он копируется (normal yy - yy копирование строки), окно закрывается (execute "q" - :q), тэг вставляется в основной файл ("p"), затем вставляется новая строка (o), в нее вписывается завершающий тэг "==", создается новая строка ("O") между тэгом и его завершением и - можно писать.

Получается очень удобно. Так можно копировать не только тэги, но и примитивы для заголовков (тильды разного количества), выделений и так далее (на скриншоте хорошо заметны отдельные элементы в самом верху). Что удобно - tag.txt можно редактировать вручную "не отходя от кассы" или использовать предложенный сэром ollycat метод автоматического сбора тэгов.

В принципе это дело можно доработать так, чтобы при выделенном тексте этот текст обрамлялся нужным тегом (дополнить скрипт условием проверки и в случае чего - копированием нужно фрагмента в регистр) можно изменить порядок вызова функций, чтобы он был более прозрачным и так далее.

Так же я задумался о том, как быть с добавлением тэга к дате заметки. Точнее так. Я вижу несколько путей работы - первый это глобальный скрипт на питоне, который каждый раз сканирует файл, находит между датами теги и сам их цепляет к датам. Второй - локальный скрипт, который будет работать примерно так - после вставки тэга стать курсором на == и запусть скрипт по хоткею. Скрипт поднимется выше, найдет название тега, скопирует его, поднимется еще выше, найдет первую строку, начинающуюся с "^д 200" и допишет тег к ней в хвост. Возможно, я реализую оба момента.

Но это еще "повод на подумать", поскольку я пока не решил для себя окончательно как именно должны выглядеть тэги в тексте (допустим =нот= ... == удобно обрабатывать, зато =нот= ... =нот= выглядит эстетичнее и легче читается). Еще - как быть с несколькими тегами? А еще мне очень удобно писать заголовки к тегам. Примерно так:

=нот= мысли о блоге
...
==

Думаю, все это устаканится со временем. Точнее так - практика расставит все на свои места.

P.S. Упреждая возможные вопросы. В Vim есть множество хороших плагинов для добавления сниппетов в текст. Но мне хотелось чего-нибудь своего и простого, чтобы не перегружать Vim. Кстати, из плагинов пользую - аутлайнер (TVO) и Project - аффигительно удобные штуки.

all_АБТФ, vim, me, интересно_в_основном_мне, foss forever

Previous post Next post
Up