У каждого языка программирования есть формальная грамматика. Компилятор читает её, строит parse tree и отвергает всё, что не подходит. Редактор полностью игнорирует грамматику и позволяет вам печатать что угодно.
Это рассогласование — источник удивительно большого трения. Autocomplete предлагает идентификаторы, которые не имеют смысла в контексте. Syntax highlighting ломается посреди рефакторинга. Вы получаете ошибки “Unexpected token” за ошибки, которые редактор видел, как вы их совершали. Мы считаем это нормальным, потому что текстовые редакторы — всё, что было у нас сорок лет.
Текст — промежуточное представление. Компилятор выбрасывает его в тот момент, когда делает parse. Так почему же именно текст мы редактируем?
Что на самом деле означает структурное редактирование
Структурное редактирование означает, что источником истины является Abstract Syntax Tree, а не буфер символов. Редактор рендерит дерево в виде текста для вашего удобства, но каждая операция манипулирует узлами напрямую. FunctionDeclaration. BinaryExpression. IfStatement. Это атомы.
Хотите добавить параметр? Вы не ставите курсор между скобками и не печатаете. Вы вызываете операцию “add parameter” на узле FunctionDeclaration. Редактор создаёт новый узел Parameter с placeholder. Отрендеренный текст обновляется. Вы никогда не создадите несбалансированные скобки, потому что скобки — не символы, которые вы вводите. Это визуальные границы, генерируемые рендерером.
Это не научная фантастика. Lisp работает так с 1960-х годов, потому что S-expressions по определению являются деревьями. Smalltalk рассматривал методы как выбираемые объекты в браузере, а не как файлы, по которым можно делать grep. В более новое время язык Unison хранит код как Merkle tree из узлов AST, а JetBrains MPS — projectional editor, в котором грамматика определяет и язык, и опыт редактирования.
Гарантия структурной безопасности
Вот что делает древовидный редактор, когда вы рефакторите. Этот скрипт на Python приближает внутреннюю логику:
import ast
# The canonical representation is a tree, not text
tree = ast.parse("result = calculate(x, y)")
# Find the Call node and append a keyword argument
for node in ast.walk(tree):
if isinstance(node, ast.Call):
node.keywords.append(
ast.keyword(arg='debug', value=ast.Constant(value=True))
)
# Render to text only when needed (Python 3.9+)
print(ast.unparse(tree))
# result = calculate(x, y, debug=True)
Операция структурно безопасна. Вы не можете случайно получить calculate(x, y debug=True), потому что keywords — это типизированный список узлов keyword, а не строковый буфер. Рендерер вставляет запятую и знак равенства. Дерево всегда синтаксически валидно.
Так работают большинство форматтеров и линтеров. Black, prettier и rustfmt все делают parse в AST, трансформируют дерево и выводят текст. Разница в том, что они читают текст, трансформируют и пишут текст. Древовидный редактор пропускает текстовый round-trip.
Почему никто не использует древовидные редакторы
Если это так хорошо, почему каждый профессиональный разработчик всё ещё использует VS Code, Vim или Emacs?
Скорость взаимодействия — первая причина. Редактирование текста оптимизирует тесный цикл: вы думаете об изменении, ваши пальцы печатают символы, ваши глаза проверяют. Каждое нажатие клавиши — одна и та же операция. В древовидном редакторе “insert an if statement”, “rename a variable” и “extract a method” — все разные жесты. Вы не можете просто долбить по клавишам. Когнитивные накладные расходы накапливаются.
Стена экосистемы — вторая причина. Каждый инструмент в вашем pipeline предполагает текст. git diff, grep, code review на GitHub, поиск по коду, каждый туториал в интернете. Структурированные форматы существуют, но ни один не вытеснил сырой текст как исходный код. Сетевой эффект абсолютен.
Проблема визуального рендеринга — третья. Программисты читают код как текст с десятилетиями типографских конвенций. Куда идёт комментарий, если он описывает половину узла? Как отобразить дерево посреди операции, когда пользователь ещё не закончил указывать, чего он хочет? Рендеринг дерева как читаемого, редактируемого текста сложнее, чем рендеринг текста как дерева.
Структурные команды в текстовых редакторах
Вам не нужно менять редактор, чтобы получить преимущества осведомлённости о дереве. Несколько инструментов уже работают с AST, представляя текстовый интерфейс.
Paredit и Smartparens для Lisp рассматривают S-expressions как деревья. Вы “заглатываете” выражение в родительскую область видимости или “выплёвываете” его. Скобки остаются текстом, но команды редактирования — это операции над деревом. Вы перемещаете целые subtree, никогда не создавая синтаксической ошибки.
Современные рефакторинги IDE делают parse вашего кода, строят AST, определяют, какие переменные становятся параметрами, и переписывают дерево. Когда вы делаете “extract method” в IntelliJ, он не выполняет text replacement. Он выполняет структурную трансформацию и выводит результат.
Language server внутренне строят AST для каждой операции. Go-to-definition, rename и inline hints — всё это обход дерева. Протокол передаёт текстовые позиции для совместимости, но интеллект структурный.
Как экспериментировать, не меняя редактор
Если вы хотите сузить разрыв между тем, как вы пишете код, и тем, как компилятор его понимает, начните здесь:
-
Используйте модуль
astPython. Напишите скрипт, который делает parse реального кода, обходит дерево с помощьюast.walkи трансформирует его. Большинство инструментов Python (flake8, mypy, Black) делают именно это. -
Исследуйте Tree-sitter. Сделайте parse файла в онлайн-площадке и изучите concrete syntax tree. Посмотрите, что на самом деле видит парсер.
-
Попробуйте структурное редактирование для Lisp. Если вы пишете на Clojure или Emacs Lisp, установите Paredit. Заставьте себя перемещаться по expression, а не по символу, в течение одного дня. Медлительность поучительна.
Текстовый файл никуда не денется. Слишком много инструментов, слишком много истории, слишком много muscle memory. Но разрыв между текстовым редактированием и структурным пониманием — реальный источник багов, трения и когнитивной нагрузки. Вам не нужен древовидный редактор, чтобы это исправить. Нужно перестать притворяться, что текст — это настоящее.