В программе всё должно быть прекрасно: и алгоритмы, и выравнивание исходного текста.
Эйс Брейкпоинт
Сначала может показаться, что форматирование исходного текста придумали зануды, но на самом деле выровненный по определенным правилам текст легче воспринимается, а значит – на его изучение тратится меньше времени. А время, как вы знаете, – самый ценный ресурс.
Так как уже написано множество платных и бесплатных утилит форматирования, я решил не изобретать велосипед, а выбрать готовый.

После нескольких экспериментов мне удалось найти оптимальный вариант: утилита ptop.exe, которая входит в состав FreePascal.
После нас хоть PTOP
Для того чтобы добраться до этой утилиты, необходимо на сайте разработчиков скачать файл установки, подходящий для вашей операционной системы. Если вы не планируете использовать Free Pascal, то при инсталляции выберите только опцию установки утилит.

После завершения установки перенесите файл ptop.exe поближе к вашему проекту (для себя я решил, что все внешние утилиты будут храниться в папке extras\, в подпапке с названием утилиты).
Чтобы сгенерировать файл конфигурации, запустите утилиту в командной строке с параметром -g, указав имя создаваемого файла конфигурации.
ptop.exe -g ptop.cfg
Code language: CSS (css)
Можно его и не создавать, но лично мне не понравилось, что ptop.exe делает капитализацию (меняет первый символ на заглавный) всех ключевых слов, и чтобы это отменить, надо прошерстить файл конфигурации, удалив слово capital в описаниях действий для всех ключевых слов.
Для форматирования файла-исходника c перезаписью оригинального файла потребуется выполнить такую вот команду:
ptop.exe -g ptop.cfg source.pas source.pas
Code language: CSS (css)
Модуль форматирования
Хотя для форматирования понадобится написать всего один небольшой скрипт, я решил выделить его в отдельный модуль, отнеся его к инструментам (папка Script\Tools\Formetter\Formattrer.pas).
const
FORMATTER_EXE = 'Extras\FreeFormat\ptop.exe';
FORMATTER_CONFIG = 'Extras\FreeFormat\ptop.cfg';
FORMATTER_PARAM = '-c %0.s %1.s %2.s '; // цифры роли не играю, параметры по очереди подставляются
function Formatter_FormatText( AText:string ):string;
// форматирование исходного текста Delphi внешней утилитой
var
tmpDataFile: string;
tmpConfigFile: string;
tmpFormatter: string;
tmpMemo: TMemo;
tmpParam: string;
begin
// утилита и файл конфигурации лежат в специальной папке внутри нашего проекта
tmpFormatter := ExtractFilePath( Application.ExeName ) + FORMATTER_EXE;
tmpConfigFile := ExtractFilePath( Application.ExeName ) + FORMATTER_CONFIG;
// если чего-то не нашли, то возбуждаем исключение
if not FileExists(tmpFormatter) then
RaiseException('Утилита форматирования не найдена: '+tmpFormatter)
else
if (FORMATTER_CONFIG <> '') and not FileExists(tmpConfigFile) then
RaiseException('Файл конфигурации не найден: '+tmpConfigFile)
else
begin
// создаем временный файл
tmpDataFile := GetTempFileName+'.pas';
// используем Memo для создания файла
tmpMemo := TMemo.Create(MainForm);
tmpMemo.Parent := MainForm; // нужно, чтобы работало сохранение на диск
tmpMemo.Visible := False;
try
tmpMemo.Lines.Text := AText;
tmpMemo.Lines.SaveToFile(tmpDataFile); // сохраняем текст во временный файл
// делаем конвертацию
tmpParam := Format(FORMATTER_PARAM,[tmpConfigFile,tmpDataFile,tmpDataFile]);
OpenFile(tmpParam,tmpFormatter);
case WaitExternalExe( tmpFormatter ) of
-1: RaiseException('Утилита форматирования не запустилась: '+tmpFormatter);
-2: RaiseException('Утилита форматирования зависла: '+tmpFormatter)
end;
tmpMemo.Lines.Clear; // загружаем результат
tmpMemo.Lines.LoadFromFile(tmpDataFile);
Result := tmpMemo.Lines.Text;
finally
tmpMemo.Free;
end;
end;
end;
Code language: Delphi (delphi)
Функция Formatter_FormatText() вызывает внешнюю утилиту для выполнения форматирования текста. Настройка утилиты сводится к настройке трёх констант: в двух из них хранится относительный путь к самой утилите и файлу конфигурации, а в третьей находится строка с описанием параметров вызова утилиты, которая рассчитана на использование стандартной команды Format(). Эта команда производит подстановку значений различных типов в строку шаблона. В нашем случае подставляются три строковых параметра: файл конфигурации, исходный файл и файл результата.
Отдельное внимание стоит уделить скрипту, который можно считать универсальным. Это функция WaitExternalExe() – ожидание завершения внешней программы. Принцип её работы заключается в том, что в течение заданного времени ожидается запуск программы с определенным заголовком, а затем скрипт ждёт её завершение.
function WaitExternalExe( ACaption:string; AStartCount: integer = 10; AFinishCount:integer = 0; ACountDelay:integer = 10 ):integer;
// ожидание завершения работы внешней программы
// используется поиск по заголовку окна
//
// ACaption - заголовок окна
// AStartCount - число циклов ожидания запуска программы
// AFinishCount - число циклов ожидания завершения программы; 0 - бесконечный цикла ожидания;
// ACountDelay - задержка внутри цикла ожидания, мС
var
h: integer; // дескриптор окна
tmpCounter: integer;
begin
tmpCounter := AStartCount;
// ожидание открытия
// ищем окно
while (h = 0) and (tmpCounter > 0) do
begin
Sleep(ACountDelay);
h := FindWindow('', ACaption);
Dec(tmpCounter);
end;
if h = 0 then
Result := -1 // программа не запустилась
else
begin
tmpCounter := AFinishCount;
while (h <> 0) and (tmpCounter >= 0) do
begin
Sleep(ACountDelay);
h := FindWindow('', ACaption);
if AFinishCount > 0 then
Dec(tmpCounter);
end;
if h = 0 then
Result := 0 // программа отработала
else
Result := -2; // программа зависла
end;
end;
Code language: Delphi (delphi)
В случае успеха функция возвращает 0, другие значения означают ошибки. Эти ошибки должны разбираться в том месте, откуда вызывается данная функция. В нашем случае – в Formatter_FormatText(). Но так как эта функция также является библиотечной, то для отображения ошибок я не использую в ней функции ShowMessage() и ей подобные, а вызываю исключение, перенося ответственность за обработку ошибок на скрипты более высокого уровня. В нашем случае вызов функции форматирования прикладного уровня выглядит так:
procedure efmExample_btnFormatCode_OnClick (Sender: TObject; var Cancel: boolean);
// форматирование кода
begin
try
// вызываем функцию форматирования
efmExample.memSnippet.Text := Formatter_FormatText( efmExample.memSnippet.Text );
except
// в случае ошибки Formatter_FormatText() создаёт исключения,
// которые можно перехватить и отобразить текст исключения
ShowMessage( ExceptionMessage );
end;
end;
Code language: Delphi (delphi)
Результат
Теперь можно не утруждать себя ручным выравниванием примеров, взятых из своих исходников или форума.

Открываем пример на редактирование и нажимаем кнопку “Форматировать код” (1), а затем “Сохранить” (2).

Теперь исходник выглядит гораздо аккуратней:
