Перейти к содержанию

Переменные

Панель 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: её непосредственные потомки запрашиваются автоматически, потому что сам заголовок области не показывается.

Большие коллекции берутся страницами, а не целиком. Массив на сто тысяч элементов не приезжает одним ответом и не морозит окно: страницы подгружаются по мере прокрутки.

Это заметно на практике: поэтому разворачивание большой структуры быстрое, и поэтому значение иногда появляется не мгновенно при первом открытии.

Значения относятся к своей остановке

Всё показанное в панели закэшировано относительно текущей остановки. Как только программа сдвинулась — шаг, продолжение, новая точка останова — кэш сбрасывается и дерево строится заново. Ответы, пришедшие с опозданием, когда программа уже ушла дальше, отбрасываются, а не показываются: значение с прошлой остановки рядом с текущей строкой было бы хуже, чем отсутствие значения.

Обрезанные и слишком большие значения

Адаптеры обрезают длинные значения. Когда это происходит, в строке видно то, что пришло, а панель InspectorCtrl+I — показывает полное значение выбранной строки, прямо сообщает, что адаптер его обрезал, и предлагает скопировать или отформатировать как JSON.

Ничего не показано

Если дерево пусто, а программа остановлена, посмотрите в Стек вызовов: фрейму без отладочной информации нечего сообщать об областях видимости. Это нормально для оптимизированного и стороннего кода, а также для Rust- или C/C++-бинарника, собранного в release.