Skip to content

Instantly share code, notes, and snippets.

@reznikmm
Created November 14, 2022 14:46
Show Gist options
  • Save reznikmm/a3b14d715ca32ee4b68c6a050ab95ca8 to your computer and use it in GitHub Desktop.
Save reznikmm/a3b14d715ca32ee4b68c6a050ab95ca8 to your computer and use it in GitHub Desktop.
Indent

Автоматические отступы

Не могу сообразить с какой стороны подойти к автоматизации отступов в редакторе.

Emacs

http://cc-mode.sourceforge.net/html-manual/Indentation-Engine-Basics.html

  • Определить синтаксическую конструкцию, первую на строке, на которой мы находимся, и найти ее "опорную точку" (anchor position). Например, открывающуюся скобку на предыдущей строке.
  • Найти в настройках смещение(-ия) отступа для этой синтаксической конструкции и применить его.

Pretty print

http://stackoverflow.com/questions/1318976/smart-indent-algorithm-documentation

Одна из идей - применить подход pretty printer-а: построить AST, запустить по нему Visiter-а и сформировать layout-ы в виде вложенных прямоугольников.

AST doesn't help

http://steve-yegge.blogspot.com/2008/03/js2-mode-new-javascript-mode-for-emacs.html

Перемотать к Indentation

Тестовый подход

Каждый токен классифицируем как

  • '(3' токен начинающий вложенный блок, для таких токенов указываем сдвиг 3
  • ')' токен заканчивающий вложенный блок
  • ',' токен разделитель элементов внутри блоке
  • '.' прочие токены

Токены в разных синтаксических правилах будем рассматривать, как различные. Тогда алгоритм следующий:

  1. производим синтаксический разбор и строим AST из '(),.'
  2. если уровень вложенности 0, выравниваем в позицию 1
  3. если первый токен в строке ')' выравниваем его под соответствующим '(' без сдвига
  4. если предыдущий токен ',' выравниваем строку под соответствующим '(' со сдвигом
  5. если предыдущий токен '(' выравниваем строку под соответствующим '(' со сдвигом
  6. иначе выравниваем под соответствующим '('+2. (Возможно нужен алгоритм сложнее, учитывающий отступ от предыдущей аналогичной строки

Пример синтаксиса

 generic_subprogram_declaration:: ::= 
     generic_formal_part  **procedure**,,//)//,, defining_program_unit_name parameter_profile;,,//,//,,

 generic_formal_part:: ::=
   **generic**,,//(3//,, {generic_formal_parameter_declaration | use_clause}

 use_clause:: ::= **use** package_name {, package_name};,,//,//,,

 parameter_profile:: ::=
   [(,,//(1//,,parameter_specification {;,,//,//,, parameter_specification}),,//)//,, ]

 generic_formal_parameter_declaration:: ::= 
     **with** subprogram_specification [is subprogram_default];,,//,//,,

Пример форматирования

generic -- пр. 2
   use Some_Package;  -- пр. 5
   with procedure Proc (X : Integer;  -- пр. 4
                        Y : Integer); -- пр. 4
procedure Do  -- пр. 3
  (Param :  -- пр. 6 тут ошибка, срабатывает пр. 2
     Long_Type_Name := Long_Default_Expression;  -- пр. 6
   Result : out Integer);  -- пр. 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment