Skip to content

fix(lsp): answer while stdin is open and decode \uXXXX in JSON - #295

Merged
the-homeless-god merged 2 commits into
digitable-lol:mainfrom
MyWWWChat:fix/lsp-answers-while-stdin-open
Oct 4, 2026
Merged

the-homeless-god merged 2 commits into
digitable-lol:mainfrom
MyWWWChat:fix/lsp-answers-while-stdin-open

Conversation

@MyWWWChat

@MyWWWChat MyWWWChat commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Исправляет #294.

Что дерево теперь делает, чего не делало

  • flang lsp и --mcp-mode отвечают, пока стандартный ввод открыт. Ввод читался fread(chunk, 1, 8192, stdin) — это ждёт полный кусок или конец ввода, а редактор ввод не закрывает. Теперь repl_read_some: read(STDIN_FILENO, …) с повтором на EINTR, возвращает то, что уже пришло. Оба места чтения (lsp_read_frame и строки --mcp-mode).
  • Строки JSON с \uXXXX разбираются (run_text): \uXXXX и суррогатные пары — в UTF-8; одинокая половина пары по-прежнему отказ. Прежде сообщение с таким экранированием сервер выбрасывал («неразобранный JSON»).
  • Правка — в flang/src/emit/c/flang_repl.c и та же в печатной копии bootstrap/flang_repl.c (печатная = шапка из 9 строк + исходник; сверено до и после).

Проверка сервера в редакторе

scripts/editors/lsp-check.fscript на main красна при любом двоичном: «диагностика до редактора не доехала». Первый шаг пропускал по серверу на Node, а Node снят — ворота проходили вхолостую, и Neovim без g:flang_dvoichnyy_lsp сервера не находил. Теперь:

  • первый шаг требует, чтобы на лету отвечал двоичный (FLANG_LSP_NE_POTOK — «двоичный flang lsp не отвечает при открытом вводе»); функция «Node отвечает на лету» убрана;
  • Neovim запускается с g:flang_dvoichnyy_lsp = 1 и bootstrap/ первым в PATH — проверяется двоичный этого дерева;
  • ожидаемая строка перехода была 6, объявление «Удвоить» в probe-transition.flang стоит на строке 3 — до этого шага проверка прежде не доходила.

Утверждений в файле 21 (было 23: ушли два у убранной функции): доказано 17, объявлено 4 — те же четыре, что и прежде. scripts/ledgers/proved-share-ledger.txt — строка перемерена --proof (старая говорила 23/23 при уже разошедшемся md5).

Что не меняется

