Перейти из форума на сайт.

НовостиФайловые архивы
ПоискАктивные темыТоп лист
ПравилаКто в on-line?
Вход Забыли пароль? Первый раз на этом сайте? Регистрация
Компьютерный форум Ru.Board » Компьютеры » Программы » FAR Manager (часть 6)

Модерирует : gyra, Maz

Maz (26-09-2022 12:52): FAR Manager (часть 7)  Версия для печати • ПодписатьсяДобавить в закладки
На первую страницук этому сообщениюк последнему сообщению

   

Alexyz21



Silver Member
Редактировать | Профиль | Сообщение | Цитировать | Сообщить модератору

Код:
-- coding: utf-8
-- Minimal Far version:     3.0.3300
 
-- http://forum.farmanager.com/viewtopic.php?p=141965#p141965
-- Исходный скрипт был написан для плагина LuaFAR for Editor.
-- Первоначальный автор: Максим Гончар ("maxdrfl" в форуме Far Manager).
-- Адаптация к Far3 API, плагину LuaMacro и некоторые изменения в коде: Shmuel Zeigerman.
 
--[[
        ОРИГИНАЛЬНАЯ СПРАВКА (адаптировано):
        ------------------------------------
Небольшой калькулятор. Написан в первую очередь для проверки работы диалогов и скорости сборки скриптов lua.
Свойства:
    - синтаксис lua
    - функции из math находятся в _G
    - сборка на лету. Указание этапа работы на котором произошла ошибки
    - 4 строки вывода с настраиваемым форматом (см. lua:string.format)
    - если в строке есть команда return, результатом вычисления считается возвращаемое значение
    - поддерживаются пользовательские функции.
 
Пользовательские функции хранятся в модуле fl_calc.lua. Наличие модуля не обязательно для работы калькулятора.
Краткая справка пишется в том же файле в таблицу help. Вызывается из калькулятора по F1.
Для справки см. уже определённые функции fib, fact, mean, sum.
--]]
 
local M  -- message localization table
local F = far.Flags
local KEEP_DIALOG_OPEN = 0
local HOTKEY_IS_DONE = 0
local SendMessage = far.SendDlgMessage
 
local farbuild = select(4, far.AdvControl("ACTL_GETFARMANAGERVERSION", true))
local enable_custom_hotkeys = (farbuild >= 4269)  -- DN_HOTKEY was fixed in LuaFAR build 483
local python  -- Lunatic Python module
local lastres  -- last result
 
-- tobase(10,2)    --> "1010"
-- tobase(200,16)  --> "C8"
-- tobase(-200,16) --> "-C8"
local function tobase(num, base)
  local floor, fmod = math.floor, math.fmod
  base = assert(base >=2 and base <= 36) and floor(base)
  local offset = string.byte("A") - 10
  local t = {""}
  if num < 0 then t[1],num = "-",-num end
  num = floor(num)
  repeat
    local r = fmod(num, base) -- don't use % operation (it may be Lua implementation dependent)
    num = (num - r) / base
    table.insert(t, 2, r<10 and tostring(r):sub(1,1) or string.char(r+offset)) -- sub() needed for Lua 5.3
  until num == 0
  return table.concat(t)
end
 
local function loadhelp()
  -- load user functions and help message
  local userlib, strhelp
  local ok,lib = pcall(require, "shmuz.fl_calc")
  if ok then
    userlib, strhelp = lib, lib.help
    if strhelp then
      local message={}
      for i=1,#strhelp,2 do
        table.insert(message, ('%-20.20s - %s'):format(strhelp[i], strhelp[i+1]))
      end
      table.sort(message)
      strhelp = table.concat(message,'\n')
    end
  end
  strhelp = strhelp or M.mNoFuncAvail
 
  -- also list functions available in math
  local tb = { [1] = "\n\1\nmath:\n  " }
  for k in pairs(math) do table.insert(tb,k) end
  table.sort(tb)
  for i=2,#tb do
    local suffix = i==#tb and "" or (i-1)%8==0 and ",\n  " or ", "
    tb[i] = tb[i]..suffix
  end
  strhelp = strhelp..table.concat(tb)
 
  -- add help for special formatting feature
  strhelp = strhelp.."\n\1\n"..
    "Format hint:\n  #n (where n=2..36) gives radix n result representation"
  return userlib, strhelp
end
 
local function getdata(item) return item.text; end
local function setdata(item,data) item.text=data; end
 
local function calculator()
  local sDialog = require "shmuz.simpledialog"
  local xx = M.mSyntax:len()+8
  local function shortcut(n) lastres = n or lastres+1 return "&"..lastres end
  local items = {
    guid="E7588240-0523-4AA5-8A31-EE829E20CD26";
    { tp="dbox";                  text=M.mMainDlgTitle;                                  },
 
    { tp="text";                  text=M.mSyntax; x1=7;                                  },
    { tp="rbutt"; name="lng_lua"; text="&Lua";    x1=xx;    y1=""; group=1; val=1;       },
    { tp="rbutt"; name="lng_c";   text="&C";      x1=xx+9;  y1="";                       },
    { tp="rbutt"; name="lng_py";  text="&Python"; x1=xx+16; y1=""; disable=not python;   },
 
    { tp="edit";  name="calc";    x1=7; hist='LuaCalc'; focus=1;                         },
 
    { tp="text";                  x1=5;  x2=5;  text=shortcut(0);             ystep=0;   },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
    { tp="text";                  x1=""; x2=""; text=shortcut();                         },
 
    { tp="rbutt"; name="decrad";  x1=7;  group=1; val=1;        Item="dec";   ystep=1-lastres; },
    { tp="rbutt"; name="octrad";  x1="";                        Item="oct";              },
    { tp="rbutt"; name="hexrad";  x1="";                        Item="hex";              },
    { tp="rbutt"; name="rawrad";  x1="";                        Item="raw";              },
    { tp="rbutt"; name="hflrad";  x1="";                        Item="hfl";              },
    { tp="rbutt"; name="dbhrad";  x1="";                        Item="dbh";              },
 
    { tp="edit",  name="decfmt";  x1=11; x2=16; text="%g" ;     Fmt="dec";    ystep=1-lastres; },
    { tp="edit",  name="octfmt";  x1=""; x2=""; text="%o" ;     Fmt="oct";               },
    { tp="edit",  name="hexfmt";  x1=""; x2=""; text="%#x";     Fmt="hex";               },
    { tp="edit",  name="rawfmt";  x1=""; x2=""; text="%s" ;     Fmt="raw";               },
    { tp="edit",  name="hflfmt";  x1=""; x2=""; text="%a" ;     Fmt="hfl";               },
    { tp="edit",  name="dbhfmt";  x1=""; x2=""; text="dbh";     Fmt="dbh";               },
 
    { tp="text";                  x1=18; x2=18; text=":";                     ystep=1-lastres; },
    { tp="text";                  x1=""; x2=""; text=":";                                },
    { tp="text";                  x1=""; x2=""; text=":";                                },
    { tp="text";                  x1=""; x2=""; text=":";                                },
    { tp="text";                  x1=""; x2=""; text=":";                                },
    { tp="text";                  x1=""; x2=""; text=":";                                },
 
    { tp="text";  name="dec";     x1=20;             Update=1;  Fmt="decfmt"; ystep=1-lastres; },
    { tp="text";  name="oct";     x1="";             Update=1;  Fmt="octfmt";            },
    { tp="text";  name="hex";     x1="";             Update=1;  Fmt="hexfmt";            },
    { tp="text";  name="raw";     x1="";             Update=1;  Fmt="rawfmt";            },
    { tp="text";  name="hfl";     x1="";             Update=1;  Fmt="hflfmt";            },
    { tp="text";  name="dbh";     x1="";             Update=1;  Fmt="dbhfmt";            },
 
    { tp="text";                  x1=5;  text=M.mLabelStatus;                            },
    { tp="text";  name="status";  x1=13; text='ok';  Update=1;                ystep=0;   },
 
    { tp="butt";  name="btnCalc"; centergroup=1; text=M.mButtonCalc; default=1;          },
    { tp="butt";  name="btnIns";  centergroup=1; text=M.mButtonInsert;                   },
    { tp="butt";  name="btnCopy"; centergroup=1; text=M.mButtonCopy;                     },
  }
 
  local dPos, dItems = sDialog.Indexes(items)
  local curlang = nil
  local compiled = nil
  local result = 0
  local active_item = dItems.dec
  local userlib, strhelp = loadhelp()
  local environ = setmetatable({},
    {
      __index = function(t,k)
          return userlib and userlib[k] or math[k] or _G[k]
      end
    })
  local cfunction = function(c) return environ[c] end
  local keys = { Enter="btnCalc"; Ins="btnIns"; F5 = "btnCopy"; }
 
  local pg
  if python then
    python.execute [[from math import *]]
    python.execute [[
def my_eval(txt):
  try: return eval(txt), None
  except Exception as E: return None, str(E)
]]
    pg = python.globals()
  end
 
  function dItems.btnCalc.Action(handle)
    if tonumber(result) then
      SendMessage(handle, F.DM_SETTEXT, dPos.calc, result)
    end
    return KEEP_DIALOG_OPEN
  end
 
  function dItems.btnCopy.Action()
    far.CopyToClipboard(getdata(active_item))
    return KEEP_DIALOG_OPEN
  end
 
  function dItems.btnIns.Action()
    far.MacroPost(("print %q"):format(getdata(active_item)))
  end
 
  local function format(item, res)
    if type(res) == 'number' then
      local fmt = getdata(dItems[item.Fmt])
      local base = tonumber(fmt:match("^#(%d+)"))
      if base and base>=2 and base <=36 then
        setdata(item, tobase(res, base))
      else
        local ok,str = pcall(string.format, fmt, res)
        setdata(item, ok and str or M.mErrorFormat)
      end
    elseif curlang == "Python" then
      local fmt = getdata(dItems[item.Fmt])
      local s = ("%q %% %s"):format(fmt, res)
      local s2 = pg.my_eval(s)
      setdata(item, s2[0] or "<error>")
    end
  end
 
  local function setdbh(item, res)
    -- Bits:
    -- 63: sign (s)
    -- 52-62: exponent (e)
    -- 0-51: mantissa (m)
    if type(res) == 'number' then
      local ok,str = pcall(string.format, "%A", res)
      if ok then
        if res == 0 then res = str:find("^%-") and "8" or "0"
        else res = string.format("%X", bit.band(tonumber(str:match("P([%-%+%d]+)$") or "0") + (str:find("^%-") and 3071 or 1023), 0xFFF))..(str:match("%.(%x+)P") or "")
        end
        res = (res..string.rep("0",16-#res)):gsub("%x%x","%1 "):sub(1,-2)
      else res = M.mErrorFormat
      end
      setdata(item, res)
    end
  end
 
  local function reset()
    setdata(dItems.dec, '')
    setdata(dItems.oct, '')
    setdata(dItems.hex, '')
    setdata(dItems.raw, '')
    setdata(dItems.hfl, '')
    setdata(dItems.dbh, '')
    setdata(dItems.status, nil)
    compiled = nil
    result = 0
  end
 
  local function compile(handle)
    local str = SendMessage(handle, F.DM_GETTEXT, dPos.calc)
    if not str:find("%S") then str = "0" end
 
    if curlang == "Lua" then
       -- add parentheses to avoid tail call (that gives better error messages)
      compiled = loadstring('return ('..str..')') or loadstring(str)
    elseif curlang == "C" then
      compiled = loadstring(( [[
        local getvar = ...
        local calc = require "shmuz.c_calc"
        return calc.expr("%s", getvar)]] ):format(str))
    elseif curlang == "Python" then
      local txt = ("str(%s)"):format(str)
      local res = pg.my_eval(txt)
      if res[0] then
        compiled = res[0]
      else
        local txt = res[1]:match("(.-)%s*%(<string")
        setdata(dItems.status, txt or res[1])
      end
    end
 
    if curlang ~= "Python" then
      if compiled then setfenv(compiled, environ)
      else setdata(dItems.status, M.mErrorCompile)
      end
    end
  end
 
  local function call()
    if curlang=="Python" then
      result = compiled
    else
      if curlang=="Lua"   then result = compiled()
      elseif curlang=="C" then result = compiled(cfunction)
      end
      if type(result)=='function' then
        setdata(dItems.status, M.mErrorSubcall)
      elseif not tonumber(result) then
        setdata(dItems.status, M.mErrorCall)
      end
    end
  end
 
  local function form()
    if curlang ~= "Python" then
      result = tonumber(result) or ''
    end
    format(dItems.dec, result)
    format(dItems.oct, result)
    format(dItems.hex, result)
    format(dItems.raw, result)
    format(dItems.hfl, result)
    setdbh(dItems.dbh, result)
    setdata(dItems.status, 'ok')
  end
 
  local chain={reset, compile, call, form}
  local function do_chain(handle)
    local ok, msg
    for _,f in ipairs(chain) do
      ok, msg = pcall(f, handle)
      if not ok or getdata(dItems.status) then break end
    end
    if not ok then
      reset()
      msg = type(msg)=="string" and msg or "error message is not a string"
      msg = string.match(msg, ".*:%d+: (.*)") or msg
      setdata(dItems.status, msg)
    end
    for i,v in ipairs(items) do
      if v.Update then SendMessage(handle, F.DM_SETTEXT, i, getdata(items[i])) end
    end
  end
 
  local function set_language(handle)
    curlang = SendMessage(handle,F.DM_GETCHECK,dPos.lng_lua)==1 and "Lua" or
              SendMessage(handle,F.DM_GETCHECK,dPos.lng_c)==1 and "C" or "Python"
  end
 
  items.keyaction = function(handle,p1,key)
    if key == "F1" then
      far.Message(strhelp, M.mHelpDlgTitle, nil, 'l')
    else
      local name = keys[key]
      if name then SendMessage(handle, F.DM_CLOSE, dPos[name]) end
    end
  end
 
  items.proc = function(handle,msg,p1,p2)
    if msg==F.DN_INITDIALOG then
      set_language(handle)
      do_chain(handle)
    ----------------------------------------------------------------------------
    elseif msg==F.DN_EDITCHANGE then
      setdata(items[p1], p2[10])
      if p1==dPos.calc then
        do_chain(handle)
      else
        local fmt=items[p1].Fmt
        if fmt then
          format(dItems[fmt], result)
          SendMessage(handle, F.DM_SETTEXT, dPos[fmt], getdata(dItems[fmt]))
        end
      end
    ----------------------------------------------------------------------------
    elseif msg==F.DN_BTNCLICK then
      if p2 ~= 0 then
        local btn = items[p1]
        if btn.Item then
          active_item = dItems[btn.Item]
        elseif btn.name:find("^lng") then
          set_language(handle)
          SendMessage(handle, F.DM_SETFOCUS, dPos.calc)
          do_chain(handle)
        end
      end
    ----------------------------------------------------------------------------
    elseif msg==F.DN_HOTKEY then
      if enable_custom_hotkeys then
        local n = tonumber(p2.UnicodeChar)
        if n and n>=0 and n<=lastres then
          if n==0 then
            SendMessage(handle, F.DM_SETFOCUS, dPos.calc)
          else
            SendMessage(handle, F.DM_SETCHECK, dPos.decrad+n-1, 1)
            SendMessage(handle, F.DM_SETFOCUS, dPos.decfmt+n-1)
          end
          return HOTKEY_IS_DONE
        end
      end
    ----------------------------------------------------------------------------
    elseif msg==F.DN_CLOSE and p1>=1 then
      local btn=items[p1]
      if btn.Action then return btn.Action(handle) end
    end
  end
 
  if not enable_custom_hotkeys then
    for _,v in ipairs(items) do
      if v.text and v.text:match("^&[0-"..lastres.."]$") then v.text=v.text:sub(2) end
    end
  end
  sDialog.Run(items)
 
end -- local function calculator()
 
local Lang = {
  English = {
    mMainDlgTitle = "Lua Calculator";
    mLabelStatus  = "Status:";
    mButtonCalc   = "Calculate";
    mButtonInsert = "Insert (Ins)";
    mButtonCopy   = "Copy (F5)";
    mHelpDlgTitle = "Functions:";
    mNoFuncAvail  = "<No user functions available>";
    mErrorCall    = "Error: call";
    mErrorCompile = "Error: compile";
    mErrorSubcall = "Error: subcall";
    mErrorFormat  = "Error: format";
    mSyntax       = "Syntax:";
  };
  Russian = {
    mMainDlgTitle = "Lua-калькулятор";
    mLabelStatus  = "Статус:";
    mButtonCalc   = "Вычислить";
    mButtonInsert = "Вставить (Ins)";
    mButtonCopy   = "Скопировать (F5)";
    mHelpDlgTitle = "Функции:";
    mNoFuncAvail  = "<Нет пользовательских функций>";
    mErrorCall    = "Ошибка: вызов";
    mErrorCompile = "Ошибка: компиляция";
    mErrorSubcall = "Ошибка: подвызов";
    mErrorFormat  = "Ошибка: формат";
    mSyntax       = "Синтаксис:";
  };
}
 
Macro {
  description="Lua Calc";
  area="Common"; key="CtrlAltF4";
  id="1A26B745-1722-49F4-8075-2B2CA6C5487A";
  -- the condition function is not used here for its intended purpose; rather we take
  -- advantage of the fact that lua_State here is "main" (not that of a coroutine)
  condition = function()
    local ok, py = pcall(require, "python")
    python = ok and py
    return true
  end;
  action=function()
    -- mf.acall: 3.0.4003=bad; 3.0.4005=good
    M = Lang[win.GetEnv("FARLANG")] or Lang.English
    local _ = mf.acall and mf.acall(calculator) or calculator()
  end;
}

Всего записей: 3471 | Зарегистр. 16-06-2007 | Отправлено: 12:30 02-06-2021 | Исправлено: Alexyz21, 09:34 03-06-2021
   

На первую страницук этому сообщениюк последнему сообщению

Компьютерный форум Ru.Board » Компьютеры » Программы » FAR Manager (часть 6)
Maz (26-09-2022 12:52): FAR Manager (часть 7)


Реклама на форуме Ru.Board.

Powered by Ikonboard "v2.1.7b" © 2000 Ikonboard.com
Modified by Ru.B0ard
© Ru.B0ard 2000-2024

BitCoin: 1NGG1chHtUvrtEqjeerQCKDMUi6S6CG4iC

Рейтинг.ru