|
| 1 | +# Технический обзор проекта anycode |
| 2 | + |
| 3 | +**anycode** — это высокопроизводительная веб-IDE, предназначенная для написания, редактирования и управления кодом прямо в браузере. Проект создан с упором на скорость и поддерживает широкий спектр языков программирования. |
| 4 | + |
| 5 | +## Технологический стек |
| 6 | + |
| 7 | +### Бэкенд (Rust) |
| 8 | + |
| 9 | +- **Tokio**: Асинхронный рантайм, являющийся стандартом для написания производительных сетевых приложений на Rust. |
| 10 | +- **Axum**: Минималистичный и мощный веб-фреймворк, используемый для маршрутизации HTTP-запросов. |
| 11 | +- **Socketioxide**: Реализация сервера `Socket.IO`, обеспечивающая надежную двунаправленную связь с клиентом в реальном времени. |
| 12 | +- **LSP-types**: Набор структур данных для удобной работы с протоколом LSP. |
| 13 | + |
| 14 | +### Фронтенд (TypeScript/React) |
| 15 | + |
| 16 | +- **React & TypeScript**: Основа для создания интерактивного и строго типизированного пользовательского интерфейса. |
| 17 | +- **Vite**: Современный сборщик, обеспечивающий практически мгновенную горячую перезагрузку модулей (HMR) и быструю сборку проекта. |
| 18 | +- **PNPM**: Эффективный менеджер пакетов, идеально подходящий для монорепозиториев благодаря своей системе хранения пакетов. |
| 19 | + |
| 20 | +## Архитектура и взаимодействие компонентов |
| 21 | + |
| 22 | +Проект имеет монорепозиторную архитектуру, управляемую с помощью `pnpm workspaces`. Это позволяет централизованно управлять зависимостями и упрощает взаимодействие между пакетами. |
| 23 | + |
| 24 | +- `anycode-backend/` (Rust): Серверная часть, которая служит мостом между веб-интерфейсом и локальной системой пользователя. Фронтенд общается с бэкендом через **WebSockets** (с использованием `Socket.IO`), отправляя запросы на чтение/запись файлов, поиск, запуск терминала и взаимодействие с LSP. |
| 25 | +- `anycode-base/`: "Движок" редактора. Этот пакет не зависит от UI-фреймворков и содержит всю основную логику: |
| 26 | + - Управление состоянием редактора (текст, курсор, выделение). |
| 27 | + - Интеграция с `web-tree-sitter` для парсинга кода в реальном времени. |
| 28 | + - Реализация виртуализированного рендеринга для отображения только видимой части файла, что обеспечивает высокую производительность при работе с большими объемами кода. |
| 29 | +- `anycode-react/`: React-компонент, который оборачивает `anycode-base` и предоставляет ему React-контекст, управляя его жизненным циклом и событиями. |
| 30 | +- `anycode/`: Основное приложение, которое собирает все части вместе. Оно использует `anycode-react` для отображения редактора, а также реализует остальные элементы интерфейса (файловый менеджер, терминал) и логику их взаимодействия с бэкендом. |
| 31 | + |
| 32 | +## Ключевые функции: детальный обзор |
| 33 | + |
| 34 | +### Движок редактора |
| 35 | + |
| 36 | +Ядро `anycode` — это собственный движок, построенный на базе `anycode-base`. Его ключевые особенности: |
| 37 | +- **Парсинг с помощью Tree-sitter**: Вместо использования простых регулярных выражений, редактор строит полное синтаксическое дерево (AST) кода. Это позволяет реализовать точную и быструю подсветку синтаксиса, а также является основой для более сложных функций анализа кода. |
| 38 | +- **Управление текстом**: Для эффективной работы с текстом используется библиотека `vscode-textbuffer`, которая оптимизирована для частых вставок и удалений, характерных для текстовых редакторов. |
| 39 | + |
| 40 | +### Виртуализация рендеринга: как это работает |
| 41 | + |
| 42 | +Ключ к производительности редактора при работе с большими файлами — это техника виртуализации. Вместо того чтобы наивно отображать тысячи DOM-узлов для каждой строки, `anycode` гарантирует, что в DOM всегда находится лишь небольшое, постоянное количество элементов. |
| 43 | + |
| 44 | +1. **Viewport (Окно просмотра)**: Основная идея — рендерить только те строки, которые физически видны пользователю. Эта видимая область называется "viewport". Количество отображаемых строк вычисляется на основе высоты viewport и высоты одной строки. Например, если высота окна 800px, а высота строки 20px, в DOM будет находиться всего около 40 элементов строк плюс небольшой буфер. |
| 45 | + |
| 46 | +2. **Spacers (Распорки)**: Чтобы полоса прокрутки браузера отражала реальный размер файла (а не только размер видимой части), используются два вспомогательных элемента-"распорки" (`div`): |
| 47 | + - **Верхний спейсер**: Располагается над видимыми строками. Его высота равна суммарной высоте всех строк, находящихся *выше* viewport. |
| 48 | + - **Нижний спейсер**: Располагается под видимыми строками. Его высота равна суммарной высоте всех строк *ниже* viewport. |
| 49 | + Эти спейсеры "растягивают" контейнер до полного размера файла, обеспечивая корректное поведение скроллбара. |
| 50 | + |
| 51 | +3. **Динамическое обновление при скролле**: При прокрутке происходит следующее: |
| 52 | + - **Прокрутка вниз**: Строки, уходящие за верхнюю границу viewport, удаляются из DOM. На их место внизу добавляются новые строки, которые должны стать видимыми. При этом высота верхнего спейсера увеличивается, а нижнего — уменьшается. |
| 53 | + - **Прокрутка вверх**: Процесс обратный: строки, уходящие за нижнюю границу, удаляются, а сверху добавляются новые. Высота верхнего спейсера уменьшается, а нижнего — увеличивается. |
| 54 | + |
| 55 | +Этот механизм гарантирует, что независимо от размера файла (будь то 100 строк или 100 тысяч строк), количество DOM-элементов остается постоянным, что и обеспечивает высочайшую производительность и отзывчивость интерфейса. |
| 56 | + |
| 57 | +### Рендеринг и редактирование кода |
| 58 | + |
| 59 | +Производительность редактора достигается за счет комбинации нескольких техник: |
| 60 | + |
| 61 | +- **Высокоэффективное редактирование**: Процесс внесения изменений происходит в несколько этапов, каждый из которых максимально оптимизирован: |
| 62 | + 1. **Обновление модели текста**: Изменение (вставка или удаление символа) сначала применяется к структуре данных в `vscode-textbuffer`. |
| 63 | + 2. **Инкрементальный парсинг**: Далее информация об изменении передается в `tree-sitter`. Ключевое преимущество `tree-sitter` в том, что он является **инкрементальным парсером**. Ему не нужно заново анализировать весь файл. Он перестраивает только ту часть синтаксического дерева, которая была затронута изменением. Этот процесс занимает доли миллисекунд даже для очень больших файлов. |
| 64 | + 3. **Обновление кеша и перерисовка**: После обновления дерева пересчитывается информация для подсветки затронутых строк. Эти данные обновляются в кеше строк, и редактор точечно обновляет только измененные DOM-элементы. |
| 65 | + |
| 66 | +Благодаря такому подходу, где на каждом шаге избегается полная переобработка данных, редактирование кода ощущается мгновенным. В результате применения этих оптимизаций, таких как виртуализация, кеширование и инкрементальный парсинг, достигается исключительно плавное взаимодействие с редактором: курсор, выделение и скроллинг работают нативно, без задержек. |
| 67 | + |
| 68 | +### Интеграция с Language Server Protocol (LSP) |
| 69 | + |
| 70 | +Бэкенд на Rust выступает в роли клиента для различных языковых серверов (например, `rust-analyzer` для Rust, `gopls` для Go). |
| 71 | +1. Фронтенд отправляет информацию о действиях пользователя (например, наведение мыши на символ) на бэкенд. |
| 72 | +2. Бэкенд перенаправляет этот запрос соответствующему языковому серверу по стандартному протоколу LSP. |
| 73 | +3. Получив ответ (например, информацию о типе или документацию), бэкенд отправляет его обратно на фронтенд, который отображает подсказку. |
| 74 | + |
| 75 | +### Встроенный терминал |
| 76 | + |
| 77 | +Интегрированный терминал — это комбинация двух технологий: |
| 78 | +- **`Xterm.js`** на фронтенде: Мощная библиотека для эмуляции терминала в браузере, которая отвечает за рендеринг текста, обработку ввода и поддержку таких функций, как цвета и стили. |
| 79 | +- **`portable-pty`** на бэкенде: Rust-библиотека, которая создает на сервере настоящий псевдотерминал (pty) и подключает к нему системную оболочку (например, `bash` или `zsh`). Весь ввод и вывод из этой оболочки передается на фронтенд через WebSockets. |
0 commit comments