Помощь в написании Lua-плагина

Столкнулись с проблемой в использовании макросов? Здесь можно получить помощь.
User avatar
Majestio
Posts: 32
Joined: Mon 22 Aug, 2016 08:58
Has thanked: 2 times

Помощь в написании Lua-плагина

Post by Majestio »

Latest post of the previous page:

Всем привет, и очередной вопрос) Каким образом узнать, что в редакторе в данный момент установлена настройка "Использовать BOM" при записи файла? Это мне нужно для сброса текущего содержимого во временный файл, и чтобы было один-к-одному по сравнению со штатным сохранением. Пока без разбору пишу:

Code: Select all

File:write(string.char(239,187,191))
А хотелось бы немного более по-фэншую. А в chm-хелпе по LuaFar'у этого не нахожу.
Last edited by Majestio on Tue 21 Apr, 2020 17:25, edited 1 time in total.
User avatar
zg
zero-gravity
Posts: 5878
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 158 times
Contact:

Помощь в написании Lua-плагина

Post by zg »

EOPT_BOM, я не знаю, как это можно было пропустить при чтении документации.
buniak_a_h
Posts: 2286
Joined: Sat 20 Apr, 2013 00:17
Location: Питер
Has thanked: 139 times
Been thanked: 245 times
Contact:

Помощь в написании Lua-плагина

Post by buniak_a_h »

zg, я знаю. Найти, в каком поле какой таблицы какой функции этот флаг может возвращаться - совершенно нереально, если не знать, что конкретно искать.
А так-то спасибо.
Last edited by buniak_a_h on Tue 21 Apr, 2020 18:56, edited 1 time in total.
User avatar
zg
zero-gravity
Posts: 5878
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 158 times
Contact:

Помощь в написании Lua-плагина

Post by zg »

editor.GetInfo — что может быть логичнее для получения информации о редакторе?
buniak_a_h
Posts: 2286
Joined: Sat 20 Apr, 2013 00:17
Location: Питер
Has thanked: 139 times
Been thanked: 245 times
Contact:

Помощь в написании Lua-плагина

Post by buniak_a_h »

