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

Здесь обсуждается всё, что касается макросов.
User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Tue 16 Jun, 2015 12:36

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

Для установки модуля необходимо скачать архив luacheck-master.zip, взять оттуда папку luacheck (из luacheck-master\src\ ), и поместить в %FARPROFILE%\Macros\modules.

А ниже предлагаются утилиты для удобной работы с luacheck в фаре (содержимое вложения распаковать куда-нибудь в %FARPROFILE%\Macros\scripts).
  1. luacheck_editor.lua позволяет проверять lua-код в активном редакторе фара.
    Запуск назначен на комбинацию Ctrl-Shift-F7 (только для *.lua;*.moon).
    Найденные ошибки и предупреждения отображаются в виде списка.
    Управление:
  2. luacheck_cmdline.lua запускает luacheck из командной строки, c выводом отчётов в консоль.
    • Установка:
    • Запускать с помощью префикса luacheck, например: luacheck: *.lua
      Синтаксис можно посмотреть запустив без параметров, а более подробно — в документации.
Update:
С версии 1.3 поддерживается также работа с Moonscript (в редакторе)
Attachments
luacheck_scripts-1.3.3.7z
(6.87 KiB) Downloaded 59 times

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Tue 14 Jul, 2015 17:23

Latest post of the previous page:

John Doe, я в порядке тренировки (в дополнение к „невылезанию“ вверх) реализовал себе «пинг-понг» и отдельное разворачивание/восстановление по F5 — развёрнутый список позиционируется в центре, при восстановлении возвращается в ранее заданную позицию:
  1. --- luacheck_editor.lua Mon Jul 13 22:37:20 2015
  2. +++ luacheck_editor.lua Tue Jul 14 19:25:43 2015
  3. @@ -3,7 +3,7 @@
  4.  
  5.  -- list options
  6.  local MaxHeight = 10
  7. -local ListPos = "Bottom" --Top,Bottom,Max or nil
  8. +local InitListPos = "Bottom" --Top,Bottom,Center
  9.  local AutoPos = true
  10.  local ConvertToAnsi = true
  11.  
  12. @@ -140,6 +140,32 @@
  13.    return newBreakKeysArr
  14.  end
  15.  
  16. +local function maximizable(list)
  17. +  return list.nItems>list.nLines and list.nLines<list.MaxItems
  18. +end
  19. +local ListState = {
  20. +  currPos = InitListPos;
  21. +  prevPos = nil;
  22. +  maxHght = false;
  23. +  jump = function( self, to )
  24. +      assert( self.currPos ~= self.prevPos )
  25. +      if to == nil then  -- ping-pong
  26. +        local opposite = { ["Top"] = "Bottom", ["Bottom"] = "Top" }
  27. +        to = ( self.currPos == "Center" ) and opposite[ self.prevPos ] or "Center"
  28. +      end
  29. +      if to ~= self.currPos then
  30. +        self.prevPos = self.currPos
  31. +      end
  32. +      self.currPos = to
  33. +      assert( self.currPos ~= self.prevPos )
  34. +    end;
  35. +  zoom = function( self, list )
  36. +      if maximizable(list) then
  37. +        self.maxHght = not self.maxHght
  38. +      end
  39. +    end;
  40. +}
  41. +
  42.  local function setPos(info) editor.SetPosition(nil,info); editor.Redraw() end
  43.  local function scrollEditor(dir)
  44.    local ei = editor.GetInfo()
  45. @@ -169,9 +195,9 @@
  46.      local ei = editor.GetInfo()
  47.      local y = w.line-ei.TopScreenLine --calculated screen line of warning
  48.      local a,b = 0,ei.WindowSizeY      --valid screen lines (a..b)
  49. -    if ListPos=="Top" then
  50. -      a = a+nLines+1
  51. -    elseif ListPos=="Bottom" then
  52. +    if ListState.currPos=="Top" then
  53. +      a = a+nLines+3
  54. +    elseif ListState.currPos=="Bottom" then
  55.        b = b-nLines-3
  56.      end
  57.      TopScreenLine = (y<a or force_top) and math.max(w.line-a,1)
  58. @@ -187,9 +213,6 @@
  59.      setPos(bak_pos)
  60.    end
  61.  end
  62. -local function maximizable(list)
  63. -  return list.nItems>list.nLines and list.nLines<list.MaxItems
  64. -end
  65.  local bKeys = expandBreakKeys {
  66.    {BreakKey="C+UP    C+NUMPAD8",action=function()  scrollEditor(-1) end},
  67.    {BreakKey="C+DOWN  C+NUMPAD2",action=function()  scrollEditor(1) end},
  68. @@ -203,15 +226,11 @@
  69.    {BreakKey="C+PRIOR C+NUMPAD9",action=function(w,list)
  70.       if w.prev_line then gotoWarning({line=w.prev_line,column=w.prev_column,name=w.name},list.nLines) end
  71.     end},
  72. -  {BreakKey="C+HOME NUMPAD7",   action=function()  ListPos = "Top" end},
  73. -  {BreakKey="C+END  NUMPAD1",   action=function()  ListPos = "Bottom" end},
  74. -  {BreakKey="NUMPAD4",          action=function(_,list)
  75. -     ListPos = not ListPos and (maximizable(list) and "Max" or ListPos)
  76. -   end},
  77. -  {BreakKey="F5 CLEAR",         action=function(_,list)
  78. -     local next = {["Top"]="Bottom",["Bottom"]=false,[false]=maximizable(list) and "Max" or "Top",["Max"]="Top"}
  79. -     ListPos = next[ListPos]
  80. -   end},
  81. +  {BreakKey="C+HOME NUMPAD7", action=function() ListState:jump( "Top"    ) end},
  82. +  {BreakKey="C+END  NUMPAD1", action=function() ListState:jump( "Bottom" ) end},
  83. +  {BreakKey="       NUMPAD4", action=function() ListState:jump( "Center" ) end},
  84. +  {BreakKey="         CLEAR", action=function() ListState:jump(--[[auto]]) end},
  85. +  {BreakKey="F5"            , action=function(_,list) ListState:zoom(list) end},
  86.    {BreakKey="ADD",              action=function() editor.AddSessionBookmark() end},
  87.    {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},
  88.    {BreakKey="F1",               action=showHelp},
  89. @@ -265,14 +284,14 @@
  90.        Props.X = maxlen<xSize-4 and (xSize-maxlen)/2-2 or -1
  91.        local nItems = #Items
  92.        local nLines = math.min(nItems,MaxHeight,MaxItems)
  93. -      if not ListPos or ListPos=="Max" or nLines==MaxItems then
  94. +      if ListState.currPos=="Center" or ListState.maxHght or nLines==MaxItems then
  95.          Props.X,Props.Y = -1,-1
  96. -      elseif ListPos=="Top" then
  97. -        Props.Y = -2
  98. -      elseif ListPos=="Bottom" then
  99. +      elseif ListState.currPos=="Top" then
  100. +        Props.Y = 0
  101. +      elseif ListState.currPos=="Bottom" then
  102.          Props.Y = MaxItems-nLines>0 and MaxItems-nLines+2 or -1
  103.        end
  104. -      Props.MaxHeight = ListPos=="Max" and 0 or MaxHeight
  105. +      Props.MaxHeight = ListState.maxHght and 0 or MaxHeight
  106.        -- show list
  107.        Props.SelectIndex = pos
  108.        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: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Tue 14 Jul, 2015 20:16

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

P.S.
Этот парень похоже читает наш форум https://github.com/mpeterv/luacheck/com ... a519ef0897

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Tue 14 Jul, 2015 20:26

John Doe wrote: вторую указанную мной строку забыли исправить
В каком сценарии это скажется?
John Doe wrote: Обошлось
Уфф! ;)
John Doe wrote: Разворачивание отдельной кнопкой понравилось.
Спасибо.
John Doe wrote: А пинг-понг по-моему баловство.
На вкус и цвет…
John Doe wrote: парень похоже читает наш форум
Прямой связи не увидел. Но хорошо, что читает, т.к. будет в курсе наших особенностей использования Луа.
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Tue 14 Jul, 2015 20:36

HaRT wrote: В каком сценарии это скажется?
Список может закрыть собой строку, к которой относится предупреждение.
HaRT wrote: Прямой связи не увидел.
В шапке, в инструкции по установке luacheck_cmdline.lua я только вчера описал аналогичный патч , а сегодня он уже и не нужен.
(На самом деле я не думаю что он читает наш форум, скорее совпадение)

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Tue 14 Jul, 2015 21:15

John Doe wrote: пинг-понг по-моему баловство
Можно было бы оставить в виде опции…
John Doe wrote: Список может закрыть собой строку, к которой относится предупреждение.
Спасибо, воспроизвёл; патч исправил.
Кстати, там в подобном сценарии ломается отображение Колореровского перекрестья. С этим можно что-то поделать?
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Wed 15 Jul, 2015 09:25

HaRT wrote: Кстати, там в подобном сценарии ломается отображение Колореровского перекрестья.
Что значит в подобном сценарии?
У меня по Ctrl-Enter с крестом всё в порядке, а по Shift-Up/Down он не перерисовывается, да.
Решается добавлением flags="EnableOutput"; в соответствующий макрос.

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Wed 15 Jul, 2015 11:47

John Doe wrote: Что значит в подобном сценарии?
Если я отправлю список наверх, закрою его, сделаю строку с предупреждением верхней и открою список вновь, то вертикальная черта перекрестья претерпевает излом. Там вообще в зависимости от предшествующих действий можно получить разнообразные .
И flags="EnableOutput"; для макроса на [b]CtrlShiftF7[/b] не помогает. :(
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Wed 15 Jul, 2015 11:56

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: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Wed 15 Jul, 2015 12:07

John Doe wrote: заменить
Спасибо!
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Fri 17 Jul, 2015 17:59

В шапке v1.1
  • Up/Down теперь сразу позиционируют редактор к месту соответствующего предупреждения.
  • Для максимизации теперь служит отдельная клавиша
  • Косметика: убраны пустые поля, улучшено позиционирование относительно верха/низа.

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Fri 17 Jul, 2015 18:51

John Doe wrote: Для максимизации теперь служит отдельная клавиша
А также повторение позиционирования — удобно.
John Doe wrote: улучшено позиционирование относительно верха/низ
Спасибо!
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Sat 25 Jul, 2015 12:03

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: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Mon 20 Jun, 2016 17:25

Предложение: в меню предупреждений ввести быстрый фильтр по серьёзности. Например, по [b]CtrlH[/b] скрывать/показывать все „второстепенные“ предупреждения (те, которые не помечаются восклицательным знаком).
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Mon 20 Jun, 2016 21:02

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

Не уверен что правильно рубить с плеча и скрывать остальные.
Но какое-то более гибкое решение можно рассмотреть. Обратите внимание на опции, возможно стоит реализовать интерактивную конфигурацию.
В частности, вашему предложению соответствует значении опции only={"1.."}

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Mon 20 Jun, 2016 21:29

John Doe wrote: возможно стоит реализовать интерактивную конфигурацию
Не уверен, что нужна интерактивная. Лично мне было бы достаточно где-нибудь в скрипте прописать набор паттернов, которые бы скрывались/показывались по нажатию [b]CtrlH[/b] в списке предупреждений. А по умолчанию — {"1.."}.
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 11130
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 12 times
Been thanked: 72 times

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

Post by John Doe » Tue 21 Jun, 2016 12:38

HaRT wrote: Лично мне было бы достаточно [...]
  1. local _NAME,_VER = "luacheck","1.2A"
  2. local _forumtopic = "http://forum.farmanager.com/viewtopic.php?f=15&t=9650"
  3. local luacheck_min_version,lmv_err_msg = "0.11.0","luacheck version %s or newer expected"
  4. -- list options
  5. local O = {
  6.   MaxHeight = 10,
  7.   InitPos   = "Bottom", --Top,Bottom,Center
  8.   AutoPos   = true,
  9.   --CycleMode = "ping-pong",
  10.   --ConvertToAnsi = true,
  11. }
  12.  
  13. -- luacheck options
  14. local options_def = { --http://luacheck.readthedocs.org/en/0.11.0/config.html
  15.   new_read_globals={
  16.     "Macro","NoMacro","Event","NoEvent","MenuItem","NoMenuItem","CommandLine","NoCommandLine",
  17.   };
  18.   new_globals={
  19.     "_filename",                    --scripts executed in luamacro via cmdline prefix
  20.     "export","IsLuaStateRecreated", --lua plugins
  21.   }
  22.  
  23.   --global=false;
  24.   --allow_defined=true;
  25.   --allow_defined_top=true;
  26.   --unused=false;
  27.   --unused_args=false;
  28.   --unused_secondaries=false;
  29.   --redefined=false;
  30.   --http://luacheck.readthedocs.org/en/0.11.0/cli.html#patterns
  31.   --ignore={"4../.*"};
  32.   --enable={};
  33.   --only={};
  34. }
  35. local options_alt = {}; for k,v in pairs(options_def) do options_alt[k] = v end
  36. options_alt.only = {"1.."}
  37. local use_alt
  38.  
  39. local function showHelp()
  40.   if far.Message([[
  41. Основные действия:
  42. • Enter           - перейти к позиции предупреждения
  43. • Esc             - закрыть список и восстановить исходную позицию
  44.  
  45. Дополнительные действия (не закрывают список):
  46. • Ctrl-PgUp       - перейти к позиции, на которую ссылается предупреждение
  47. • Ctrl-Up/Down    - скроллировать текст редактора
  48.  
  49. Управление расположением списка:
  50. • Ctrl-Home, Num7 - вверху
  51. • Ctrl-End,  Num1 - внизу
  52. • Num4            - по центру
  53. • F6, Divide      - перебор режимов
  54. • F5, Num5        - максимизация
  55.  
  56. Действия с закладками
  57. • Ctrl-0..9       - перейти к позиции закладки 0..9
  58. • Ctrl-Shift-0..9 - установить закладку 0..9 в текущей позиции
  59. • Add             - добавить сессионную закладку с текущей позицией]],
  60. ("%s v%s"):format(_NAME,_VER),"OK;Go to forum;","l")==2 then win.ShellExecute(nil,"open",_forumtopic) end
  61. end
  62. --todo
  63. --• Ctrl-Shift-Enter,
  64. --  Ctrl-Enter      - перейти к позиции предупреждения
  65. --• Shift-Up,  Num2 - перейти к предыдущему предупреждению
  66. --• Shift-Down,Num8 - перейти к следующему предупреждению
  67.  
  68. local luacheck = require "luacheck"
  69. if luacheck._VERSION<luacheck_min_version then error(lmv_err_msg:format(luacheck_min_version)) end
  70.  
  71. local function MessagePopup(msg,title,flags,delay)
  72.   local s = far.SaveScreen()
  73.   far.Message(msg,title or "","",flags)
  74.   win.Sleep(delay or 500); far.RestoreScreen(s)
  75. end
  76.  
  77. local Id = "CFD31C22-0D17-4D87-829A-14561B529D34"
  78. local function expandBreakKeys(BreakKeysArr)
  79.   local newBreakKeysArr = {}
  80.   for _,item in ipairs(BreakKeysArr) do
  81.     if item then
  82.       for key in item.BreakKey:gmatch("%S+") do
  83.         local newitem = {}
  84.         for k,v in pairs(item) do newitem[k]=v end
  85.         newitem.BreakKey = key
  86.         table.insert(newBreakKeysArr,newitem)
  87.       end
  88.     end
  89.   end
  90.   return newBreakKeysArr
  91. end
  92.  
  93. local function setEditorPos(info) editor.SetPosition(nil,info); editor.Redraw() end
  94.  
  95. local bak_pos
  96. local function restorePos()
  97.   if bak_pos then
  98.     editor.Select(nil,bak_pos)
  99.     setEditorPos(bak_pos)
  100.   end
  101. end
  102.  
  103. local function scrollEditor(dir)
  104.   local ei = editor.GetInfo()
  105.   ei.TopScreenLine = ei.TopScreenLine+dir
  106.   if ei.TopScreenLine<1 or ei.TopScreenLine>ei.TotalLines-ei.WindowSizeY+1 then mf.beep(); return end
  107.   if ei.CurLine-ei.TopScreenLine-(dir==1 and -1 or ei.WindowSizeY)==0 then
  108.     ei.CurLine = ei.CurLine+dir
  109.   end
  110.   setEditorPos(ei)
  111. end
  112.  
  113. local F = far.Flags
  114.  
  115. local list = {}
  116. function list:calcProps(Items,Props)
  117.   self.Pos = self.Pos or O.InitPos
  118.   Items = assert(Items or self.Items,"Items not set")
  119.   local nItems = #Items
  120.   Props = assert(Props or self.Props,"Props not set")
  121.   -- calculate required list's dimensions and position
  122.   local r = far.AdvControl(F.ACTL_GETFARRECT)
  123.   local xSize,ySize = r.Right-r.Left,r.Bottom-r.Top --Far size
  124.   local MaxItems = ySize-3 --max items n to fit
  125.   local X,Y
  126.   X = Items.maxlen<xSize-4 and (xSize-Items.maxlen)/2-2 or -1
  127.   local nLines = math.min(nItems,O.MaxHeight,MaxItems) --actual list lines n
  128.   local Pos = self.Pos or O.InitPos
  129.   local isMaximizable = nItems>nLines and nLines<MaxItems
  130.   local isMaximized = self.isMaximized and isMaximizable
  131.   if Pos=="Center" or isMaximized then
  132.     X,Y = -1,-1
  133.   elseif Pos=="Top" then
  134.     Y = 0
  135.   elseif Pos=="Bottom" then
  136.     Y = MaxItems-nLines>0 and MaxItems-nLines+1+1 or -1
  137.   end
  138.   -- set properties
  139.   Props.X,Props.Y,Props.MaxHeight = X,Y,isMaximized and 0 or O.MaxHeight
  140.   self.Props,self.Items,self.nItems = Props,Items,nItems
  141.   self.nLines,self.isMaximized = nLines,isMaximized
  142.   self.EditorShiftTop = Far.GetConfig"Editor.ShowTitleBar" and 0 or 1
  143.   self.EditorShiftBottom = Far.KeyBar_Show()-1
  144. end
  145. function list:maximize(state)
  146.   self.isMaximized = state==nil and not self.isMaximized or state
  147.   self:calcProps()
  148. end
  149. function list:setPos(Pos)
  150.   if Pos==self.Pos then
  151.     return list:maximize()
  152.   elseif Pos=="ping-pong" then
  153.     if self.Pos=="Center" then
  154.       Pos = self.prevPos=="Top" and "Bottom" or "Top"
  155.     else
  156.       Pos = "Center"
  157.     end
  158.   elseif not Pos then
  159.     local next = {["Top"]="Bottom",["Bottom"]="Center",["Center"]="Top"}
  160.     Pos = next[self.Pos]
  161.   end
  162.   self.prevPos = Pos~="Center" and Pos or self.prevPos
  163.   self.Pos = Pos
  164.   self.isMaximized = false
  165.   self:calcProps()
  166. end
  167. function list:gotoWarning(pos,to_prev,force_top)
  168.   local w = self.Items[pos]
  169.   local line = to_prev and w.prev_line or w.line
  170.   if not line then return end
  171.   local column = to_prev and w.prev_column or w.column
  172.   local end_column = not to_prev and w.end_column
  173.   --select
  174.   local width
  175.   if end_column then
  176.     width = end_column-column+1
  177.   elseif w.name then
  178.     width = w.name:len()
  179.   else
  180.     local str = editor.GetString(nil,line)
  181.     if not str then return end
  182.     local a,b = str.StringText:find("^%S+",column)
  183.     width = a and b-a+1 or str.StringLength-column+1
  184.   end
  185.   editor.Select(nil,F.BTYPE_STREAM,line,column,width,1)
  186.   --goto
  187.   local nLines,TopScreenLine = self.nLines
  188.   if nLines then --trying to correct TopScreenLine in order not to let cursor be hidden behind list
  189.     local ei = editor.GetInfo()
  190.     local y = line-ei.TopScreenLine --calculated screen line of warning
  191.     local a,b = 0,ei.WindowSizeY    --valid screen lines (a..b)
  192.     if self.Pos=="Top" then
  193.       a = a+nLines+3+self.EditorShiftTop
  194.     elseif self.Pos=="Bottom" then
  195.       b = b-nLines-4+1+self.EditorShiftBottom
  196.     end
  197.     TopScreenLine = (y<a or force_top) and math.max(line-a,1)
  198.                  or (y>b)              and line-b
  199.     --win.OutputDebugString(("%s…%s = %s = %s"):format(a,b,y,TopScreenLine or '-'))
  200.   end
  201.   setEditorPos{CurLine=line,CurPos=column,TopScreenLine=TopScreenLine}
  202. end
  203. function list:Up(pos)   return pos-1>=1 and pos-1 or self.nItems end
  204. function list:Down(pos) return pos+1<=self.nItems and pos+1 or 1 end
  205. local function go(dir,pos,autopos)
  206.   local nextpos = list[dir](list,pos)
  207.   if autopos then list:gotoWarning(nextpos) end
  208.   return nextpos
  209. end
  210.  
  211. local Check --fw decl
  212. local bKeys = expandBreakKeys {
  213.   {BreakKey="C+UP   C+NUMPAD8 C+8",action=function() scrollEditor(-1) end},
  214.   {BreakKey="C+DOWN C+NUMPAD2 C+2",action=function() scrollEditor(1) end},
  215.   {BreakKey="C+RETURN C+NEXT C+NUMPAD3 C+3",action=function(pos) list:gotoWarning(pos) end},
  216.   {BreakKey="CS+RETURN",        action=function(pos) list:gotoWarning(pos,nil,true) end},
  217.   {BreakKey="RETURN",           action=function(pos)
  218.      if list.Props.SelectIndex~=pos then list:gotoWarning(pos) end
  219.      return "break"
  220.    end},
  221.   {BreakKey="ESCAPE",           action=function() restorePos(); return "break" end},
  222.   {BreakKey="C+PRIOR C+NUMPAD9 C+9",action=function(pos) list:gotoWarning(pos,true) end},
  223.   {BreakKey="C+HOME NUMPAD7 7", action=function() list:setPos("Top") end},
  224.   {BreakKey="C+END  NUMPAD1 1", action=function() list:setPos("Bottom") end},
  225.   {BreakKey="NUMPAD4 4",        action=function() list:setPos("Center") end},
  226.   {BreakKey="F6 DIVIDE",        action=function() list:setPos(O.CycleMode) end},
  227.   {BreakKey="F5 CLEAR 5",       action=function() list:maximize() end},
  228.   {BreakKey="ADD",              action=function() editor.AddSessionBookmark() end},
  229.   {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},
  230.   {BreakKey="F1",               action=showHelp},
  231.   --http://bugs.farmanager.com/view.php?id=1301#c12736
  232.   {BreakKey="UP",               action=function(pos) return go("Up",pos,O.AutoPos) end},
  233.   {BreakKey="S+UP NUMPAD8 8",   action=function(pos) return go("Up",pos,not O.AutoPos) end},
  234.   {BreakKey="DOWN",             action=function(pos) return go("Down",pos,O.AutoPos) end},
  235.   {BreakKey="S+DOWN NUMPAD2 2", action=function(pos) return go("Down",pos,not O.AutoPos) end},
  236.   --{BreakKey="F3",               action=function(pos) require"le"(list.Items[pos],"Event") end},
  237.   --{BreakKey="F9",               action=function() require"le"(O,"Options");list:calcProps() end},
  238.   {BreakKey="C+H",              action=function() use_alt = not use_alt; mf.postmacro(Check) return "break" end},
  239. }
  240.  
  241. local Props = {
  242.   Title=_NAME;
  243.   Bottom="Ctrl-Enter, Ctrl-Up/Down, F5, F6, F1";
  244.   Id=win.Uuid(Id);
  245. }
  246.  
  247. function Check()
  248.   local options = not use_alt and options_def or options_alt
  249.   local ei = editor.GetInfo()
  250.   local sel = editor.GetSelection()
  251.   if sel then --save for further restoring
  252.     ei.BlockStartPos = sel.StartPos
  253.     ei.BlockWidth = sel.EndPos-sel.StartPos+1
  254.     ei.BlockHeight = sel.EndLine-sel.StartLine+1
  255.   end
  256.   bak_pos = ei
  257.   local source = {}
  258.   for i=1,ei.TotalLines do source[i] = editor.GetString(nil,i).StringText end
  259.   local text = table.concat(source,"\n")
  260.   if O.ConvertToAnsi then
  261.     text = win.WideCharToMultiByte(win.Utf8ToUtf16(text),win.GetACP())
  262.   end
  263.   local report = luacheck.check_strings({text}, options)[1]
  264.   if not report then
  265.     far.Message("Internal error: unable to get report",_NAME,nil,"w")
  266.     return
  267.   end
  268.   if #report==0 then
  269.     MessagePopup("No warnings",_NAME)
  270.   else -- proceed with warnings list
  271.     local Items,pos,maxlen,err = {},nil,0
  272.     for i,w in ipairs(report) do
  273.       err = w.code:sub(1,1)=="0"
  274.       w.text =  ("%4u:%-3u "):format(w.line,w.column)..
  275.                 ("│ %s%s │ "):format(err and "E" or "W",w.code)..
  276.                 luacheck.get_message(w)
  277.       local len = w.text:len()
  278.       maxlen = len>maxlen and len or maxlen
  279.       w.checked = err and "‼" or w.code:sub(1,1)=="1" and "!" --[[??]] or w.secondary and "²"
  280.       if not pos and w.line==ei.CurLine and w.column==ei.CurPos then pos = i end
  281.       Items[i] = w
  282.       if not w.end_column then mf.beep() end--??
  283.     end
  284.     Items.maxlen = maxlen
  285.     if err then mf.beep(); mf.postmacro(MessagePopup,"Errors found!",_NAME,"w",300) end
  286.     list:calcProps(Items,Props)
  287.     if O.AutoPos then list:gotoWarning(pos or 1) end
  288.     repeat --todo use dialog instead of menu
  289.       -- show list
  290.       Props.SelectIndex = pos
  291.       local item
  292.       item,pos = far.Menu(Props,Items,bKeys)
  293.       -- process breakkeys
  294.       if not item then
  295.         break
  296.       elseif item.keys then
  297.         Keys(item.BreakKey:gsub("^CS%+","CtrlShift"):gsub("^C%+","Ctrl"))
  298.       elseif not item.action then
  299.         list:gotoWarning(pos)
  300.       else
  301.         pos = item.action(pos) or pos
  302.         if pos=="break" then break end
  303.       end
  304.     until false
  305.   end
  306. end
  307.  
  308. Event { description="luacheck menu handler";
  309.   group="DialogEvent";
  310.   action=function(Event,param)
  311.     local hDlg,Msg = param.hDlg,param.Msg
  312.     if Msg==F.DN_RESIZECONSOLE then
  313.       if Event==F.DE_DLGPROCINIT and Menu.Id==Id then
  314.         hDlg:send(F.DM_CLOSE,-1,0)
  315.         list:calcProps()
  316.       end
  317.     elseif Msg==F.DN_INITDIALOG and Event==F.DE_DLGPROCINIT then
  318.       local info = hDlg:send(F.DM_GETDIALOGINFO)
  319.       if info and info.Id==win.Uuid(Id) then
  320.         local r = hDlg:send(F.DM_GETITEMPOSITION,1)
  321.         hDlg:send(F.DM_SETITEMPOSITION,1,{Left=r.Left-2,Top=r.Top-1,Right=r.Right-2,Bottom=r.Bottom-1})
  322.         r = hDlg:send(F.DM_GETDLGRECT)
  323.         hDlg:send(F.DM_RESIZEDIALOG,0,{Y=r.Bottom-r.Top-1,X=r.Right-r.Left-3})
  324.         hDlg:send(F.DM_MOVEDIALOG,0,{X=2,Y=list.Pos=="Bottom" and 1 or 0})
  325.       end
  326.     end
  327.   end
  328. }
  329.  
  330. Macro { description="luacheck menu helper";
  331.   area="Menu";  key="ShiftUp ShiftDown";    flags="NoSendKeysToPlugins";
  332.   uid="60596FEB-E7C5-47A5-A3C9-B782C8F8EF93";
  333.   condition=function()return O.AutoPos and Menu.Id==Id end;
  334.   action=function()
  335.     Keys(mf.akey(1,1):match"Up" and "Num8" or "Num2")
  336.   end;
  337. }
  338.  
  339. Macro { description="luacheck: process current editor";
  340.   area="Editor";    key="CtrlShiftF7";  filemask="*.lua";
  341.   uid="CE634ECE-1039-43F3-80CC-8BB17B1FDB05";
  342.   action=function()
  343.     use_alt = false
  344.     Check()
  345.   end;
  346. }

User avatar
HaRT
Moderator
Posts: 8048
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 67 times
Been thanked: 100 times

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

Post by HaRT » Tue 21 Jun, 2016 13:45

John Doe wrote: CODE: [ВЫДЕЛИТЬ ВСЁ] [EXPAND/COLLAPSE] [DOWNLOAD] (LUACHECK_EDITOR.LUA)
Спасибо, вижу, что по нажатию на [b]CtrlH[/b] список фильтруется в соответствии с [b]options_alt.only[/b]. Несколько соображений:
1. Слово alt у меня не вызывает никаких ассоциаций с происходящим, я бы предпочёл раздедение major/minor, primary/secondary, …. Ну или объясните, пожалуйста, как бы это лучше осознать и запомнить.
2. Обнаружился неприятный эффект: если после фильтрации список оказался пуст, то кратковременно показывается сообщение “No warnings” и список уже не открывается (если вдуматься, это и не удивительно), но вот фильтр после этого снимается только перезагрузкой макросов — неудобно. Предлагаю, чтобы при включенной фильтрации список показывался, даже если он пустой.
3. Чтобы короткий/пустой список не создавал иллюзию чистого кода, предлагаю в качестве признака отфильтрованности добавить, например, звёздочку в название меню. (Например, AltHistory так индицирует тип фильтра: от начала или в любом месте строки.)
4. Хорошо бы добавить [b]CtrlH[/b] в подсказку на нижней рамке и в Справку.
Фар есть инструмент, а не нянька. © 2009 DrKnS

Post Reply

Return to “Обсуждение макросов”