Как стать автором
Обновить

Комментарии 28

Самый важный вопрос. Умеет ли это сохранять «незначимые символы», а проще говоря пробелы?
Хороший вопрос. Про это они рассказывали отдельно. Это называется Lexical Preservation.

Есть отдельный тикет про пробелы, который якобы решен: github.com/javaparser/javaparser/issues/124

И есть некая начальная реализация этой идеи: github.com/javaparser/javaparser/pull/654

В частности, текущая реализация совершенно точно старается сохранить наличие комментариев.

По поводу всего остального, есть проблемы.

В частности вот тут оказывается, что их реализация добавляет и удаляет переносы строк там, где не нужно: github.com/javaparser/javaparser/issues/1293

А вот тут люди заметили, что ноды реордерятся без особой нужды: github.com/javaparser/javaparser/issues/912

С другой стороны, там уже 4 тысячи коммитов, и они продолжают идти (последний коммит был несколько дней назад), так что — может и дождемся?

Кстати, а зачем тебе сохранять пробелы?
Например чтобы делать массовый рефакторинг имеющегося кода по своим собственным правилам.
Если будешь разбираться, как оно там внутри пробелы расставляет (и можно ли таким образом повлиять на форматирование) — напиши, пожалуйста?
Я так понимаю, Dr_XaoS под рефакторингом имел ввиду не расстановку пробелов по собственным правилам, а примерно то же, что я описал ниже. Например, есть задача сменить название класса Foo на Bar. Тогда ожидается, что будут заменены только эти 3 символа, а не «покорежен» (как вы нам обещаете в заголовке) весь файл.
Кстати, а зачем тебе сохранять пробелы?
Чтобы получать минимальные диффы при коммите. В частности, страшно раздражают графические редакторы, которые из-за одной незначительной правки корежат весь файл (например, SVG). После нескольких десятков изменений уже практически невозможно отследить кто, когда и что менял.
Кстати, может быть это предпосылка к тому, чтобы делать структурные диффы, вместо сырого текста?
В любом случае неприятно, когда все форматирование идет «коту под хвост». Если я поменял в редакторе цвет квадратика с синего на красный, то только blue на red в строго определенном месте он должен заменить. А не выворачивать все шиворот-навыворот.
Ну просто lexical preservation это капец какая сложная задача :)
Не самая простая, возможно. Но и далеко не самая сложная относительно других задач приложения. Просто разработчикам на результат совершенно «по барабану».
Всё-таки настаиваю, что задача капец какая сложная. Потому что все трансформации выполняются на уровне AST, а не исходного кода. А AST ничего о сырце до лексера не знает. То есть это не так что ты прошёлся по текстовому файлу, и заменил там все названия класса с одного на другой find-and-replace'ом, а какая-то безумная конструкция, которая кроме логики должна хранить ещё и представление где-то между строчек…
Интересно, если это «капец какая сложная», то какой эпитет вы подберете для по-настоящему сложных задач? :-)

А AST ничего о сырце до лексера не знает.
Правильнее сказать, интерфейс AST-узлов не знает ничего об исходной структуре. Но это не мешает нам придумать для него любую реализацию — может, у вас синтаксическое дерево вообще в виде записей в SQL-таблице хранится? Тогда очевидно, что реализация узла должна знать, как минимум, первичный ключ записи в таблице.
Эпитет «всё пропало» :-) Задача достаточно сложная, чтобы в IntelliJ IDEA и Eclipse этой возможности реализовано не было, хотя делают эти редакторы лучшие в мире программисты и компании, специально занимающиеся данным вопросом