Верно. Получаю таблицу. В таблице есть поле CodePage, но нет поля SetBOM. Есть поле Options, но признак "писать BOM" никак не ассоциируется с Options (я плохо знаю английский, но по мне - так Options - это режимы работы редактора). В самом описании функции не перечислено, что конкретно может быть указано в поле Options. Ну, писать ли после EOL/EOF, расширять ли Tab - это понятно. Режимы ReadOnly, AutoIndent - тоже. Но BOM - ну никак не ассоциируется с режимами редактора. Это, как и кодовая страница, скорее, характеристика файла, а не editor.Options. Поэтому я, также как и автор вопроса, на этот флаг никак выйти не смог.
Есть ещё одно соображение: в SetParam признак SetBOM - отдельный. Логичным кажется поведение SetParam с nil-ом в 3-м параметре, возвращающее предыдущее значение. Увы, не всё, что кажется логичным мне, кажется таковым авторам :-(
User avatar
zg
zero-gravity
Posts: 5878
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 158 times
Contact:

Помощь в написании Lua-плагина

Post by zg »

buniak_a_h wrote: Tue 21 Apr, 2020 20:33В самом описании функции не перечислено, что конкретно может быть указано в поле Options.
там есть ссылка.
User avatar
Majestio
Posts: 32
Joined: Mon 22 Aug, 2016 08:58
Has thanked: 2 times

Помощь в написании Lua-плагина

Post by Majestio »

zg, пасип! А вообще, я согласен с постом buniak_a_h.
User avatar
Majestio
Posts: 32
Joined: Mon 22 Aug, 2016 08:58
Has thanked: 2 times

Помощь в написании Lua-плагина

Post by Majestio »

Всем привет!

Хочу еще раз поблагодарить всех, кто помогал советами. У меня все получилось как задумывал. Первая моя программа на Lua, равно как и, собственно, far-скрипт. Готов поделиться сделанным, но не знаю на сколько это будет востребовано.

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

Filter - записываем временный файл, обрабатываем его командой, потом загружаем в редактор
Pipe - записываем временный файл, обрабатываем его командой, потом загружаем в редактор STDOUT выполненной команды
Compiler - сохраняем файл, запускаем команду компилятора, по результату или диалог с Ok, либо диалог с ошибкой от компилятора
Execute - сохраняем файл, запускаем команду интерпретатора, который обрабатывает содержимое редактора - результат выводим в виде диалога

Вот пример моего теперешнего конфига EditorTools.conf:

Code: Select all

; Поля конфига следующие:
;
; Режим, "Название-инструмента", "командная строка"
; 
; Режим:
;
;   [F]ilter - записываем временный файл, обрабатываем его командой, потом загружаем в редактор
;   [P]ipe - записываем временный файл, обрабатываем его командой, но загружаем STDOUT команды
;   [C]ompiler - сохраняем файл, запускаем команду компилятора 
;   [E]xecute - сохраняем файл, запускаем команду интерпретатора, результат выводим в виде диалога 
;
; Плейсхолдеры:
;
;   %p - путь к файлу в редакторе
;   %n - имя файла в редакторе (без расширения)
;   %e - расширение имени файла в редакторе
;   %t - полное имя временного файла
;   %o - полное имя временного файла-результата (куда пишется из пайпа)
;   %r - полное имя временного файла-результата (куда может писать сама программа)
;
; Пример:
;
; F,'Инструмент-1','comm-1.cmd'
; P,'Инструмент-2','comm-2.cmd'
; C,'Инструмент-3','comm-3.cmd'
; E,'Инструмент-4','comm-4.cmd'
;

P,'AStyle (Space-P)','C:\Tools\AStyle\AStyle.exe --options=C:\Tools\AStyle\.astylerc-space --stdin=%t'
F,'AStyle (Space-F)','C:\Tools\AStyle\AStyle.exe --options=C:\Tools\AStyle\.astylerc-space --stdin=%t --stdout=%r'
P,'TidyP','C:\Tools\tidy.exe -config c:\Tools\tidy.conf "%t"'
P,'Hello Ruby','ruby.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\hello.rb'
P,'Test Perl-P','perl.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\test-p.pl "%p%n.%e"'
F,'Test Perl-F','perl.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\test-f.pl "%t" "%r"'
C,'Компилировать FASM программу','C:\Tools\Fasm\FASM.CMD "%t" "%p%n.exe"'
E,'Исполнить Perl скрипт','perl.exe %t'
E,'Исполнить SWI-Prolog скрипт','C:\Tools\Prolog\bin\swipl.exe -q -f %t' 
Сам скрипт EditorTools.lua:

Code: Select all

------------------------------------------------------------------------------------------------------------------------
-- Скрипт EditorTools v.1.1
-- подключение внешних инструментов в редакторе Far'а 
--
-- 2020 (C) Автор Majestio aka JoeUser
--
-- http://majestio.info
--
------------------------------------------------------------------------------------------------------------------------
-- local inspect = require('inspect')
local ScriptName = ...
local EOPT_BOM = 0x00000200
local BTYPE_STREAM = 1
local SW_HIDE = 0
------------------------------------------------------------------------------------------------------------------------
local EditorTools = function ()
  local CurPath = mf.fsplit(ScriptName,3)
  local ConfigName = ScriptName:gsub("[^.]+$","conf")
  local Conf = io.open(ConfigName,"r")
  -- читаем файл конфигурации ------------------------------------------------------------------------------------------
  if Conf == nil then 
    far.Message('Файл конфигурации нельзя прочесть!', 'Ошибка', ';Ok', 'w')
    return
  else
    local Cmd = {}
    local Idx = 1
    -- разбираем файл конфигурации на список "инструментов" ------------------------------------------------------------
    for line in Conf:lines() do 
      if regex.match(line,'^(F|P|C|E)') then
        for w1,w2,w3 in regex.gmatch(line, "^(F|P|C|E)\\s*,\\s*'\\s*([^']+?)\\s*'\\s*,\\s*'\\s*([^']+?)\\s*'\\s*$") do 
          Cmd[Idx] = {w1,w2,w3}
        end
        Idx = Idx + 1
      end
    end
    Conf:close()      
    -- формируем и выводим диалог выбора "инструментов" ----------------------------------------------------------------
    local Choice = '' 
    for Idx = 1, #Cmd do
      Choice = Choice..Cmd[Idx][2]..'\n';
    end
    local ChoiceIdx = Menu.Show(Choice, nil, 8+0x200)
    if ChoiceIdx == 0 then return end
    -- формируем имя временного файла для сброса содержимого редактора -------------------------------------------------
    math.randomseed(os.time())
    local RndNumber = math.random(1000)
    local EditorFullName = editor.GetFileName()
    local EditorFilePath = regex.match(EditorFullName,"^(.+\\\\).+$")
    local EditorFileName = regex.match(EditorFullName,"^.+\\\\([^\\.]+)\\.*.*$")
    local EditorFileExt = regex.match(EditorFullName,"^.+?\\.([^\\.]+)$")
    if EditorFileExt == nil then EditorFileExt = "" end
    local TmpName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'..EditorFileExt
    local OutName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."out"
    local ResName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."res"
    local ErrName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."err"
    -- в командной строке производим замены в плэйсхолдерах ------------------------------------------------------------
    local CmdName = regex.gsub(Cmd[ChoiceIdx][3],"%p",EditorFilePath) -- %p на значение EditorFilePath
    CmdName = regex.gsub(CmdName,"%n",EditorFileName)                 -- %n на значение EditorFileName
    CmdName = regex.gsub(CmdName,"%e",EditorFileExt)                  -- %e на значение EditorFileExt
    CmdName = regex.gsub(CmdName,"%t",TmpName)                        -- %t на значение TmpName
    CmdName = regex.gsub(CmdName,"%o",OutName)                        -- %o на значение OutName
    CmdName = regex.gsub(CmdName,"%r",ResName)                        -- %r на значение ResName
    -- запускаем внешнюю обработку в зависимости от "режима" выбранного инструмента ------------------------------------
    if WriteFile(TmpName) ~= nil then
      local Out, Err = ExecCommand(CmdName, TmpName, OutName, ResName, ErrName, Cmd[ChoiceIdx][1])
      if Cmd[ChoiceIdx][1] == "C" then
        if Err == "" or Err == nil then 
          far.Message("Компиляция прошла удачно", 'Результат компиляции', ';Ok', 'k')
        else
          far.Message(win.OemToUtf8(Err), 'Ошибка', ';Ok', 'w')
        end
      else
        if Out ~= "" and Out ~= nil then 
          if Cmd[ChoiceIdx][1] == "E" then
            far.Message(win.WideCharToMultiByte(win.MultiByteToWideChar(Out,1251),65001), 'Результат выполнения', ';Ok', 'k')
          else
            LoadContent(Out) 
          end 
        else
          if Err == "" or Err == nil then
            far.Message('Обработчик вернул пустой вывод!', 'Ошибка', ';Ok', 'w')
          end
        end 
      end
    else
      far.Message('Ошибка записи временного файла!!', 'Ошибка', ';Ok', 'w')
    end
  end
end
------------------------------------------------------------------------------------------------------------------------
-- Загрузка файла в редактор
------------------------------------------------------------------------------------------------------------------------
function LoadContent(Content)
  local Ei = editor.GetInfo()
  local EId = Ei.EditorID
  local Flags = far.Flags
  editor.UndoRedo(EId, Flags.EUR_BEGIN)
  editor.Select(EId, BTYPE_STREAM, 1, 1, 1, Ei.TotalLines+1)
  editor.DeleteBlock(EId)
  Content = regex.gsub(Content,"^(\xef\xbb\xbf)","")
  editor.InsertText(EId,Content)
  editor.UndoRedo(EId,Flags.EUR_END)
  editor.SetPosition(EId, 1, 1)
end
------------------------------------------------------------------------------------------------------------------------
-- Запуск процесса по обработке файла
------------------------------------------------------------------------------------------------------------------------
function ExecCommand(CmdName, TmpName, OutName, ResName, ErrName, Mode)
  local RetOut, RetErr 
  local File = io.popen(('"%s >"%s" 2>"%s"'):format(CmdName, OutName, ErrName),"w")
  if File == nil then
    far.Message('Ошибка при запуске команды!', 'Ошибка', ';Ok', 'w')
    return nil, nil
  end
  File:close()
  local TheName = OutName
  if Mode ~= "P" and Mode ~= "E" then TheName = ResName end
  if win.GetFileInfo(TheName) ~= nil then
    OutFile = io.open(TheName)
    if OutFile~= nil then
      RetOut = OutFile:read("*a")
      OutFile:close()
    end
  end
  if win.GetFileInfo(ErrName) ~= nil then
    ErrFile = io.open(ErrName)
    if ErrFile~= nil then
      RetErr = ErrFile:read("*a")
      ErrFile:close()
    end
  end
  win.ShellExecute(nil,nil,win.GetEnv"COMSPEC",('/c "del "%s" "%s" "%s" "%s"'):format(TmpName, OutName, ResName, ErrName),nil,SW_HIDE)
  return RetOut, RetErr
end
------------------------------------------------------------------------------------------------------------------------
-- Запись файла
------------------------------------------------------------------------------------------------------------------------
function WriteFile (FileName)
  local Info = editor.GetInfo()
  local File = io.open(FileName,"wb")
  if File == nil then
    far.Message('Ошибка записи временного файла!', 'Ошибка', ';Ok', 'w')
    return nil
  else
    if (bit.band(Info.Options, EOPT_BOM) == EOPT_BOM) then  
      File:write(string.char(239,187,191)) 
    end
    for Line = 1, Info.TotalLines do
      local Gs = editor.GetString(Info.EditorID, Line, 0) 
      File:write(Gs.StringText, Gs.StringEOL) 
    end
    File:close()
    return Info.TotalLines
  end
end
------------------------------------------------------------------------------------------------------------------------
-- Macro
------------------------------------------------------------------------------------------------------------------------
Macro {
  area="Editor"; key="CtrlE"; flags=""; description="EditorTools"; 
  action = function()
    EditorTools()
  end;
}
Last edited by Majestio on Mon 22 Jun, 2020 07:15, edited 6 times in total.
Post Reply

Return to “Нужна помощь”