Luacheck FAR scripts — статический анализатор для Lua/MoonScript

Здесь выкладываются готовые к использованию макросы и скрипты.
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

Luacheck FAR scripts — статический анализатор для Lua/MoonScript

Post by John Doe »

Luacheck это статический анализатор для Lua.
Luacheck может обнаруживать разнообразные проблемы, такие как использование неопределённых глобальных переменных, неиспользованные переменные и значения, доступ к неинициализированным переменным, недостижимый код и многое другое.

А для удобной работы с luacheck в фаре предлагаю данный пакет скриптов, обеспечивающий работу Luacheck в редакторе и в командной строке.
Кроме того, в редакторе для Luacheck обеспечивается прозрачная "трансляция" MoonScript, что позволяет анализировать и *.moon-файлы.

Инструкции по установке, настройке, и работе — во встроенной справке.

Требования:
  • FAR 3 не старше b5106
  • luacheck не ниже v0.19
Attachments
far_standards.lua.cfg_v1.5.7z
Обновлённые определения (far 6114 / lm 772)
(8.5 KiB) Downloaded 92 times
luaсheck_far_v1.4.3.7z
far5505.lm712
(23.38 KiB) Downloaded 340 times
Last edited by John Doe on Sat 09 Nov, 2019 16:08, edited 3 times in total.
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

Latest post of the previous page:

John Doe, я в порядке тренировки (в дополнение к „невылезанию“ вверх) реализовал себе «пинг-понг» и отдельное разворачивание/восстановление по F5 — развёрнутый список позиционируется в центре, при восстановлении возвращается в ранее заданную позицию:
  1. --- luacheck_editor.lua Mon Jul 13 22:37:20 2015
  2.  
  3. +++ luacheck_editor.lua Tue Jul 14 19:25:43 2015
  4.  
  5. @@ -3,7 +3,7 @@
  6.  
  7.  
  8.  
  9.  -- list options
  10.  
  11.  local MaxHeight = 10
  12.  
  13. -local ListPos = "Bottom" --Top,Bottom,Max or nil
  14.  
  15. +local InitListPos = "Bottom" --Top,Bottom,Center
  16.  
  17.  local AutoPos = true
  18.  
  19.  local ConvertToAnsi = true
  20.  
  21.  
  22.  
  23. @@ -140,6 +140,32 @@
  24.  
  25.    return newBreakKeysArr
  26.  
  27.  end
  28.  
  29.  
  30.  
  31. +local function maximizable(list)
  32.  
  33. +  return list.nItems>list.nLines and list.nLines<list.MaxItems
  34.  
  35. +end
  36.  
  37. +local ListState = {
  38.  
  39. +  currPos = InitListPos;
  40.  
  41. +  prevPos = nil;
  42.  
  43. +  maxHght = false;
  44.  
  45. +  jump = function( self, to )
  46.  
  47. +      assert( self.currPos ~= self.prevPos )
  48.  
  49. +      if to == nil then  -- ping-pong
  50.  
  51. +        local opposite = { ["Top"] = "Bottom", ["Bottom"] = "Top" }
  52.  
  53. +        to = ( self.currPos == "Center" ) and opposite[ self.prevPos ] or "Center"
  54.  
  55. +      end
  56.  
  57. +      if to ~= self.currPos then
  58.  
  59. +        self.prevPos = self.currPos
  60.  
  61. +      end
  62.  
  63. +      self.currPos = to
  64.  
  65. +      assert( self.currPos ~= self.prevPos )
  66.  
  67. +    end;
  68.  
  69. +  zoom = function( self, list )
  70.  
  71. +      if maximizable(list) then
  72.  
  73. +        self.maxHght = not self.maxHght
  74.  
  75. +      end
  76.  
  77. +    end;
  78.  
  79. +}
  80.  
  81. +
  82.  
  83.  local function setPos(info) editor.SetPosition(nil,info); editor.Redraw() end
  84.  
  85.  local function scrollEditor(dir)
  86.  
  87.    local ei = editor.GetInfo()
  88.  
  89. @@ -169,9 +195,9 @@
  90.  
  91.      local ei = editor.GetInfo()
  92.  
  93.      local y = w.line-ei.TopScreenLine --calculated screen line of warning
  94.  
  95.      local a,b = 0,ei.WindowSizeY      --valid screen lines (a..b)
  96.  
  97. -    if ListPos=="Top" then
  98.  
  99. -      a = a+nLines+1
  100.  
  101. -    elseif ListPos=="Bottom" then
  102.  
  103. +    if ListState.currPos=="Top" then
  104.  
  105. +      a = a+nLines+3
  106.  
  107. +    elseif ListState.currPos=="Bottom" then
  108.  
  109.        b = b-nLines-3
  110.  
  111.      end
  112.  
  113.      TopScreenLine = (y<a or force_top) and math.max(w.line-a,1)
  114.  
  115. @@ -187,9 +213,6 @@
  116.  
  117.      setPos(bak_pos)
  118.  
  119.    end
  120.  
  121.  end
  122.  
  123. -local function maximizable(list)
  124.  
  125. -  return list.nItems>list.nLines and list.nLines<list.MaxItems
  126.  
  127. -end
  128.  
  129.  local bKeys = expandBreakKeys {
  130.  
  131.    {BreakKey="C+UP    C+NUMPAD8",action=function()  scrollEditor(-1) end},
  132.  
  133.    {BreakKey="C+DOWN  C+NUMPAD2",action=function()  scrollEditor(1) end},
  134.  
  135. @@ -203,15 +226,11 @@
  136.  
  137.    {BreakKey="C+PRIOR C+NUMPAD9",action=function(w,list)
  138.  
  139.       if w.prev_line then gotoWarning({line=w.prev_line,column=w.prev_column,name=w.name},list.nLines) end
  140.  
  141.     end},
  142.  
  143. -  {BreakKey="C+HOME NUMPAD7",   action=function()  ListPos = "Top" end},
  144.  
  145. -  {BreakKey="C+END  NUMPAD1",   action=function()  ListPos = "Bottom" end},
  146.  
  147. -  {BreakKey="NUMPAD4",          action=function(_,list)
  148.  
  149. -     ListPos = not ListPos and (maximizable(list) and "Max" or ListPos)
  150.  
  151. -   end},
  152.  
  153. -  {BreakKey="F5 CLEAR",         action=function(_,list)
  154.  
  155. -     local next = {["Top"]="Bottom",["Bottom"]=false,[false]=maximizable(list) and "Max" or "Top",["Max"]="Top"}
  156.  
  157. -     ListPos = next[ListPos]
  158.  
  159. -   end},
  160.  
  161. +  {BreakKey="C+HOME NUMPAD7", action=function() ListState:jump( "Top"    ) end},
  162.  
  163. +  {BreakKey="C+END  NUMPAD1", action=function() ListState:jump( "Bottom" ) end},
  164.  
  165. +  {BreakKey="       NUMPAD4", action=function() ListState:jump( "Center" ) end},
  166.  
  167. +  {BreakKey="         CLEAR", action=function() ListState:jump(--[[auto]]) end},
  168.  
  169. +  {BreakKey="F5"            , action=function(_,list) ListState:zoom(list) end},
  170.  
  171.    {BreakKey="ADD",              action=function() editor.AddSessionBookmark() end},
  172.  
  173.    {BreakKey="CS+1 CS+2 CS+3 CS+4 CS+5 CS+6 CS+7 CS+8 CS+9 CS+0 C+1 C+2 C+3 C+4 C+5 C+6 C+7 C+8 C+9 C+0",keys=true},
  174.  
  175.    {BreakKey="F1",               action=showHelp},
  176.  
  177. @@ -265,14 +284,14 @@
  178.  
  179.        Props.X = maxlen<xSize-4 and (xSize-maxlen)/2-2 or -1
  180.  
  181.        local nItems = #Items
  182.  
  183.        local nLines = math.min(nItems,MaxHeight,MaxItems)
  184.  
  185. -      if not ListPos or ListPos=="Max" or nLines==MaxItems then
  186.  
  187. +      if ListState.currPos=="Center" or ListState.maxHght or nLines==MaxItems then
  188.  
  189.          Props.X,Props.Y = -1,-1
  190.  
  191. -      elseif ListPos=="Top" then
  192.  
  193. -        Props.Y = -2
  194.  
  195. -      elseif ListPos=="Bottom" then
  196.  
  197. +      elseif ListState.currPos=="Top" then
  198.  
  199. +        Props.Y = 0
  200.  
  201. +      elseif ListState.currPos=="Bottom" then
  202.  
  203.          Props.Y = MaxItems-nLines>0 and MaxItems-nLines+2 or -1
  204.  
  205.        end
  206.  
  207. -      Props.MaxHeight = ListPos=="Max" and 0 or MaxHeight
  208.  
  209. +      Props.MaxHeight = ListState.maxHght and 0 or MaxHeight
  210.  
  211.        -- show list
  212.  
  213.        Props.SelectIndex = pos
  214.  
  215.        local item
Надеюсь, что не продублировал Вашу сегодняшнюю работу.
Last edited by HaRT on Thu 01 Jan, 1970 01:00, edited 0 times in total.
Reason: В патч добавлено исправление прокрутки редактора при открытии списка
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

HaRT wrote: в дополнение к „невылезанию“ вверх
Только вторую указанную мной строку забыли исправить.
HaRT wrote: Надеюсь, что не продублировал Вашу сегодняшнюю работу.
Обошлось )
Разворачивание отдельной кнопкой понравилось.
А пинг-понг по-моему баловство.

P.S.
Этот парень похоже читает наш форум https://github.com/mpeterv/luacheck/com ... a519ef0897
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: вторую указанную мной строку забыли исправить
В каком сценарии это скажется?
John Doe wrote: Обошлось
Уфф! ;)
John Doe wrote: Разворачивание отдельной кнопкой понравилось.
Спасибо.
John Doe wrote: А пинг-понг по-моему баловство.
На вкус и цвет…
John Doe wrote: парень похоже читает наш форум
Прямой связи не увидел. Но хорошо, что читает, т.к. будет в курсе наших особенностей использования Луа.
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

HaRT wrote: В каком сценарии это скажется?
Список может закрыть собой строку, к которой относится предупреждение.
HaRT wrote: Прямой связи не увидел.
В шапке, в инструкции по установке luacheck_cmdline.lua я только вчера описал аналогичный патч , а сегодня он уже и не нужен.
(На самом деле я не думаю что он читает наш форум, скорее совпадение)
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: пинг-понг по-моему баловство
Можно было бы оставить в виде опции…
John Doe wrote: Список может закрыть собой строку, к которой относится предупреждение.
Спасибо, воспроизвёл; патч исправил.
Кстати, там в подобном сценарии ломается отображение Колореровского перекрестья. С этим можно что-то поделать?
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

