Переменные¶
Панель Variables показывает деревом всё, что находится в области видимости выбранного фрейма стека. Открывается по Ctrl+V, и именно на ней фокус оказывается при открытии окна.
Как читать дерево¶
Верхний уровень — области видимости, о которых сообщил адаптер: Locals,
Arguments, глобальные и всё прочее, что есть в языке. Под каждой — её
переменные, под структурной переменной — её поля.
Если Locals — единственная область видимости и адаптер не пометил её как
дорогую, лишняя строка Locals скрывается: переменные сразу показываются на
верхнем уровне и загружаются автоматически. Если областей несколько или
единственная область дорогая, их заголовки остаются видимыми и свёрнутыми.
| Клавиши | Действие |
|---|---|
| J / K, Down / Up | двигать выделение |
| L / Right | развернуть узел |
| H / Left | свернуть узел |
| Enter / Space | переключить узел |
| G / Shift+G | первая / последняя строка |
Цвет означает вид значения¶
Цвет говорит не о важности, а о том, на что вы смотрите:
| Цвет | Вид |
|---|---|
| Зелёный | строка |
| Синий | число, bool |
| Приглушённый | nil / null / None |
| Серый в фигурных скобках | имя типа |
Поиск¶
/ открывает строку поиска внизу панели. Совпадения ищутся по ходу
набора, выделение прыгает на ближайшее вниз от строки, с которой
начали, и заворачивается в конце списка. Enter заканчивает ввод; после него
N и Shift+N ходят вперёд и назад по найденному, а счётчик справа
показывает, где вы сейчас, — 3/17. Esc сбрасывает поиск.
| Где ищет | только в имени переменной; ни значение, ни тип не ищутся |
| Регистр | строчный запрос ищет без учёта регистра, любая заглавная буква включает точное сравнение |
| Сравнение | подстрока — не регулярное выражение и не fuzzy |
Поиск достаёт и то, что вы не раскрывали. Поле внутри свёрнутого узла
находится по имени, а прыжок на него раскрывает путь до него. То, чего адаптер
ещё не присылал, поиск добирает сам: пока вы набираете, окно обходит дерево и
запрашивает недостающие узлы, начиная с мелких, — и счётчик растёт по мере
ответов. Слово scanning рядом со счётчиком означает, что обход ещё идёт; пока
он идёт, пустая выдача не выдаётся за no matches, потому что «не нашлось» и
«ещё не дошли» — разные ответы.
Всё, что адаптер прислал, остаётся доступным поиску до следующего движения программы — свёрнут узел или нет.
Раскрытое поиском остаётся раскрытым и после Esc: привести вас туда и было его задачей. Сам поиск переживает шаг — запрос и подсветка остаются, совпадения пересчитываются в новом снимке, а выделение возвращается на то же поле. В этом и смысл: нашли поле, жмёте F8 и смотрите, как меняется его значение, ничего не набирая заново.
Чем поиск ограничен¶
| Ограничение | Значение | Что делает |
|---|---|---|
| Показываем совпадений | 10 | список обрезается здесь, вместе с ним встаёт и обход |
| Узлов | 2000 | обход встаёт, спросив у адаптера столько узлов |
| Глубина | 12 уровней | глубже в очередь не попадает вовсе |
| Запросов за порцию | 32 | придерживает темп, ничего не останавливает |
| Пауза в наборе | 500 мс | сколько запрос должен простоять, прежде чем его пересчитают |
| Элементов с контейнера | 100 | первая страница массива, а не весь он |
Первые три останавливают поиск и объединены «или»: что первым наступит, то и
остановит. partial появляется всегда, когда что-то осталось за бортом:
совпадений больше, чем помещается, или дерево обойдено не всё. Если и то и
другое закончилось само — обычный счётчик или no matches.
Предел совпадений — это предел на список, а не на обход. Один загруженный узел приезжает со всеми детьми разом, поэтому предел, останавливающий только обход, превращал бы обещанные десять ответов в сотню. Список обрезается на десяти, а о том, что за ним, сообщается, а не показывается.
Ctrl+/ показывает ещё одну порцию — ещё десять совпадений — и выдаёт обходу на их поиск ещё 2000 узлов и 12 уровней. Он сдвигает пределы, а не снимает их, и обход продолжается с того места, где встал: ни один узел не спрашивается дважды за одну остановку. Правка запроса возвращает предел к десяти: другой запрос — другой поиск, и выданная порция к нему не относится.
Предел совпадений связывает только тогда, когда совпадений много. Запрос,
которому мало что отвечает, останавливается не им, а пределом узлов или
глубины — поэтому узкий поиск успевает уйти далеко, прежде чем скажет
partial. Эти пределы защищают от противоположных ошибок: десять совпадений —
от слишком широкого запроса, 2000 узлов — от слишком узкого. Вместе они и не
дают циклическому или практически бесконечному графу объектов превратить / в
бесконечный поток запросов.
Совпадения пересчитываются, когда набор приостановился, а не на каждую букву: иначе быстро набирающий человек оплачивал бы каждый промежуточный запрос, который и не думал искать. Пауза считается от последней нажатой клавиши, поэтому длинное имя, набранное подряд, стоит ровно одного пересчёта. Enter ждать не заставляет.
Новая остановка сбрасывает всё: спрошенное, бюджеты и все выданные Ctrl+/. Сам поиск при этом живёт — запрос и подсветка остаются.
Что видно¶
Каждая совпавшая строка подсвечена заливкой, а внутри неё выделен совпавший кусок имени — так видно, почему строка попала в список. Текущее совпадение — это и есть выделенная строка, второго вида выделения держать в голове не нужно. Значение не подсвечивается никогда: поиск туда не смотрит, а подсветка обещала бы совпадение там, где его не искали.
Загрузка ленивая, и это намеренно¶
Свёрнутый узел не порождает запроса. Данные подгружаются в момент разворачивания, причём только непосредственные потомки — граф объектов никогда не обходится рекурсивно.
Единственное исключение — описанная выше единственная недорогая область
Locals: её непосредственные потомки запрашиваются автоматически, потому что
сам заголовок области не показывается.
Большие коллекции берутся страницами, а не целиком. Массив на сто тысяч элементов не приезжает одним ответом и не морозит окно: страницы подгружаются по мере прокрутки.
Это заметно на практике: поэтому разворачивание большой структуры быстрое, и поэтому значение иногда появляется не мгновенно при первом открытии.
Значения относятся к своей остановке¶
Всё показанное в панели закэшировано относительно текущей остановки. Как только программа сдвинулась — шаг, продолжение, новая точка останова — кэш сбрасывается и дерево строится заново. Ответы, пришедшие с опозданием, когда программа уже ушла дальше, отбрасываются, а не показываются: значение с прошлой остановки рядом с текущей строкой было бы хуже, чем отсутствие значения.
Обрезанные и слишком большие значения¶
Адаптеры обрезают длинные значения. Когда это происходит, в строке видно то, что пришло, а панель Inspector — Ctrl+I — показывает полное значение выбранной строки, прямо сообщает, что адаптер его обрезал, и предлагает скопировать или отформатировать как JSON.
Ничего не показано¶
Если дерево пусто, а программа остановлена, посмотрите в Стек вызовов: фрейму без отладочной информации нечего сообщать об областях видимости. Это нормально для оптимизированного и стороннего кода, а также для Rust- или C/C++-бинарника, собранного в release.