EnvEdit — редактор переменных среды

Здесь выкладываются готовые к использованию макросы и скрипты.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit — редактор переменных среды

Post by Smitis »



Скрипт показывает три списка переменных среды: для процесса, для пользователя из HKCU\Environment, для системы из HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment. Можно настроить, с чего начинать показ.
Переменные показываются as is, т.е. то, что вернула система, никакого специального раскрытия переменных среды не делается.
Поддерживаются только переменные REG_SZ и REG_EXPAND_SZ (остальные типы всё равно не используются самой системой).

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

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

Клавиши:
AltShiftE - Вызов макроса по умолчанию. Эта же комбинация по умолчанию используется для переключения списков переменных, аналогично Tab.
Tab и ShiftTab - Переключение списков переменных.
Enter - Редактирование переменной.
F4 или ShiftF4 - Редактирование переменной во встроенном редакторе.
Ins или Num0 - Добавление новой переменной.
Del или NumDel - Удаление переменной.
F12 или ShiftF12 - Восстановление последней удалённой переменной. Для каждого из трёх списков запоминается своя последняя удалённая переменная. После перезагрузки макросов эти сохранённые значения теряются.
F4 или ShiftF4 в диалоге редактирования вызывают встроенный редактор ФАРа. Предполагается, что делается это для переменных типа PATH, где несколько частей разделены точкой с запятой. Поэтому, при вызове редактора точки с запятой заменяются на переводы строк, а по окончании редактирования всё собирается обратно, лишние переводы строк и точки с запятой удаляются.

Уделение переменных из реестра и правильная запись их в реестр работает только с luafar/luamacro build >= 552 (или FAR 3.0 build 4491)
Для работы скрипта требуется модуль DialogClass ver>=1.11

EnvEdit 1.10
  1. --[=[--[=[ ------------------------------------------------------------------------------------------------------------------
  2.  
  3. Редактор переменных среды
  4.  
  5. v. 1.10 (C) 2014-2019 Smitis
  6.  
  7.  
  8.  
  9. TODO:
  10.  
  11.     - Восстановление фильтра после редактирования переменной
  12.  
  13.  
  14.  
  15. Обсуждение:
  16.  
  17.     http://forum.farmanager.com/viewtopic.php?t=9982
  18.  
  19.  
  20.  
  21. Для работы требуется модуль DialogClass v.>=1.11
  22.  
  23.     http://forum.farmanager.com/viewtopic.php?t=8523
  24.  
  25.  
  26.  
  27. --]=] ------------------------------------------------------------------------------------------------------------------
  28.  
  29.  
  30.  
  31. ------------------------------------------------------------------------------------------------------------------------
  32.  
  33. -- Конфигурация
  34.  
  35. -- Пользовательские настройки можно поместить в файл с именем тем же, что и у скрипта и расширением cfg.
  36.  
  37. ------------------------------------------------------------------------------------------------------------------------
  38.  
  39. local cfg = {}
  40.  
  41. cfg.DialogWidth = 100 -- ширина диалога редактирования
  42.  
  43. cfg.NameWidth = 30 -- ширина поля под имя переменной в списке
  44.  
  45. cfg.ValueWidth = 80 -- ширина поля под значение переменной в списке
  46.  
  47. -- общая ширина окна списка = NameWidth+ValueWidth+12
  48.  
  49. -- --║--NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN-│-VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV-║--
  50.  
  51. cfg.MenuHeight = 40 -- максимальная высота списка, высота окна списка = MenuHeight+4
  52.  
  53. cfg.MacroKey = "AltShiftE" -- клавиши для вызова макроса, если пустая строка, макрос будет отключен
  54.  
  55. cfg.ModeSwitch = "AS+E" -- для быстрого переключения списков после вызова макроса "не отрываясь от клавиатуры"
  56.  
  57. cfg.StartMode = 1 -- с чего начинаем: 1 - для процесса, 2 - для пользователя, 3 - для системы
  58.  
  59. cfg.NameHistory = "" -- имя истории для имён переменных, если пустая строка, история отключена
  60.  
  61. cfg.ValueHistory = "" -- имя истории для значения переменных, если пустая строка, история отключена
  62.  
  63. cfg.PluginMenu = true -- добавлять или нет вызов из меню плагинов
  64.  
  65. cfg.Favorites = {"PATH","PATHEXT","INCLUDE","LIB"} -- переменные, которые без сортировки будут показаны в начале списка
  66.  
  67. ------------------------------------------------------------------------------------------------------------------------
  68.  
  69. -- Загрузка персональных настроек
  70.  
  71. ------------------------------------------------------------------------------------------------------------------------
  72.  
  73. do local f,m=loadfile((...):gsub("[^.]+$","cfg"))
  74.  
  75. if f then setfenv(f,{cfg=cfg}) if not pcall(f) then msgbox("EnvEdit","\nCONFIG ERROR\n ",1)
  76.  
  77. end end end
  78.  
  79. ------------------------------------------------------------------------------------------------------------------------
  80.  
  81. -- Локализация
  82.  
  83. ------------------------------------------------------------------------------------------------------------------------
  84.  
  85. local langs = {
  86.  
  87.     english = {
  88.  
  89.         MenuTitle       = {"Process Environment Variables","User Environment Variables","System Environment Variables"},
  90.  
  91.         MenuBottom      = "F1:Help",
  92.  
  93.         DialogTitle     = {"Edit Environment Variable","Insert Environment Variable","Restore Environment Variable"},
  94.  
  95.         DeleteTitle     = "DELETE",
  96.  
  97.         DeleteMsg       = "Delete variable\n\n%s",
  98.  
  99.         OverwriteTitle  = "OVERWRITE",
  100.  
  101.         OverwriteMsg    = "Overwrite variable\n\n%s",
  102.  
  103.         RenameCopyTitle = "RENAME/COPY",
  104.  
  105.         RenameCopyMsg   = "Rename or copy variable\n\n%s\n\nto\n\n%s",
  106.  
  107.         NamePrompt      = "&Variable:",
  108.  
  109.         TypePrompt      = "&Type:",
  110.  
  111.         ValuePrompt     = "&Value:",
  112.  
  113.         OkButton        = "Ok",
  114.  
  115.         RenameButton    = "Rename",
  116.  
  117.         CopyButton      = "Copy",
  118.  
  119.         CancelButton    = "Cancel",
  120.  
  121.         EditButton      = "F4:Editor",
  122.  
  123.         PluginMenuDesc  = "Edit Environment Variables",
  124.  
  125.         NewName         = "* input new name *",
  126.  
  127.         NewValue        = "* input new value *",
  128.  
  129.         NoRestore       = "No data to restore",
  130.  
  131.         EditorTitle     = "Edit variable: ",
  132.  
  133.         MenuHelpTitle   = "HELP",
  134.  
  135.         MenuHelpMsg     = [=[
  136.  
  137.             Tab, ShiftTab  - Switch varialbe list (process, user, system)
  138.  
  139.             Enter          - Edit variable
  140.  
  141.             F4, ShiftF4    - Edit variable in editor
  142.  
  143.             Ins, Num0      - Insert new variable
  144.  
  145.             Del, NumDel    - Delete variable
  146.  
  147.             F12, ShiftF12  - Restore last deleted variable
  148.  
  149.         ]=],
  150.  
  151.     },
  152.  
  153.     russian = {
  154.  
  155.         MenuTitle       = {"Переменые окружения процесса","Пользовательские переменные окружения","Системные переменные окружения"},
  156.  
  157.         MenuBottom      = "F1:Помощь",
  158.  
  159.         DialogTitle     = {"Редактирование переменной среды","Вставка переменной среды","Восстановление переменной среды"},
  160.  
  161.         DeleteTitle     = "УДАЛЕНИЕ",
  162.  
  163.         DeleteMsg       = "Удалить переменную\n\n%s",
  164.  
  165.         OverwriteTitle  = "ПЕРЕПИСАТЬ",
  166.  
  167.         OverwriteMsg    = "Переписать переменную\n\n%s",
  168.  
  169.         RenameCopyTitle = "ПЕРЕИМЕНОВАТЬ/КОПИРОВАТЬ",
  170.  
  171.         RenameCopyMsg   = "Переименовать или копировать переменную\n\n%s\n\nв\n\n%s",
  172.  
  173.         NamePrompt      = "&Переменная:",
  174.  
  175.         TypePrompt      = "&Тип:",
  176.  
  177.         ValuePrompt     = "&Значение:",
  178.  
  179.         OkButton        = "Подтвердить",
  180.  
  181.         RenameButton    = "Переименовать",
  182.  
  183.         CopyButton      = "Копировать",
  184.  
  185.         CancelButton    = "Отменить",
  186.  
  187.         EditButton      = "F4:Редактор",
  188.  
  189.         PluginMenuDesc  = "Редактирование переменных окружения",
  190.  
  191.         NewName         = "* введите новое имя *",
  192.  
  193.         NewValue        = "* введите новое значение *",
  194.  
  195.         NoRestore       = "Нет данных для восстановления",
  196.  
  197.         EditorTitle     = "Редактирование переменной: ",
  198.  
  199.         MenuHelpTitle   = "ПОМОЩЬ",
  200.  
  201.         MenuHelpMsg     = [=[
  202.  
  203.             Tab, ShiftTab      - Переключение списков переменных (процесса, пользователя, системы)
  204.  
  205.             Enter         - Редактирование переменной
  206.  
  207.             F4, ShiftF4   - Редактирование переменной в редакторе
  208.  
  209.             Ins, Num0     - Добавление новой переменной
  210.  
  211.             Del, NumDel   - Удаление переменной
  212.  
  213.             F12, ShiftF12 - Восстановление последней удалённой переменной
  214.  
  215.         ]=],
  216.  
  217.     }
  218.  
  219. }
  220.  
  221. local lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  222.  
  223. ------------------------------------------------------------------------------------------------------------------------
  224.  
  225.  
  226.  
  227. local EnvEditMenuId = win.Uuid("09814E7E-CBA7-43A4-9F65-0222E72CFADA")
  228.  
  229. local EnvEditHelpId = win.Uuid("F9EDF605-EC94-4216-8353-A96E8BB7F42D")
  230.  
  231. local EnvEditDeleteId = win.Uuid("1AA4D9CC-3173-43C2-9FB7-57842CD93EBC")
  232.  
  233. local EnvEditRestoreId = win.Uuid("634F82F7-32F5-4BF8-BF5A-9469FD9E3124")
  234.  
  235. local EnvEditRenameCopyId = win.Uuid("0A0A426D-EB4F-403C-B5F1-584B4507CE2D")
  236.  
  237. local EnvEditOverwriteId = win.Uuid("8E58D881-339C-4274-9CBA-58BD3CF00BA4")
  238.  
  239. local EnvEditPluginMenuId = "9F0AB063-515E-4E74-8214-5B801BA4B789"
  240.  
  241. local EnvEditMacroId = "9C60576F-38F0-4974-A03D-2FF851343B20"
  242.  
  243. local EnvEditChangeId = "5D2D74B0-B1CC-4091-AAA2-1C5789B14E01"
  244.  
  245. local EnvEditEditorId = "D5D70290-C316-45F1-9EA1-5CF4188FB2C3"
  246.  
  247.  
  248.  
  249. local F = far.Flags
  250.  
  251. local dialog = require "DialogClass"
  252.  
  253. local ffi = require "ffi"
  254.  
  255. local C = ffi.C
  256.  
  257. ffi.cdef [=[
  258.  
  259.     wchar_t* GetEnvironmentStringsW();
  260.  
  261.     void FreeEnvironmentStringsW(wchar_t*);
  262.  
  263.     size_t wcslen(const wchar_t*);
  264.  
  265.     int SendMessageA(HWND, UINT, WPARAM, LPARAM);
  266.  
  267.     int SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, DWORD_PTR*);
  268.  
  269. ]=]
  270.  
  271.  
  272.  
  273. --local farbuild = select(4,far.AdvControl(F.ACTL_GETFARMANAGERVERSION,true))
  274.  
  275. --local wrenable = farbuild >= 4491
  276.  
  277.  
  278.  
  279. local vtypes = {string="REG_SZ", expandstring="REG_EXPAND_SZ", REG_SZ="string", REG_EXPAND_SZ="expandstring"}
  280.  
  281. local vtindex = {string=1, expandstring=2, REG_SZ=1, REG_EXPAND_SZ=2}
  282.  
  283.  
  284.  
  285. ------------------------------------------------------------------------------------------------------------------------
  286.  
  287.  
  288.  
  289. local mode = 1 -- что редактируем: 0:выходим, 1:для процесса, 2:для пользователя, 3:для системы
  290.  
  291. local RootKey, PathKey
  292.  
  293. local backup = {{Name="",Value="",Type=""},{Name="",Value="",Type=""},{Name="",Value="",Type=""}} -- сохранение предыдущего значения переменной для восстановления
  294.  
  295.  
  296.  
  297. ------------------------------------------------------------------------------------------------------------------------
  298.  
  299. local function Message(msg,...)
  300.  
  301.     return far.Message(" \n"..msg.."\n ",...)
  302.  
  303. end
  304.  
  305. ------------------------------------------------------------------------------------------------------------------------
  306.  
  307. local environment, favorites, envmenu
  308.  
  309.  
  310.  
  311. local function FindVar(name) -- поиск переменной в меню для восстановления позиции
  312.  
  313.     name = name:lower()
  314.  
  315.     for i,var in ipairs(envmenu) do
  316.  
  317.         if var.Name:lower()==name then
  318.  
  319.             return i
  320.  
  321.         end
  322.  
  323.     end
  324.  
  325.     return 0
  326.  
  327. end
  328.  
  329. ------------------------------------------------------------------------------------------------------------------------
  330.  
  331. local HWND_BROADCAST = ffi.cast("HWND",0xffff)
  332.  
  333. local WM_SETTINGCHANGE = 0x001A
  334.  
  335. local SMTO_ABORTIFHUNG = 0x0002
  336.  
  337. local MSG_TIMEOUT = 5000
  338.  
  339.  
  340.  
  341. local function SendSettingChange(mode)
  342.  
  343.     if mode==nil or mode~=1 then -- для локальных переменных обновлять не надо
  344.  
  345.         --C.SendMessageA(HWND_BROADCAST,WM_SETTINGCHANGE,0,ffi.cast("LPARAM","Environment"))
  346.  
  347.         C.SendMessageTimeoutA(HWND_BROADCAST,WM_SETTINGCHANGE,0,ffi.cast("LPARAM","Environment"),SMTO_ABORTIFHUNG,MSG_TIMEOUT,ffi.cast("DWORD_PTR*",0))
  348.  
  349.     end
  350.  
  351. end
  352.  
  353. ------------------------------------------------------------------------------------------------------------------------
  354.  
  355. local function ModalEdit(text,title)
  356.  
  357.     text = text:gsub(';','\n')
  358.  
  359.     text = text:gsub('%b""',function(x) return x:gsub('\n',';') end) -- точки с запятой в кавычках
  360.  
  361.     text = text:gsub('\n+','\n') -- лишние переводы строк
  362.  
  363.     text = text.."\n"
  364.  
  365.     local tmpfile = far.MkTemp()
  366.  
  367.     local hfile = io.open(tmpfile,"w") hfile:write(text) hfile:close()
  368.  
  369.     editor.Editor(tmpfile,title or " ",0,0,-1,-1,bor(F.EF_DISABLEHISTORY,F.EF_DISABLESAVEPOS),0,0,65001)
  370.  
  371.     hfile = io.open(tmpfile,"r") text = hfile:read("*a") hfile:close()
  372.  
  373.     win.DeleteFile(tmpfile)
  374.  
  375.     return text:gsub('[\n;]+',';'):gsub('[; ]+$',''):gsub('^[; ]+','')
  376.  
  377. end
  378.  
  379. ------------------------------------------------------------------------------------------------------------------------
  380.  
  381. local function EditVar(var,op)
  382.  
  383.     op = op or 1 -- 1:edit, 2:insert, 3:restore
  384.  
  385.     local prev = {Name=var.Name,Value=var.Value,Type=var.Type}
  386.  
  387.     local new = {Name=var.Name,Value=var.Value,Type=var.Type}
  388.  
  389.     local D,DI = dialog.New {
  390.  
  391.         Guid = EnvEditChangeId,
  392.  
  393.         Title = lang.DialogTitle[op],
  394.  
  395.         W = cfg.DialogWidth,
  396.  
  397.         H = mode==1 and 10 or 12,
  398.  
  399.         DlgProc = function(hDlg,Msg,Param1,Param2,D,DI)
  400.  
  401.             if Msg==F.DN_CLOSE and Param1==DI.OkButton.Id then
  402.  
  403.                 new.Name = DI.Name:GetText()
  404.  
  405.                 new.Value = DI.Value:GetText()
  406.  
  407.                 if mode~=1 then new.Type = DI.Type:GetText() end
  408.  
  409.  
  410.  
  411.                 -- При пустом имени или пустом значении вернёмся к редактированию
  412.  
  413.                 if new.Name=="" or new.Value=="" then
  414.  
  415.                     return false
  416.  
  417.                 end
  418.  
  419.  
  420.  
  421.                 -- Спрашиваем переименовать, копировать или отменить при изменение имени при редактированиее.
  422.  
  423.                 -- При отмене вернёмся к редактированию.
  424.  
  425.                 local rc = 1 -- 0:cancel, 1:change, 2:rename, 3:copy
  426.  
  427.                 if op==1 and new.Name:lower()~=prev.Name:lower() then
  428.  
  429.                     rc = (Message(lang.RenameCopyMsg:format(prev.Name,new.Name),lang.RenameCopyTitle,lang.RenameButton..";"..lang.CopyButton..";"..lang.CancelButton,"","",EnvEditRenameCopyId)+1)%4
  430.  
  431.                     if rc==0 then return true end
  432.  
  433.                 end
  434.  
  435.  
  436.  
  437.                 -- Спрашиваем при переименовании, копировании, вставке или восстановлении если уже существует такая переменная
  438.  
  439.                 if (rc>1 or op>1) and FindVar(new.Name)>0 then
  440.  
  441.                     if Message(lang.OverwriteMsg:format(new.Name),lang.OverwriteTitle,";OkCancel","","",EnvEditOverwriteId)~=1 then
  442.  
  443.                         return true
  444.  
  445.                     end
  446.  
  447.                 end
  448.  
  449.  
  450.  
  451.                 -- Если дошли сюда, значит наконец можно установить переменную
  452.  
  453.                 if mode==1 then
  454.  
  455.                     win.SetEnv(new.Name,new.Value)
  456.  
  457.                     if rc==2 then -- при переименовании удалить старую переменную
  458.  
  459.                         win.SetEnv(prev.Name,nil)
  460.  
  461.                     end
  462.  
  463.                 else
  464.  
  465.                     win.SetRegKey(RootKey,PathKey,new.Name,vtypes[new.Type],new.Value)
  466.  
  467.                     if rc==2 then -- при переименовании удалить старую переменную
  468.  
  469.                         win.DeleteRegValue(RootKey,PathKey,prev.Name)
  470.  
  471.                     end
  472.  
  473.                     SendSettingChange()
  474.  
  475.                 end
  476.  
  477.                 var.Name,var.Value,var.Type = new.Name,new.Value,new.Type
  478.  
  479.             end
  480.  
  481.  
  482.  
  483.             -- Вызов модального редактора
  484.  
  485.             local key = (Msg==F.DN_CONTROLINPUT and Param2.EventType==F.KEY_EVENT and Param2.KeyDown) and far.InputRecordToName(Param2) or ""
  486.  
  487.             if (Msg==F.DN_BTNCLICK and Param1==DI.EditButton.Id) or key=="F4" or key=="ShiftF4" then
  488.  
  489.                 DI.Value:SetText(ModalEdit(DI.Value:GetText(),lang.EditorTitle..DI.Name:GetText()))
  490.  
  491.                 return true
  492.  
  493.             end
  494.  
  495.         end,
  496.  
  497.     }
  498.  
  499.     DI {"t+", Text=lang.NamePrompt}
  500.  
  501.     DI {"e+", Name="Name", Text=var.Name, History=cfg.NameHistory}
  502.  
  503.     if mode~=1 then
  504.  
  505.         DI {"t+", Text=lang.TypePrompt}
  506.  
  507.         DI {"xd+", Name="Type", W=14, LI={{Flags=0,Text="REG_SZ"},{Flags=0,Text="REG_EXPAND_SZ"},SelectIndex=vtindex[var.Type]}, Text=""}
  508.  
  509.     end
  510.  
  511.     DI {"t+", Text=lang.ValuePrompt}
  512.  
  513.     DI {"e+", Name="Value", Text=var.Value, Flags=(op==1 and F.DIF_FOCUS or 0), History=cfg.ValueHistory}
  514.  
  515.     DI {"s+"}
  516.  
  517.     DI {"b=!+", Name="OkButton", Text=lang.OkButton}
  518.  
  519.     DI {"b=", Name="CancelButton", Text=lang.CancelButton}
  520.  
  521.     DI {"b=;", Name="EditButton", Text=lang.EditButton}
  522.  
  523.     return D()==DI.OkButton.Id
  524.  
  525. end
  526.  
  527. ------------------------------------------------------------------------------------------------------------------------
  528.  
  529. local function EditEnvironment()
  530.  
  531.     lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  532.  
  533.     local items, item
  534.  
  535.     local pos = {0,0,0} -- текущая позиция в меню по каждому типу переменных
  536.  
  537.     local jump -- переменная, если требуется изменение текущей pos
  538.  
  539.     local MenuHotKeys = {
  540.  
  541.                 {BreakKey="F1"},
  542.  
  543.                 {BreakKey="F4"},{BreakKey="S+F4"},
  544.  
  545.                 {BreakKey="F12"},{BreakKey="S+F12"},
  546.  
  547.                 {BreakKey="INSERT"},{BreakKey="NUMPAD0"},
  548.  
  549.                 {BreakKey="DELETE"},{BreakKey="DECIMAL"},{BreakKey="F8"},
  550.  
  551.                 {BreakKey="TAB"},{BreakKey="C+TAB"},
  552.  
  553.                 {BreakKey="S+TAB"},{BreakKey="CS+TAB"},
  554.  
  555.     }
  556.  
  557.     if cfg.ModeSwitch and cfg.ModeSwitch~="" then
  558.  
  559.         MenuHotKeys[#MenuHotKeys+1] = {BreakKey=cfg.ModeSwitch}
  560.  
  561.     end
  562.  
  563.     local name, value, vtype, filter
  564.  
  565.     mode = cfg.StartMode
  566.  
  567.     while mode>0 do -- цикл переключения списка отображаемых переменных 1/2/3 - процесс/пользователь/система
  568.  
  569.         environment = {}
  570.  
  571.         favorites = {}
  572.  
  573.         envmenu = {}
  574.  
  575.         if mode==1 then -- переменные процесса
  576.  
  577.             local envstrings = C.GetEnvironmentStringsW()
  578.  
  579.             local envptr = envstrings -- указатель на очередную переменную
  580.  
  581.             local envlen = C.wcslen(envptr)
  582.  
  583.             while envlen > 0 do
  584.  
  585.                 value = win.Utf16ToUtf8(ffi.string(ffi.cast("char*",envptr),2*envlen))
  586.  
  587.                 if value:sub(1,1)~="=" then -- кроме "=<диск>=<путь>"
  588.  
  589.                     name,value = value:match("^(.-)=(.*)$")
  590.  
  591.                     if name and value then
  592.  
  593.                         environment[#environment+1] = {Name=name,Value=value}
  594.  
  595.                     end
  596.  
  597.                 end
  598.  
  599.                 envptr = envptr+envlen+1 -- указатель на следующую строку
  600.  
  601.                 envlen = C.wcslen(envptr)
  602.  
  603.             end
  604.  
  605.             C.FreeEnvironmentStringsW(envstrings)
  606.  
  607.         else
  608.  
  609.             local index = 0
  610.  
  611.             if mode==2 then -- пользовательские переменные
  612.  
  613.                 RootKey = "HKCU"
  614.  
  615.                 PathKey = "Environment"
  616.  
  617.             elseif mode==3 then -- системные переменные
  618.  
  619.                 RootKey = "HKLM"
  620.  
  621.                 PathKey = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
  622.  
  623.             else
  624.  
  625.                 return
  626.  
  627.             end
  628.  
  629.             name = win.EnumRegValue(RootKey,PathKey,index)
  630.  
  631.             while name do
  632.  
  633.                 value,vtype = win.GetRegKey(RootKey,PathKey,name)
  634.  
  635.                 if vtypes[vtype] then
  636.  
  637.                     environment[#environment+1] = {Name=name,Value=value,Type=vtypes[vtype]}
  638.  
  639.                 end
  640.  
  641.                 index = index+1
  642.  
  643.                 name = win.EnumRegValue(RootKey,PathKey,index)
  644.  
  645.             end
  646.  
  647.         end
  648.  
  649.         table.sort(environment,function(a,b) return(a.Name:lower()<b.Name:lower()) end)
  650.  
  651.         for _,f in ipairs(cfg.Favorites) do -- формируем список избраного
  652.  
  653.             for _,e in ipairs(environment) do
  654.  
  655.                 if f:upper()==e.Name:upper() then
  656.  
  657.                     e.Fav = true -- помечаем как избранное
  658.  
  659.                     envmenu[#envmenu+1] = e
  660.  
  661.                     break
  662.  
  663.                 end
  664.  
  665.             end
  666.  
  667.         end
  668.  
  669.         if #envmenu>0 and #envmenu<#environment then -- Разделитель между избранным и остальным
  670.  
  671.             envmenu[#envmenu+1] = {Name="",separator=true}
  672.  
  673.         end
  674.  
  675.         for _,e in ipairs(environment) do -- Перенос оставшегося списка
  676.  
  677.             if e.Name~="" and not e.Fav then
  678.  
  679.                 envmenu[#envmenu+1] = e
  680.  
  681.             end
  682.  
  683.         end
  684.  
  685.         for _,e in ipairs(envmenu) do -- Форматируем для far.Menu
  686.  
  687.             if not e.separator then
  688.  
  689.                 e.text = ("%%-%is │ %%-%is"):format(cfg.NameWidth,cfg.ValueWidth):format(e.Name:sub(1,cfg.NameWidth),e.Value:sub(1,cfg.ValueWidth))
  690.  
  691.             end
  692.  
  693.         end
  694.  
  695.         if jump then -- определяем позицию для перехода (после вставки, переименования и т.п.)
  696.  
  697.             pos[mode] = FindVar(jump)
  698.  
  699.             jump = nil
  700.  
  701.         end
  702.  
  703.         while true do -- цикл - показываем меню / обрабатываем клавиши
  704.  
  705.             local res
  706.  
  707.             res,pos[mode] = far.Menu(
  708.  
  709.                 {
  710.  
  711.                     Title=lang.MenuTitle[mode],
  712.  
  713.                     Bottom=lang.MenuBottom,
  714.  
  715.                     SelectIndex=pos[mode],
  716.  
  717.                     Id=EnvEditMenuId,
  718.  
  719.                     Flags=bor(F.FMENU_SHOWAMPERSAND,F.FMENU_WRAPMODE),
  720.  
  721.                     MaxHeight=cfg.MenuHeight,
  722.  
  723.                 },
  724.  
  725.                 envmenu, MenuHotKeys
  726.  
  727.             )
  728.  
  729.             if res==nil then -- Esc
  730.  
  731.                 mode = 0
  732.  
  733.                 break
  734.  
  735.             --elseif not res.BreakKey or (res.BreakKey and (res.BreakKey=="F4" or res.BreakKey=="S+F4")) then -- Enter, F4
  736.  
  737.             elseif not res.BreakKey then -- Enter
  738.  
  739.                 local var = envmenu[pos[mode]]
  740.  
  741.                 if EditVar(var) then
  742.  
  743.                     jump = var.Name
  744.  
  745.                     break
  746.  
  747.                 end
  748.  
  749.             elseif res.BreakKey=="F4" or res.BreakKey=="S+F4" then -- модальный редактор
  750.  
  751.                 local var = envmenu[pos[mode]]
  752.  
  753.                 var.Value = ModalEdit(var.Value,lang.EditorTitle..var.Name)
  754.  
  755.                 if var.Value=="" then var.Value=nil end -- пустое значение - удаляем переменую
  756.  
  757.                 if mode==1 then
  758.  
  759.                     win.SetEnv(var.Name,var.Value)
  760.  
  761.                     jump = var.Name
  762.  
  763.                     break
  764.  
  765.                 elseif var.Value then
  766.  
  767.                     win.SetRegKey(RootKey,PathKey,var.Name,vtypes[var.Type],var.Value)
  768.  
  769.                     jump = var.Name
  770.  
  771.                     SendSettingChange()
  772.  
  773.                     break
  774.  
  775.                 else
  776.  
  777.                     backup[mode] = {Name=var.Name,Value=var.Value,Type=var.Type}
  778.  
  779.                     win.DeleteRegValue(RootKey,PathKey,prev.Name)
  780.  
  781.                     SendSettingChange()
  782.  
  783.                     break
  784.  
  785.                 end
  786.  
  787.             elseif res.BreakKey=="F12" or res.BreakKey=="S+F12" then -- восстановление
  788.  
  789.                 local var = {Name=backup[mode].Name,Value=backup[mode].Value,Type=backup[mode].Type}
  790.  
  791.                 if var.Name=="" then
  792.  
  793.                     Message(lang.NoRestore,lang.RestoreTitle,";Ok","","",EnvEditRestoreId)
  794.  
  795.                 elseif EditVar(var,3) then
  796.  
  797.                     jump = var.Name
  798.  
  799.                     SendSettingChange(mode)
  800.  
  801.                     break
  802.  
  803.                 end
  804.  
  805.             elseif res.BreakKey=="INSERT" or res.BreakKey=="NUMPAD0" then
  806.  
  807.                 local var = {Name=lang.NewName,Value=lang.NewValue}
  808.  
  809.                 if mode~=1 then var.Type="REG_SZ" end
  810.  
  811.                 if EditVar(var,2) then
  812.  
  813.                     jump = var.Name
  814.  
  815.                     SendSettingChange(mode)
  816.  
  817.                     break
  818.  
  819.                 end
  820.  
  821.             elseif res.BreakKey=="DELETE" or res.BreakKey=="DECIMAL" then
  822.  
  823.                 local var = envmenu[pos[mode]]
  824.  
  825.                 if Message(lang.DeleteMsg:format(var.Name),lang.DeleteTitle,";OkCancel","","",EnvEditDeleteId) == 1 then
  826.  
  827.                     backup[mode] = {Name=var.Name,Value=var.Value,Type=var.Type}
  828.  
  829.                     if mode==1 then
  830.  
  831.                         win.SetEnv(var.Name,nil)
  832.  
  833.                     else
  834.  
  835.                         win.DeleteRegValue(RootKey,PathKey,var.Name)
  836.  
  837.                         SendSettingChange()
  838.  
  839.                     end
  840.  
  841.                     if pos[mode]==#envmenu then pos[mode]=pos[mode]-1 end
  842.  
  843.                     break
  844.  
  845.                 end
  846.  
  847.             elseif res.BreakKey=="TAB" or res.BreakKey=="C+TAB" or res.BreakKey==cfg.ModeSwitch then
  848.  
  849.                 mode = mode + 1
  850.  
  851.                 if mode>3 then mode = 1 end
  852.  
  853.                 break
  854.  
  855.             elseif res.BreakKey=="S+TAB" or res.BreakKey=="CS+TAB" then
  856.  
  857.                 mode = mode - 1
  858.  
  859.                 if mode<1 then mode = 3 end
  860.  
  861.                 break
  862.  
  863.             elseif res.BreakKey=="F1" then
  864.  
  865.                 Message(lang.MenuHelpMsg:gsub('%s*\n%s*','\n'):gsub('^%s+',''):gsub('[%s%c]+$',''),lang.MenuHelpTitle,";Ok","l",nil,EnvEditHelpId)
  866.  
  867.             end
  868.  
  869.         end
  870.  
  871.     end
  872.  
  873. end;
  874.  
  875. ------------------------------------------------------------------------------------------------------------------------
  876.  
  877. if cfg.MacroKey and cfg.MacroKey~="" then
  878.  
  879.     Macro {
  880.  
  881.         description = "EnvEdit";
  882.  
  883.         area = "Shell Search QView Info Tree Editor Viewer";
  884.  
  885.         id = EnvEditMacroId;
  886.  
  887.         key = "AltShiftE";
  888.  
  889.         action = EditEnvironment;
  890.  
  891.     }
  892.  
  893. end
  894.  
  895. ------------------------------------------------------------------------------------------------------------------------
  896.  
  897. if cfg.PluginMenu then
  898.  
  899.     MenuItem {
  900.  
  901.         description = "EnvEdit";
  902.  
  903.         menu = "Plugins";
  904.  
  905.         area = "Shell Search QView Info Tree Editor Viewer";
  906.  
  907.         guid = EnvEditPluginMenuId;
  908.  
  909.         text = function(menu,area)
  910.  
  911.             lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  912.  
  913.             return lang.PluginMenuDesc
  914.  
  915.         end;
  916.  
  917.         action = EditEnvironment;
  918.  
  919.     }
  920.  
  921. end
  922.  
  923. ------------------------------------------------------------------------------------------------------------------------
Attachments
EnvEdit.1.10.7z
EnvEdit 1.10
(6.88 KiB) Downloaded 221 times
Last edited by Smitis on Mon 10 Jun, 2019 10:20, edited 1 time in total.
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

EnvEdit - редактор переменных среды

Post by HaRT »

Скрипт не пробовал, но интересно, правильно ли будут разбиваться пути, некоторые из которых закавычены из-за наличия в них точки с запятой.
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
DrKnS
Posts: 6114
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 12 times
Been thanked: 426 times

EnvEdit - редактор переменных среды

Post by DrKnS »

Smitis wrote: - При изменении переменных через реестр, надо бы послать HWND_BROADCAST с WM_SETTINGCHANGE как минимум. Но что-то не заладилось, посмотрите, кто в теме, плиз. (Раньше делал через вызов setx.exe, там сообщение посылалось автоматически).
Как-то так:
  1. ffi.cdef[[int SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, DWORD_PTR*);]]
  2.  
  3. local HWND_BROADCAST = ffi.cast("HWND", 0xffff)
  4.  
  5. local WM_SETTINGCHANGE = 0x001A
  6.  
  7. local SMTO_ABORTIFHUNG = 0x0002
  8.  
  9. local MSG_TIMEOUT = 5000
  10.  
  11. ffi.C.SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, ffi.cast("LPARAM", "Environment"), SMTO_ABORTIFHUNG, MSG_TIMEOUT, ffi.cast("DWORD_PTR*", 0))
С setx лучше не связываться, оно тупое и больше 1024 символов не умеет.
User avatar
Wave
Posts: 1885
Joined: Thu 04 Aug, 2005 18:47
Has thanked: 14 times
Been thanked: 26 times

EnvEdit - редактор переменных среды

Post by Wave »

А мне интересен аналог плагина EnvMan. Т.е. который может группировать переменные окружения в пакеты и в любой момент разворачивать их в пользовательскую среду. Нужно это для работы с серверами, т.е. чтобы мог быстро развернуть кучу переменных с путями php и т.п., а в плагине не устраивает его привязанность к реестру — свои настройки он в реестре хранит (не до конца портирован на FAR3).
Пользуюсь ФАРом больше 20 лет © собирательный.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

HaRT wrote:Скрипт не пробовал, но интересно, правильно ли будут разбиваться пути, некоторые из которых закавычены из-за наличия в них точки с запятой.
Не правильно будут - кавычки не проверяются. Но в принципе, можно сделать.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

v. 1.01
- Сделал восстановление удаленной переменной по F12 (хранится до перезагрузки макросов).
- HWND_BROADCAST посылается, но не знаю, правильно ли.
Правильная работа гарантируется только в luafar/luamacro >= build 552 (ночная сборка 4488).
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

v. 1.02
- По многочисленным просьбам :) при вызове встроенного редактора точки с запятой в кавычках в разбивке на строки не участвуют.
- Тип переменной сделан списком.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

Wave wrote:А мне интересен аналог плагина EnvMan. Т.е. который может группировать переменные окружения в пакеты и в любой момент разворачивать их в пользовательскую среду. Нужно это для работы с серверами, т.е. чтобы мог быстро развернуть кучу переменных с путями php и т.п., а в плагине не устраивает его привязанность к реестру — свои настройки он в реестре хранит (не до конца портирован на FAR3).
Посмотрел, может быть слишком поверхостно, но как-то не проникся. Тоже самое я делаю командными файлами (или PowerShell), более гибко получается.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

v. 1.03
- Исправлена отправка HWND_BROADCAST (LPARAM передавался не тем параметром). Но всё равно не знаю, правильно отправляется или нет.
- Вернул возможность редактировать имя и тип.
Копирование и переименование решил не делать. Копирование и сейчас получается,как побочный эффект, если изменить имя.

П.С.
Вот сейчас подумалось, по сравнению с тем что было до публикации здесь, из функционала реально добавилось восстановление удалённой переменной и не очень нужные мне переменные процесса. Да, я привёл скрипт более или менее в порядок, переделал без вызова внешней утилиты, добавил конфигурацию, изменение языка, но времени на это потратилось даже больше, чем на редактирование этих переменных за последний год (один раз при переустановке винды, два-три раза правил path). :)
Разум когда-нибудь победит.
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

EnvEdit - редактор переменных среды

Post by HaRT »

Smitis wrote: Исправлена отправка HWND_BROADCAST (LPARAM передавался не тем параметром). Но всё равно не знаю, правильно отправляется или нет.
Думаю, можно частично проверить другим экземпляром Фара: если он не подхватывает изменения, то отправляется точно неправильно. ;)
Фар есть инструмент, а не нянька. © 2009 DrKnS
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

Забыл про эту фичу. Попробовал. Не приходит. Через setx приходит, а так нет.
Разум когда-нибудь победит.
User avatar
DrKnS
Posts: 6114
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 12 times
Been thanked: 426 times

EnvEdit - редактор переменных среды

Post by DrKnS »

Smitis wrote: Не приходит.
Я ж вроде выше уже написал, как правильно посылать.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

DrKnS
Что-то у меня вчера переклинило. Ни в каком виде не хотело работать.
А сейчас с утра Ваш вариант заработал.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

v. 1.04

- Отправка HWND_BROADCAST.
Разум когда-нибудь победит.
User avatar
Smitis
Posts: 1709
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 23 times
Been thanked: 55 times

EnvEdit - редактор переменных среды

Post by Smitis »

v. 1.05

- Проверка на пустое имя делается не при выходе из диалога в DlgProc, а уже после закрытия. Иначе нельзя выйти по ESC при пустом имени.
- Добавлена проверка на пустое значение.
- При изменении в диалоге имени спрашиваем что делать - переименовать или копировать. При отказе возвращаемся к редактированию.
- При переименовании, копировании, вставке, восстановлении если уже существует переменная с таким именем, запрашиваем подтверждение на перезапись. При отказе возвращаемся к редактированию.
Разум когда-нибудь победит.
Post Reply

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