Справка по системе макросов Far Manager

Начиная с 30.09.2012 (Far 3.0.2851), в Far Manager вместо встроенного макроязыка используется скриптовый язык Lua (версия 5.1).

Начиная с 23.04.2014 (LuaMacro build 310), добавлена поддержка скриптового языка MoonScript.

Под макросом понимается скрипт (на языке Lua или MoonScript) и его мета-данные, такие как:

  • Области начала исполнения скрипта.
  • Клавиши, инициирующие исполнение скрипта из данных областей.
  • Предварительные условия для исполнения скрипта.
  • Флаги времени исполнения: EnableOutput и NoSendKeysToPlugins.

Функциональность

  • Запись и воспроизведение макросов.
  • Библиотеки функций Lua.
  • Библиотеки функций LuaFAR (API плагинов).
  • Библиотеки функций макроязыка (API макросов).
  • Для плагинов: API MacroControl.


Загрузка макрофайлов

  • Стационарные макросы и обработчики событий загружаются из Lua-файлов (расширение *.lua) и/или MoonScript-файлов (расширение *.moon). В дальнейшем будем называть эти файлы макрофайлами. Загрузка макросов происходит при исполнении макрофайлов плагином LuaMacro.

  • Макрофайлы грузятся из последовательности папок (рекурсивно, с подпапками), определямой одним из следующих способов (в порядке приоритетов):

    1. Последовательность папок, указанная явно (в команде или аргументе функции)
    2. Значение переменной MacroPath в файле luamacro.ini
    3. Папка %FARPROFILE%\Macros\scripts

  • Far Manager никогда не вносит никаких изменений в вышеуказанные папки. Набор и содержимое файлов в них определяется исключительно пользователем.

  • Один макрофайл может содержать произвольное количество макросов и обработчиков событий.

  • При исполнении макрофайла ему передаётся один параметр – полный путь к данному макрофайлу. Если в начале макрофайла определить переменную, например,
    local MacroFileName = ...
    то эта переменная будет доступна всем макросам и обработчикам событий в данном файле.

  • Если макрофайлы грузятся из последовательности деревьев root1;root2;..., то это значит, что:

    • Дерево root2 начнёт грузиться только после загрузки root1
    • Для каждого дерева rootN первым всегда исполняется макрофайл
      rootN\_macroinit.lua, если такой файл существует. Порядок исполнения прочих макрофайлов в данном дереве не определён.


Формат макросов и обработчиков событий


Стационарные макросы

Загрузка макроса происходит при вызове глобальной функции Macro, которой передаётся один аргумент – таблица с параметрами макроса. При успешной загрузке функция возвращает true.

  Macro {
    area         = "Shell Info Tree";                         -- string
    key          = "CtrlF11 ShiftHome";                       -- string (опциональное поле)
    description  = "Macro example";                           -- string (опциональное поле)
    flags        = "NoPluginPanels EmptyCommandLine";         -- string (опциональное поле)
    filemask     = "*.txt,*.cpp";                             -- string (опциональное поле)
    priority     = 50;                                        -- number (опциональное поле)
    sortpriority = 50;                                        -- number (опциональное поле)
    condition    = function(key) return Far.Height>30 end;    -- function (опциональное поле)
    action       = function() msgbox("","Macro example") end; -- function
    id           = "F0109446-AA63-4873-AEC3-17AEE993AA53";    -- string (опциональное поле)
  }

  1. Поле area должно содержать имена одной или нескольких областей, разделённых пробелами.

  2. Поле key может содержать имена одного или нескольких ключей, разделённых пробелами.
    Ключи могут содержать модификаторы: Ctrl,LCtrl,RCtrl,Alt,RAlt,LAlt,Shift.
    Ctrl означает “любой из LCtrl,RCtrl”, аналогично для Alt. Порядок указания модификаторов – произвольный.

    Альтернативно, поле key может быть задано как регулярное выражение, обрамлённое слешами (/).

    • В этом случае /Ctrl/ не сработает при нажатии RCtrl, надо явно обозначать /[LR]Ctrl/ и т.п.
    • Также в этом случае необходимо соблюдать порядок в последовательности Ctrl,Alt,Shift, например /[LR]Alt[LR]CtrlF1/ никогда не сработает.

  3. Опциональное поле flags может содержать набор флагов, разделённых пробелами. Изменения в названиях или интерпретации флагов описаны здесь.

  4. Опциональное поле priority (приоритет) – число от 0 до 100. Значение по умолчанию = 50.
    Макросы, добавляемые посредством MCTL_ADDMACRO, имеют приоритет = 50.

  5. Опциональное поле sortpriority (приоритет для сортировки) – число от 0 до 100. Значение по умолчанию = 50.
    Значение данного поля учитывается при определении порядка расположения макросов в меню выбора макроса.

  6. Опциональное поле filemask – строка.
    Применимо только для областей Editor и Viewer. Обрабатывается по правилам, аналогичным тем, которые Фар применяет для масок файлов при поиске из панелей и т.д. Если имя файла, открытого в редакторе или просмотрщике, не соответствует заданной маске, макрос выполняться не будет.

  7. Опциональное поле condition – функция.

    • Вызывается с одним аргументом: имя нажатого ключа. Для автостартующих макросов – вызывается без аргументов.
    • Если возвращает false/nil/ничего, то макрос не исполняется.
    • Если возвращает число, то это число используется вместо priority.
    • При других значениях возврата (например, true) используется priority.

  8. Поле action – функция.
    Если макрос успешно прошёл все предварительные проверки (область действия, флаги, маска файла, приоритет), то вызывается функция action.

  9. Допустимо более одного макроса на сочетание (key,area). В этом случае выполняется макрос с наибольшим приоритетом. Если есть более одного макроса с одинаковым наибольшим приоритетом – выводится меню выбора макроса.
    Автостартующие макросы выполняются все, независимо от приоритета. Очерёдность их исполнения не определена.


Клавиатурные макросы

  • Клавиатурные макросы обычно используются для быстрой записи и воспроизведения последовательности нажатий клавиш клавиатуры. Они имеют меньше возможностей, чем стационарные макросы, и для использования на постоянной основе стационарные макросы предпочтительнее.

  • Клавиатурные макросы загружаются из Lua-файлов (расширение *.lua), находящихся в папке %FARPROFILE%\Macros\internal.

  • Far Manager самостоятельно создаёт, модифицирует и удаляет файлы в данной папке в соответствии с выполняемыми над макросами операциями. Не рекомендуется редактировать эти файлы вручную, за исключением удаления.

  • Изменения в клавиатурных макросах становятся постоянными либо при выполнении операции MacroControl(MCTL_SAVEALL), либо автоматически (при включенной опции “Auto save setup”).

  • Поле “area” может содержать только одну область действия.

  • Поле “key” может содержать имя только одного ключа.
    В ключах применяются только модификаторы Ctrl,Alt,Shift и не применяются модификаторы LCtrl,RCtrl,LAlt,RAlt. Регулярные выражения не поддерживаются.

  • Не допустимо более одного макроса на сочетание (key,area).

  • Клавиатурные макросы имеют более высокий приоритет, чем все прочие макросы. Это сделано для того, чтобы не надо было заниматься разрешением конфликтов при временном создании клавиатурных макросов (типичный сценарий их использования).


Обработчики событий

Как и стационарные макросы, обработчики событий загружаются из Lua-файлов (расширение *.lua), находящихся в папке %FARPROFILE%\Macros\scripts и её подпапках. Каждый Lua-файл может содержать вместе и макросы, и обработчики событий.

Загрузка обработчика происходит при вызове глобальной функции Event, которой передаётся один аргумент – таблица с параметрами обработчика. При успешной загрузке функция возвращает true.

Event {
  group       = "EditorEvent";                          -- string
  description = "Event example";                        -- string (опциональное поле)
  filemask    = "*.txt,*.cpp";                          -- string (опциональное поле)
  priority    = 50;                                     -- number (опциональное поле)
  condition   = function() ...... end;                  -- function (опциональное поле)
  action      = function() ...... end;                  -- function
  id          = "F0109446-AA63-4873-AEC3-17AEE993AA53"; -- string (опциональное поле)
}

Поле group может иметь одно из следующих значений:
"DialogEvent", "EditorEvent", "EditorInput", "ExitFAR", "ViewerEvent", "ConsoleInput".
Данные имена являются производными от имён соответствующих функций, экспортируемых плагином, например:

    export.ProcessDialogEvent -> DialogEvent