хотя, если у тебя есть идеи как это сделать правильно, — можешь поделиться ими прямо здесь?
Это решается по-разному в зависимости от других задач приложения. В случае с простым текстовым редактором у вас уже есть некий буфер с оригинальным текстом, который вы выводите на экран. Соответственно, в AST-узлах могут быть проставлены ссылки (в Java — целочисленное смещение относительно начала буфера) на соответствующие им куски кода. Если редактор офигеть какой навороченный (не уверен, относятся ли сюда Eclipse и IDEA, это больше ко всяким Word'ам), то там набираемый текст может храниться в несколько более странном виде, например, rope (как это перевести на русский? :-) Тогда лучше хранить куски текста «вокруг» AST-узлов (которые очень хорошо сжимаются). Почему это не сделано в упомянутых вами программах — не знаю, лентяи, наверное. Я лично реализовывал подобное для одного небольшого конфигурационного языка с Си-подобным синтаксисом (пользователь должен иметь возможность изменить настройки как руками, так и через GUI, и чтобы при этом файл все еще был пригоден для ручного редактирования). Задача, действительно, не очень распространенная (в силу лени других разработчиков), но и не «капец какая сложная», если разработчик имеет привычку думать самостоятельно, а не сдаваться, не найдя готового решения в Интернете. Возможно, мое решение не самое лучшее (потому при случае интересуюсь, как это делают другие), но более детальное описание чем то, что размещено выше, дать не могу, чтобы не деанонимизироваться.

Off topic
Прощу прощения, все никак не удается вспомнить — мы разве с вами знакомы? Почему вы все время обращаетесь ко мне на «ты»?
Сейчас у меня нет времени, но давайте на следующих выходных я напишу статью с примером парсера простых математических выражений типа 1 + (2* 1). Пробелы при этом, естественно, будут сохраняться. От парсера какой-нибудь Java этот пример практически ничем не отличается. Чтобы вы не пропустили публикацию, отправлю вам ссылку в личку.
Не хотелось бы, чтобы в аст был какой-то мусор (типа ссылок на соответствующие куски кода). Это смешивание смысла и представление в одной сущности, это плохо. Можешь сделать так, чтобы аст остался идеально чистым?
Задача достаточно сложная, чтобы в IntelliJ IDEA и Eclipse этой возможности реализовано не было, хотя делают эти редакторы лучшие в мире программисты и компании, специально занимающиеся данным вопросом

Апелляция к авторитету? Так себе аргумент.
Вполне возможно, что просто сочли нецелесообразным тратить на это время.
Разработчики в штате — потому, что есть дела поважнее, опенсорс контрибьюторы — потому, что есть задачи поинтереснее.
Что вас пугает в этой задаче?


В идее и кнопки на тулбарах через GUI не поменять (через API можно). Тоже скажете, что это ужасно сложная задача?

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

Например, в веб-приложении у тебя есть строго отдельный HTML, строго отдельный CSS в виде классов, отдельные данные на клиенте, отдельные данные на сервере в контроллерах, отдельные — в сущностях БД мапящихся с помощью ORM, отдельные — собственно в базе данных. Цепочки всевозможных dto-маперов и редюсеров для перебрасывания инфы, архитектуры типа MVC и react-redux, итп. Если же ты попытаешься не делать так и смешаешь логику и представление (условное JSP с вызовом из него БД селектами), это будет некрасиво, и тебе за это отрубят голову, насадят на кол, и поставят на центральной площади, чтобы другим непоавдно было

так вот, можно взять один аст, и засунуть прямо в него какие-то маркеры, пустые ноды, итп. Но это будет равносильно как если бы ты перемешал HTML+CSS в одном файле — это прямой путь чтобы твоя голова на колу висела на центральной площади

а как сделать это красиво и правильно, с разделением, пока непонятно

точнее понятно — типа мы можем назначить условный динамический мапинг между астом и формой откуда оно взялось, и этот мапинг хранится отдельно (чтобы аст остался чистым). Потом для любого возможного рефакторинга пишем трансформацию, которая будет параллельно делаться три раза: над астом, над исходником и над мапингом. И как-то держим, чтобы оно всё не развалилось, какая-то мегаэвристика

но все эти вещи требует нецелесообразно большого вложения сил… по сравнению с чудесным простым решением — пусть парсер каждый раз весь код переформатирует как ему удобно
так вот, можно взять один аст, и засунуть прямо в него какие-то маркеры, пустые ноды, итп. Но это будет равносильно как если бы ты перемешал HTML+CSS в одном файле
Еще раз, зачем вы мешаете в кучу интерфейс и реализацию? Есть, например, интерфейс AST-узла. Через него нельзя получить никакие маркеры. А есть реализация. В ней может находиться все, что душе разработчика угодно. Могу вам назло FTP-сервер туда засунуть.

На вашем примере HTML+CSS разделение происходит только на уровне некого интерфейса между веб-разработчиком и веб-браузером. Загляните, например, в исходники WebKit — там у DOM-узла (читайте AST-узла) в реализации не то что стили, там даже рендерер свой имеется.
Тут бы спросить lany о том, как там в Идее с сохранением форматирования при рефакторингах. Всё хорошо?

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

Спасибо за статью, как раз недавно думал, что мне бы пригодился подобный инструмент.
Для чего конкретно пригодился бы, можешь рассказать?
Я хочу сделать небольшую утилиту для кодогенерации на основании существующего Java-кода, по сути автоматизация ряда рутинных операций.
Навскидку сложно сказать, надо поглубже разобраться с обоими и сравнить, когда на это будет время — непонятно.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий