Когда код запускается и сообщает об ошибке, мы печатаем ошибку, и в ошибке есть информация о стеке, которая может быть расположена в соответствующей позиции кода. Но иногда мы хотим иметь возможность печатать код места ошибки более прямо и точно. Например:
Это можно сделать с помощью @babel/code-frames:
const { codeFrameColumns } = require('@babel/code-frame');
const res = codeFrameColumns(code, {
start: { line: 2, column: 1 },
end: { line: 3, column: 5 },
}, {
highlightCode: true,
message: '这里出错了'
});
console.log(res);
Это странно, как он распечатывает кадр кода выше?
В этой статье мы рассмотрим принцип.
Будут даны ответы на три основных вопроса:
- Как распечатать кодовый кадр, обозначающий соответствующий код позиции (то есть формат печати на картинке выше)
- Как реализовать подсветку синтаксиса
- Как напечатать цвет в консоли
Как распечатать кадры кода
Проигнорируем выделение и выведем в таком формате:
Есть идеи?
На самом деле относительно легко думать, что если передать исходный код, номера строк и столбцов начала и конца маркера, то мы можем вычислить, какие строки отображают маркер (маркер), а какие столбцы этих строки, а потом делать каждую строку кода по очереди Обработка, если на этой строке нет метки, оставить как есть, если на этой строке есть метка, то запустить печать маркера“>”
, и напечатайте строку маркера ниже"^"
Последняя маркированная линия также печатает сообщение об ошибке.
Давайте посмотрим на реализацию @babel/code-frame:
Сначала разбейте строку на массив каждой строки, а затем вычислите позицию маркера на основе переданной позиции.
Например, столбцы с 1 по 12 во второй строке рисунка и столбцы с 0 по 5 в третьей строке.
Затем обработайте каждую строку.Если в строке есть метка, напишите ее в формате маркер + желоб (номер строки) + код, напечатайте строку маркера ниже и напечатайте сообщение на последней строке маркера. Никакие теги не обрабатываются.
Это, наконец, объясняет этот кодовый фрейм:
Мы реализовали сращивание фреймов кода, игнорируя подсветку на данный момент, так как же сделать подсветку синтаксиса?
Как реализовать подсветку синтаксиса
Реализация подсветки синтаксиса требует понимания кода, но для простой подсветки достаточно лексического анализа. Babel делает то же самое: пакет @babel/highlight дополняет логику подсветки кода.
Первый взгляд на эффект:
const a = 1;
const b = 2;
console.log(a + b);
Приведенный выше исходный код разделен на массивы токенов:
[
[ 'whitespace', '\n' ], [ 'keyword', 'const' ],
[ 'whitespace', ' ' ], [ 'name', 'a' ],
[ 'whitespace', ' ' ], [ 'punctuator', '=' ],
[ 'whitespace', ' ' ], [ 'number', '1' ],
[ 'punctuator', ';' ], [ 'whitespace', '\n' ],
[ 'keyword', 'const' ], [ 'whitespace', ' ' ],
[ 'name', 'b' ], [ 'whitespace', ' ' ],
[ 'punctuator', '=' ], [ 'whitespace', ' ' ],
[ 'number', '2' ], [ 'punctuator', ';' ],
[ 'whitespace', '\n' ], [ 'name', 'console' ],
[ 'punctuator', '.' ], [ 'name', 'log' ],
[ 'bracket', '(' ], [ 'name', 'a' ],
[ 'whitespace', ' ' ], [ 'punctuator', '+' ],
[ 'whitespace', ' ' ], [ 'name', 'b' ],
[ 'bracket', ')' ], [ 'punctuator', ';' ],
[ 'whitespace', '\n' ]
]
Как делятся токены?
Вообще говоря, лексический анализ — это автомат с конечным числом состояний (DFA), но реализация здесь относительно проста, через регулярное сопоставление:
Пакет js-tokens предоставляет регулярку и функцию.Обычность используется для идентификации токенов.Существует много групп, и функция возвращает разные типы для разных индексов группировки, чтобы можно было выполнить идентификацию токена и классификацию.
В @ Babel / Highlight Package используется:
(Канонический лексический анализ имеет много ограничений, например, не справляется с рекурсией, поэтому этот подход не является универсальным, универсальным лексическим анализом или начальным конечным автоматом DFA.)
После того, как вы классифицировали различные маркеры, отображающие разные цвета, постройте карту на линии.
@ Babel / highlight - сделать это:
Мы умеем подсвечивать синтаксис и использовать API мела для печати цветов.Каков принцип консольной печати цветов?
Как напечатать цвет в консоли
Что выводит консольASCII-код, не все коды соответствуют видимым символам. Некоторые символы в коде ASCII соответствуют управляющим символам. Например, 27 — это ESC, клавиша ESC на нашей клавиатуре, которая является аббревиатурой escape. Нажмите ее, чтобы выполнить некоторые функции управления. Здесь мы можем войти в состояние управления цветом печати, напечатав код ASCII ESC.
Формат такой:
распечатать одинESC
ASCII-код, за которым следует[
Представитель начинает,m
От имени конца используется середина;
Отдельные n управляющих символов, которые могут управлять многими стилями, такими как цвет переднего плана, цвет фона, полужирный шрифт, подчеркивание и т. д.
Код ASCII ESC равен 27, и есть несколько способов его записи: один из них — символьное представление\e
, один шестнадцатеричный\0x1b
(27 соответствует шестнадцатеричному), один восьмеричный\033
, все три представляют ESC.
Давайте попробуем: 1 означает выделение жирным шрифтом, 36 означает голубой цвет переднего плана, а 4 означает подчеркивание Следующие три метода написания эквивалентны:
\e[36;1;4m
\033[36;1;4m
\0x1b[36;1;4m
Давайте попробуем:
Оба печатают правильный стиль!
Конечно, если вы добавляете стиль, вы должны удалить его, вы можете добавить один\e[0m
Вот и все (\033[0m
,\0x1b[0m
эквивалентность).
Другой подход к chalk (библиотеке nodejs для печати цветов на терминале) заключается в инкапсуляции этих символов управления цветом ASCII.
Код после выделения каждой строки кода выше:
Таким образом, также достигается печать в разных цветах.
Суммировать
На этом этапе мы можем добиться эффекта в начале: поддержка печати кадров кода, поддержка подсветки синтаксиса и возможность печати цветов.
В этой статье мы исследуем принцип реализации этого эффекта, начиная с того, как кадр кода соединяется, затем как выделяется каждая строка кода, а затем как подсветка печатает цвет.
Будь то печать фреймов кода, подсветка синтаксиса или печать цветов консоли, все они являются очень распространенными функциями.Я надеюсь, что эта статья поможет вам полностью понять принципы этих трех аспектов.