Терминал stdin moveCursor несовпадение с широкими символами

Мне нужно программно переместить позицию курсора терминала с помощью NodeJS. Я использую process.stdout.moveCursor(x, y) , который отлично работает с обычными символами ASCII шириной в 1 символ.

Однако это не работает с более длинными символами EAST ASIAN WIDTH, такими как китайские иероглифы, японские иероглифы и полноразмерные английские символы. Например, width по сравнению с width, если я сдвину каретку на 1 единицу вправо, позиция каретки окажется в середине , в результате чего каретка даже не появится в терминалах Windows.

Несмотря на то, что я мог бы отслеживать ширину каждого отдельного символа и выполнять вычисления, как показано ниже, я чувствую, что должен быть способ перемещать курсор на основе целых символов, а не на основе какой-либо единицы x, которая находится в moveCursor (поскольку естественно, нажатие стрелки влево в терминале приведет к правильному перемещению курсора.)

process.stdout.write("Test data! 測試資料123テスト");
/* to move caret 5 characters from the right requires
 the following value to get the correct result */
const offsetRight = 3 * -1 + 2 * -2;
process.stdout.moveCursor(offsetRight, 0);

Примечание. Я использую последнюю версию nodeJS, и программа в основном работает с командной строкой Windows 10/11. Однако я тестировал его на Ubuntu и WSL, и у обоих одна и та же проблема.

🤔 А знаете ли вы, что...
С Node.js можно создавать приложения, работающие в режиме реального времени, такие как чаты и игры.


56
1

Ответ:

Решено

Одно из решений, которое я нашел, — проявить творческий подход с помощью escape-кода «Сохранить/восстановить текущую позицию курсора» ANSI escape-кода . Однако я полагаю, что это решение работает только для терминалов ANSI.

Курсор вперед (\x1b[nC) и курсор назад (\x1b[n) имеют ту же проблему, что описана в вопросе, поскольку она все еще зависит от преобразования символов X в единицы ячейки ширины Y. Вместо этого функция «Сохраненная позиция курсора» работает правильно, поскольку она отражает абсолютную позицию ячеек курсора независимо от того, есть ли более широкие символы с широкими несколькими ячейками или нет.

const test = "Test data! 測試資料123テスト";
const offsetRight = 3; //Cursor should stop right after '123'
process.stdout.write(test.slice(0, test.length - offsetRight));
process.stdout.write('\x1b[s'); //Save cursor position
process.stdout.write(test.slice(test.length - offsetRight));
process.stdout.write('\x1b[u'); //Restore cursor position