Функции condition и action обработчика вызываются с теми же параметрами, с которыми вызывается соответствующая экспортируемая функция (см. мануал LuaFAR).

При наличии нескольких обработчиков одного и того же события (т.е. обработчиков с одинаковым полем group), эти обработчики будут вызваны по очереди: обработчик с более высоким приоритетом вызывается раньше. Приоритет определяется динамически с учётом функции condition, если таковая имеется, как и для макросов.

Событие "ExitFAR" вызывается в следующих случаях: (a) выход из Far Manager, (b) выгрузка плагина LuaMacro, (c) выгрузка либо перезагрузка макросов.


Добавление пунктов в меню плагинов

Как и стационарные макросы, добавочные пункты меню загружаются из Lua- и MoonScript-файлов, находящихся в папке %FARPROFILE%\Macros\scripts и её подпапках.

Загрузка пункта меню происходит при вызове глобальной функции MenuItem, которой передаётся один аргумент – таблица с параметрами. При успешной загрузке функция возвращает true.

MenuItem {
  description = "Menu item";                        -- string (опциональное поле)
  menu   = "Plugins Disks Config";                  -- string
  area   = "Shell Editor Viewer Dialog Menu";       -- string (опциональное поле)
  guid   = "A435D567-AD64-4DD1-8C61-28CB90358817";  -- string
  text   = function(menu,area) return "Hello!" end; -- string или function
  action = function(OpenFrom,Item) ...... end;      -- function
}

Поля description и area – опциональные. Их значения по умолчанию – пустая строка. Остальные поля – обязательные.

  • Поле menu содержит перечисление меню Far Manager, в которые нужно добавить данный пункт меню. Допустимые значения элементов: "Plugins", "Disks" и "Config" – обозначают соответственно меню плагинов, меню дисков и меню конфигурации плагинов.

  • Поле area содержит перечисление областей, при вызове из которых меню плагинов нужно добавить данный пункт меню. Это поле используется только если поле menu содержит элемент Plugins. Допустимые значения элементов совпадают с названиями макрообластей.

  • Поле guid содержит уникальный идентификатор (GUID) данного пункта меню.

  • Поле text – если тип данного поля – строка, то она используется непосредственно как текст пункта меню.
    Если тип данного поля – функция, то пункт меню будет добавлен только в случае, если эта функция возвратит строку.
    Функция получает 2 аргумента:

    1. menu – тип меню ("Plugins" или "Disks" или "Config")
    2. area – имя текущей макрообласти

  • Поле action – функция, вызываемая при активации добавленного пункта меню. Получает те же аргументы, что и функция export.Open (см. luafar_manual.chm), за исключением Guid. При вызове из меню конфигурации, значения обоих аргументов – nil. Возвращаемое значение игнорируется.


Добавление префиксов командной строки

Как и стационарные макросы, добавочные префиксы командной строки загружаются из Lua- и MoonScript-файлов, находящихся в папке %FARPROFILE%\Macros\scripts и её подпапках.

Префиксы загружаются глобальной функцией CommandLine, которой передаётся один аргумент – таблица с параметрами. Функция возвращает количество успешно загруженных префиксов.

CommandLine {
  description = "Adding prefixes";                  -- string (опциональное поле)
  prefixes = "abc:def:1234";                        -- string
  action = function(prefix,text) ...... end;        -- function
}

  • Поле prefixes содержит список префиксов, разделённых двоеточиями. Пробелы не допускаются.

  • Поле action – функция, вызываемая при активации командной строки одним из зарегистрированных префиксов. Функция получает 2 аргумента: prefix – реальный префикс в нижнем регистре; text – оставшаяся часть командной строки без начальных и конечных пробелов.


Lua-модули

Lua-модули могут быть помещены в папку %FARPROFILE%\Macros\modules и её подпапки, так как

%FARPROFILE%\Macros\modules\?.lua;%FARPROFILE%\Macros\modules\?\init.lua;

автоматически добавляется в package.path.


Плагин LuaMacro

Данный плагин необходим для работы макросов, поэтому должен быть установлен. То же касается и рантайма (lua51.dll, luafar3.dll и lpeg.dll), необходимого для работы плагина.

При выходе из Far Manager плагин LuaMacro выгружается последним, чтобы могли быть обработаны запросы MCTL_XXX из функций ExitFARW других плагинов.


Работа с командной строки

  • macro: load [path]
    (Пере)загрузить макрофайлы. Опциональный параметр path имеет тот же смысл, что поле Path в структуре FarMacroLoad.
  • macro: save
    Сохранить созданные или модифицированные клавиатурные макросы.
  • macro: unload
    Выгрузить макросы (кроме созданных операцией MCTL_ADDMACRO) и обработчики событий.
  • macro: about
    Показать версии плагина и используемых плагином библиотек.
  • lua: [=] <code>
  • moon: [=] <code>
    Исполнить код <code>, написанный соответственно на Lua или MoonScript.
    Если <code> следует за символом =, то вызывается far.Show(), например:
    lua:=5+2,6,"foo" эквивалентно lua:far.Show(5+2,6,"foo").
  • lua: [=] @<filename> [<args>]
  • moon: [=] @<filename> [<args>]
    Исполнить скрипт <filename>, написанный соответственно на Lua или MoonScript.
    • Если нужно передать скрипту аргументы, их следует указать после имени файла через пробел.
    • Аргументы являются списком выражений, разделённых запятыми.
    • Выражения должны использовать тот же язык программирования, что и скрипт.
    • Глобальная (в пределах окружения скрипта) переменная _filename содержит имя файла.

Примечание 1:
Вместо префикса macro: может использоваться эквивалентный ему префикс lm:.

Примечание 2:
Вместо префиксов lua: и moon: могут использоваться соответственно префиксы luas: и moons:. В этом случае макрос не создаётся, а производится немедленное (“синхронное”) исполнение кода. Если код завершается нормально, то величина CmdLine.Result содержит таблицу с массивом возвращённых величин, а поле n этой таблицы – количество этих величин. В случае прерывания кода по ошибке, значение CmdLine.Result равно nil.

Примечание 3:
Дополнительные префиксы командной строки могут быть определены и загружены из макрофайлов.


Файл luamacro.ini

Файл luamacro.ini содержит некоторые настройки плагина. Если файла нет, или в нём отсуствует определённая настройка, плагин использует умолчательное значение для данной настройки.

  • MacroPath
    Определяет пути, с которых будут грузиться макрофайлы.
    Представляет собой последовательность из 0 или более путей, разделённых точками с запятой.
    Значение по умолчанию: %FARPROFILE%\Macros\scripts.


Файл luafar_init.lua

Плагин LuaMacro исполняет файл %FARPROFILE%\luafar_init.lua (если этот файл существует) перед загрузкой своего стартового скрипта. См. описание этой особенности в мануале LuaFAR.


Библиотеки функций макроязыка

Описание API в данном документе не является самодостаточным, оно является дополняющим и уточняющим к описанию свойств и функций объектов Фара в разделе Макроязык Энциклопедии Фара.

В идеале, API должен совпадать с оригинальным API макроязыка, за исключением случаев, перечисленных в статье Изменения API в сравнении с макроязыком.


Изменения API в сравнении с макроязыком

  1. Все идентификаторы чувствительны к регистру символов.
  2. Вместо прямого указания клавиш используется функция Keys.
  3. $AKey –> Keys("AKey")
  4. $SelWord –> Keys("SelWord")
  5. $XLat –> Keys("XLat")
  6. $Exit –> exit()
  7. Логические свойства имеют тип boolean (поэтому нет смысла сравнивать их с числом 0).
  8. Функция prompt может возвращать либо стринг, либо false (но никогда не число 0).
  9. Многие функции помещены в таблицу mf (сокращение от macrofunctions), например: mf.abs, mf.fsplit и т.д.
  10. Функция mf.beep возвращает булевое значение, а не число.
  11. Функция mf.fexist возвращает булевое значение, а не число.
  12. Функции mload и msave изменились, см. их описание.
  13. Свойства, зависящие от контекста исполнения, находятся в таблице Object, например: Object.CurPos, Object.Empty.
  14. CheckHotkey -> Object.CheckHotkey
  15. GetHotkey -> Object.GetHotkey
  16. Логические свойства проверки области исполнения находятся в таблице Area, например: Area.Editor, Area.Shell.
  17. Macro.Area -> Area.Current.
  18. Dialog.AutoCompletion -> Area.DialogAutoCompletion
  19. Shell.AutoCompletion -> Area.ShellAutoCompletion
  20. CallPlugin –> Plugin.Call. Этот вызов – всегда асинхронный. Для синхронного вызова следует использовать Plugin.SyncCall.
  21. Функции Plugin.Menu, Plugin.Config и Plugin.Command возвращают булевое значение.
  22. mmode(3,x) больше не влияет на синхронность/асинхронность вызовов плагинов из макроса; ничего не делает; возвращает 0.
  23. Dlg.Info.Id -> Dlg.Id
  24. Dlg.Info.Owner -> Dlg.Owner
  25. Far.Cfg.Get -> Far.Cfg_Get. Эта функция возвращает стринг в случае успеха или false в случае неудачи.
  26. Far.Cfg.Err больше не существует.
  27. FullScreen -> Far.FullScreen
  28. IsUserAdmin -> Far.IsUserAdmin
  29. History.Disable -> Far.DisableHistory
  30. KbdLayout -> Far.KbdLayout
  31. KeyBar.Show -> Far.KeyBar_Show
  32. Window.Scroll -> Far.Window_Scroll
  33. Menu.Info.Id -> Menu.Id
  34. MsX, MsY, MsButton, MsCtrlState, MsEventFlags — см. таблицу Mouse
  35. RCounter больше не существует.
  36. Macro.Const, Macro.Func, Macro.Keyword и Macro.Var больше не существуют.
  37. Спецификация макроса: флаг DisableOutput больше не существует; перерисовка экрана по умолчанию запрещена; добавлен флаг EnableOutput (применять его, если нужна перерисовка экрана во время исполнения макроса).
  38. Спецификация макроса: флаги Selection и NoSelection больше не применяются для областей редактора/вьювера/диалога. Для этих областей следует использовать соответственно EVSelection и NoEVSelection.
  39. Спецификация макроса: флаг RunAfterFARStart действует и при запуске Far Manager c ключом /e или /v. При этом будут запускаться только автостартующие макросы, поле area которых содержит соответственно Editor или Viewer.


Глобальные свойства и функции

Свойства: нет.

Функции:

  akey
  band, bnot, bor, bxor, lshift, rshift
  eval
  exit
  Keys
  mmode
  msgbox
  print
  prompt

Примечания:

1. Функции band, bnot, bor, bxor, lshift и rshift (операции с битами)
   - это глобальные ссылки на одноимённые функции из библиотеки bit64
   (см. LuaFAR manual).

2. Функции akey и mmode, будучи вызваны из функции condition макроса, возвращают false.

3. Для единообразия, все данные функции, кроме битовых, продублированы в таблице mf,
   например: eval и mf.eval - это одна и та же функция.


exit

exit ()

Параметры:
  нет

Возвращает:
  ничего

Описание:
  Завершить работу макроса.


Keys

Keys (...)

Параметры:
  Один или больше аргументов типа string.
  Каждый аргумент может содержать несколько ключей, разделённых пробельными символами.
  Аргументы регистронезависимы.

Возвращает:
  ничего

Описание:
  Послать один или более ключей Far Manager'у.

Примечания:

  1. Специальные ключи:
     "AKey"    - послать Far Manager'у клавишу, вызвавшую данный макрос.
     "SelWord" - выделить слово под курсором.
     "XLat"    - преобразовать слово под курсором.
     "EnOut"   - разрешить вывод на экран (то же, что mmode(1,0))
     "DisOut"  - запретить вывод на экран (то же, что mmode(1,1))

  2. Перед каждым ключом может быть указан множитель, например "3*Down" эквивалентно "Down Down Down".

Пример:
  mykeys = "CtrlF5 Esc"
  Keys("AKey A b CtrlC ShiftEnter", mykeys)


mf

Свойства: нет.

Функции:

  abs                len
  acall              max
  akey               mdelete
  asc                min
  atoi               mload
  beep               mmode
  chr                mod
  clip               msave
  date               msgbox
  env                postmacro
  eval               print
  exit               prompt
  fattr              replace
  fexist             rindex
  float              size2str
  flock              sleep
  fmatch             string
  fsplit             strpad
  GetMacroCopy       strwrap
  iif                substr
  index              testfolder
  int                trim
  itoa               ucase
  key                usermenu
  Keys               waitkey
  lcase              xlat


acall

... = mf.acall (func, ...)

Параметры:
  func:    function
  ...:     0 или более Lua-величин

Возвращает:
  ...:     0 или более Lua-величин

Описание:
  Данная функция вызывает "асинхронно" функцию func, передавая ей все последующие
  аргументы.

  mf.acall является как бы специализацией Plugin.Call для плагина LuaMacro,
  но, в отличие от Plugin.Call, она позволяет выполнять код в контексте вызывающей
  функции, а также передавать и возвращать любые Lua-величины.

  Как и Plugin.Call, mf.acall является "асинхронной": при выводе функцией func
  диалога или меню на экран, mf.acall сразу завершает работу и возвращает true.

  Если функция func не выводит диалог или меню на экран, то имеет место "синхронный"
  режим работы: в этом случае mf.acall возвращает все величины, возвращённые
  функцией func.


eval

ret = eval(S[,Mode[,Lang]])

Данная функция соответствует описанию в Энциклопедии Far Manager, со следующими расширениями:

1. eval может исполнять как Lua-код, так и MoonScript-код

Добавлен опциональный 3-й параметр Lang, указывающий язык кода параметра S в режимах 0, 1, 3. Допустимые значения: "lua" и "moonscript". Значение по умолчанию – "lua".

2. Параметр S может обозначать скрипт-файл

В режимах 0, 1, 3 параметр S может обозначать скрипт-файл, если этот параметр начинается с символа @. В этом случае параметр S должен иметь следующий формат:

    @<имя файла-скрипта> [<параметры скрипта>]
  • В имени файла допустимо использование переменных окружения.
  • Опциональные параметры скрипта представляют список выражений, разделённых запятыми.
  • Выражения должны использовать тот же язык программирования, что и файл-скрипт.

Пример:

    eval("@%MyFarScripts%\\calc.moon 'factorial', 3+5", 0, "moonscript")

3. Новые коды, возвращаемые eval(S, 2)

  • 0 (нормальный возврат) : дополняется значениями, возвращаемыми “запускаемым” макросом.
  • -3 : если было выведено меню выбора макроса, и пользователь его отменил.
  • -4 : если “запускаемый” макрос был прерван в результате ошибки времени исполнения.


GetMacroCopy

macro = mf.GetMacroCopy (index)

Параметры:
  index:  integer

Возвращает:
  macro:  table или nil

Описание:
  Функция GetMacroCopy возвращает копию таблицы загруженного макроса или обработчика
  события по его индексу во внутреннем  массиве (начиная от 1). Если индекс превышает
  размер массива, возвращается nil - таким образом можно определить конец массива.

Примечания:
  * Неактивные (выгруженные или удалённые) элементы имеют поле "disabled" == true.
  * Отличить таблицу макроса от таблицы события можно по полю "area" типа string,
    которое присутствует только у макросов.


mdelete

mf.mdelete (key, name [, location])

Параметры:
  key:       string
  name:      string
  location:  string ("roaming" или "local"; по умолчанию: "roaming")

Возвращает:
  ничего

Описание:
  Функция mdelete удаляет значение или ключ из базы данных.
  Для удаления ключа следует указать параметр name == "*" (звёздочку).


mload

ret = mf.mload (key, name [, location])

Параметры:
  key:       string
  name:      string
  location:  string ("roaming" или "local"; по умолчанию: "roaming")

Возвращает:
  ret:      number, string, boolean, table, int64 или nil.

Описание:
  Функция mload читает значение из базы данных.


msave

mf.msave (key, name, value [, location])

Параметры:
  key:       string
  name:      string
  value:     nil, boolean, number, string, table, int64
  location:  string ("roaming" или "local"; по умолчанию: "roaming")

Возвращает:
  ничего

Описание:
  Функция msave сохраняет переданное значение в базу данных.

  При сохранении таблиц будут сохраняться:
     ключи типов:     number, string, boolean, table
     значения типов:  number, string, boolean, table, int64

  Сохраняются вложенные таблицы, при этом рекурсивные вложения корректно обрабатываются.

  Сохраняется связь таблицы с её метатаблицей.

Примечание
  int64 - особый тип userdata, создаваемый библиотекой bit64.


postmacro

result = mf.postmacro (func, ...)

Параметры:
  func:    function
  ...:     0 или более Lua-величин

Возвращает:
  result:  boolean

Описание:
  Функция помещает новый макрос в очередь для исполнения. При исполнении макроса
  будет вызвана функция func, которой будут переданы аргументы ...


usermenu

mf.usermenu (mode, filename)

Параметры:
  mode:     number (0 по умолчанию)
  filename: string или nil

Возвращает:
  ничего

Описание:
  Открывает или создаёт пользовательское меню.

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

  Поведение функции в зависимости от величины младшего байта mode:

    0: равносильно нажатию F2 в панелях; filename игнорируется.
    1: выводится диалог выбора пользовательского меню; filename игнорируется.
    2: файл открывается "как есть", т.е. по заданному filename.
    3: файл filename открывается в %farprofile%\Menus (папка создаётся
       автоматически).


Area

Area - таблица со следующими полями:

Свойства:

  Current:               string
  Other:                 boolean
  Shell:                 boolean
  Viewer:                boolean
  Editor:                boolean
  Dialog:                boolean
  Search:                boolean
  Disks:                 boolean
  MainMenu:              boolean
  Menu:                  boolean
  Help:                  boolean
  Info:                  boolean
  QView:                 boolean
  Tree:                  boolean
  FindFolder:            boolean
  UserMenu:              boolean
  ShellAutoCompletion:   boolean
  DialogAutoCompletion:  boolean

Функции:

  Нет.


APanel, PPanel

APanel, PPanel - таблицы со следующими полями:

Свойства:

  Bof:          boolean
  ColumnCount:  number
  CurPos:       number
  Current:      string
  DriveType:    number
  Empty:        boolean
  Eof:          boolean
  FilePanel:    boolean
  Filter:       boolean
  Folder:       boolean
  Format:       string
  Height:       number
  HostFile:     string
  ItemCount:    number
  Left:         boolean
  LFN:          boolean
  OPIFlags:     number
  Path:         string
  Path0:        string
  Plugin:       boolean
  Prefix:       string
  Root:         boolean
  SelCount:     number
  Selected:     boolean
  Type:         number
  UNCPath:      string
  Visible:      boolean
  Width:        number

Функции:

  Нет.


Panel

Panel - таблица со следующими полями:

Свойства:

  Нет.

Функции:

  FAttr
  FExist
  Item
  Select
  SetPath
  SetPos
  SetPosIdx
  CustomSortMenu
  LoadCustomSortMode
  SetCustomSortMode

Примечание:
  Функции CustomSortMenu, LoadCustomSortMode и SetCustomSortMode присутствуют только
  если в качестве движка Lua используется LuaJIT 2.


CustomSortMenu

Panel.CustomSortMenu ()

Параметры:
  Нет

Возвращает:
  Ничего

Описание:
  Функция выводит меню со списком загруженных пользовательских сортировок.
  Нажатие Enter устанавливает выбранный режим сортировки на активной панели,
  нажатие CtrlEnter - на пассивной, CtrlShiftEnter - на обеих.

  Клавиши Add и Subtract работают так же, как в меню выбора режима сортировки Far.
  При этом также поддерживаются модификаторы Ctrl и CtrlShift, определяющие выбор панелей
  для установки режима сортировки.


LoadCustomSortMode

Panel.LoadCustomSortMode (Mode, Settings)

Параметры:
  Mode:         режим сортировки, целое число >=100 и <=0x7FFFFFFF
  Settings:     таблица, содержит следующие поля:
                  Condition:
                     Функция. Если задана, то будет вызвана с одним аргументом - режим сортировки.
                     Если возвращаемое значение ложно, то сортировка отменяется.
                     Следует отметить, что данная функция может перезагрузить все параметры сортировки,
                     снова вызвав Panel.LoadCustomSortMode().
                  Compare:
                     Функция, см. её описание ниже.
                  DirectoriesFirst, SelectedFirst, RevertSorting, SortGroups:
                     Данные опциональные поля задают соответствующие опции сортировки:
                     0 - опция выключена, 1 - опция включена, любое другое значение
                     или отсутствие данного поля означают "использовать текущую
                     установку Far Manager".
                  InvertByDefault:
                     Включать ли по умолчанию обратную сортировку.
                  Indicator:
                     Индикация режима сортировки на панели, строка из двух символов
                     (первый - для прямой, второй - для обратной сортировки).
                  NoSortEqualsByName:
                     По умолчанию, равные с точки зрения алгоритма сортировки элементы
                     сортируются по имени. Если это нежелательно, установите данное поле
                     в true.
                  Description:
                     Текстовое описание режима сортировки. Если данное поле задано,
                     оно используется в меню (см. Panel.CustomSortMenu).
                  SortFunction:
                     Опция выбора функции сортировки из двух встроенных.
                     Задаётся строкой: "shellsort" (значение по умолчанию) или "qsort".
                  InitSort:
                     Функция. Если задана, то вызывается перед началом сортировки.
                     Получает один параметр: таблицу FarOptions (см. ниже одноимённый
                     параметр функции Compare).
                  EndSort:
                     Функция. Если задана, то вызывается после окончания сортировки.

                Если значение Settings равно nil или false, это означает выгрузку
                (удаление) данного режима сортировки.

Возвращает:
  Ничего

Описание:
  Функция загружает (или выгружает) пользовательский режим сортировки для панелей.
  Если режим загружен, он может быть установлен в панели посредством вызова функции
  Panel.SetCustomSortMode.

Функция Compare
  result = Compare (Pi1, Pi2, FarOptions)

  Параметры:
    Pi1 и Pi2  - сравниваемые элементы панели, структуры типа SortingPanelItem.
    FarOptions - таблица, содержащая текущие опции сортировки панели в Far Manager
                 (все значения - булевые): DirectoriesFirst, SelectedFirst,
                 RevertSorting, SortGroups, NumericSort, CaseSensitiveSort.

  Возвращает:
    result     - если 1-й элемент должен оказаться после прямой сортировки выше 2-го,
                 нужно возвратить отрицательное число, если ниже - положительное,
                 а если элементы по критерию сортировки равны - ноль.

Примечание 1:
  Пользовательская сортировка использует библиотеку FFI от LuaJIT 2. Программирование
  с использованием LuaJIT FFI требует предварительного освоения документации.

Примечание 2:
  Пользовательские режимы сортировок панелей восстанавливаются при перезапуске Far,
  если текущая конфигурация была сохранена, при условии, что соответствующие вызовы
  Panel.LoadCustomSortMode() производятся в процессе загрузки макросов.
  Восстановление происходит после окончания загрузки макросов, до начала исполнения
  автостартующих макросов.

Примечание 3:
  Пользовательские режимы сортировки принудительно выгружаются при выгрузке макросов.

Пример:
  -- Загрузить сортировку по длине имени файла.
  local ffi = require "ffi"
  local C = ffi.C
  Panel.LoadCustomSortMode (100,
    {
      Compare = function(p1, p2, opt)
        local l1, l2 = C.wcslen(p1.FileName), C.wcslen(p2.FileName)
        return l1<l2 and -1 or l1>l2 and 1 or 0
      end;
      Indicator = "bB";
    })


SetCustomSortMode

Panel.SetCustomSortMode (Mode, whatpanel [, order])

Параметры:
  Mode:         режим сортировки, целое число >=100 и <=0x7FFFFFFF
  whatpanel:    0=активная панель, 1=пассивная панель
  order:        "auto"    - стандартный выбор направления сортировки (значение по умолчанию)
                "current" - сохранить текущее направление сортировки в панели
                "direct"  - установить прямую сортировку
                "reverse" - установить обратную сортировку

Возвращает:
  Ничего

Описание:
  Если заданный режим сортировки загружен (см. Panel.LoadCustomSortMode),
  то будет произведена установка этого режима сортировки в заданной панели.
  Иначе не будет произведено никаких действий.

Пример:
  -- Установить заданную пользовательскую сортировку в активной панели.
  Macro {
    description="Sort files by their name length";
    area="Shell"; key="CtrlShiftF1";
    action=function() Panel.SetCustomSortMode(100,0) end;
  }


BM

BM - таблица со следующими полями:

Свойства:

  Нет.

Функции:

  Add
  Back
  Clear
  Del
  Get
  Goto
  Next
  Pop
  Prev
  Push
  Stat


CmdLine

CmdLine - таблица со следующими полями:

Свойства:

  Bof:        boolean
  Empty:      boolean
  Eof:        boolean
  Selected:   boolean
  CurPos:     number
  ItemCount:  number
  Value:      string
  Result:     table или nil

Функции:

  Нет.


Dlg

Dlg - таблица со следующими полями:

Свойства:

  CurPos:     number
  Id:         string (GUID)
  Owner:      string (GUID)
  ItemCount:  number
  ItemType:   number
  PrevPos:    number

Функции:

  GetValue
  SetFocus


Drv

Drv - таблица со следующими полями:

Свойства:

  ShowMode:  number
  ShowPos:   number

Функции:

  Нет.


Editor

Editor - таблица со следующими полями:

Свойства:

  CurLine:   number
  CurPos:    number
  FileName:  string
  Lines:     number
  RealPos:   number
  SelValue:  string
  State:     number
  Value:     string

Функции:

  DelLine
  GetStr
  InsStr
  Pos
  Sel
  Set
  SetStr
  SetTitle
  Undo


Far

Far - таблица со следующими полями:

Свойства:

  FullScreen:      boolean
  Height:          number
  IsUserAdmin:     boolean
  PID:             number
  Title:           string
  UpTime:          number
  Width:           number

Функции:

  Cfg_Get (устаревшая, используйте GetConfig)
  DisableHistory
  GetConfig
  KbdLayout
  KeyBar_Show
  Window_Scroll


GetConfig

val, tp = Far.GetConfig (keyname)

Параметры:
  keyname: string

Возвращает:
  val:     boolean, string, number, or int64
             Это значение запрашиваемой величины.
             Преобразование типов между Far Manager и Lua осуществляются следующим образом:
               boolean -> boolean
               3-state -> 0,1,2 преобразуются соответственно в false,true,"other"
               string  -> string
               integer -> number (если возможно преобразование без потери точности) или
                          userdata (int64) - величина, создаваемая библиотекой bit64.

  tp:      string ("boolean", "3-state", "string", "integer")
             Это тип оригинальной величины в Far Manager.

Примечание:
  В случае ошибки (некорректный аргумент, или Far Manager не нашёл указанной опции)
  данная функция прерывает исполнение (вызывает error()).


Help

Help - таблица со следующими полями:

Свойства:

  FileName:  string
  SelTopic:  string
  Topic:     string

Функции:

  Нет.


Menu

Menu - таблица со следующими полями:

Свойства:

  Id:     string (GUID)
  Value:  string

Функции:

  Filter
  FilterStr
  GetValue
  ItemStatus
  Select
  Show


Mouse

Mouse - таблица со следующими полями:

Свойства:

  X:              number
  Y:              number
  Button:         number
  CtrlState:      number
  EventFlags:     number
  LastCtrlState:  number

Функции:

  Нет.

Примечание:

  Mouse.LastCtrlState отличается от Mouse.CtrlState тем, что обновляется
  как по событиям от мыши, так и по клавиатурным событиям.


Object

Свойства, зависящие от контекста исполнения.

Object: таблица со следующими полями:

Свойства:

  Bof:         boolean
  CurPos:      number
  Empty:       boolean
  Eof:         boolean
  Height:      number
  ItemCount:   number
  Selected:    boolean
  Title:       string
  Width:       number

Функции:

  CheckHotkey
  GetHotkey


Plugin

Plugin - таблица со следующими полями:

Свойства:

  Нет.

Функции:

  Call
  Command
  Config
  Exist
  Load
  Menu
  SyncCall
  Unload


Call

... = Plugin.Call (PluginId, ...)

Параметры:
  PluginId: string (GUID плагина в текстовом представлении)
  ...     : ноль или более дополнительных параметров

Возвращает:
  ...     : ноль или более возвращаемых значений

Описание:
  1. Функция осуществляет "асинхронный" вызов плагина.
     Если вызов в действительности оказался асинхронным (например, если плагин вывел
     диалог на экран), функция возвращает true, не дожидаясь возврата от плагина,
     и макрос продолжает исполнение.

  2. Если вызов в действительности оказался синхронным, макросу возвращаются величины
     в соответствии с тем, что вернул плагин:
     - Если плагин не найден или вернул 0, макросу возвращается false.
     - Если плагин вернул 1 или INVALID_HANDLE_VALUE, макросу возвращается true.
     - Если плагин вернул указатель на структуру FarMacroCall, см пункт 4.

  3. Параметры передаются плагину в соответствии с их Lua-типами:
       nil      -> FMVT_NIL
       boolean  -> FMVT_BOOLEAN
       number   -> FMVT_DOUBLE
       int64    -> FMVT_INTEGER (int64 - тип userdata, создаваемый библиотекой bit64)
       string   -> FMVT_STRING  (автоматически преобразуется из UTF-8 в UTF-16LE)
       {string} -> FMVT_BINARY  (для того, чтобы передать произвольный стринг без
                                 преобразования UTF-8 -> UTF16LE, его нужно передавать,
                                 помещённым в таблицу как элемент с ключом 1)

  4. Величины, возвращаемые плагином через структуру FarMacroCall, передаются макросу
     следующим образом:
       FMVT_NIL     -> nil
       FMVT_BOOLEAN -> boolean
       FMVT_DOUBLE  -> number
       FMVT_INTEGER -> number, если "укладывается" в 53 бита, иначе int64
       FMVT_STRING  -> string (автоматически преобразуется из UTF-16LE в UTF-8)
       FMVT_BINARY  -> table (в таблице передаётся строка как элемент с ключом 1;
                              передаётся как есть, без преобразования)
       FMVT_ARRAY   -> table (массив элементов; в таблице установлено два поля:
                              ["type"] = "array", и
                              ["n"] = количество элементов массива)


SyncCall

... = Plugin.SyncCall (PluginId, ...)

Данная функция работает идентично Plugin.Call, за исключением того, что:

1. Её вызов - всегда синхронный, то-есть возврат управления макросу происходит
   только после возврата функции OpenW плагина.
2. Данная функция не имеет ограничений в использовании, которые есть у Plugin.Call.


Viewer

Viewer - таблица со следующими полями:

Свойства:

  FileName:  string
  State:     number

Функции:

  Нет.


Разное


Макросы, начинающиеся с @

Если макропоследовательность начинается с символа @, то последующая её часть интерпретируется как имя файла, содержащего Lua-скрипт.

  • Переменные окружения в заданном имени файла автоматически расширяются.
  • Глобальная (в пределах окружения скрипта) переменная _filename содержит имя файла.
  • Такие скрипты легче отлаживать и модифицировать, так как не требуется их предварительная перезагрузка.

Пример 1:

    lua: @%FARHOME%\test\test.lua 123, "hello"

Пример 2:
запуск скрипта из редактора.


Переменные

Окружение

Макросы, загружаемые из одного файла, имеют общее окружение (environment). Переменные, объявляемые без ключевого слова local, принадлежат этому окружению.

  Пример: var = 15

Переменные окружения макрофайла сохраняют свои значения между вызовами макросов. Их значения сбрасываются в исходные при выполнении любой операции загрузки макросов: старт Far Manager, macro:load, lm:load, far.MacroLoadAll, MacroControl(MCTL_LOADALL).

Глобальные переменные

Для установки глобальных переменных, значения которых будут сохраняться в течение всей сессии Far Manager и будут доступны всем скриптам, нужно использовать таблицу _G.

  Пример: _G.var = 15

Глобальные переменные не меняют своего значения даже при операциях перезагрузки макросов, за исключением рестарта Far Manager или перезагрузки плагина LuaMacro.

При чтении несуществующей переменной окружения, прочтётся одноимённая глобальная переменная (наследование в некотором смысле).

  Пример:
    var = 5
    _G.var = 10
    far.Message(var) --> 5
    var = nil
    far.Message(var) --> 10

Upvalues

Локальные переменные, доступные из функций одного или нескольких макросов (upvalues), являются общими для этих функций и сохраняют свои значения между вызовами макросов. Их значения сбрасываются в исходные при выполнении любой операции загрузки макросов.

  Пример:
    local var = 15
    function inc_var() var = var+1 end
    function dec_var() var = var-1 end


Ограничения в использовании некоторых функций

Следующие функции имеют особенности реализации, которые накладывают определённые ограничения на их использование в макросах:

  • exit
  • mf.acall
  • mf.usermenu (в “асинхронном” режиме вызова)
  • Keys
  • Plugin.Call
  • Plugin.Command
  • Plugin.Config
  • Plugin.Menu
  • print

  1. Если макрос создаёт корутины с помощью coroutine.wrap(f), то вышеперечисленные функции не будут работать, будучи вызванными из тела функции f.
    Данного ограничения нет, если корутины создаются с помощью coroutine.create(f).

  2. Вышеперечисленные функции, будучи вызванными прямо или косвенно посредством функции pcall, приведут к немедленному возврату pcall с результатом false.
    Данного ограничения нет при использовании LuaJIT 2.x.

  3. Вышеперечисленные функции работают только, будучи вызванными из тела макроса (обычно это функция action). Это значит, что данные функции не будут работать, будучи вызванными из:

    • диалоговых процедур
    • функции condition макроса
    • обработчиков событий
    • и т.д. и т.п.

Ограничения пункта 3 не имеют места, если вышеперечисленные функции вызываются не напрямую, а посредством mf.postmacro или far.MacroPost.


Интроспекция

Содержимое глобальных таблиц API макроязыка можно просмотреть с помощью функции pairs, отдельно для функций и “свойств” таблицы.

На примере таблицы Editor:

    for k,v in pairs(Editor) do .... end -- для функций

    for k,v in pairs(Editor.properties) do .... end -- для свойств


unicode.utf8.cfind

Эта функция аналогична unicode.utf8.find, кроме того, что она принимает входное смещение и возвращает выходные смещения в символах, а не в байтах. (Исключением являются “position captures”, которые всё же возвращаются в байтах).


editor.SubscribeChangeEvent

Библиотека LuaFAR содержит функцию editor.SubscribeChangeEvent. Для макросов-обработчиков событий эта функция переопределена плагином LuaMacro:

  • Вызов оригинальной функции происходит только при переходе внутреннего счётчика подписок из 0 в 1 (если аргумент Subscribe==true), либо из 1 в 0 (если аргумент Subscribe==false). Поэтому нужно, чтобы в каждом обработчике, делающем вызов Subscribe==true, был и парный вызов Subscribe==false.

  • В отличие от плагинов, событие EE_CHANGE может приходить независимо от того, вызывал ли данный обработчик функцию editor.SubscribeChangeEvent или не вызывал.

  • Счётчики подписок отдельные для каждой сессии редактора.


package.nounload

package.nounload – это таблица, ключи которой являются именами модулей, не удаляемых из package.loaded при выгрузке или перезагрузке макросов (операции MCTL_LOADALL, lm:load, lm:unload).

  • Таблица создаётся автоматически плагином LuaMacro.
  • Обычно в эту таблицу заносятся имена модулей, использующих LuaJIT FFI и вызывающих ffi.cdef.

Например, если исполнить

    package.nounload.mylib = true

то модуль mylib не будет удалён из package.loaded при операциях выгрузки или перезагрузки макросов.


Примеры


Выделить слово под курсором

Macro {
  description="Выделить/снять выделение слова под курсором";
  area="Editor"; key="CtrlM";
  action=function()
    Keys"RCtrl9 CtrlRight CtrlLeft"
    Keys(Object.Selected and "CtrlU" or "CtrlShiftRight")
    Keys"Ctrl9"
  end;
}


Переход в меню выбора дисков

-- Переход в меню выбора дисков на противоположной панели,
-- включение видимости панели, в которой будет происходить
-- смена диска, если её не было.
Macro {
  description="Переход в меню выбора дисков на противоположной панели";
  area="Disks"; key="CtrlM";
  action=function()
    Keys"Esc"
    if not PPanel.Visible then
      Keys(APanel.Left and "CtrlF2" or "CtrlF1")
    end
    Keys"Tab F9 Enter End Enter"
  end;
}


Выделить файлы новее текущего

-- Выделить в активной панели все файлы/папки новее текущего,
-- используя API плагинов (LuaFAR).
Macro {
  description="Выделить в активной панели все файлы/папки новее текущего";
  area="Shell"; key="CtrlM";
  action=function()
    local info = panel.GetPanelInfo(nil,1)
    local curItem = panel.GetCurrentPanelItem(nil,1)
    for i=1,info.ItemsNumber do
      local item = panel.GetPanelItem(nil,1,i)
      if item.LastWriteTime > curItem.LastWriteTime then
        panel.SetSelection(nil,1,i,true)
      end
    end
    panel.RedrawPanel(nil,1)
  end;
}

-- Выделить в активной панели все файлы/папки новее текущего,
-- используя API макросов (LuaFAR + LuaMacro).
Macro {
  description="Выделить в активной панели все файлы/папки новее текущего";
  area="Shell"; key="CtrlM";
  action=function()
    d = Panel.Item(0,0,17)
    for i=1,APanel.ItemCount do
      if Panel.Item(0,i,17) > d then
        Panel.Select(0,1,1,i)
      end
    end
  end;
}


Создание папки с именем = текущей дате

Macro {
  description="создание папки с именем = текущей дате";
  area="Shell"; key="CtrlShiftF7"; flags="NoPluginPanels";
  action=function()
    folder = mf.date("%d.%m0.%Y")
    if Panel.FExist(0,folder)==0 then
      Keys"F7 CtrlY"
      print(folder)
      Keys"Enter"
    end
  end;
}


Запуск скрипта из редактора

-- Данный макрос сначала сохраняет содержимое редактора (если оно не было сохранено),
-- затем исполняет редактируемый файл как Lua-скрипт.
Macro {
  description="Save and run script from editor";
  area="Editor"; key="CtrlF10";
  action=function()
    for k=1,2 do
      local info=editor.GetInfo()
      if bit64.band(info.CurState, far.Flags.ECSTATE_SAVED)~=0 then
        local Flags = info.FileName:sub(-5):lower()==".moon"
          and "KMFLAGS_MOONSCRIPT" or "KMFLAGS_LUA"
        far.MacroPost('@"' .. info.FileName .. '"', Flags)
        break
      end
      if k==1 then editor.SaveFile(); end
    end
  end;
}


Используемые программные продукты


Lua

Lua is licensed under the terms of the MIT license reproduced below. This means that Lua is free software and can be used for both academic and commercial purposes at absolutely no cost.

For details and rationale, see http://www.lua.org/license.html .

Copyright © 1994-2008 Lua.org, PUC-Rio.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


LPeg

License

Copyright © 2008 Lua.org, PUC-Rio.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


MoonScript

License (MIT)

Copyright © 2013 by Leaf Corcoran

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Статьи


FAR Manager. Macros and whatnot.

By Gleb Varenov (“Acerbic”) » Tue 23 Apr, 2013 22:53
Revision 1.1

Gather round, boys and girls, for I am about to tell you a story.

Macro in your FAR Manager? It’s more likely than you think.

The “macro” term is used loosely in Far to describe a broad range of user-made modifications of the application’s behavior. For the sake of simplicity, let me divide them into several use cases:

  1. Assigning hotkeys / remapping key bindings. This is the simplest. You want one custom key (or combination with Ctrl, Shift, Alt modifiers) do what another key (combination) already does. It is one for one replacement.

  2. Your typical macro. Press one key to emulate a sequence of many keys. Its not much different from just a hot key. You press a key – it is treated as if you pressed some fixed predefined string of keys.

  3. Script. Now this is interesting. Script involves logic and decision making, not just some fixed reaction. A script has means to analyze current situation and affect Far Manager in non-trivial ways. Requires programming skills to create, but luckily the are many scripts already written and you may find one just fitting your needs.

  4. Plugin. Well, this is a moot point. With the course Far development is following now the gap between a complex script and a full fledged plugin is closing rapidly. As of right now, a script has most of functional capabilities a plugin has, it has access to both macro API and plugin API, in the latest builds a macro script can be started by an event, not just by a key pressed and so forth…

History and identification of obsolete.

FAR Manager has traveled a long way from its early versions and so did its macro capabilities. In Far1 and Far2 the configuration was stored in Windows registry, including macros. In Far3 configuration was moved to SQLite database files located in user’s profile folder. But later it was decided that it would be better to allow users simpler access to macros and they were moved from a database to individual files (still inside user’s profile folder). Also, parallel to moving macro definitions to external files, the macro language was changed to LUA.

In addition to that, there is a very popular plugin called “MacroLib”. It provides extended macro features on top of built-in system. It used to overlay old macro language, but then switched to LUA as well. It always stored macros in external files.

So, what to look out for to spot outdated manuals / macro recipes?

  1. *.reg files. Partial and full configurations were distributed as reg import files in times of Far1 and Far2. That included macros. No *.reg files are used by Far3 plugins or Far3 itself, but some old (ANSI) Far1 plugins can still use them. Any macros contained in them won’t work in Far3.

  2. *.farconfig files. Those are XML text files containing configurations for Far3. They are still used for other parts of configuration (coloring schemes and such) but not for macros anymore.

  3. Old macro language. It contained keywords like “$IF” “$ELSE” – denoted by dollar sign.

  4. Old MacroLib files *.fml – new MacroLib macro files use “fmlua” extension.

It is important to note that internal help in Far (called by “F1”) is massively lagging behind development – hence this article.

What now?

At present, by means of storage macros fall in three groups.

  1. Files of the built-in macro system. *.lua Located in %FARPROFILE%/Macros/internal and %FARPROFILE%/Macros/scripts

  2. MacroLib files *.fmlua. By default are located within plugin’s folder, but it can be configured to read macros from any user defined path (or several).

  3. Other macro processing plugins. “Lua4Editor”, for example. I don’t know much about these, you are on your own here, folks.

Important warning! There are plugins written in LUA. These are something different from macros. They are legit plugins with all the things a “usual” plugin has (like being listed in plugins' menu “F11”). Except they are written in LUA and distributed as source files. They should not confuse you as they lie in their folders in %FARHOME%/Plugins

Conversion.

It is best to rewrite your macros in LUA from scratch. If they are few and simple, it won’t take much effort. If they are complex, conversion is likely to fail to do it automatically. But if you are still interested in doing things hard way, there are few tools to help you. They were meant as quick fixes for transition period and aren’t supported anymore, probably.

  1. Far1, Far2 –> Far 3 2x3 perl converter This tool is used to convert old configuration from registry to database. This includes macros. The result will be a bunch of XML files containing far configurations and macros in the old language.

  2. Translation from old language to the new one is done by Macro2Lua Converter plugin. The readme is in Russian, but here is an excerpt regarding main usage via command line

    M2L: convert <input file> <output file> [<syntax>]
    where <syntax> is optional input format specifier and is one of following: xml_file, xml_macros, xml_keymacros, xml_macro, fml_file, fml_macro, chunk, expression. General file format is the part before underscore, the specific section of a file is the part after underscore. “chunk” and “expression” are some kind of raw macro pieces of texts. The result should be a XML file (<farconfig>...</farconfig>) with macros translated to LUA inside of it or a MacroLib fmlua file if original was *.fml and corresponding syntax was specified.

  3. Far3 2927-3000 –> Far3 3001+ Now you need an older version of Far3 (pre3001). You import your macros to Far per usual command, then use a script provided in the following forum thread:
    Macros have been moved from macros.db to files

Managing confusion.

While all macros are written in LUA, file contents are not interchangeable as of right now. It means that you can’t rename X.fmlua to X.lua, move it to %FARPROFILE%/Macros/scripts and expect it to work. Likewise you can’t just move files from /internal to /scripts.

Luckily, with few rules I am about to explain, you won’t get lost in all of the LUA files lying around.

  1. Don’t touch your internals! Files in %FARPROFILE%/Macros/internal are to be manipulated (created/edited/deleted) by FAR Manager itself. And while it is possible to edit them manually, better to leave them alone. Unless you really know what are you doing. Or just feeling adventurous.

  2. MacroLib files are always named *.fmlua, so you can never confuse them with native script files, even if you configured the MacroLib so they are located in the same directory.

  3. User-made native script files are located in %FARPROFILE%/Macros/scripts and are named *.lua. They are read at Far launch, but you can make Far to re-read the folder via command line (more on that later).

So, only (2) and (3) are in user’s management and they are different in names, location and internal structure.

But there are similarities too.

  1. Both MacroLib and native macros have a concept of “Area of execution” – basically, a broad condition limiting macro effect. Typical are “Editor” – when editor is open, “Shell” – when file panels are in focus, etc…

  2. In addition to general area, some more conditions might be specified for activation of a macro. Like passive panel being visible, command line not being empty and similar. These conditions/flags are legacy carried over from times when macro language was primitive and things like that were hard to check in script itself. Alternatives are being developed (like custom function conditionals in native scripts) but there is no sign that old flags will be abandoned yet.

  3. And finally, there are two flags that control execution of the macro itself. One is to disable/enable intermediate visual output during macro execution (reduces flicker of menus and dialogs being open/closed, for example), another is to control if plugins can intercept keyboard events generated by macro. No other macro can intercept current macro while it is executing – so you don’t have to worry about nasty macro interferences.

Out of the box.

In the beginning of time the macro language was ugly and everyone was sad. And few of the developers raised their voices: “Look! There in the great outside lies shiny LUA. Let us take it for ourselves, let us bind it to our manager and then we won’t be suffering dollar-signed keywords no more.” And so they did. And night turned day, and day turned night, and the Moon died and was born again as they tinkered and meddled and compiled and debugged. Seasons passed by, but finally, the day has come and their labor was over. And they stood proud among men and shouted: “Behold this LuaMacro plugin! We can rework our ugly macros into LUA, we have the technology now. But wait! There’s more: we can write plugins in LUA as well, if we desire so.” And everyone rejoiced. And gathered developers of Far and saw what their brethren did, and saw that it was good. So good in fact, they put the new plugin in the core package and abandoned their old ways of macros.

So, native macro capabilities are provided by LuaMacro plugin, which is distributed with Far itself as part of its core package. The plugin has no configuration dialog, but has a list of commands to manipulate it:

  • lm: unload – Far forgets all macros. They are still on disk and can be loaded back with next command.

  • lm: load – makes Far discard all macros and then re-read them from directories anew.

  • lm: post <sequence>|@<filename> – executes a macro code immediately. Either a “raw” piece of code typed in command line, or same raw code saved in a file. File name is prefixed with “@” symbol.

  • lm: check <sequence>|@<filename> – same as above. Except the macro is not executed but checked for syntax errors.

  • lm: save – saves changes made to “internal” macro files. Useful if you have “Auto save setup” option turned off.

When “load” and “unload” operations are concerned, only native macros are affected. I.e. those *.lua that are located in /internal/ and /scripts/. MacroLib macros are not touched. List of all currently loaded native macros is available in Far built-in help “F1”. That part of help is not translated to English yet, and its not very convenient in operation anyway. Check this macro out though.

Note. “lm:” commands are similar to ones provided by FarCommands plugin via “macro:” and “far:macro ” prefixes. There was a difference in that FarCommands used “<” symbol to specify filename, but now it supports both “<” and “@” for this.

It is time now to explain why some macros are put in /internal/ and others in /scripts/. Its fairly simple – “internal” is a codename for “recorded” and all the recoded macros go there. More on recorded macros is in the “Hotkeys / Macro use case” chapter. User-made macros are to be placed in /scripts/. Sadly, there’s no comprehensible manual on how to write them. One is reduced to scavenging for bits and pieces of knowledge by perusing Far’s changelog and dissecting macros written by others (SimSU macro pack for example, topic in Russian forum: http://forum.farmanager.com/viewtopic.php?f=15&t=7075). Here is a script for the Editor that pastes a macro template on “Ctrl+F11” by Shmuel: InsertMacro.lua.7z

MacroLib.

This is what all the cool kids use. MacroLib is a plugin that provides somewhat extended functionality to macros. It is built on top of native macro system, so 99% of the code working for “regular” macro will work for MacroLib as well. Project’s main page: http://code.google.com/p/far-plugins/wiki/MacroLib, download page: http://code.google.com/p/far-plugins/downloads/list?q=MacroLib, documentation (Russian): http://code.google.com/p/far-plugins/wiki/FML. MacroLib files are named *.fmlua and are located in one or several directories designated by user in configuration dialog. The dialog allows you to update macros from disk and shows you a very neat list of all macros currently loaded with ability to sort, filter, run a macro from the list.

MacroLib used to have many advantages over built-in system, but nowadays Far has caught up for the most part and is ahead in some experimental things (like events). However, there are two things *.fmlua scripts have over *.lua ones.

  1. You can use modifiers to your assigned hotkeys, such as “Hold” (macro is invoked after the key was held for a certain period of time), “Double”(on double click or double key tap), “Release” (macro is called on key being released, rather than being pressed).
  2. You frame your macro code in double curly brackets for extra swag {{ }}.

Hotkey / Macro use case.

Can’t get used to saving edited file by “F2”? Too lazy to run through menus every time you want to view your current Folder Shortcuts? Then this chapter is for YOU. This chapter covers a very simple usage of Far macros – redefining hotkeys for existing actions and creating hotkeys for actions that don’t have them by default. The easiest way to do said things is by using “Recorded Macro” feature. The Far Manager has an ability to record your actions (keyboard events) and assign them to a specific key, pressing which will replay your actions. This function is in there from Far1 and is explained in “F1” Help, but I will rehash it for you anyway. You start recording by pressing “Ctrl+.” (Control key plus dot key) or “CtrlShift+.”, a little red “R” letter appears in the top-left corner and your following key presses will be recorded. You continue to use Far as usual, doing things you want to be put in the macro, or just pressing one key you want to be remapped. Then you finish recording by pressing “Ctrl+.” or “CtrlShift+.” again. Then you will be asked for a key to which this macro will be assigned, you can select one from a drop-down list with a mouse or just press the desired combination, then “Enter”. At this moment an optional dialog might appear to configure additional parameters of you macro.

So,

  1. “Ctrl+.” or “CtrlShift+.”
  2. Do stuff on record.
  3. “Ctrl+.” or “CtrlShift+.”
  4. Select a desired key to assign to.
  5. (optional) Configuration dialog.

If you finish recording with “CtrlShift+.” on step 3 you will be shown a dialog on step 5. Otherwise you won’t be. To know more about this dialog, press “F1” while in there, its covered in the Help. Starting the recording with “CtrlShift+.” puts a “NoSendKeysToPlugins” flag on your macro, which means that during macro playback plugins won’t be able to react to keyboard events generated by this macro – it forces plugins to ignore this macro in that regard.

If you made a mistake in your macro during recording you may interrupt the recording by usual “Ctrl+.” and then hit “Esc” when asked about desired key. If you select a key that is already taken by a macro, you will be asked if you want to overwrite previous macro. This means you cannot have two recorded macros on the same key in the same area of execution. You can, however, have one for each area (one in Editor, one in Viewer, etc.) If you need to delete a macro you previously recorded, you create an empty macro for the key you want to free: “Ctrl+.”, “Ctrl+.”, the key. Then select “yes” to confirm deletion.

If you have “F9”–>“Options”–>“System Settings”–>“Auto save setup” option turned on, then every change to your recorded macros (creation, modification, deletion) will be immediately saved to files. Otherwise you can use lm: save command to save your recorded macros or press “Shift+F9” to save full setup. If you want to know what macros are already recorded, you can navigate to %FARPROFILE%/Macros/internal. It is possible delete macros in there, just don’t forget to use lm: load command to update, or restart Far.

Example: lets bind a hotkey to “File associations” menu.

  1. (preparation) Make sure you are in the Shell area of Far, its where two panels with files and folders are.
  2. Press “Ctrl+.” and make sure the red “R” letter appeared.
  3. Press “F9” to move input focus to Far’s menu (usually is the top line of the window), then “c” for commands, then “a”. Now, if done right the “File associations” menu is on screen.
  4. Press “Ctrl+."again, a little "Define macro” box should pop up. Press “Ctrl+Shift+a” and confirm that corresponding key code appeared in the box (“CtrlShiftA”).
  5. Press “Enter” and enjoy a new quality of life improvement you just created for yourself. Now every time you press “Ctrl+Shift+a” combo in Far shell, the menu will instantly appear.

Script use case.

“Script” is a program that runs within/by other program (as opposed to one run by CPU/OS). Scripts in Far evolved from macros to a point when macros themselves are considered primitive cases of scripting. Being programs, scripts require “Programming / Coding” skill to be created, therefore, if you intend to use Far to its fullest potential you might want to invest few skill points in it on your next level up. Alternatively, you can utilize macros written by someone else – just copy the files in appropriate folders. As mentioned before, Far uses LUA language for scripting. From within the script you have access to

  1. Far (plugin) API – functions of Far that are available to plugins.

  2. Far macro API – some specific functions that were available in old language. These overlap “Plugin API” to some extend and considered legacy API. Better use “Plugin API” where possible.

  3. Custom functions exported by plugins – some plugins export their functions to be called from macro. Those depend on plugin being installed and loaded, of course.

  4. LUA libraries – native to LUA (see language manual) plus few libraries additionally shipped with LuaFar (“bit64”, “win” – gate to Win API, Selene Unicode)

  5. Far UI – you can control Far simply by issuing keyboard/mouse commands to it. Why bother finding a function that will open Editor for file under cursor when you can just send “F4” to Far?

Your main source of information about Far APIs is in %FARHOME%\Encyclopedia files. Lets look at them.

  • “FarEncyclopedia.ru.chm” – includes (1) and (2), in Russian. Macro API is outdated (pre-LUA). There’s an online version too: http://api.farmanager.com/ru/

  • “luafar_manual.chm” – originally a LuaFar plugin manual (writing plugins in LUA), but we can use it in scripts too. Covers (1) in LUA in English. Very spartan – most of the functions have no textual descriptions, only input parameters and result values (implies ability to read “FarEncyclopedia.ru.chm”). For the most part it is not a problem though, functions' names are self-descriptive.

  • “macroapi_manual.chm” – mapping of (2) to LUA. Again, almost no descriptions.

Damn, its kinda depressing, ain’t it? Luckily for you, I have a magical artifact that will allow you to understand Russian: abracadabra. Paste a link to Russian website or text fragment and hit “Enter”. And Acerbic saves the day once again! You are welcome.

To sum it up: you will use “luafar_manual.chm” in conjunction with translated online encyclopedia for Far plugin API reference and “macroapi_manual.chm” in conjunction with this link for Macro API reference. I found this script very helpful: lua_explorer. It allows you to browse Lua tables/values/functions soup available to LUA script. Thread on the forum.

Native or MacroLib?

MacroLib.

Sample script.

Here’s a little demonstration of what you can do in MacroLib: “RCtrl Folder shortcuts.fmlua”

;;
;; Folder shortcuts menu
;; RCtrl single pressing or holding will pop-up the shortcuts menu. Press RCtrl again (or Esc) to close it.
;; RCtrl1-0 will go to set shortcut
;;

const FolderShortcutsId = "4CD742BC-295F-4AFA-A158-7AA05A16BEA1"

macro
area="Shell"
description="Folder shortcuts popup"
key="RCtrl:Hold RCtrl:Release"  ;; call on holding LCtrl or single press of the button (Need to specify Release after Hold bc of a bug)
EatOnRun=0 ;; allows RCtrl:Release in Menu area after RCtrl:Hold was caught
{{
    Keys("F9 c d");
}}

macro
area="Menu"
description="Folder shortcuts: RCtrl+digit"
key="/RCtrl\d/"
{{
    if (Menu.Id == #%FolderShortcutsId) then
        Keys(regex.match(akey(1),"RCtrl(\\d)?")) -- double escaping \\ because of LUA strings parsing
    end;
}}

macro
area="Menu"
description="Folder shortcuts: pass RCtrl+not_digit through"
key="/RCtrl(?!\d$).+/"      ;; Takes RCtrlSOMETHING. Ignores RCtrl0 .. RCtrl9 and bare RCtrl
{{
    if (Menu.Id == #%FolderShortcutsId) then
        Keys("Esc AKey");
    end;
}}

macro
area="Menu"
description="Folder shortcuts popup close on second RCtrl or on RCtrl:Release after RCtrl:Hold"
key="RCtrl:Release"
{{
    if (Menu.Id == #%FolderShortcutsId) then
        Keys("Esc");
    end;
}}