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

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

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

Postby Smitis » Sat 19 Dec, 2015 20:26



Скрипт показывает три списка переменных среды: для процесса, для пользователя из 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.08
  1. --[=[ ------------------------------------------------------------------------------------------------------------------
  2. Редактор переменных среды
  3. v. 1.08 (C) 2014-2016 Smitis
  4.  
  5. Обсуждение:
  6.     http://forum.farmanager.com/viewtopic.php?t=9982
  7.  
  8. Для работы требуется модуль DialogClass v.>=1.11
  9.     http://forum.farmanager.com/viewtopic.php?t=8523
  10.  
  11. --]=] ------------------------------------------------------------------------------------------------------------------
  12.  
  13. ------------------------------------------------------------------------------------------------------------------------
  14. -- Конфигурация
  15. -- Пользовательские настройки можно поместить в файл с именем тем же, что и у скрипта и расширением cfg.
  16. ------------------------------------------------------------------------------------------------------------------------
  17. local cfg = {}
  18. cfg.DialogWidth = 100 -- ширина диалога редактирования
  19. cfg.EditorWidth = 100 -- ширина окна редактора
  20. cfg.EditorHeight = 30 -- высота редактора
  21. cfg.NameWidth = 30 -- ширина поля под имя переменной в списке
  22. cfg.ValueWidth = 80 -- ширина поля под значение переменной в списке
  23. -- общая ширина окна списка = NameWidth+ValueWidth+12
  24. -- --║--NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN-│-VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV-║--
  25. cfg.MenuHeight = 40 -- максимальная высота списка, высота окна списка = MenuHeight+4
  26. cfg.MacroKey = "AltShiftE" -- клавиши для вызова макроса, если пустая строка, макрос будет отключен
  27. cfg.ModeSwitch = "AS+E" -- для быстрого переключения списков после вызова макроса "не отрываясь от клавиатуры"
  28. cfg.StartMode = 1 -- с чего начинаем: 1 - для процесса, 2 - для пользователя, 3 - для системы
  29. cfg.NameHistory = "" -- имя истории для имён переменных, если пустая строка, история отключена
  30. cfg.ValueHistory = "" -- имя истории для значения переменных, если пустая строка, история отключена
  31. cfg.PluginMenu = true -- добавлять или нет вызов из меню плагинов
  32. cfg.Favorites = {"PATH","PATHEXT","INCLUDE","LIB"} -- переменные, которые без сортировки будут показаны в начале списка
  33. ------------------------------------------------------------------------------------------------------------------------
  34. -- Загрузка персональных настроек
  35. ------------------------------------------------------------------------------------------------------------------------
  36. do local f,m=loadfile((...):gsub("[^.]+$","cfg"))
  37. if f then setfenv(f,{cfg=cfg}) if not pcall(f) then msgbox("EnvEdit","\nCONFIG ERROR\n ",1)
  38. end end end
  39. ------------------------------------------------------------------------------------------------------------------------
  40. -- Локализация
  41. ------------------------------------------------------------------------------------------------------------------------
  42. local langs = {
  43.     english = {
  44.         MenuTitle       = {"Process Environment Variables","User Environment Variables","System Environment Variables"},
  45.         MenuBottom      = "F1:Help",
  46.         DialogTitle     = {"Edit Environment Variable","Insert Environment Variable","Restore Environment Variable"},
  47.         DeleteTitle     = "DELETE",
  48.         DeleteMsg       = "Delete variable\n\n%s",
  49.         OverwriteTitle  = "OVERWRITE",
  50.         OverwriteMsg    = "Overwrite variable\n\n%s",
  51.         RenameCopyTitle = "RENAME/COPY",
  52.         RenameCopyMsg   = "Rename or copy variable\n\n%s\n\nto\n\n%s",
  53.         NamePrompt      = "&Variable:",
  54.         TypePrompt      = "&Type:",
  55.         ValuePrompt     = "&Value:",
  56.         OkButton        = "Ok",
  57.         RenameButton    = "Rename",
  58.         CopyButton      = "Copy",
  59.         CancelButton    = "Cancel",
  60.         EditButton      = "F4:Editor",
  61.         PluginMenuDesc  = "Edit Environment Variables",
  62.         NewName         = "* input new name *",
  63.         NewValue        = "* input new value *",
  64.         NoRestore       = "No data to restore",
  65.         MenuHelpTitle   = "HELP",
  66.         MenuHelpMsg     = [=[
  67.             Tab, ShiftTab      - Switch varialbe list (process, user, system)
  68.             Enter          - Edit variable
  69.             F4, ShiftF4    - Edit variable in editor
  70.             Ins, Num0      - Insert new variable
  71.             Del, NumDel    - Delete variable
  72.             F12, ShiftF12  - Restore last deleted variable
  73.         ]=],
  74.     },
  75.     russian = {
  76.         MenuTitle       = {"Переменые окружения процесса","Пользовательские переменные окружения","Системные переменные окружения"},
  77.         MenuBottom      = "F1:Помощь",
  78.         DialogTitle     = {"Редактирование переменной среды","Вставка переменной среды","Восстановление переменной среды"},
  79.         DeleteTitle     = "УДАЛЕНИЕ",
  80.         DeleteMsg       = "Удалить переменную\n\n%s",
  81.         OverwriteTitle  = "ПЕРЕПИСАТЬ",
  82.         OverwriteMsg    = "Переписать переменную\n\n%s",
  83.         RenameCopyTitle = "ПЕРЕИМЕНОВАТЬ/КОПИРОВАТЬ",
  84.         RenameCopyMsg   = "Переименовать или копировать переменную\n\n%s\n\nв\n\n%s",
  85.         NamePrompt      = "&Переменная:",
  86.         TypePrompt      = "&Тип:",
  87.         ValuePrompt     = "&Значение:",
  88.         OkButton        = "Подтвердить",
  89.         RenameButton    = "Переименовать",
  90.         CopyButton      = "Копировать",
  91.         CancelButton    = "Отменить",
  92.         EditButton      = "F4:Редактор",
  93.         PluginMenuDesc  = "Редактирование переменных окружения",
  94.         NewName         = "* введите новое имя *",
  95.         NewValue        = "* введите новое значение *",
  96.         NoRestore       = "Нет данных для восстановления",
  97.         MenuHelpTitle   = "ПОМОЩЬ",
  98.         MenuHelpMsg     = [=[
  99.             Tab, ShiftTab      - Переключение списков переменных (процесса, пользователя, системы)
  100.             Enter         - Редактирование переменной
  101.             F4, ShiftF4   - Редактирование переменной в редакторе
  102.             Ins, Num0     - Добавление новой переменной
  103.             Del, NumDel   - Удаление переменной
  104.             F12, ShiftF12 - Восстановление последней удалённой переменной
  105.         ]=],
  106.     }
  107. }
  108. local lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  109. ------------------------------------------------------------------------------------------------------------------------
  110.  
  111. local EnvEditMenuId = win.Uuid("09814E7E-CBA7-43A4-9F65-0222E72CFADA")
  112. local EnvEditHelpId = win.Uuid("F9EDF605-EC94-4216-8353-A96E8BB7F42D")
  113. local EnvEditDeleteId = win.Uuid("1AA4D9CC-3173-43C2-9FB7-57842CD93EBC")
  114. local EnvEditRestoreId = win.Uuid("634F82F7-32F5-4BF8-BF5A-9469FD9E3124")
  115. local EnvEditRenameCopyId = win.Uuid("0A0A426D-EB4F-403C-B5F1-584B4507CE2D")
  116. local EnvEditOverwriteId = win.Uuid("8E58D881-339C-4274-9CBA-58BD3CF00BA4")
  117. local EnvEditPluginMenuId = "9F0AB063-515E-4E74-8214-5B801BA4B789"
  118. local EnvEditMacroId = "9C60576F-38F0-4974-A03D-2FF851343B20"
  119. local EnvEditChangeId = "5D2D74B0-B1CC-4091-AAA2-1C5789B14E01"
  120. local EnvEditEditorId = "D5D70290-C316-45F1-9EA1-5CF4188FB2C3"
  121.  
  122. local F = far.Flags
  123. local dialog = require "DialogClass"
  124. local ffi = require "ffi"
  125. local C = ffi.C
  126. ffi.cdef [=[
  127.     wchar_t* GetEnvironmentStringsW();
  128.     void FreeEnvironmentStringsW(wchar_t*);
  129.     size_t wcslen(const wchar_t*);
  130.     int SendMessageA(HWND, UINT, WPARAM, LPARAM);
  131.     int SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, DWORD_PTR*);
  132. ]=]
  133.  
  134. --local farbuild = select(4,far.AdvControl(F.ACTL_GETFARMANAGERVERSION,true))
  135. --local wrenable = farbuild >= 4491
  136.  
  137. local vtypes = {string="REG_SZ", expandstring="REG_EXPAND_SZ", REG_SZ="string", REG_EXPAND_SZ="expandstring"}
  138. local vtindex = {string=1, expandstring=2, REG_SZ=1, REG_EXPAND_SZ=2}
  139.  
  140. ------------------------------------------------------------------------------------------------------------------------
  141.  
  142. local mode = 1 -- что редактируем: 0:выходим, 1:для процесса, 2:для пользователя, 3:для системы
  143. local RootKey, PathKey
  144. local backup = {{Name="",Value="",Type=""},{Name="",Value="",Type=""},{Name="",Value="",Type=""}} -- сохранение предыдущего значения переменной для восстановления
  145.  
  146. ------------------------------------------------------------------------------------------------------------------------
  147. local function Message(msg,...)
  148.     return far.Message(" \n"..msg.."\n ",...)
  149. end
  150. ------------------------------------------------------------------------------------------------------------------------
  151. local environment, favorites, envmenu
  152.  
  153. local function FindVar(name) -- поиск переменной в меню для восстановления позиции
  154.     name = name:lower()
  155.     for i,var in ipairs(envmenu) do
  156.         if var.Name:lower()==name then
  157.             return i
  158.         end
  159.     end
  160.     return 0
  161. end
  162. ------------------------------------------------------------------------------------------------------------------------
  163. local HWND_BROADCAST = ffi.cast("HWND",0xffff)
  164. local WM_SETTINGCHANGE = 0x001A
  165. local SMTO_ABORTIFHUNG = 0x0002
  166. local MSG_TIMEOUT = 5000
  167.  
  168. local function SendSettingChange(mode)
  169.     if mode==nil or mode~=1 then -- для локальных переменных обновлять не надо
  170.         --C.SendMessageA(HWND_BROADCAST,WM_SETTINGCHANGE,0,ffi.cast("LPARAM","Environment"))
  171.         C.SendMessageTimeoutA(HWND_BROADCAST,WM_SETTINGCHANGE,0,ffi.cast("LPARAM","Environment"),SMTO_ABORTIFHUNG,MSG_TIMEOUT,ffi.cast("DWORD_PTR*",0))
  172.     end
  173. end
  174. ------------------------------------------------------------------------------------------------------------------------
  175. local function ModalEdit(text)
  176.     text = text:gsub(';','\n')
  177.     text = text:gsub('%b""',function(x) return x:gsub('\n',';') end) -- точки с зяпятой в кавычках
  178.     text = text:gsub('\n+','\n') -- лишние переводы строк
  179.     text = text.."\n"
  180.     dialog.New { -- рисуем пустой диалог с одной только рамкой, в которую впишем редактор
  181.         Guid = EnvEditEditorId,
  182.         W=cfg.EditorWidth, H=cfg.EditorHeight, Frame=2,
  183.         DlgProc = function(hDlg,Msg,Param1,Param2,D,DI)
  184.             if Msg==F.DN_DRAWDIALOGDONE then
  185.                 local coord = D:Send(F.DM_GETDLGRECT,0,0) -- реальные координаты окна после всех центровок
  186.                 local tmpfile = far.MkTemp()
  187.                 local hfile = io.open(tmpfile,"w") hfile:write(text) hfile:close()
  188.                 editor.Editor(tmpfile,lang.DialogTitle[op],coord.Left+4,coord.Top+2,coord.Right-4,coord.Bottom-2,bor(F.EF_DISABLEHISTORY,F.EF_DISABLESAVEPOS),0,0,65001)
  189.                 hfile = io.open(tmpfile,"r") text = hfile:read("*a") hfile:close()
  190.                 win.DeleteFile(tmpfile)
  191.                 D:Send(F.DM_CLOSE)
  192.             end
  193.         end
  194.     } ()
  195.     return text:gsub('[\n;]+',';'):gsub('[; ]+$',''):gsub('^[; ]+','')
  196. end
  197. ------------------------------------------------------------------------------------------------------------------------
  198. local function EditVar(var,op)
  199.     op = op or 1 -- 1:edit, 2:insert, 3:restore
  200.     local prev = {Name=var.Name,Value=var.Value,Type=var.Type}
  201.     local new = {Name=var.Name,Value=var.Value,Type=var.Type}
  202.     local D,DI = dialog.New {
  203.         Guid = EnvEditChangeId,
  204.         Title = lang.DialogTitle[op],
  205.         W = cfg.DialogWidth,
  206.         H = mode==1 and 10 or 12,
  207.         DlgProc = function(hDlg,Msg,Param1,Param2,D,DI)
  208.             if Msg==F.DN_CLOSE and Param1==DI.OkButton.Id then
  209.                 new.Name = DI.Name:GetText()
  210.                 new.Value = DI.Value:GetText()
  211.                 if mode~=1 then new.Type = DI.Type:GetText() end
  212.  
  213.                 -- При пустом имени или пустом значении вернёмся к редактированию
  214.                 if new.Name=="" or new.Value=="" then
  215.                     return false
  216.                 end
  217.  
  218.                 -- Спрашиваем переименовать, копировать или отменить при изменение имени при редактированиее.
  219.                 -- При отмене вернёмся к редактированию.
  220.                 local rc = 1 -- 0:cancel, 1:change, 2:rename, 3:copy
  221.                 if op==1 and new.Name:lower()~=prev.Name:lower() then
  222.                     rc = (Message(lang.RenameCopyMsg:format(prev.Name,new.Name),lang.RenameCopyTitle,lang.RenameButton..";"..lang.CopyButton..";"..lang.CancelButton,"","",EnvEditRenameCopyId)+1)%4
  223.                     if rc==0 then return true end
  224.                 end
  225.  
  226.                 -- Спрашиваем при переименовании, копировании, вставке или восстановлении если уже существует такая переменная
  227.                 if (rc>1 or op>1) and FindVar(new.Name)>0 then
  228.                     if Message(lang.OverwriteMsg:format(new.Name),lang.OverwriteTitle,";OkCancel","","",EnvEditOverwriteId)~=1 then
  229.                         return true
  230.                     end
  231.                 end
  232.  
  233.                 -- Если дошли сюда, значит наконец можно установить переменную
  234.                 if mode==1 then
  235.                     win.SetEnv(new.Name,new.Value)
  236.                     if rc==2 then -- при переименовании удалить старую переменную
  237.                         win.SetEnv(prev.Name,nil)
  238.                     end
  239.                 else
  240.                     win.SetRegKey(RootKey,PathKey,new.Name,vtypes[new.Type],new.Value)
  241.                     if rc==2 then -- при переименовании удалить старую переменную
  242.                         win.DeleteRegValue(RootKey,PathKey,prev.Name)
  243.                     end
  244.                     SendSettingChange()
  245.                 end
  246.                 var.Name,var.Value,var.Type = new.Name,new.Value,new.Type
  247.             end
  248.  
  249.             -- Вызов модального редактора
  250.             local key = (Msg==F.DN_CONTROLINPUT and Param2.EventType==F.KEY_EVENT and Param2.KeyDown) and far.InputRecordToName(Param2) or ""
  251.             if (Msg==F.DN_BTNCLICK and Param1==DI.EditButton.Id) or key=="F4" or key=="ShiftF4" then
  252.                 DI.Value:SetText(ModalEdit(DI.Value:GetText()))
  253.                 return true
  254.             end
  255.         end,
  256.     }
  257.     DI {"t+", Text=lang.NamePrompt}
  258.     DI {"e+", Name="Name", Text=var.Name, History=cfg.NameHistory}
  259.     if mode~=1 then
  260.         DI {"t+", Text=lang.TypePrompt}
  261.         DI {"xd+", Name="Type", W=14, LI={{Flags=0,Text="REG_SZ"},{Flags=0,Text="REG_EXPAND_SZ"},SelectIndex=vtindex[var.Type]}, Text=""}
  262.     end
  263.     DI {"t+", Text=lang.ValuePrompt}
  264.     DI {"e+", Name="Value", Text=var.Value, Flags=(op==1 and F.DIF_FOCUS or 0), History=cfg.ValueHistory}
  265.     DI {"s+"}
  266.     DI {"b=!+", Name="OkButton", Text=lang.OkButton}
  267.     DI {"b=", Name="CancelButton", Text=lang.CancelButton}
  268.     DI {"b=;", Name="EditButton", Text=lang.EditButton}
  269.     return D()==DI.OkButton.Id
  270. end
  271. ------------------------------------------------------------------------------------------------------------------------
  272. local function EditEnvironment()
  273.     lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  274.     local items, item
  275.     local pos = {0,0,0} -- текущая позиция в меню по каждому типу переменных
  276.     local jump -- переменная, если требуется изменение текущей pos
  277.     local MenuHotKeys = {
  278.                 {BreakKey="F1"},
  279.                 {BreakKey="F4"},{BreakKey="S+F4"},
  280.                 {BreakKey="F12"},{BreakKey="S+F12"},
  281.                 {BreakKey="INSERT"},{BreakKey="NUMPAD0"},
  282.                 {BreakKey="DELETE"},{BreakKey="DECIMAL"},{BreakKey="F8"},
  283.                 {BreakKey="TAB"},{BreakKey="C+TAB"},
  284.                 {BreakKey="S+TAB"},{BreakKey="CS+TAB"},
  285.     }
  286.     if cfg.ModeSwitch and cfg.ModeSwitch~="" then
  287.         MenuHotKeys[#MenuHotKeys+1] = {BreakKey=cfg.ModeSwitch}
  288.     end
  289.     local name, value, vtype
  290.     mode = cfg.StartMode
  291.     while mode>0 do -- цикл переключения списка отображаемых переменных 1/2/3 - процесс/пользователь/система
  292.         environment = {}
  293.         favorites = {}
  294.         envmenu = {}
  295.         if mode==1 then -- переменные процесса
  296.             local envstrings = C.GetEnvironmentStringsW()
  297.             local envptr = envstrings -- указатель на очередную переменную
  298.             local envlen = C.wcslen(envptr)
  299.             while envlen > 0 do
  300.                 value = win.Utf16ToUtf8(ffi.string(ffi.cast("char*",envptr),2*(envlen+1)))
  301.                 if value:sub(1,1)~="=" then -- кроме "=<диск>=<путь>"
  302.                     name,value = value:match("^(.-)=(.*)$")
  303.                     if name and value then
  304.                         environment[#environment+1] = {Name=name,Value=value}
  305.                     end
  306.                 end
  307.                 envptr = envptr+envlen+1 -- указатель на следующую строку
  308.                 envlen = C.wcslen(envptr)
  309.             end
  310.             C.FreeEnvironmentStringsW(envstrings)
  311.         else
  312.             local index = 0
  313.             if mode==2 then -- пользовательские переменные
  314.                 RootKey = "HKCU"
  315.                 PathKey = "Environment"
  316.             elseif mode==3 then -- системные переменные
  317.                 RootKey = "HKLM"
  318.                 PathKey = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
  319.             else
  320.                 return
  321.             end
  322.             name = win.EnumRegValue(RootKey,PathKey,index)
  323.             while name do
  324.                 value,vtype = win.GetRegKey(RootKey,PathKey,name)
  325.                 if vtypes[vtype] then
  326.                     environment[#environment+1] = {Name=name,Value=value,Type=vtypes[vtype]}
  327.                 end
  328.                 index = index+1
  329.                 name = win.EnumRegValue(RootKey,PathKey,index)
  330.             end
  331.         end
  332.         table.sort(environment,function(a,b) return(a.Name:lower()<b.Name:lower()) end)
  333.         for _,f in ipairs(cfg.Favorites) do -- формируем список избраного
  334.             for _,e in ipairs(environment) do
  335.                 if f:upper()==e.Name:upper() then
  336.                     e.Fav = true -- помечаем как избранное
  337.                     envmenu[#envmenu+1] = e
  338.                     break
  339.                 end
  340.             end
  341.         end
  342.         if #envmenu>0 and #envmenu<#environment then -- Разделитель между избранным и остальным
  343.             envmenu[#envmenu+1] = {Name="",separator=true}
  344.         end
  345.         for _,e in ipairs(environment) do -- Перенос оставшегося списка
  346.             if e.Name~="" and not e.Fav then
  347.                 envmenu[#envmenu+1] = e
  348.             end
  349.         end
  350.         for _,e in ipairs(envmenu) do -- Форматируем для far.Menu
  351.             if not e.separator then
  352.                 e.text = ("%%-%is │ %%-%is"):format(cfg.NameWidth,cfg.ValueWidth):format(e.Name:sub(1,cfg.NameWidth),e.Value:sub(1,cfg.ValueWidth))
  353.             end
  354.         end
  355.         if jump then -- определяем позицию для перехода (после вставки, переименования и т.п.)
  356.             pos[mode] = FindVar(jump)
  357.             jump = nil
  358.         end
  359.         while true do -- цикл - показываем меню / обрабатываем клавиши
  360.             local res
  361.             res,pos[mode] = far.Menu(
  362.                 {
  363.                     Title=lang.MenuTitle[mode],
  364.                     Bottom=lang.MenuBottom,
  365.                     SelectIndex=pos[mode],
  366.                     Id=EnvEditMenuId,
  367.                     Flags=bor(F.FMENU_SHOWAMPERSAND,F.FMENU_WRAPMODE),
  368.                     MaxHeight=cfg.MenuHeight,
  369.                 },
  370.                 envmenu, MenuHotKeys
  371.             )
  372.             if res==nil then -- Esc
  373.                 mode = 0
  374.                 break
  375.             --elseif not res.BreakKey or (res.BreakKey and (res.BreakKey=="F4" or res.BreakKey=="S+F4")) then -- Enter, F4
  376.             elseif not res.BreakKey then -- Enter
  377.                 local var = envmenu[pos[mode]]
  378.                 if EditVar(var) then
  379.                     jump = var.Name
  380.                     break
  381.                 end
  382.             elseif res.BreakKey=="F4" or res.BreakKey=="S+F4" then -- модальный редактор
  383.                 local var = envmenu[pos[mode]]
  384.                 var.Value = ModalEdit(var.Value)
  385.                 if var.Value=="" then var.Value=nil end -- пустое значение - удаляем переменую
  386.                 if mode==1 then
  387.                     win.SetEnv(var.Name,var.Value)
  388.                     jump = var.Name
  389.                     break
  390.                 elseif var.Value then
  391.                     win.SetRegKey(RootKey,PathKey,var.Name,vtypes[var.Type],var.Value)
  392.                     jump = var.Name
  393.                     SendSettingChange()
  394.                     break
  395.                 else
  396.                     backup[mode] = {Name=var.Name,Value=var.Value,Type=var.Type}
  397.                     win.DeleteRegValue(RootKey,PathKey,prev.Name)
  398.                     SendSettingChange()
  399.                     break
  400.                 end
  401.             elseif res.BreakKey=="F12" or res.BreakKey=="S+F12" then -- восстановление
  402.                 local var = {Name=backup[mode].Name,Value=backup[mode].Value,Type=backup[mode].Type}
  403.                 if var.Name=="" then
  404.                     Message(lang.NoRestore,lang.RestoreTitle,";Ok","","",EnvEditRestoreId)
  405.                 elseif EditVar(var,3) then
  406.                     jump = var.Name
  407.                     SendSettingChange(mode)
  408.                     break
  409.                 end
  410.             elseif res.BreakKey=="INSERT" or res.BreakKey=="NUMPAD0" then
  411.                 local var = {Name=lang.NewName,Value=lang.NewValue}
  412.                 if mode~=1 then var.Type="REG_SZ" end
  413.                 if EditVar(var,2) then
  414.                     jump = var.Name
  415.                     SendSettingChange(mode)
  416.                     break
  417.                 end
  418.             elseif res.BreakKey=="DELETE" or res.BreakKey=="DECIMAL" then
  419.                 local var = envmenu[pos[mode]]
  420.                 if Message(lang.DeleteMsg:format(var.Name),lang.DeleteTitle,";OkCancel","","",EnvEditDeleteId) == 1 then
  421.                     backup[mode] = {Name=var.Name,Value=var.Value,Type=var.Type}
  422.                     if mode==1 then
  423.                         win.SetEnv(var.Name,nil)
  424.                     else
  425.                         win.DeleteRegValue(RootKey,PathKey,var.Name)
  426.                         SendSettingChange()
  427.                     end
  428.                     if pos[mode]==#envmenu then pos[mode]=pos[mode]-1 end
  429.                     break
  430.                 end
  431.             elseif res.BreakKey=="TAB" or res.BreakKey=="C+TAB" or res.BreakKey==cfg.ModeSwitch then
  432.                 mode = mode + 1
  433.                 if mode>3 then mode = 1 end
  434.                 break
  435.             elseif res.BreakKey=="S+TAB" or res.BreakKey=="CS+TAB" then
  436.                 mode = mode - 1
  437.                 if mode<1 then mode = 3 end
  438.                 break
  439.             elseif res.BreakKey=="F1" then
  440.                 Message(lang.MenuHelpMsg:gsub('%s*\n%s*','\n'):gsub('^%s+',''):gsub('[%s%c]+$',''),lang.MenuHelpTitle,";Ok","l",nil,EnvEditHelpId)
  441.             end
  442.         end
  443.     end
  444. end;
  445. ------------------------------------------------------------------------------------------------------------------------
  446. if cfg.MacroKey and cfg.MacroKey~="" then
  447.     Macro {
  448.         description = "EnvEdit";
  449.         area = "Shell Search QView Info Tree Editor Viewer";
  450.         guid = EnvEditMacroId;
  451.         key = "AltShiftE";
  452.         action = EditEnvironment;
  453.     }
  454. end
  455. ------------------------------------------------------------------------------------------------------------------------
  456. if cfg.PluginMenu then
  457.     MenuItem {
  458.         description = "EnvEdit";
  459.         menu = "Plugins";
  460.         area = "Shell Search QView Info Tree Editor Viewer";
  461.         guid = EnvEditPluginMenuId;
  462.         text = function(menu,area)
  463.             lang = langs[win.GetEnv("FARLANG"):lower()] or langs.english
  464.             return lang.PluginMenuDesc
  465.         end;
  466.         action = EditEnvironment;
  467.     }
  468. end
  469. ------------------------------------------------------------------------------------------------------------------------

Пример файла настроек
  1. ------------------------------------------------------------------------------------------------------------------------
  2. -- Конфигурация
  3. ------------------------------------------------------------------------------------------------------------------------
  4. cfg.DialogWidth = 100 -- ширина диалога редактирования
  5. cfg.EditorWidth = 100 -- ширина окна редактора
  6. cfg.EditorHeight = 30 -- высота редактора
  7. cfg.NameWidth = 30 -- ширина поля под имя переменной в списке
  8. cfg.ValueWidth = 80 -- ширина поля под значение переменной в списке
  9. cfg.MenuHeight = 40 -- максимальная высота списка, высота окна списка = MenuHeight+4
  10. cfg.MacroKey = "AltShiftE" -- клавиши для вызова макроса, если пустая строка, макрос будет отключен
  11. cfg.ModeSwitch = "AS+E" -- для быстрого переключения списков после вызова макроса "не отрываясь от клавиатуры"
  12. cfg.StartMode = 1 -- с чего начинаем: 1 - для процесса, 2 - для пользователя, 3 - для системы
  13. cfg.NameHistory = "" -- имя истории для имён переменных, если пустая строка, история отключена
  14. cfg.ValueHistory = "" -- имя истории для значения переменных, если пустая строка, история отключена
  15. cfg.PluginMenu = true -- добавлять или нет вызов из меню плагинов
  16. cfg.Favorites = {"PATH","PATHEXT","PSModulePath"} -- переменные, которые без сортировки будут показаны в начале списка
  17. ------------------------------------------------------------------------------------------------------------------------
Attachments
EnvEdit.1.08.7z
EnvEdit 1.08
(7.08 KiB) Downloaded 56 times
Last edited by Smitis on Sun 12 Jun, 2016 07:23, edited 14 times in total.

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

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

Postby HaRT » Sat 19 Dec, 2015 23:35

Скрипт не пробовал, но интересно, правильно ли будут разбиваться пути, некоторые из которых закавычены из-за наличия в них точки с запятой.
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
DrKnS
Posts: 4458
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 105 times
Contact:

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

Postby DrKnS » Sun 20 Dec, 2015 02:45

Smitis wrote:Source of the post - При изменении переменных через реестр, надо бы послать HWND_BROADCAST с WM_SETTINGCHANGE как минимум. Но что-то не заладилось, посмотрите, кто в теме, плиз. (Раньше делал через вызов setx.exe, там сообщение посылалось автоматически).
Как-то так:
  1. ffi.cdef[[int SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, DWORD_PTR*);]]
  2. local HWND_BROADCAST = ffi.cast("HWND", 0xffff)
  3. local WM_SETTINGCHANGE = 0x001A
  4. local SMTO_ABORTIFHUNG = 0x0002
  5. local MSG_TIMEOUT = 5000
  6. 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: 1700
Joined: Thu 04 Aug, 2005 18:47
Location: Харьков, Украина
Has thanked: 2 times
Been thanked: 9 times
Contact:

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

Postby Wave » Sun 20 Dec, 2015 10:29

А мне интересен аналог плагина EnvMan. Т.е. который может группировать переменные окружения в пакеты и в любой момент разворачивать их в пользовательскую среду. Нужно это для работы с серверами, т.е. чтобы мог быстро развернуть кучу переменных с путями php и т.п., а в плагине не устраивает его привязанность к реестру — свои настройки он в реестре хранит (не до конца портирован на FAR3).
Пользуюсь ФАРом больше 15 лет © собирательный.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Sun 20 Dec, 2015 12:23

HaRT wrote:Скрипт не пробовал, но интересно, правильно ли будут разбиваться пути, некоторые из которых закавычены из-за наличия в них точки с запятой.
Не правильно будут - кавычки не проверяются. Но в принципе, можно сделать.
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Mon 21 Dec, 2015 09:05

v. 1.01
- Сделал восстановление удаленной переменной по F12 (хранится до перезагрузки макросов).
- HWND_BROADCAST посылается, но не знаю, правильно ли.
Правильная работа гарантируется только в luafar/luamacro >= build 552 (ночная сборка 4488).
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Mon 21 Dec, 2015 10:22

v. 1.02
- По многочисленным просьбам :) при вызове встроенного редактора точки с запятой в кавычках в разбивке на строки не участвуют.
- Тип переменной сделан списком.
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Tue 22 Dec, 2015 08:40

Wave wrote:А мне интересен аналог плагина EnvMan. Т.е. который может группировать переменные окружения в пакеты и в любой момент разворачивать их в пользовательскую среду. Нужно это для работы с серверами, т.е. чтобы мог быстро развернуть кучу переменных с путями php и т.п., а в плагине не устраивает его привязанность к реестру — свои настройки он в реестре хранит (не до конца портирован на FAR3).
Посмотрел, может быть слишком поверхостно, но как-то не проникся. Тоже самое я делаю командными файлами (или PowerShell), более гибко получается.
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Tue 22 Dec, 2015 15:00

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

П.С.
Вот сейчас подумалось, по сравнению с тем что было до публикации здесь, из функционала реально добавилось восстановление удалённой переменной и не очень нужные мне переменные процесса. Да, я привёл скрипт более или менее в порядок, переделал без вызова внешней утилиты, добавил конфигурацию, изменение языка, но времени на это потратилось даже больше, чем на редактирование этих переменных за последний год (один раз при переустановке винды, два-три раза правил path). :)
Разум когда-нибудь победит.

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

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

Postby HaRT » Tue 22 Dec, 2015 16:12

Smitis wrote:Source of the post Исправлена отправка HWND_BROADCAST (LPARAM передавался не тем параметром). Но всё равно не знаю, правильно отправляется или нет.
Думаю, можно частично проверить другим экземпляром Фара: если он не подхватывает изменения, то отправляется точно неправильно. ;)
Фар есть инструмент, а не нянька. © 2009 DrKnS

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Tue 22 Dec, 2015 22:22

Забыл про эту фичу. Попробовал. Не приходит. Через setx приходит, а так нет.
Разум когда-нибудь победит.

User avatar
DrKnS
Posts: 4458
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 105 times
Contact:

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

Postby DrKnS » Tue 22 Dec, 2015 22:46

Smitis wrote:Source of the post Не приходит.

Я ж вроде выше уже написал, как правильно посылать.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Wed 23 Dec, 2015 07:58

DrKnS
Что-то у меня вчера переклинило. Ни в каком виде не хотело работать.
А сейчас с утра Ваш вариант заработал.
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Wed 23 Dec, 2015 09:16

v. 1.04

- Отправка HWND_BROADCAST.
Разум когда-нибудь победит.

Smitis
Posts: 1430
Joined: Fri 18 Mar, 2005 12:51
Location: Питер
Has thanked: 9 times
Been thanked: 21 times
Contact:

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

Postby Smitis » Fri 25 Dec, 2015 14:51

v. 1.05

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

User avatar
DrKnS
Posts: 4458
Joined: Thu 04 Aug, 2005 06:44
Location: Kyiv
Has thanked: 2 times
Been thanked: 105 times
Contact:

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

Postby DrKnS » Fri 25 Dec, 2015 15:04

Smitis wrote:Source of the postИначе нельзя выйти по ESC при пустом имени

Так Param1 надо проверять.


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

Who is online

Users browsing this forum: No registered users and 1 guest