HaRT wrote: Кстати, там в подобном сценарии ломается отображение Колореровского перекрестья.
Что значит в подобном сценарии?
У меня по Ctrl-Enter с крестом всё в порядке, а по Shift-Up/Down он не перерисовывается, да.
Решается добавлением flags="EnableOutput"; в соответствующий макрос.
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: Что значит в подобном сценарии?
Если я отправлю список наверх, закрою его, сделаю строку с предупреждением верхней и открою список вновь, то вертикальная черта перекрестья претерпевает излом. Там вообще в зависимости от предшествующих действий можно получить разнообразные .
И flags="EnableOutput"; для макроса на [b]CtrlShiftF7[/b] не помогает. :(
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

Code: Select all

if AutoPos and not pos then mf.postmacro(Keys,"CtrlEnter") end
заменить на

Code: Select all

if AutoPos and not pos then mf.postmacro(function()mmode(1,0) Keys"CtrlEnter"end) end
P.S.
В следующей версии наверно избавлюсь от макроса в этом месте.
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: заменить
Спасибо!
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

В шапке v1.1
  • Up/Down теперь сразу позиционируют редактор к месту соответствующего предупреждения.
  • Для максимизации теперь служит отдельная клавиша
  • Косметика: убраны пустые поля, улучшено позиционирование относительно верха/низа.
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: Для максимизации теперь служит отдельная клавиша
А также повторение позиционирования — удобно.
John Doe wrote: улучшено позиционирование относительно верха/низ
Спасибо!
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

buniak_a_h wrote:Про luacheck: Вы уверены, что он правильно анализирует? Получаю ошибку mutating read-only global variable ... . На самом деле (а) я не понимаю, почему эта переменная read-only;
Неоправданное использование глобальных переменных это потенциальный источник ошибок, поэтому его следует избегать.
В lua если переменная не объявлена предварительно с ключевым словом local, значит она считается глобальной.
Частный случай: переменная по замыслу локальна, но в каком-то месте кода употребляется с опечаткой в имени (например с большой буквы вместо маленькой).
luacheck позволяет легко находить такие ошибки, тогда как "глазами" это сделать проблематичною
buniak_a_h wrote:(б) она в этом месте прекрасно инициализируется; если б этот оператор не работал, вообще ничего не работало бы.
Надо понимать, что анализ luacheck это не ошибки, а всего лишь предупреждения.
В вашем случае это может и не баг, luacheck знать этого не может, но само действие потенциально опасно.
Сделайте переменную локальной, и предупреждений не будет.
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

Предложение: в меню предупреждений ввести быстрый фильтр по серьёзности. Например, по [b]CtrlH[/b] скрывать/показывать все „второстепенные“ предупреждения (те, которые не помечаются восклицательным знаком).
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

HaRT wrote: скрывать/показывать все „второстепенные“ предупреждения
Не берусь судить о второстепенности, а пометка восклицательным знаком это больше моя самодеятельность: для себя пометил предупреждения коды которых начинаются с 1 (все они связаны с использованием глобальных переменных).

Не уверен что правильно рубить с плеча и скрывать остальные.
Но какое-то более гибкое решение можно рассмотреть. Обратите внимание на опции, возможно стоит реализовать интерактивную конфигурацию.
В частности, вашему предложению соответствует значении опции only={"1.."}
User avatar
HaRT
Moderator
Posts: 10822
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 221 times
Been thanked: 358 times

luacheck — статический анализатор для Lua

Post by HaRT »

John Doe wrote: возможно стоит реализовать интерактивную конфигурацию
Не уверен, что нужна интерактивная. Лично мне было бы достаточно где-нибудь в скрипте прописать набор паттернов, которые бы скрывались/показывались по нажатию [b]CtrlH[/b] в списке предупреждений. А по умолчанию — {"1.."}.
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
John Doe
Бюрократ
Posts: 13807
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 73 times
Been thanked: 426 times
Contact:

luacheck — статический анализатор для Lua

Post by John Doe »

HaRT wrote: Лично мне было бы достаточно [...]
  1. local _NAME,_VER = "luacheck","1.2A"
  2.  
  3. local _forumtopic = "http://forum.farmanager.com/viewtopic.php?f=15&t=9650"
  4.  
  5. local luacheck_min_version,lmv_err_msg = "0.11.0","luacheck version %s or newer expected"
  6.  
  7. -- list options
  8.  
  9. local O = {
  10.  
  11.   MaxHeight = 10,
  12.  
  13.   InitPos   = "Bottom", --Top,Bottom,Center
  14.  
  15.   AutoPos   = true,
  16.  
  17.   --CycleMode = "ping-pong",
  18.  
  19.   --ConvertToAnsi = true,
  20.  
  21. }
  22.  
  23.  
  24.  
  25. -- luacheck options
  26.  
  27. local options_def = { --http://luacheck.readthedocs.org/en/0.11.0/config.html
  28.  
  29.   new_read_globals={
  30.  
  31.     "Macro","NoMacro","Event","NoEvent","MenuItem","NoMenuItem","CommandLine","NoCommandLine",
  32.  
  33.   };
  34.  
  35.   new_globals={
  36.  
  37.     "_filename",                    --scripts executed in luamacro via cmdline prefix
  38.  
  39.     "export","IsLuaStateRecreated", --lua plugins
  40.  
  41.   }
  42.  
  43.  
  44.  
  45.   --global=false;
  46.  
  47.   --allow_defined=true;
  48.  
  49.   --allow_defined_top=true;
  50.  
  51.   --unused=false;
  52.  
  53.   --unused_args=false;
  54.  
  55.   --unused_secondaries=false;
  56.  
  57.   --redefined=false;
  58.  
  59.   --http://luacheck.readthedocs.org/en/0.11.0/cli.html#patterns
  60.  
  61.   --ignore={"4../.*"};
  62.  
  63.   --enable={};
  64.  
  65.   --only={};
  66.  
  67. }
  68.  
  69. local options_alt = {}; for k,v in pairs(options_def) do options_alt[k] = v end
  70.  
  71. options_alt.only = {"1.."}
  72.  
  73. local use_alt
  74.  
  75.  
  76.  
  77. local function showHelp()
  78.  
  79.   if far.Message([[
  80.  
  81. Основные действия:
  82.  
  83. • Enter           - перейти к позиции предупреждения
  84.  
  85. • Esc             - закрыть список и восстановить исходную позицию
  86.  
  87.  
  88.  
  89. Дополнительные действия (не закрывают список):
  90.  
  91. • Ctrl-PgUp       - перейти к позиции, на которую ссылается предупреждение
  92.  
  93. • Ctrl-Up/Down    - скроллировать текст редактора
  94.  
  95.  
  96.  
  97. Управление расположением списка:
  98.  
  99. • Ctrl-Home, Num7 - вверху
  100.  
  101. • Ctrl-End,  Num1 - внизу
  102.  
  103. • Num4            - по центру
  104.  
  105. • F6, Divide      - перебор режимов
  106.  
  107. • F5, Num5        - максимизация
  108.  
  109.  
  110.  
  111. Действия с закладками
  112.  
  113. • Ctrl-0..9       - перейти к позиции закладки 0..9
  114.  
  115. • Ctrl-Shift-0..9 - установить закладку 0..9 в текущей позиции
  116.  
  117. • Add             - добавить сессионную закладку с текущей позицией]],
  118.  
  119. ("%s v%s"):format(_NAME,_VER),"OK;Go to forum;","l")==2 then win.ShellExecute(nil,"open",_forumtopic) end
  120.  
  121. end
  122.  
  123. --todo
  124.  
  125. --• Ctrl-Shift-Enter,
  126.  
  127. --  Ctrl-Enter      - перейти к позиции предупреждения
  128.  
  129. --• Shift-Up,  Num2 - перейти к предыдущему предупреждению
  130.  
  131. --• Shift-Down,Num8 - перейти к следующему предупреждению
  132.  
  133.  
  134.  
  135. local luacheck = require "luacheck"
  136.  
  137. if luacheck._VERSION<luacheck_min_version then error(lmv_err_msg:format(luacheck_min_version)) end
  138.  
  139.  
  140.  
  141. local function MessagePopup(msg,title,flags,delay)
  142.  
  143.   local s = far.SaveScreen()
  144.  
  145.   far.Message(msg,title or "","",flags)
  146.  
  147.   win.Sleep(delay or 500); far.RestoreScreen(s)
  148.  
  149. end
  150.  
  151.  
  152.  
  153. local Id = "CFD31C22-0D17-4D87-829A-14561B529D34"
  154.  
  155. local function expandBreakKeys(BreakKeysArr)
  156.  
  157.   local newBreakKeysArr = {}
  158.  
  159.   for _,item in ipairs(BreakKeysArr) do
  160.  
  161.     if item then
  162.  
  163.       for key in item.BreakKey:gmatch("%S+") do
  164.  
  165.         local newitem = {}
  166.  
  167.         for k,v in pairs(item) do newitem[k]=v end
  168.  
  169.         newitem.BreakKey = key
  170.  
  171.         table.insert(newBreakKeysArr,newitem)
  172.  
  173.       end
  174.  
  175.     end
  176.  
  177.   end
  178.  
  179.   return newBreakKeysArr
  180.  
  181. end
  182.  
  183.  
  184.  
  185. local function setEditorPos(info) editor.SetPosition(nil,info); editor.Redraw() end
  186.  
  187.  
  188.  
  189. local bak_pos
  190.  
  191. local function restorePos()
  192.  
  193.   if bak_pos then
  194.  
  195.     editor.Select(nil,bak_pos)
  196.  
  197.     setEditorPos(bak_pos)
  198.  
  199.   end
  200.  
  201. end
  202.  
  203.  
  204.  
  205. local function scrollEditor(dir)
  206.  
  207.   local ei = editor.GetInfo()
  208.  
  209.   ei.TopScreenLine = ei.TopScreenLine+dir
  210.  
  211.   if ei.TopScreenLine<1 or ei.TopScreenLine>ei.TotalLines-ei.WindowSizeY+1 then mf.beep(); return end
  212.  
  213.   if ei.CurLine-ei.TopScreenLine-(dir==1 and -1 or ei.WindowSizeY)==0 then
  214.  
  215.     ei.CurLine = ei.CurLine+dir
  216.  
  217.   end
  218.  
  219.   setEditorPos(ei)
  220.  
  221. end
  222.  
  223.  
  224.  
  225. local F = far.Flags
  226.  
  227.  
  228.  
  229. local list = {}
  230.  
  231. function list:calcProps(Items,Props)
  232.  
  233.   self.Pos = self.Pos or O.InitPos
  234.  
  235.   Items = assert(Items or self.Items,"Items not set")
  236.  
  237.   local nItems = #Items
  238.  
  239.   Props = assert(Props or self.Props,"Props not set")
  240.  
  241.   -- calculate required list's dimensions and position
  242.  
  243.   local r = far.AdvControl(F.ACTL_GETFARRECT)
  244.  
  245.   local xSize,ySize = r.Right-r.Left,r.Bottom-r.Top --Far size
  246.  
  247.   local MaxItems = ySize-3 --max items n to fit
  248.  
  249.   local X,Y
  250.  
  251.   X = Items.maxlen<xSize-4 and (xSize-Items.maxlen)/2-2 or -1
  252.  
  253.   local nLines = math.min(nItems,O.MaxHeight,MaxItems) --actual list lines n
  254.  
  255.   local Pos = self.Pos or O.InitPos
  256.  
  257.   local isMaximizable = nItems>nLines and nLines<MaxItems
  258.  
  259.   local isMaximized = self.isMaximized and isMaximizable
  260.  
  261.   if Pos=="Center" or isMaximized then
  262.  
  263.     X,Y = -1,-1
  264.  
  265.   elseif Pos=="Top" then
  266.  
  267.     Y = 0
  268.  
  269.   elseif Pos=="Bottom" then
  270.  
  271.     Y = MaxItems-nLines>0 and MaxItems-nLines+1+1 or -1
  272.  
  273.   end
  274.  
  275.   -- set properties
  276.  
  277.   Props.X,Props.Y,Props.MaxHeight = X,Y,isMaximized and 0 or O.MaxHeight
  278.  
  279.   self.Props,self.Items,self.nItems = Props,Items,nItems
  280.  
  281.   self.nLines,self.isMaximized = nLines,isMaximized
  282.  
  283.   self.EditorShiftTop = Far.GetConfig"Editor.ShowTitleBar" and 0 or 1
  284.  
  285.   self.EditorShiftBottom = Far.KeyBar_Show()-1
  286.  
  287. end
  288.  
  289. function list:maximize(state)
  290.  
  291.   self.isMaximized = state==nil and not self.isMaximized or state
  292.  
  293.   self:calcProps()
  294.  
  295. end
  296.  
  297. function list:setPos(Pos)
  298.  
  299.   if Pos==self.Pos then
  300.  
  301.     return list:maximize()
  302.  
  303.   elseif Pos=="ping-pong" then
  304.  
  305.     if self.Pos=="Center" then
  306.  
  307.       Pos = self.prevPos=="Top" and "Bottom" or "Top"
  308.  
  309.     else
  310.  
  311.       Pos = "Center"
  312.  
  313.     end
  314.  
  315.   elseif not Pos then
  316.  
  317.     local next = {["Top"]="Bottom",["Bottom"]="Center",["Center"]="Top"}
  318.  
  319.     Pos = next[self.Pos]
  320.  
  321.   end
  322.  
  323.   self.prevPos = Pos~="Center" and Pos or self.prevPos
  324.  
  325.   self.Pos = Pos
  326.  
  327.   self.isMaximized = false
  328.  
  329.   self:calcProps()
  330.  
  331. end
  332.  
  333. function list:gotoWarning(pos,to_prev,force_top)
  334.  
  335.   local w = self.Items[pos]
  336.  
  337.   local line = to_prev and w.prev_line or w.line
  338.  
  339.   if not line then return end
  340.  
  341.   local column = to_prev and w.prev_column or w.column
  342.  
  343.   local end_column = not to_prev and w.end_column
  344.  
  345.   --select
  346.  
  347.   local width
  348.  
  349.   if end_column then
  350.  
  351.     width = end_column-column+1
  352.  
  353.   elseif w.name then
  354.  
  355.     width = w.name:len()
  356.  
  357.   else
  358.  
  359.     local str = editor.GetString(nil,line)
  360.  
  361.     if not str then return end
  362.  
  363.     local a,b = str.StringText:find("^%S+",column)
  364.  
  365.     width = a and b-a+1 or str.StringLength-column+1
  366.  
  367.   end
  368.  
  369.   editor.Select(nil,F.BTYPE_STREAM,line,column,width,1)
  370.  
  371.   --goto
  372.  
  373.   local nLines,TopScreenLine = self.nLines
  374.  
  375.   if nLines then --trying to correct TopScreenLine in order not to let cursor be hidden behind list
  376.  
  377.     local ei = editor.GetInfo()
  378.  
  379.     local y = line-ei.TopScreenLine --calculated screen line of warning
  380.  
  381.     local a,b = 0,ei.WindowSizeY    --valid screen lines (a..b)
  382.  
  383.     if self.Pos=="Top" then
  384.  
  385.       a = a+nLines+3+self.EditorShiftTop
  386.  
  387.     elseif self.Pos=="Bottom" then
  388.  
  389.       b = b-nLines-4+1+self.EditorShiftBottom
  390.  
  391.     end
  392.  
  393.     TopScreenLine = (y<a or force_top) and math.max(line-a,1)
  394.  
  395.                  or (y>b)              and line-b
  396.  
  397.     --win.OutputDebugString(("%s…%s = %s = %s"):format(a,b,y,TopScreenLine or '-'))
  398.  
  399.   end
  400.  
  401.   setEditorPos{CurLine=line,CurPos=column,TopScreenLine=TopScreenLine}
  402.  
  403. end
  404.  
  405. function list:Up(pos)   return pos-1>=1 and pos-1 or self.nItems end
  406.  
  407. function list:Down(pos) return pos+1<=self.nItems and pos+1 or 1 end
  408.  
  409. local function go(dir,pos,autopos)
  410.  
  411.   local nextpos = list[dir](list,pos)
  412.  
  413.   if autopos then list:gotoWarning(nextpos) end
  414.  
  415.   return nextpos
  416.  
  417. end
  418.  
  419.  
  420.  
  421. local Check --fw decl
  422.  
  423. local bKeys = expandBreakKeys {
  424.  
  425.   {BreakKey="C+UP   C+NUMPAD8 C+8",action=function() scrollEditor(-1) end},
  426.  
  427.   {BreakKey="C+DOWN C+NUMPAD2 C+2",action=function() scrollEditor(1) end},
  428.  
  429.   {BreakKey="C+RETURN C+NEXT C+NUMPAD3 C+3",action=function(pos) list:gotoWarning(pos) end},
  430.  
  431.   {BreakKey="CS+RETURN",        action=function(pos) list:gotoWarning(pos,nil,true) end},
  432.  
  433.   {BreakKey="RETURN",           action=function(pos)
  434.  
  435.      if list.Props.SelectIndex~=pos then list:gotoWarning(pos) end
  436.  
  437.      return "break"
  438.  
  439.    end},
  440.  
  441.   {BreakKey="ESCAPE",           action=function() restorePos(); return "break" end},
  442.  
  443.   {BreakKey="C+PRIOR C+NUMPAD9 C+9",action=function(pos) list:gotoWarning(pos,true) end},
  444.  
  445.   {BreakKey="C+HOME NUMPAD7 7", action=function() list:setPos("Top") end},
  446.  
  447.   {BreakKey="C+END  NUMPAD1 1", action=function() list:setPos("Bottom") end},
  448.  
  449.   {BreakKey="NUMPAD4 4",        action=function() list:setPos("Center") end},
  450.  
  451.   {BreakKey="F6 DIVIDE",        action=function() list:setPos(O.CycleMode) end},
  452.  
  453.   {BreakKey="F5 CLEAR 5",       action=function() list:maximize() end},
  454.  
  455.   {BreakKey="ADD",              action=function() editor.AddSessionBookmark() end},
  456.  
  457.   {BreakKey="CS+1 CS+2 CS+3 CS+4 CS+5 CS+6 CS+7 CS+8 CS+9 CS+0 C+1 C+2 C+3 C+4 C+5 C+6 C+7 C+8 C+9 C+0",keys=true},
  458.  
  459.   {BreakKey="F1",               action=showHelp},
  460.  
  461.   --http://bugs.farmanager.com/view.php?id=1301#c12736
  462.  
  463.   {BreakKey="UP",               action=function(pos) return go("Up",pos,O.AutoPos) end},
  464.  
  465.   {BreakKey="S+UP NUMPAD8 8",   action=function(pos) return go("Up",pos,not O.AutoPos) end},
  466.  
  467.   {BreakKey="DOWN",             action=function(pos) return go("Down",pos,O.AutoPos) end},
  468.  
  469.   {BreakKey="S+DOWN NUMPAD2 2", action=function(pos) return go("Down",pos,not O.AutoPos) end},
  470.  
  471.   --{BreakKey="F3",               action=function(pos) require"le"(list.Items[pos],"Event") end},
  472.  
  473.   --{BreakKey="F9",               action=function() require"le"(O,"Options");list:calcProps() end},
  474.  
  475.   {BreakKey="C+H",              action=function() use_alt = not use_alt; mf.postmacro(Check) return "break" end},
  476.  
  477. }
  478.  
  479.  
  480.  
  481. local Props = {
  482.  
  483.   Title=_NAME;
  484.  
  485.   Bottom="Ctrl-Enter, Ctrl-Up/Down, F5, F6, F1";
  486.  
  487.   Id=win.Uuid(Id);
  488.  
  489. }
  490.  
  491.  
  492.  
  493. function Check()
  494.  
  495.   local options = not use_alt and options_def or options_alt
  496.  
  497.   local ei = editor.GetInfo()
  498.  
  499.   local sel = editor.GetSelection()
  500.  
  501.   if sel then --save for further restoring
  502.  
  503.     ei.BlockStartPos = sel.StartPos
  504.  
  505.     ei.BlockWidth = sel.EndPos-sel.StartPos+1
  506.  
  507.     ei.BlockHeight = sel.EndLine-sel.StartLine+1
  508.  
  509.   end
  510.  
  511.   bak_pos = ei
  512.  
  513.   local source = {}
  514.  
  515.   for i=1,ei.TotalLines do source[i] = editor.GetString(nil,i).StringText end
  516.  
  517.   local text = table.concat(source,"\n")
  518.  
  519.   if O.ConvertToAnsi then
  520.  
  521.     text = win.WideCharToMultiByte(win.Utf8ToUtf16(text),win.GetACP())
  522.  
  523.   end
  524.  
  525.   local report = luacheck.check_strings({text}, options)[1]
  526.  
  527.   if not report then
  528.  
  529.     far.Message("Internal error: unable to get report",_NAME,nil,"w")
  530.  
  531.     return
  532.  
  533.   end
  534.  
  535.   if #report==0 then
  536.  
  537.     MessagePopup("No warnings",_NAME)
  538.  
  539.   else -- proceed with warnings list
  540.  
  541.     local Items,pos,maxlen,err = {},nil,0
  542.  
  543.     for i,w in ipairs(report) do
  544.  
  545.       err = w.code:sub(1,1)=="0"
  546.  
  547.       w.text =  ("%4u:%-3u "):format(w.line,w.column)..
  548.  
  549.                 ("│ %s%s │ "):format(err and "E" or "W",w.code)..
  550.  
  551.                 luacheck.get_message(w)
  552.  
  553.       local len = w.text:len()
  554.  
  555.       maxlen = len>maxlen and len or maxlen
  556.  
  557.       w.checked = err and "‼" or w.code:sub(1,1)=="1" and "!" --[[??]] or w.secondary and "²"
  558.  
  559.       if not pos and w.line==ei.CurLine and w.column==ei.CurPos then pos = i end
  560.  
  561.       Items[i] = w
  562.  
  563.       if not w.end_column then mf.beep() end--??
  564.  
  565.     end
  566.  
  567.     Items.maxlen = maxlen
  568.  
  569.     if err then mf.beep(); mf.postmacro(MessagePopup,"Errors found!",_NAME,"w",300) end
  570.  
  571.     list:calcProps(Items,Props)
  572.  
  573.     if O.AutoPos then list:gotoWarning(pos or 1) end
  574.  
  575.     repeat --todo use dialog instead of menu
  576.  
  577.       -- show list
  578.  
  579.       Props.SelectIndex = pos
  580.  
  581.       local item
  582.  
  583.       item,pos = far.Menu(Props,Items,bKeys)
  584.  
  585.       -- process breakkeys
  586.  
  587.       if not item then
  588.  
  589.         break
  590.  
  591.       elseif item.keys then
  592.  
  593.         Keys(item.BreakKey:gsub("^CS%+","CtrlShift"):gsub("^C%+","Ctrl"))
  594.  
  595.       elseif not item.action then
  596.  
  597.         list:gotoWarning(pos)
  598.  
  599.       else
  600.  
  601.         pos = item.action(pos) or pos
  602.  
  603.         if pos=="break" then break end
  604.  
  605.       end
  606.  
  607.     until false
  608.  
  609.   end
  610.  
  611. end
  612.  
  613.  
  614.  
  615. Event { description="luacheck menu handler";
  616.  
  617.   group="DialogEvent";
  618.  
  619.   action=function(Event,param)
  620.  
  621.     local hDlg,Msg = param.hDlg,param.Msg
  622.  
  623.     if Msg==F.DN_RESIZECONSOLE then
  624.  
  625.       if Event==F.DE_DLGPROCINIT and Menu.Id==Id then
  626.  
  627.         hDlg:send(F.DM_CLOSE,-1,0)
  628.  
  629.         list:calcProps()
  630.  
  631.       end
  632.  
  633.     elseif Msg==F.DN_INITDIALOG and Event==F.DE_DLGPROCINIT then
  634.  
  635.       local info = hDlg:send(F.DM_GETDIALOGINFO)
  636.  
  637.       if info and info.Id==win.Uuid(Id) then
  638.  
  639.         local r = hDlg:send(F.DM_GETITEMPOSITION,1)
  640.  
  641.         hDlg:send(F.DM_SETITEMPOSITION,1,{Left=r.Left-2,Top=r.Top-1,Right=r.Right-2,Bottom=r.Bottom-1})
  642.  
  643.         r = hDlg:send(F.DM_GETDLGRECT)
  644.  
  645.         hDlg:send(F.DM_RESIZEDIALOG,0,{Y=r.Bottom-r.Top-1,X=r.Right-r.Left-3})
  646.  
  647.         hDlg:send(F.DM_MOVEDIALOG,0,{X=2,Y=list.Pos=="Bottom" and 1 or 0})
  648.  
  649.       end
  650.  
  651.     end
  652.  
  653.   end
  654.  
  655. }
  656.  
  657.  
  658.  
  659. Macro { description="luacheck menu helper";
  660.  
  661.   area="Menu";  key="ShiftUp ShiftDown";    flags="NoSendKeysToPlugins";
  662.  
  663.   uid="60596FEB-E7C5-47A5-A3C9-B782C8F8EF93";
  664.  
  665.   condition=function()return O.AutoPos and Menu.Id==Id end;
  666.  
  667.   action=function()
  668.  
  669.     Keys(mf.akey(1,1):match"Up" and "Num8" or "Num2")
  670.  
  671.   end;
  672.  
  673. }
  674.  
  675.  
  676.  
  677. Macro { description="luacheck: process current editor";
  678.  
  679.   area="Editor";    key="CtrlShiftF7";  filemask="*.lua";
  680.  
  681.   uid="CE634ECE-1039-43F3-80CC-8BB17B1FDB05";
  682.  
  683.   action=function()
  684.  
  685.     use_alt = false
  686.  
  687.     Check()
  688.  
  689.   end;
  690.  
  691. }
Post Reply

Return to “Полезные макросы и скрипты”