На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА
1. Раздел предназначен для обсуждения ПО.
2. Поиск кряков, серийников, варезных версий ПО - запрещен.
3. Холивары также не приветствуются - для этого есть соответствующий раздел.
4. При создании тем в разделе настоятельно рекомендуется придерживаться следующего шаблона оформления.
5. Ссылки для скачивания дистрибутивов ПО должны вести на официальный сайт! Запрещено размещение ссылок на файлы, находящиеся на файлообменниках типа RapidShare, iFolder, DepositFiles, Sms4File, VipFile и прочих "условно-бесплатных" ресурсах.
Модераторы: winsoft
  
> FAR Manager
    Far Manager

    Windows. FreeWare.

    Многофункциональный файловый менеджер для работы с различными файлами, позволяет просматривать файлы и каталоги, редактировать, копировать и переименовывать файлы. Поддерживает Unicode имеет удобный и простой в использовании пользовательский интерфейс с многоязычной поддержкой. Позволяет работать с архивами, FTP-клиентами, и просматривать сеть с помощью реализованных в стандартную поставку плагинов. Кроме того есть возможность расширения функциональности за счет подключения дополнительных плагинов.

    user posted image

    Ну очень странно что его уже давным давно не включили в разделе "Полезного ПО" :-?

    Подключаемые модули (плагины)

    Возможности FAR существенно расширяются благодаря плагинам различного назначения:

    • управление принтерами, как подключёнными к ПК, так и сетевыми;
    • подсветка синтаксиса в исходных текстах программ;
    • работа с FTP-серверами (с поддержкой доступа через различные типы прокси, автоматической докачкой и прочее);
    • работа с SFTP-серверами (плагин WinSCP);
    • поиск и замена символов одновременно во множестве файлов с применением регулярных выражений;
    • средства переименования групп файлов с возможностью использования сложных составных масок из символов подстановки и шаблонов;
    • NNTP/SMTP/POP3/IMAP4 клиенты и отправка сообщений на пейджер;
    • работа при нестандартных размерах текстового экрана;
    • перекодировка текстов с учётом национальных кодовых таблиц;
    • манипуляции с содержимым корзины;
    • управление приоритетами процессов на локальном или на сетевом ПК;
    • автозавершение слов в редакторе и работа с шаблонами;
    • редактирование реестра Windows;
    • создание и изменение ярлыков Windows;
    • всевозможные манипуляции с файлами и текстом, делающие комфортной работу с фидонетовскими материалами;
    • кодирование и декодирование файлов в формате UUE;
    • симметричное и асимметричное шифрование файлов;
    • управление программой Winamp и модификация комментариев MP3-файлов;
    • просмотр и редактирование содержимого ресурсов различных игр;
    • работа с различными серверами через ODBC + работа с серверами Oracle через OCI;
    • управление службой RAS;
    • запуск внешних программ (компиляторов, конвертеров и проч.) при редактировании текстов в редакторе FAR;
    • отображение содержимого файлов справки Windows (.hlp и .chm);
    • калькуляторы с разными возможностями;
    • функции проверки орфографии при обработке текста в редакторе FAR;
    • работа с файл-образами дисков для ZX Spectrum и пк Вектор-06Ц;
    • подготовка каталога сменных накопителей и многое другое.
    • вычисление и проверка CRC и криптографических хеш значений файлов (SHA-1; SHA-2; Whirlpool и других).
    • Отображение скрытой файловой системы на телефонах SonyEricsson
    • Некоторые важные плагины (например, для работы с FTP, печати, сравнения файлов, работы с архивами, сетью) входят в поставку FAR. Но подавляющее большинство плагинов доступно для скачивания в интернете, пользователь может устанавливать их в соответствии со своими задачами. В настоящее время насчитывается более 700 плагинов для FAR.

    Домашняя страничка: https://farmanager.com
      Lua-скрипт EditorTools

      Позволяет подключать и исполнять в редакторе Far'а различные обработчики - фильтры, компиляторы, интерпретаторы. Исполнять их без отрытия дополнительных окон, отлавливать stdout и stdrr, загружать результаты обработки назад в редактор, выводить сообщения об ошибках и результатах обработки в виде диалогов. Возможно кому-то пригодится.

      Предыстория

      Для быстрого редактирования файлов - встроенный редактор Far'а просто прекрасен. Но, к сожалению, определенных функций в нем не хватает. Конечно можно, при наличии времени и сил, сесть и написать свой инструмент обработки в виде полноценного плагина, либо Lua-скрипта. Меня же заинтересовал чисто практический вопрос - найти способ подключения уже готовых инструментов не через подсистему ассоциаций файлов. Надоело сохраняться, обрабатывать файл, потом опять грузить файл в редактор. Ну и вот родилась идея создать более-менее универсальное средство.

      Прошу учесть - это моя первая программа на языке Lua, так что принимайте мой отказ от ответственности, еличе :D

      На момент написания скрипта мне нужно было подключить:

      • Форматер С++ кода AStyle
      • Форматер HTML5 Tidy
      • Компилятор Fasm
      • Интерпретатор Perl
      • Интерпретатор Ruby
      • Интерпретатор SWI-Prolog

      Функионал

      Команды обработки прописываются в файл конфигурации EditorTools.conf, который лежит рядом с макросом.
      Программы могут работать в четырех режимах:

      1) Filter
      Используется для запуска программ, которые могут непосредственно вносить изменения в файл.
      После выполнения содержимое редактора заменяется результатом обработки

      2) Pipe
      Используется для запуска программ, которые могут читать и обрабатывать файл, но вывод умеют делать только в STDOUT
      После выполнения содержимое редактора заменяется результатом обработки

      3) Compiler
      Используется для запуска компиляторов
      После выполнения выводится диалог об успешной компиляции, либо диалог, содержащий ошибки компилятора

      4) Execute
      Используется для запуска как правило интерпретаторов
      После выполнения выводится диалог, в котором отображается результат обрабтки текста внешней программой

      Скрипт EditorTools.lua
      Скрытый текст

      ExpandedWrap disabled
        ------------------------------------------------------------------------------------------------------------------------
        -- Скрипт 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
      Скрытый текст

      ExpandedWrap disabled
        ; Поля конфига следующие:
        ;
        ; Режим, "Название-инструмента", "командная строка"
        ;
        ; Режим:
        ;
        ;   [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
      ExpandedWrap disabled
        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
      ExpandedWrap disabled
        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
      ExpandedWrap disabled
        // 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.
        А чем он лучше Total Commander-a ?
          Цитата ... @
          А чем он лучше Total Commander-a ?

          Три преимущества (ну на вкус и цвет):

          * удобная работа с консольными программами
          * встроенный быстрый редактор, который как и сам Фар можно обвесить плагинами
          * уже давно подключили поддержку Lua, с нативными плагинами можно не париться
            Цитата ... @
            А чем он лучше Total Commander-a ?

            Total - это как DOS Navigator: швейцарский нож, уже не помещающийся в руку из-за неудобной толщины.

            А вот FAR - это классический Norton, быстро и легко. Мультитул, у которого можно отстегнуть всё лишнее.
              Цитата Mr.Delphist @
              А вот FAR - это классический Norton, быстро и легко. Мультитул, у которого можно отстегнуть всё лишнее.

              Когда-то был более удачный вариант - Volkov Commander, типа Нортона - но гораздо шустрее и меньше хавал ресурсов.
              А на счет FAR'а - полностью согласен. А если его запускать под ConEmu, то еще добавляется мешок сахара.
                Я даже видел гика, что запускал FAR из-под вайна вместо MC в линухе.
                  Цитата Qraizer @
                  видел гика, что запускал FAR из-под вайна вместо MC в линухе.

                  О, мсье знает толк в извращениях! :crazy:
                    Цитата 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 (виртуальные машины)
                    Сообщение отредактировано: Kopa -
                      Кто-то знает (может объяснить) отчего так:
                      1. Создаю 3 файла: a-.txt, a!.txt и a=.txt
                      2. Они сортируются в Far'е именно в таком порядке, но по коду символа должно быть: a!.txt, a-.txt, a=.txt
                      т.к. : код(!)=$21, код(-)=$2D, код(=)=$3D.

                      Т.е. почему знак '-' столь важен стал?

                      Добавлено
                      П.С. вот запустил в NDN (Necro... DOS Navigator), там всё правильно!
                      И виндовый проводник сортирует как надо.
                        По тыкайте Ctrl+F<3-11> и посмотрите разные варианты
                          Да, по Ctrl-F7 (Несорт) стало сортировать нормально. Но это ж не выход, т.к. у меня всегда установлена сортировка по расширению. Непонятна причина, увы.
                            Так он сортирует по одному указанному критерию. По другим критериям никаких гарантий какого-либо порядка. Тебе же нужно два критерия одновременно. Вроде было как-то у них на форуме обсуждение объединения нескольких критериев для создания своих правил, но к чему пришли, я не знаю. Мож плагин какой нарелизили.
                              Впрочем, чушь это. Даже если включить сортировку по имени, всё равно тот же результат.
                              Я порылся в FARовых сырцах, там всё упирается в CompareString() суть WinAPI. Проверил (основано на string_sort.cpp / compare_natural_base()):
                              ExpandedWrap disabled
                                #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);
                                }
                              ExpandedWrap disabled
                                Greater
                              Увы, это винда считает, что '!' > '-'. У кого есть возможность, проверьте, плз, на нерусской. Я пробовал указывать LOCALE_SYSTEM_DEFAULT, LOCALE_INVARIANT и даже явное 0x409 сиречь en-US. Всё равно Greater

                              P.S. Если будет выдавать цифры, значит CompareString() вернула эррор, и это системный код ошибки last error
                              Сообщение отредактировано: Qraizer -
                                Если интересно, то Calculate Linux 6.6.57 + wine (wine-9.20 (Staging) или wine-9.0 (Proton-9.0-2)) при установленной Windows 10 в префиксе выдают Greater.
                                  В общем, разгадка на поверхности, хотя и не так уж очевидна. CompareString() же выполняет лексикографическое сравнение с учётом национальных предпочтений. Это очевидно. А вот что не так уж, так это то, что '-' ассоциируется с дефисами и тире, в частности переносами, как явными, так и мягкими. Ну и лексикографически они располагаются перед разделителями, типа там пробел, таб итп, т.к. по сравнению с ними должны иметь меньший вес.
                                  Я заглянул в 7-ку, там такое же поведение. Даже поставил XPю на виртуалку и заморочился пакетом её поддержки в Студии, что собрать под неё. И в ней тоже Greater. Осталось только ради интереса чекнуть 98SE, но это VS6 расчехлять... ну так мы тут крутые парни или зумеры ленивые
                                  Сообщение отредактировано: Qraizer -
                                    В общем, это был непростой процесс. Даже на виртуалке под современными процессорами 98-я не работает должным образом. Пришлось искать патчи. Но это уже был не просто спортивный интерес, это было дело принципа. Нашёл образ, нашёл патчи, нашёл ключ активации, проинсталил, нашёл, как и чем собрать под Win98. Greater. Ну кто б сомневался.
                                      Цитата Qraizer @
                                      Так он сортирует по одному указанному критерию. По другим критериям никаких гарантий какого-либо порядка. Тебе же нужно два критерия одновременно.
                                      Частично. Указывая сортировать по расширению, он группирует мои *.txt-файлы, это так. Но далее меня б более чем устроила сортировка по коду символа (в некоем смысле это очевидный порядок), но разрабы зачек-то замутили ещё какой-то смысл в дальнейшем упорядочении. Эх...
                                        Это не разрабы, это правила юникода. Тебе бы понравилось, если файлы с именами из латиницы+кириллицы сортировались на основе хрен пойми чего вместо национальных правил? и заметь, кириллица не обязательно означает русский, как и латиница не обязательно английский, французы с немцами тебе это подтвердят, а уж турки так вообще.
                                          Цитата Qraizer @
                                          Тебе бы понравилось, если файлы с именами из латиницы+кириллицы сортировались на основе хрен пойми чего вместо национальных правил?
                                          1. Хочется пример этого "хрен пойми чего", дабы не на эмоциях рассуждать, а по логике.
                                          2. Думаю, что понравилось бы, несмотря на местами встречавшийся порядок "ЁЈАБВ...", т.к. логика абсолютна.
                                            Хозяйке на заметку: временнЫе штампы

                                            Может кому и пригодиться...

                                            Моя шляпа позволяет в начало имени файла или каталога вставлять дату-время. Спросите "зачем это надо". А-б-и-с-ь-н-я-ю! Очень удобно иметь список файлов и каталогов, отсортированных по имени (а по факту по дате-времени) не меняя порядок сортировки в самом ФАРе. Особенно прекрасно это ощущается в каталогах резервных копий - просто душа дятлом поёт!!!

                                            Т.е. делаете просто файл или каталог под именем "1", травите на него команду и получаете к примеру "2025.08.19-15.43.56_1". Осталось только при переименовании убрать последних два символа, если нужен просто временной штамп.

                                            ⭐ Солюшен

                                            1) В самом ФАРе делаете очередной пункт меню в его меню, вызываемом по [F2], допустим "Вставить временной штамп"
                                            2) В качестве горячей клавиши что угодно, а можно и без нее. А в качестве команды что-то типа C:\Tools\set-timestamp.cmd "!.!", ну или ваш варик

                                            В качестве командного файла:

                                            ExpandedWrap disabled
                                              @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%"

                                            :victory:
                                              Нужна была подобная функциональность для ведения логов. Никак не смог заставить возвращать секунды.
                                                Цитата Qraizer @
                                                Никак не смог заставить возвращать секунды.

                                                ?? %TIME% возвращает секунды с точностью до сотых...
                                                  Я ж об этом. Сорри, непонятно выразился. Я использовал что-то типа
                                                  ExpandedWrap disabled
                                                    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
                                                  а про наличие переменных запамятовал напрочь.
                                                  Сообщение отредактировано: Qraizer -
                                                    Хозяйке на заметку: удобочитаемая распечатка PATH

                                                    Может кому и пригодиться...

                                                    Так бывает, что при "задействовании" очередного пакета, требующего изменение системного параметра PATH, уже теряется "понимание" содержимого этой переменной. Ибо путей уже over дохера...
                                                    Мой солюшен это решает - он позволяет вывести содержимое переменной поэлементно и в столбец.

                                                    Для этого делаем пункт в меню Фар, вызываемом по [F2], допустим "Смотрим пути". В качестве горячей клавиши что угодно, а можно и без нее. А в качестве команды что-то типа:

                                                    ExpandedWrap disabled
                                                      path | E:\Tools\MSys64\usr\bin\sed -e 's/;/\n/g'

                                                    И получаем что-то типа на выводе в консоль:

                                                    ExpandedWrap disabled
                                                      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
                                                      У кого его нет:
                                                      ExpandedWrap disabled
                                                        @echo off
                                                         
                                                        setlocal
                                                        set var=%path%
                                                        :onceMore
                                                         
                                                        for /f "tokens=1,* delims=;" %%a in ("%var%") do (
                                                          echo %%a
                                                         
                                                          set var=%%b
                                                          goto onceMore
                                                        )
                                                        endlocal
                                                        Хозяйке на заметку: отступы во встроенном редакторе Far

                                                        Может кому и пригодиться... Как говорится "мопед не мой". Пришлось знатно переписать скрипт, так как оригинальный постоянно съедал последнюю строку. Сегодня меня это уже достало!

                                                        Shift+Tab - сдвигает выделенный потоковый блок вправо
                                                        Shift+BS - сдвигает выделенный потоковый блок влево


                                                        УПС: Есть баги! Буду дорабатывать >:(

                                                        Макро ложить вот сюда: %FARHOME%\Profile\Macros\scripts\BlockIndent (ну или где у вас там хранится, может в профилях пользователя венды)

                                                        Скрытый текст
                                                        BlockIndent.lua

                                                        ExpandedWrap disabled
                                                          --[[
                                                            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;
                                                          }

                                                          Хозяйке на заметку: извлечение встроенной BASE64-кодированной картинки во встроенном редакторе Far

                                                          Может кому и пригодиться... Надоело пользоваться online-извлекаторами с тоннами рекламы, сделал свой. Уютный и ламповый! :)

                                                          Пользоваться просто. Допустим есть нечто в виде:

                                                          ExpandedWrap disabled
                                                            <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

                                                          ExpandedWrap disabled
                                                            --[[
                                                                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;
                                                            }

                                                          ЗЫ: Валидацию самого сохраняемого изображения я не делал. Выделяйте блок аккуратно и правильно ;)
                                                            Цитата Majestio @
                                                            Выделяйте блок аккуратно и правильно
                                                            Было бы логично, если бы он сам выделял нужное просто по факту нахождения курсора где-то внутри нужного текста.
                                                            Прикреплённый файлПрикреплённый файлScreenshot_from_2025_11_30_11_26_52.png (57,24 Кбайт, скачиваний: 26)
                                                              Цитата Dushevny @
                                                              Было бы логично, если бы он сам выделял нужное просто по факту нахождения курсора где-то внутри нужного текста.

                                                              Возможно, но мне лениво. Особенно если это касается парсинга многострочного src...

                                                              user posted image
                                                                Раз уж пошла такая пьянка, вот мой скрипт для автоотступов
                                                                ExpandedWrap disabled
                                                                  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 в тот момент, когда он предлагает варианты для дополнения, но это не моя проблема, скрипт не в состоянии обнаружить такие ситуации сам.
                                                                  Скрытый текст
                                                                  На неделе попробую глянуть. Ща пока о5 занят.
                                                                  1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                                                  0 пользователей:


                                                                  Рейтинг@Mail.ru
                                                                  [ Script execution time: 0,0893 ]   [ 21 queries used ]   [ Generated: 14.03.26, 22:46 GMT ]