FAR Manager
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.175] |
|
|
ПРАВИЛА РАЗДЕЛА
FAR Manager
|
Прикр. сообщ.
#1
,
|
|
|
|
Far Manager
Windows. FreeWare. Многофункциональный файловый менеджер для работы с различными файлами, позволяет просматривать файлы и каталоги, редактировать, копировать и переименовывать файлы. Поддерживает Unicode имеет удобный и простой в использовании пользовательский интерфейс с многоязычной поддержкой. Позволяет работать с архивами, FTP-клиентами, и просматривать сеть с помощью реализованных в стандартную поставку плагинов. Кроме того есть возможность расширения функциональности за счет подключения дополнительных плагинов. ![]() Ну очень странно что его уже давным давно не включили в разделе "Полезного ПО" Подключаемые модули (плагины) Возможности FAR существенно расширяются благодаря плагинам различного назначения: Домашняя страничка: https://farmanager.com |
|
Сообщ.
#1
,
|
|
|
|
Lua-скрипт EditorTools
Позволяет подключать и исполнять в редакторе Far'а различные обработчики - фильтры, компиляторы, интерпретаторы. Исполнять их без отрытия дополнительных окон, отлавливать stdout и stdrr, загружать результаты обработки назад в редактор, выводить сообщения об ошибках и результатах обработки в виде диалогов. Возможно кому-то пригодится. Предыстория Для быстрого редактирования файлов - встроенный редактор Far'а просто прекрасен. Но, к сожалению, определенных функций в нем не хватает. Конечно можно, при наличии времени и сил, сесть и написать свой инструмент обработки в виде полноценного плагина, либо Lua-скрипта. Меня же заинтересовал чисто практический вопрос - найти способ подключения уже готовых инструментов не через подсистему ассоциаций файлов. Надоело сохраняться, обрабатывать файл, потом опять грузить файл в редактор. Ну и вот родилась идея создать более-менее универсальное средство. Прошу учесть - это моя первая программа на языке Lua, так что принимайте мой отказ от ответственности, еличе ![]() На момент написания скрипта мне нужно было подключить: Функионал Команды обработки прописываются в файл конфигурации EditorTools.conf, который лежит рядом с макросом. Программы могут работать в четырех режимах: 1) Filter Используется для запуска программ, которые могут непосредственно вносить изменения в файл. После выполнения содержимое редактора заменяется результатом обработки 2) Pipe Используется для запуска программ, которые могут читать и обрабатывать файл, но вывод умеют делать только в STDOUT После выполнения содержимое редактора заменяется результатом обработки 3) Compiler Используется для запуска компиляторов После выполнения выводится диалог об успешной компиляции, либо диалог, содержащий ошибки компилятора 4) Execute Используется для запуска как правило интерпретаторов После выполнения выводится диалог, в котором отображается результат обрабтки текста внешней программой Скрипт EditorTools.lua Скрытый текст ![]() ![]() ------------------------------------------------------------------------------------------------------------------------ -- Скрипт EditorTools v.1.1 -- подключение внешних инструментов в редакторе Far'а -- -- 2020 (C) Автор Majestio aka JoeUser -- -- http://majestio.info -- ------------------------------------------------------------------------------------------------------------------------ -- local inspect = require('inspect') local ScriptName = ... local EOPT_BOM = 0x00000200 local BTYPE_STREAM = 1 local SW_HIDE = 0 ------------------------------------------------------------------------------------------------------------------------ local EditorTools = function () local CurPath = mf.fsplit(ScriptName,3) local ConfigName = ScriptName:gsub("[^.]+$","conf") local Conf = io.open(ConfigName,"r") -- читаем файл конфигурации ------------------------------------------------------------------------------------------ if Conf == nil then far.Message('Файл конфигурации нельзя прочесть!', 'Ошибка', ';Ok', 'w') return else local Cmd = {} local Idx = 1 -- разбираем файл конфигурации на список "инструментов" ------------------------------------------------------------ for line in Conf:lines() do if regex.match(line,'^(F|P|C|E)') then for w1,w2,w3 in regex.gmatch(line, "^(F|P|C|E)\\s*,\\s*'\\s*([^']+?)\\s*'\\s*,\\s*'\\s*([^']+?)\\s*'\\s*$") do Cmd[Idx] = {w1,w2,w3} end Idx = Idx + 1 end end Conf:close() -- формируем и выводим диалог выбора "инструментов" ---------------------------------------------------------------- local Choice = '' for Idx = 1, #Cmd do Choice = Choice..Cmd[Idx][2]..'\n'; end local ChoiceIdx = Menu.Show(Choice, nil, 8+0x200) if ChoiceIdx == 0 then return end -- формируем имя временного файла для сброса содержимого редактора ------------------------------------------------- math.randomseed(os.time()) local RndNumber = math.random(1000) local EditorFullName = editor.GetFileName() local EditorFilePath = regex.match(EditorFullName,"^(.+\\\\).+$") local EditorFileName = regex.match(EditorFullName,"^.+\\\\([^\\.]+)\\.*.*$") local EditorFileExt = regex.match(EditorFullName,"^.+?\\.([^\\.]+)$") if EditorFileExt == nil then EditorFileExt = "" end local TmpName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'..EditorFileExt local OutName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."out" local ResName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."res" local ErrName = EditorFilePath..EditorFileName..'-tmp-'..RndNumber..'.'.."err" -- в командной строке производим замены в плэйсхолдерах ------------------------------------------------------------ local CmdName = regex.gsub(Cmd[ChoiceIdx][3],"%p",EditorFilePath) -- %p на значение EditorFilePath CmdName = regex.gsub(CmdName,"%n",EditorFileName) -- %n на значение EditorFileName CmdName = regex.gsub(CmdName,"%e",EditorFileExt) -- %e на значение EditorFileExt CmdName = regex.gsub(CmdName,"%t",TmpName) -- %t на значение TmpName CmdName = regex.gsub(CmdName,"%o",OutName) -- %o на значение OutName CmdName = regex.gsub(CmdName,"%r",ResName) -- %r на значение ResName -- запускаем внешнюю обработку в зависимости от "режима" выбранного инструмента ------------------------------------ if WriteFile(TmpName) ~= nil then local Out, Err = ExecCommand(CmdName, TmpName, OutName, ResName, ErrName, Cmd[ChoiceIdx][1]) if Cmd[ChoiceIdx][1] == "C" then if Err == "" or Err == nil then far.Message("Компиляция прошла удачно", 'Результат компиляции', ';Ok', 'k') else far.Message(win.OemToUtf8(Err), 'Ошибка', ';Ok', 'w') end else if Out ~= "" and Out ~= nil then if Cmd[ChoiceIdx][1] == "E" then far.Message(win.WideCharToMultiByte(win.MultiByteToWideChar(Out,1251),65001), 'Результат выполнения', ';Ok', 'k') else LoadContent(Out) end else if Err == "" or Err == nil then far.Message('Обработчик вернул пустой вывод!', 'Ошибка', ';Ok', 'w') end end end else far.Message('Ошибка записи временного файла!!', 'Ошибка', ';Ok', 'w') end end end ------------------------------------------------------------------------------------------------------------------------ -- Загрузка файла в редактор ------------------------------------------------------------------------------------------------------------------------ function LoadContent(Content) local Ei = editor.GetInfo() local EId = Ei.EditorID local Flags = far.Flags editor.UndoRedo(EId, Flags.EUR_BEGIN) editor.Select(EId, BTYPE_STREAM, 1, 1, 1, Ei.TotalLines+1) editor.DeleteBlock(EId) Content = regex.gsub(Content,"^(\xef\xbb\xbf)","") editor.InsertText(EId,Content) editor.UndoRedo(EId,Flags.EUR_END) editor.SetPosition(EId, 1, 1) end ------------------------------------------------------------------------------------------------------------------------ -- Запуск процесса по обработке файла ------------------------------------------------------------------------------------------------------------------------ function ExecCommand(CmdName, TmpName, OutName, ResName, ErrName, Mode) local RetOut, RetErr local File = io.popen(('"%s >"%s" 2>"%s"'):format(CmdName, OutName, ErrName),"w") if File == nil then far.Message('Ошибка при запуске команды!', 'Ошибка', ';Ok', 'w') return nil, nil end File:close() local TheName = OutName if Mode ~= "P" and Mode ~= "E" then TheName = ResName end if win.GetFileInfo(TheName) ~= nil then OutFile = io.open(TheName) if OutFile~= nil then RetOut = OutFile:read("*a") OutFile:close() end end if win.GetFileInfo(ErrName) ~= nil then ErrFile = io.open(ErrName) if ErrFile~= nil then RetErr = ErrFile:read("*a") ErrFile:close() end end win.ShellExecute(nil,nil,win.GetEnv"COMSPEC",('/c "del "%s" "%s" "%s" "%s"'):format(TmpName, OutName, ResName, ErrName),nil,SW_HIDE) return RetOut, RetErr end ------------------------------------------------------------------------------------------------------------------------ -- Запись файла ------------------------------------------------------------------------------------------------------------------------ function WriteFile (FileName) local Info = editor.GetInfo() local File = io.open(FileName,"wb") if File == nil then far.Message('Ошибка записи временного файла!', 'Ошибка', ';Ok', 'w') return nil else if (bit.band(Info.Options, EOPT_BOM) == EOPT_BOM) then File:write(string.char(239,187,191)) end for Line = 1, Info.TotalLines do local Gs = editor.GetString(Info.EditorID, Line, 0) File:write(Gs.StringText, Gs.StringEOL) end File:close() return Info.TotalLines end end ------------------------------------------------------------------------------------------------------------------------ -- Macro ------------------------------------------------------------------------------------------------------------------------ Macro { area="Editor"; key="CtrlE"; flags=""; description="EditorTools"; action = function() EditorTools() end; } Пример конфига EditorTools.conf Скрытый текст ![]() ![]() ; Поля конфига следующие: ; ; Режим, "Название-инструмента", "командная строка" ; ; Режим: ; ; [F]ilter - записываем временный файл, обрабатываем его, потом загружаем в редактор ; [P]ipe - записываем временный файл, обрабатываем его, но загружаем STDOUT программы ; [C]ompiler - сохраняем файл, запускаем команду компилятора ; [E]xecute - сохраняем файл, запускаем команду интерпретатора, результат выводим в виде диалога ; ; Плейсхолдеры: ; ; %p - путь к файлу в редакторе ; %n - имя файла в редакторе (без расширения) ; %e - расширение имени файла в редакторе ; %t - полное имя временного файла ; %o - полное имя временного файла-результата (куда пишется из пайпа) ; %r - полное имя временного файла-результата (куда может писать сама программа) ; ; Пример: ; ; F,'Инструмент-1','comm-1.cmd' ; P,'Инструмент-2','comm-2.cmd' ; C,'Инструмент-3','comm-3.cmd' ; E,'Инструмент-4','comm-4.cmd' ; P,'AStyle (Space-P)','C:\Tools\AStyle\AStyle.exe --options=C:\Tools\AStyle\.astylerc-space --stdin=%t' F,'AStyle (Space-F)','C:\Tools\AStyle\AStyle.exe --options=C:\Tools\AStyle\.astylerc-space --stdin=%t --stdout=%r' P,'TidyP','C:\Tools\Tidy\tidy.exe -config c:\Tools\Tidy\tidy.conf "%t"' P,'Hello Ruby','ruby.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\hello.rb' P,'Test Perl-P','perl.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\test-p.pl "%p%n.%e"' F,'Test Perl-F','perl.exe C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools\test-f.pl "%t" "%r"' C,'Компилировать FASM программу','C:\Tools\Fasm\FASM.CMD "%t" "%p%n.exe"' E,'Исполнить Perl скрипт','perl.exe %t' E,'Исполнить SWI-Prolog скрипт','C:\Tools\Prolog\bin\swipl.exe -q -f %t' Мои конфиги форматеров Скрытый текст .astylerc-space ![]() ![]() align-pointer=type align-reference=type attach-classes attach-closing-while attach-extern-c attach-inlines attach-namespaces attach-return-type break-one-line-headers close-templates delete-empty-lines indent-cases indent-classes indent-col1-comments indent-modifiers indent-namespaces indent-preproc-block indent-preproc-define indent-switches indent=spaces=2 keep-one-line-blocks max-continuation-indent=40 min-conditional-indent=1 pad-comma pad-header pad-oper remove-brackets style=java unpad-paren .astylerc-tabs ![]() ![]() align-pointer=type align-reference=type attach-classes attach-closing-while attach-extern-c attach-inlines attach-namespaces attach-return-type break-one-line-headers close-templates delete-empty-lines indent-cases indent-classes indent-col1-comments indent-modifiers indent-namespaces indent-preproc-block indent-preproc-define indent-switches indent=force-tab=2 keep-one-line-blocks max-continuation-indent=40 min-conditional-indent=1 pad-comma pad-header pad-oper remove-brackets style=java unpad-paren tidy.conf ![]() ![]() // sample config file for HTML tidy indent: auto indent-spaces: 2 wrap: 0 markup: yes output-xml: no input-xml: no show-warnings: yes numeric-entities: yes quote-marks: yes quote-nbsp: yes quote-ampersand: no break-before-br: no uppercase-tags: no uppercase-attributes: no char-encoding: utf8 new-inline-tags: cfif, cfelse, math, mroot, mrow, mi, mn, mo, msqrt, mfrac, msubsup, munderover, munder, mover, mmultiscripts, msup, msub, mtext, mprescripts, mtable, mtr, mtd, mth new-blocklevel-tags: cfoutput, cfquery new-empty-tags: cfelse drop-empty-elements: no Установка Скрипт и его конфиг нужно переписать в каталог скриптов (в свой подкаталог). Перезапустить Far. Для себя я настроил Far так, чтобы каталог профилей лежал рядом, а не в домашнем каталоге. По итогу у меня макрос лежит в каталоге - C:\Tools\Far3-x64\Profile\Macros\scripts\EditorTools Если будут вопросы - прошу в личку. Чтобы не засорять тред про Far. |
|
Сообщ.
#2
,
|
|
|
|
А чем он лучше Total Commander-a ?
|
|
Сообщ.
#3
,
|
|
|
|
Цитата ... @ А чем он лучше Total Commander-a ? Три преимущества (ну на вкус и цвет): * удобная работа с консольными программами * встроенный быстрый редактор, который как и сам Фар можно обвесить плагинами * уже давно подключили поддержку Lua, с нативными плагинами можно не париться |
|
Сообщ.
#4
,
|
|
|
|
Цитата ... @ А чем он лучше Total Commander-a ? Total - это как DOS Navigator: швейцарский нож, уже не помещающийся в руку из-за неудобной толщины. А вот FAR - это классический Norton, быстро и легко. Мультитул, у которого можно отстегнуть всё лишнее. |
|
Сообщ.
#5
,
|
|
|
|
Цитата Mr.Delphist @ А вот FAR - это классический Norton, быстро и легко. Мультитул, у которого можно отстегнуть всё лишнее. Когда-то был более удачный вариант - Volkov Commander, типа Нортона - но гораздо шустрее и меньше хавал ресурсов. А на счет FAR'а - полностью согласен. А если его запускать под ConEmu, то еще добавляется мешок сахара. |
|
Сообщ.
#6
,
|
|
|
|
Я даже видел гика, что запускал FAR из-под вайна вместо MC в линухе.
|
|
Сообщ.
#7
,
|
|
|
|
Цитата Qraizer @ видел гика, что запускал FAR из-под вайна вместо MC в линухе. О, мсье знает толк в извращениях! |
|
Сообщ.
#8
,
|
|
|
|
Цитата Qraizer @ Я даже видел гика, что запускал FAR из-под вайна вместо MC в линухе. Мну сейчас запускает Far2 из под Wine 6.10 в рамках LiveCD Linux Puppy (пакет собранный взял из топика форума Puppy) P.S. После запуска Far2 через команду терминала: wine Far.exe дальше запускаю Total Commander, а через него повторно Far2 для получения графического вида гуи Fara ![]() Windows софт, запускаемый в рамках окружения Linux, зачастую показывает лучшую "рабочесть" чем в родной для него Windows! и это приятно удивляет и при этом не требует гигабайт дискового пространства для установки Windows системы нативно или в VM (виртуальные машины) |
|
Сообщ.
#9
,
|
|
|
|
Кто-то знает (может объяснить) отчего так:
1. Создаю 3 файла: a-.txt, a!.txt и a=.txt 2. Они сортируются в Far'е именно в таком порядке, но по коду символа должно быть: a!.txt, a-.txt, a=.txt т.к. : код(!)=$21, код(-)=$2D, код(=)=$3D. Т.е. почему знак '-' столь важен стал? Добавлено П.С. вот запустил в NDN (Necro... DOS Navigator), там всё правильно! И виндовый проводник сортирует как надо. |
|
Сообщ.
#10
,
|
|
|
|
По тыкайте Ctrl+F<3-11> и посмотрите разные варианты
|
|
Сообщ.
#11
,
|
|
|
|
Да, по Ctrl-F7 (Несорт) стало сортировать нормально. Но это ж не выход, т.к. у меня всегда установлена сортировка по расширению. Непонятна причина, увы.
|
|
Сообщ.
#12
,
|
|
|
|
Так он сортирует по одному указанному критерию. По другим критериям никаких гарантий какого-либо порядка. Тебе же нужно два критерия одновременно. Вроде было как-то у них на форуме обсуждение объединения нескольких критериев для создания своих правил, но к чему пришли, я не знаю. Мож плагин какой нарелизили.
|
|
Сообщ.
#13
,
|
|
|
|
Впрочем, чушь это. Даже если включить сортировку по имени, всё равно тот же результат.
Я порылся в FARовых сырцах, там всё упирается в CompareString() суть WinAPI. Проверил (основано на string_sort.cpp / compare_natural_base()): ![]() ![]() #include <windows.h> #include <iostream> #include <string> #include <map> std::string Str1 = "a!"; std::string Str2 = "a-"; int main() { auto Flags = LINGUISTIC_IGNORECASE | SORT_STRINGSORT; auto Result= CompareString(LOCALE_USER_DEFAULT, Flags, Str1.data(), static_cast<int>(Str1.size()), Str2.data(), static_cast<int>(Str2.size())); std::cout << [](int x){ return std::map<int, std::string>{{0, std::to_string(GetLastError())}, {CSTR_LESS_THAN, "Less" }, {CSTR_EQUAL, "Equal" }, {CSTR_GREATER_THAN, "Greater"}}[x]; }(Result); } ![]() ![]() Greater P.S. Если будет выдавать цифры, значит CompareString() вернула эррор, и это системный код ошибки last error |
|
Сообщ.
#14
,
|
|
|
|
Если интересно, то Calculate Linux 6.6.57 + wine (wine-9.20 (Staging) или wine-9.0 (Proton-9.0-2)) при установленной Windows 10 в префиксе выдают Greater.
|
|
Сообщ.
#15
,
|
|
|
|
В общем, разгадка на поверхности, хотя и не так уж очевидна. CompareString() же выполняет лексикографическое сравнение с учётом национальных предпочтений. Это очевидно. А вот что не так уж, так это то, что '-' ассоциируется с дефисами и тире, в частности переносами, как явными, так и мягкими. Ну и лексикографически они располагаются перед разделителями, типа там пробел, таб итп, т.к. по сравнению с ними должны иметь меньший вес.
Я заглянул в 7-ку, там такое же поведение. Даже поставил XPю на виртуалку и заморочился пакетом её поддержки в Студии, что собрать под неё. И в ней тоже Greater. Осталось только ради интереса чекнуть 98SE, но это VS6 расчехлять... ну так мы тут крутые парни или зумеры ленивые |
|
Сообщ.
#16
,
|
|
|
|
В общем, это был непростой процесс. Даже на виртуалке под современными процессорами 98-я не работает должным образом. Пришлось искать патчи. Но это уже был не просто спортивный интерес, это было дело принципа. Нашёл образ, нашёл патчи, нашёл ключ активации, проинсталил, нашёл, как и чем собрать под Win98. Greater. Ну кто б сомневался.
|
|
Сообщ.
#17
,
|
|
|
|
Цитата Qraizer @ Частично. Указывая сортировать по расширению, он группирует мои *.txt-файлы, это так. Но далее меня б более чем устроила сортировка по коду символа (в некоем смысле это очевидный порядок), но разрабы зачек-то замутили ещё какой-то смысл в дальнейшем упорядочении. Эх... Так он сортирует по одному указанному критерию. По другим критериям никаких гарантий какого-либо порядка. Тебе же нужно два критерия одновременно. |
|
Сообщ.
#18
,
|
|
|
|
Это не разрабы, это правила юникода. Тебе бы понравилось, если файлы с именами из латиницы+кириллицы сортировались на основе хрен пойми чего вместо национальных правил? и заметь, кириллица не обязательно означает русский, как и латиница не обязательно английский, французы с немцами тебе это подтвердят, а уж турки так вообще.
|
|
Сообщ.
#19
,
|
|
|
|
Цитата Qraizer @ 1. Хочется пример этого "хрен пойми чего", дабы не на эмоциях рассуждать, а по логике.Тебе бы понравилось, если файлы с именами из латиницы+кириллицы сортировались на основе хрен пойми чего вместо национальных правил? 2. Думаю, что понравилось бы, несмотря на местами встречавшийся порядок "ЁЈАБВ...", т.к. логика абсолютна. |
|
Сообщ.
#20
,
|
|
|
|
Хозяйке на заметку: временнЫе штампы
Может кому и пригодиться... Моя шляпа позволяет в начало имени файла или каталога вставлять дату-время. Спросите "зачем это надо". А-б-и-с-ь-н-я-ю! Очень удобно иметь список файлов и каталогов, отсортированных по имени (а по факту по дате-времени) не меняя порядок сортировки в самом ФАРе. Особенно прекрасно это ощущается в каталогах резервных копий - просто душа дятлом поёт!!! Т.е. делаете просто файл или каталог под именем "1", травите на него команду и получаете к примеру "2025.08.19-15.43.56_1". Осталось только при переименовании убрать последних два символа, если нужен просто временной штамп. ⭐ Солюшен 1) В самом ФАРе делаете очередной пункт меню в его меню, вызываемом по [F2], допустим "Вставить временной штамп" 2) В качестве горячей клавиши что угодно, а можно и без нее. А в качестве команды что-то типа C:\Tools\set-timestamp.cmd "!.!", ну или ваш варик В качестве командного файла: ![]() ![]() @echo off SET HOUR=%TIME:~0,2% SET STAMP=%date:~6,4%.%date:~3,2%.%date:~0,2%-%HOUR: =0%.%TIME:~3,2%.%TIME:~6,2% SET FOLDER=%STAMP::=-% SET FILE=%1 SET FILE=%FILE:~1,-1% ren %1 "%FOLDER%_%FILE%" |
|
Сообщ.
#21
,
|
|
|
|
Нужна была подобная функциональность для ведения логов. Никак не смог заставить возвращать секунды.
|
|
Сообщ.
#22
,
|
|
|
|
Цитата Qraizer @ Никак не смог заставить возвращать секунды. ?? %TIME% возвращает секунды с точностью до сотых... |
|
Сообщ.
#23
,
|
|
|
|
Я ж об этом. Сорри, непонятно выразился. Я использовал что-то типа
![]() ![]() rem Время запуска for /f %%a in ('date /t') do set curdate=%%a for /f %%a in ('time /t') do set curtime=%%a echo: >>> %~dp0runlog.txt echo ----------------------------------------------------------------------------------- >>> %~dp0runlog.txt echo %curdate% %curtime%: run started >>> %~dp0runlog.txt echo ----------------------------------------------------------------------------------- >>> %~dp0runlog.txt |
|
Сообщ.
#24
,
|
|
|
|
Хозяйке на заметку: удобочитаемая распечатка PATH
Может кому и пригодиться... Так бывает, что при "задействовании" очередного пакета, требующего изменение системного параметра PATH, уже теряется "понимание" содержимого этой переменной. Ибо путей уже over дохера... Мой солюшен это решает - он позволяет вывести содержимое переменной поэлементно и в столбец. Для этого делаем пункт в меню Фар, вызываемом по [F2], допустим "Смотрим пути". В качестве горячей клавиши что угодно, а можно и без нее. А в качестве команды что-то типа: ![]() ![]() path | E:\Tools\MSys64\usr\bin\sed -e 's/;/\n/g' И получаем что-то типа на выводе в консоль: ![]() ![]() E:\Documents\3.Projects>path | E:\Tools\MSys64\usr\bin\sed -e 's/;/\n/g' C:\Tools\Perl-5.40.0-x64\c\bin C:\Tools\Perl-5.40.0-x64\perl\site\bin C:\Program Files\Common Files\Oracle\Java\javapath C:\Program Files (x86)\VMware\VMware Workstation\bin\ C:\Program Files (x86)\Common Files\Intel\Shared Libraries\redist\intel64\compiler C:\Program Files (x86)\Common Files\Intel\Shared Files\cpp\bin\Intel64 C:\Tools\Python310\ C:\Tools\Python310\Scripts\ C:\Tools\Prolog\bin C:\Tools\ImageMagick C:\Program Files\dotnet\ C:\WINDOWS\system32 C:\WINDOWS C:\WINDOWS\System32\Wbem C:\WINDOWS\System32\WindowsPowerShell\v1.0\ C:\WINDOWS\System32\OpenSSH\ C:\Tools\gs\bin D:\Tools\SDK-Flutter\bin C:\Program Files\Java\jdk-17\bin C:\Program Files\nodejs\ C:\Tools\Git\cmd D:\Tools\Topaz Gigapixel AI\bin\ C:\Program Files\Calibre2\ D:\Tools\OpenServer\bin C:\Users\Majestio\AppData\Local\ValidatorBuddy C:\Users\Majestio\AppData\Local\Microsoft\WindowsApps C:\Users\Majestio\AppData\Roaming\Programs\Zero Install C:\Users\Majestio\AppData\Roaming\npm Одна "беда" - нужно иметь установленным MSYS2. В моём случае в E:\Tools\MSys64 |
|
Сообщ.
#25
,
|
|
|
|
У кого его нет:
![]() ![]() @echo off setlocal set var=%path% :onceMore for /f "tokens=1,* delims=;" %%a in ("%var%") do ( echo %%a set var=%%b goto onceMore ) endlocal |
|
Сообщ.
#26
,
|
|
|
|
Может кому и пригодиться... Как говорится "мопед не мой". Пришлось знатно переписать скрипт, так как оригинальный постоянно съедал последнюю строку. Сегодня меня это уже достало! Shift+Tab - сдвигает выделенный потоковый блок вправо Shift+BS - сдвигает выделенный потоковый блок влево УПС: Есть баги! Буду дорабатывать Макро ложить вот сюда: %FARHOME%\Profile\Macros\scripts\BlockIndent (ну или где у вас там хранится, может в профилях пользователя венды) Скрытый текст BlockIndent.lua ![]() ![]() --[[ Block Indent for Far Manager Version: 2.2 Copyright (C) 2001 Alex Yaroslavsky Copyright (C) 2025 Majestio (fixxxx) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Features: - Right or Left Indentation of the selected block (or the current line) by a tab or a space. - Each line in the block is indented relatively to its own position with no respect to other lines in the block. - Tab indentation as in Borland Turbo IDE, text is indented to the nearest tab position and not just by tab size. - Works correctly with any editor settings (expand tabs or not, inserts real tabs). --]] local function Indent(IndentByTabSize, Forward) local F = far.Flags local ei = editor.GetInfo() if not ei then return end local hasBlock = (ei.BlockType == F.BTYPE_STREAM or ei.BlockType == F.BTYPE_COLUMN) and ei.BlockStartLine local startLine = hasBlock and ei.BlockStartLine or ei.CurLine editor.UndoRedo(nil, F.EUR_BEGIN) if hasBlock then if ei.BlockType == F.BTYPE_STREAM then -- Принудительно делаем выделение "до конца окна" на всех строках блока editor.Select(nil, "BTYPE_STREAM", ei.BlockStartLine, 1, -1, ei.TotalLines) elseif ei.BlockType == F.BTYPE_COLUMN then -- Для вертикального блока — просто расширяем до конца файла editor.Select(nil, "BTYPE_COLUMN", ei.BlockStartLine, ei.BlockStartCol, ei.TotalLines - ei.BlockStartLine + 1, ei.BlockWidth) end end local IndentSize = IndentByTabSize and ei.TabSize or 1 local IndentChar = IndentByTabSize and "\t" or " " local line = startLine while true do local s = editor.GetString(nil, line, 0) if not s then break end local inBlock = not hasBlock if hasBlock then local ss = s.SelStart or 0 local se = s.SelEnd or 0 inBlock = (ss > 0) and (se == -1 or ss <= se) end if not inBlock then break end local text = s.StringText or "" local firstNonSpace = text:find("[^ \t]") or (#text + 1) local tabCol = editor.RealToTab(nil, line, firstNonSpace) - 1 local steps = math.floor(tabCol / IndentSize) if not Forward and (tabCol % IndentSize) == 0 then steps = steps - 1 end steps = math.max(0, Forward and steps + 1 or steps) -- Удаляем старый отступ editor.SetString(nil, line, text:sub(firstNonSpace), s.StringEOL) -- Вставляем новый editor.SetPosition(nil, line, 1) for i = 1, steps do editor.InsertText(nil, IndentChar) end line = line + 1 end -- Восстанавливаем курсор editor.SetPosition(nil, ei) editor.Redraw() editor.UndoRedo(nil, F.EUR_END) end Macro { area="Editor"; key="ShiftTab"; flags=""; description="Indent right by space"; action = function() Indent(false, true) end; } Macro { area="Editor"; key="ShiftBS"; flags=""; description="Indent left by space"; action = function() Indent(false, false) end; } NoMacro { area="Editor"; key=""; flags=""; description="Indent right by tab size"; action = function() Indent(true, true) end; } NoMacro { area="Editor"; key=""; flags=""; description="Indent left by tab size"; action = function() Indent(true, false) end; } |
|
Сообщ.
#27
,
|
|
|
|
Хозяйке на заметку: извлечение встроенной BASE64-кодированной картинки во встроенном редакторе Far
Может кому и пригодиться... Надоело пользоваться online-извлекаторами с тоннами рекламы, сделал свой. Уютный и ламповый! Пользоваться просто. Допустим есть нечто в виде: ![]() ![]() <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII="> Выделяем все, что между двойными кавычками и жмём Ctrl+Alt+I, в открывшемся диалоге вводим имя сохраняемого файла без расширения. Бинго! Макро ложить вот сюда: %FARHOME%\Profile\Macros\scripts\DecodeImage (ну или где у вас там хранится, может в профилях пользователя венды) Скрытый текст DecodeBase64Image.lua ![]() ![]() --[[ DecodeBase64Image для Far Manager Версия: 1.0 Автор: Majestio Copyright © 2025 Majestio Данная программа распространяется под лицензией MIT. Разрешается использование, копирование, изменение, слияние, публикация, распространение, сублицензирование и/или продажа копий программы без каких-либо ограничений при соблюдении следующих условий: 1. Вышеуказанное уведомление об авторских правах и данное условие разрешения должны быть включены во все копии или существенные части программы. 2. ПРОГРАММА ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, явных или подразумеваемых, включая (но не ограничиваясь) гарантии товарного состояния, пригодности для конкретной цели и отсутствия нарушений прав третьих лиц. Ни при каких обстоятельствах автор не несёт ответственности за любые претензии, убытки или иные обязательства, возникшие в связи с использованием программы. Назначение: - декодирует внедрённую в текст картинку Base64 и сохраняет её в файл Пример использования: выделяем всё, что находится между двойными кавычками: "data:image/png;base64,iVBORw0KGgoAAAANSUh...абырвалг=" --]] local checkImageFormat = function(format) local validFormats = { ["image/png"] = true, ["image/jpeg"] = true, ["image/jpg"] = true, ["image/gif"] = true, ["image/bmp"] = true, ["image/webp"] = true, ["image/svg+xml"] = true } return validFormats[format] end ------------------------------------------------------------------------------------------------------------------------------------- local isValidBase64 = function(str) local base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" local padding_char = "=" -- Проверка длины строки if #str % 4 ~= 0 then return false end -- Проверка символов строки local padding_count = 0 for i = 1, #str do local char = str:sub(i, i) if char == padding_char then padding_count = padding_count + 1 elseif not base64_chars:find(char, 1, true) then return false end end -- Проверка символов заполнения if padding_count > 2 then return false elseif padding_count > 0 then local last_char = str:sub(-1) if last_char ~= padding_char or str:sub(-2, -2) == padding_char then return false end end return true end ------------------------------------------------------------------------------------------------------------------------------------- local base64_decode = function(input) local output = "" local base64_reverse_chars = { ["A"]=0,["B"]=1,["C"]=2,["D"]=3,["E"]=4,["F"]=5,["G"]=6,["H"]=7,["I"]=8,["J"]=9, ["K"]=10,["L"]=11,["M"]=12,["N"]=13,["O"]=14,["P"]=15,["Q"]=16,["R"]=17,["S"]=18,["T"]=19, ["U"]=20,["V"]=21,["W"]=22,["X"]=23,["Y"]=24,["Z"]=25,["a"]=26,["b"]=27,["c"]=28,["d"]=29, ["e"]=30,["f"]=31,["g"]=32,["h"]=33,["i"]=34,["j"]=35,["k"]=36,["l"]=37,["m"]=38,["n"]=39, ["o"]=40,["p"]=41,["q"]=42,["r"]=43,["s"]=44,["t"]=45,["u"]=46,["v"]=47,["w"]=48,["x"]=49, ["y"]=50,["z"]=51,["0"]=52,["1"]=53,["2"]=54,["3"]=55,["4"]=56,["5"]=57,["6"]=58,["7"]=59, ["8"]=60,["9"]=61,["+"]=62,["/"]=63 } -- Убираем все = с конца input = input:gsub("=*$", "") local input_length = #input for i = 1, input_length, 4 do local c1 = input:sub(i, i) local c2 = input:sub(i+1, i+1) local c3 = input:sub(i+2, i+2) local c4 = input:sub(i+3, i+3) local b1 = base64_reverse_chars[c1] or 0 local b2 = base64_reverse_chars[c2] or 0 local b3 = base64_reverse_chars[c3] or 0 local b4 = base64_reverse_chars[c4] or 0 local byte1 = bit.bor(bit.lshift(b1, 2), bit.rshift(b2, 4)) local byte2 = bit.bor(bit.lshift(bit.band(b2, 0x0F), 4), bit.rshift(b3, 2)) local byte3 = bit.bor(bit.lshift(bit.band(b3, 0x03), 6), b4) output = output .. string.char(byte1) if c3 ~= "" then output = output .. string.char(byte2) end if c4 ~= "" then output = output .. string.char(byte3) end end return output end ------------------------------------------------------------------------------------------------------------------------------------- local DecodeBase64Image = function () local ei = editor.GetInfo(nil) if ei.BlockType == 0 then far.Message("Блок не выделен и декодировать нечего!", "Ошибка", nil, "w") return end local selectedText = Editor.SelValue -- Проверка формата изображения local format = selectedText:match("^data:([+%a/]+);base64,") if not format or not checkImageFormat(format) then far.Message("Выделенный блок не содержит информации об изображении", "Ошибка", nil, "w") return end -- Проверка валидности кодированной информации local encodedImage = selectedText:match(";base64,(.*)") if not encodedImage or not isValidBase64(encodedImage) then far.Message("Выделенный блок содержит некорректную информацию об изображении", "Ошибка", nil, "w") return end -- Запрос имени файла local filePath = far.InputBox(nil, "Сохранение изображения", "Введите имя файла:", nil, nil, 128, nil, 0) if not filePath or filePath == "" then return end -- Декодирование и сохранение изображения local decodedImage = base64_decode(encodedImage) local fileExtension = format:match("image/(%a+)") local fullPath = filePath .. "." .. fileExtension if win.GetFileInfo(fullPath) then local overwrite = far.Message("Файл уже существует. Перезаписать?", "Вопрос", ";YesNo", "w") if overwrite ~= 1 then return end end local file = io.open(fullPath, "wb") if file then file:write(decodedImage) file:close() far.Message("Изображение сохранено успешно!", "Успех") else far.Message("Не удалось сохранить изображение", "Ошибка", nil, "w") end end ------------------------------------------------------------------------------------------------------------------------------------- Macro { area="Editor"; key="CtrlAltI"; flags=""; description="Save Image from Base64 line"; action = function() DecodeBase64Image() end; } ЗЫ: Валидацию самого сохраняемого изображения я не делал. Выделяйте блок аккуратно и правильно |
|
Сообщ.
#28
,
|
|
|
|
Цитата Majestio @ Было бы логично, если бы он сам выделял нужное просто по факту нахождения курсора где-то внутри нужного текста.Выделяйте блок аккуратно и правильно Прикреплённый файл Screenshot_from_2025_11_30_11_26_52.png (57,24 Кбайт, скачиваний: 26)
|
|
Сообщ.
#29
,
|
|
|
|
Цитата Dushevny @ Было бы логично, если бы он сам выделял нужное просто по факту нахождения курсора где-то внутри нужного текста. Возможно, но мне лениво. Особенно если это касается парсинга многострочного src... |
|
Сообщ.
#30
,
|
|
|
|
Раз уж пошла такая пьянка, вот мой скрипт для автоотступов ![]() ![]() local strip = function(str) local i i = 1 while str:sub(i, i) == " " or str:sub(i, i) == "\t" do i = i + 1 end str = str:sub(i) i = -1 while str:sub(i, i) == " " or str:sub(i, i) == "\t" do i = i - 1 end str = str:sub(1, i) return str end local newLine = function() local F = far.Flags local ei = editor.GetInfo(nil); local x = 1 local y = ei.CurLine local curStr = editor.GetString(nil, y, 0).StringText while strip(curStr) == "" and y ~= 1 do y = y - 1 curStr = editor.GetString(nil, y, 0).StringText end while x <= #curStr do if curStr:sub(x, x) == " " or curStr:sub(x, x) == "\t" then x = x + 1 else break end -- if string.sub(curStr.StringText,x,1) == "\t" then x = ei.TabSize * ei.math.floor((x + ei.TabSize-1)/ei.TabSize) end end editor.UndoRedo(nil, F.EUR_BEGIN) editor.InsertString() if strip(editor.GetString(nil, ei.CurLine, 0).StringText) == "" then editor.SetString(nil, ei.CurLine, "") end editor.SetPosition(nil, ei.CurLine+1, x, -1, -1, -1, -1) curStr = strip(editor.GetString(nil, 0, 0).StringText) if #curStr ~= 0 then editor.SetString(nil, 0, string.rep(" ", x-1)..curStr) end editor.UndoRedo(nil, F.EUR_END) end local newTab = function() local F = far.Flags local ei = editor.GetInfo(nil); local x = ei.CurPos local y = ei.CurLine local curStr = "" while strip(curStr) == "" and y ~= 1 do y = y - 1 curStr = editor.GetString(nil, y, 0).StringText end while x <= #curStr do if curStr:sub(x, x) ~= " " and curStr:sub(x, x) ~= "\t" then x = x + 1 else break end end while x <= #curStr do if curStr:sub(x, x) == " " or curStr:sub(x, x) == "\t" then x = x + 1 else break end end if x > #curStr then x = (math.floor((ei.CurPos-1) / ei.TabSize) + 1) * ei.TabSize + 1 end local pos = ei.CurPos while pos < x do editor.UndoRedo(nil, F.EUR_BEGIN) local tmpPos = (math.floor((pos-1) / ei.TabSize) + 1) * ei.TabSize + 1 if tmpPos > x then tmpPos = x end editor.InsertText(nil, string.rep(" ", tmpPos-1 - pos+1)) editor.UndoRedo(nil, F.EUR_END) pos = tmpPos end end Macro { area="Editor"; key="Enter"; flags=""; description="Insert new line"; action = function() newLine() end; } Macro { area="Editor"; key="Tab"; flags=""; description="Insert new tab"; action = function() newTab() end; } При нажатии TAB автоматически ищет позицию правее так, чтобы курсор остановился напротив первого непробельного символа на наинижайшей непустой строке выше с пробелами и с непробельными символами правее текущей позиции курсора. Ну т.е. курсор прыгает к самой левой позиции, правее текущей, чтобы встать на границе очередного "слова" строки выше. Если предыдущая строка пустая, берётся ещё более предыдущая. Если строка выше короче текущей, тогда TAB работает стандартно, как исходный TAB. При нажатии ENTER автоматически удаляет финальные пробелы в текущей строке и перемещает курсор в новую строку в позицию самого левого непробельного символа в текущей. Т.е. выдерживается тот же отступ. Если текущая строка пуста, берётся строка выше текущей по тем же правилам, что для TAB. Если подходящей строки не найдено, в новой строке отступа не будет. При вставке отступов, что по TAB, что по ENTER, вставляемые отступы добавляются поTABно, и каждый из них добавляется в UndoRedo, что легко их откатывает поэлементно даже если было вставлено несколько за раз. Скрипт был написан мною спецом под набор исходного кода, где желаемые отступы в подавляющем большинстве случаев определяются именно этими правилами. Скрипт может конфликтовать с AutoComplete, если нажать TAB или ENTER в тот момент, когда он предлагает варианты для дополнения, но это не моя проблема, скрипт не в состоянии обнаружить такие ситуации сам. |
|
Сообщ.
#31
,
|
|
|
|
Скрытый текст На неделе попробую глянуть. Ща пока о5 занят. |