LINUX.ORG.RU

Рассчёт индента


0

1

Как сделать грамотно для строк исxодника JavaScript?

Начал с простого, написал функцию, которая вычисляет индент для текущей строки исxодя из её содержимого, содержимого предыдущей строки и в некоторых случаях содержимого предшествующей предыдущей строке. Вот примерно так:

(get-positive-indent)
(get-negative-indent)
(get-indent-for-actual-line)

они возвращают относительное значение, на которое изменяю текущее значение индента. В первой функции ищу в предыдущей строке наличие { if if() for for() do with with() while while() case: default:. Во второй подсчитываю количество } и на их количество минус один уменьшаю индент. В третьей смотрю, начинается ли строка с } или с case: или с default:.

Вроде бы несложно, но дьявол, как известно, в деталях. В процессе анализа строк приходится вырезать несущественный мусор (строки, коментарии, replace(/ /, match(/ /), если попадается такая конструкция: // */ то надо сканировать строки назад и искать, есть ли начало многострочного коментария, чтобы определить, правую или левую часть строки отрезать. Если текущая строка начинается с case: или default: заканчивается или нет предыдущая строка switch(){. Является ли предыдущая строка однострочным блоком кода не обрамлённая { }. А тут сейчас задумался как делать:

..foo( bar,
.......jazz ); // тут индент на уровне аргумента bar
..X            // а тут на уровне foo, что уже требует
               // запоминать / передавать уровень индента
               // между вызовами функции рассчитывающей индент

и что-то начинаю думать, что велосипед получается с неправильными колёсами - квадратными.

Вопрос такой: продолжать, как делал, или тут задача грамотно решается принципиально по-другому? Скажем, строится AST исxодника и чё-то там с ним делается... Если последнее, нужны подробности.

Хочется иметь набор правил, перечень сущностей, над которыми надо применить правила и просто последовательно выполнить эти правила и получить результирующее значение.

зы: elisp

★★

Последнее исправление: Reaper (всего исправлений: 3)

Ответ на: комментарий от Reaper

А что, по-русски написать нельзя было?

А насчет расчета отступов - и в учебниках по всяким сям такое было, и библиотечки есть для «автоформатирования» текста (правда, делают они не то, что надо, но если взять их код и переделать под свои нужны, вполне может получиться что надо).

Eddy_Em ☆☆☆☆☆
()

И да, зачем вам вся эта красота, если перед тем, как выложить скрипт на сервер в общественный доступ, вы его все равно сожмете, удаляя все ненужное форматирование (а то и названия функций/переменных сокращая)?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

И да, зачем вам вся эта красота, если перед тем, как выложить скрипт на сервер в общественный доступ, вы его все равно сожмете, удаляя все ненужное форматирование...

Переxод от задачи к выводу, что что-то куда-то будет класться, непонятен, но на вопрос, зачем я решаю эту задачу, ответ простой - я пишу режим для жабаскрипта в имаксе. И сразу отвечу на следующий - js2-mode меня устраивает почти всем, а пишу режим потому, что мне интересно написать режим.

Reaper ★★
() автор топика
Ответ на: комментарий от Eddy_Em

А готовые библиотечки пробовали посмотреть

Пробовал. cc-align содержит функции для рассчёта индента для c-mode, запутанный сложный для моего понимания императивный большой код также как и мой проверяющий содержимое ближайших строк. js2-mode несколько проще код, тоже проверяет содержимое ближайших строк, но ещё и привязан к анализатору кода, который строит синтаксическое дерево в процессе редактирования исxодника.

Взять что-то готовое не вижу возможности, кроме того, я хочу знать, как решить такую задачу оптимально, задачи сделать быстро взяв что-то готовое нет, пишу для себя.

Reaper ★★
() автор топика
Ответ на: комментарий от Reaper

Так и задача-то ведь не простая: нужен грамотный лексический анализатор, который позволит отделить функции от обычных скобок, выделить операторы и т.д., и т.п. Вон, насколько сложен анализатор кода в geany (который строит список функций, глобальных переменных, макросов и т.п.), да и тот глючит периодически, особенно если использовать функции внутри функций.

Eddy_Em ☆☆☆☆☆
()

Можно строить аст и потом по нему добегать до текущей позиции курсора, там по вашим же рулесам и будет ясно какой отступ. Но в интерактивном режиме постоянно репарсить сорец (инклуды бывают?) как-то не то. В виме например все подсветки и автоинденты сделаны на хитропатченных регэкспах, причем встречаются достаточно сложные экземпляры, но они все равно не покрывают некоторые случаи, ибо регэксп не замена аст. Зато решение на порядок проще, и ошибки встречаются так редко, что оно того стоит. Не знаю емакс, наверное тоже стоит стянуть основную идею со стандартных indent/*.elisp.

arturpub ★★
()
Ответ на: комментарий от Reaper

> js2-mode меня устраивает почти всем

Ну так и посмотри js2-mode, кстати, там действительно строится AST. На одних регулярных выражениях далеко не уедешь.

archimag ★★★
()
Ответ на: комментарий от Reaper

js2-mode — это индент-скрипт к емаксу, надо понимать? Не думаю, что анализатор на каждую букву деревяшку перестраивает, во-первых ему для этого нужен как минимум grammar, которого у вас похоже нет, во-вторых это достаточно ресурсоемко.

arturpub ★★
()
Ответ на: комментарий от archimag

Инкрементально что-ли строится?? Или это у меня загон про ресурсоемкость?

arturpub ★★
()
Ответ на: комментарий от arturpub

js2-mode — это индент-скрипт к емаксу, надо понимать?

Это режим для редактирования яваскрипта. Там не только индент, ещё и подсветка синтаксиса и другие вещи. И там действительно, при изменении исxодника перестраивается AST. Инкрементально или как-то по-другому, не знаю.

Reaper ★★
() автор топика
Ответ на: комментарий от archimag

Ну я посмотрел. Там определяется где мы сейчас находимся, скажем в операторном блоке, это учитывается при рассчёте значения, а потом куча императивной хрени в виде проверок, чё тут рядом есть. Разницы особой с тем, что я написал нет. Мне это всё не нравится, куча говнокода в результате, что в js2-mode, что c-mode, что у меня.

Reaper ★★
() автор топика

> Начал с простого, написал функцию, которая вычисляет индент для текущей строки исxодя из её содержимого, содержимого предыдущей строки и в некоторых случаях содержимого предшествующей предыдущей строке.

Изначально неверный посыл.

Вопрос такой: продолжать, как делал, или тут задача грамотно решается принципиально по-другому?

В том же emacs куча индентеров, почему бы тебе просто не посмотреть на них?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Изначально неверный посыл.

Какой верный-то был бы? Примеры рассчёта индента из модулей имакса изяществом не отличаются.

Reaper ★★
() автор топика
Ответ на: комментарий от tailgunner

Можешь привести пример подтверждающий недостаточность анализа текущей строки и нескольких предшествующих?

Reaper ★★
() автор топика

Вообще, бросай ты этот mode, есть же уже хорошие решения для JS, лучше помоги мне доделать closure-template-html-mode - как раз индентация храмает ))

archimag ★★★
()

Посмотри ещё на емаксовый js-mode (бывший expresso), он попроще. А вот js2-mode писали наркоманы.

anonymous
()
Ответ на: комментарий от anonymous

> А вот js2-mode писали наркоманы.

Может и наркоманы, только получилась клёвая вещь, особенно вместе с swank-js.

archimag ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.