Двоичный сервер в docs/editors/vim/autoload/flang.vim остаётся по явной просьбе: у людей стоят выпуски по 0.7.24 включительно, и они молчат. Поднять его наверх — решение для выпуска с исправлением; README и комментарий в autoload/flang.vim теперь говорят ровно это. docs/tree-inventory.md — пять чисел строк перемерены (C, Vimscript, bootstrap/**, рантаймы flang/src/emit/**, docs/editors/vim/**).

Что прогнано

Linux x86-64, gcc 13, Neovim 0.12.4. bootstrap/flang собран make -C bootstrap из того же C (flang_repl.c, остальной C на main с v0.7.24 не менялся).

Прогон Итог
замер: initialize, ввод открыт 3 с v0.7.24: 0 байт при открытом вводе, 334 после закрытия; ветка: 334 и 334
а, 😀 в строке JSON v0.7.24: «неразобранный JSON»; ветка: ответ initialize
одинокая \ud83d обе: «неразобранный JSON»
flang io scripts/editors/lsp-check.fscript --trust код 0: 334/334 байт; FLANG_TYPE доехала до буфера; переход на строку 3; наведение с подписью
то же с bootstrap/flang от v0.7.24 (правка снята) код 1: «двоичный flang lsp не отвечает при открытом вводе … 0 байт»
flang check scripts/editors/lsp-check.fscript код 0
.githooks/commit-msg.fscript, origin/main..HEAD commit messages checked: 1
.githooks/pre-push.fscript 19 из 21 зелены; proved-share-vs-tree покраснела на строке описи и после её перемера отдельно — код 0; lint-growth без origin/dev красна, с подтянутой origin/dev — код 0 («no line crossed the limits»)
prose-numbers-guard, inventory:check код 0: 210 из 210 примет, 17 языков

Что не прогнано

  • полный набор тестов, CI и печать в другие цели — правка только в хозяине C;
  • Vim 8/9 через vim-lsp — в lsp-check честно ПРОПУЩЕНА: FLANG_VIM_LSP не задан;
  • --mcp-mode живым клиентом MCP — та же функция чтения, но отдельно не гонял;
  • macOS.

`flang lsp` and `--mcp-mode` read stdin with fread(chunk, 1, 8192, stdin),
which returns only after 8192 bytes or end of input. An editor never closes
the server's stdin, so the reply to `initialize` (334 bytes) never left: 0
bytes while the input is open, 334 after it closes. Read with read(2), which
returns what has arrived (repl_read_some).

run_text rejected any JSON string with \uXXXX, so the server dropped such a
message with "unparsed JSON" on stderr. Decode \uXXXX and surrogate pairs to
UTF-8; a lone half of a pair is still rejected.

The printed copy in bootstrap/ comes in the next commit, from a reprint
(scripts/bootstrap-reprint.sh), not by hand.

scripts/editors/lsp-check.fscript now gates on the binary answering while
stdin is open (the Node server it gated on is gone, so the gate passed
vacuously) and runs Neovim on bootstrap/flang with g:flang_dvoichnyy_lsp = 1.
Its expected definition line was 6; the declaration in
probe-transition.flang is on line 3. The check never reached that step
before, because Neovim found no server.

The binary stays opt-in in autoload/flang.vim: released binaries up to
0.7.24 still hang. README and the autoload comment say so.
docs/tree-inventory.md: five line counts remeasured.
scripts/ledgers/proved-share-ledger.txt: lsp-check.fscript remeasured with
--proof (21 written: 17 proved, 4 declared; the old line said 23/23 for a
file whose md5 had already changed).

Refs digitable-lol#294
@MyWWWChat
MyWWWChat force-pushed the fix/lsp-answers-while-stdin-open branch from 53e4047 to 23e3264 Compare October 4, 2026 13:04
The seed is printed from 23e3264 by the GPU-cache build on the reprint
script (code 0, 3205 s). Of the seven files only bootstrap/flang_repl.c
changed, which is the file the fix touches; the other six are byte for
byte as before. The printed seed was built and asked before it went into
bootstrap/, and scripts/seed-fingerprint names commit 23e3264.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019LuK84yUqX31p5tyBKcaTJ
@the-homeless-god

Copy link
Copy Markdown
Member

Обе находки проверил своими прогонами на нынешнем dev, не со слов.

1. Сервер молчит, пока ввод открыт — воспроизводится. Первый мой заход был
негодный: я считал байты ПОСЛЕ закрытия ввода и получил 334 в обоих случаях,
то есть ничего не различил. Переделал — держу ввод открытым и смотрю на счётчик
по дороге:

байт через 3 с, ввод ЕЩЁ ОТКРЫТ: 0
байт после закрытия ввода:       334

Это и значит, что flang lsp в редакторе не работал никогда: редактор ввод не
закрывает.

2. \uXXXX отвергается — видно в исходнике, и это сильнее любого прогона.
flang/src/emit/c/flang_repl.c, run_text (строка 9861):

} else if (next == 'u') {
  free(buffer);
  return false;

То есть строка с \u не разбирается, а run_text зовётся из четырёх мест
(9952, 10002, 14571, 14648), включая разбор ключей JSON. Мои пробы через
textDocument/didOpen этого не задели — там, судя по ответу (469 байт и с
экранированием, и байтами UTF-8), другой путь разбора. То есть беда есть, но
место её шире и уже одновременно, чем сказано в заголовке: не «сервер
выбрасывал сообщение», а «любая строка с \u, которая идёт через run_text».
Если у тебя есть прогон, где именно LSP на этом падал, — назови его, он
уточнит область.

3. Третья находка — самая ценная, и она про проверку, а не про код.
scripts/editors/lsp-check.fscript проходил вхолостую: первый шаг спрашивал
сервер на Node, а Node из дерева снят. Проверка редактора не проверяла
редактор. Это у нас уже двенадцатый случай той же породы за сутки, и он
попадёт в заметку о проверках, которые не проверяют.

Что нужно поправить, прежде чем это уедет в ствол

  • Основание не то. PR нацелен в main, а у нас ветка работы идёт в dev,
    и уже оттуда в main под метку. Перенацелю и перебазирую сам.
  • Автор коммитов — f-tester <f@example.com>. По правилу дерева автор один:
    Marat Zimnurov <zimtir@mail.ru>. Перепишу при перебазировании.
  • Приписки про ИИ в теле PR («Generated with …» и ссылка на сессию) убраны
    мной: по правилу дерева их не бывает ни в сообщении коммита, ни в теле.
  • Столкновение по семени. PR правит bootstrap/flang_repl.c и
    scripts/seed-fingerprint; то же делает открытый PR 299. Чей-то пересев
    придётся повторить — порядок такой: сперва 299, потом этот, с новым
    seed:refresh и переснятым отпечатком.

Содержимое беру, спасибо — находка про молчащий сервер дороже всего, что я
сегодня нашёл сам.

@the-homeless-god
the-homeless-god merged commit 5f0ae6a into digitable-lol:main Oct 4, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants