Крутая игра в командной строке с кодами выхода Ansi!

задняя часть
Крутая игра в командной строке с кодами выхода Ansi!

введение

Ты:

  • Хотите узнать, как реализованы эти причудливые индикаторы выполнения в командной строке?
  • Хотите знать, почему Spring Boot может печатать цветные журналы?
  • Хотите узнать, как реализована интерактивная командная строка языков сценариев, таких как Python или PHP?
  • Хотите знать, как реализованы редакторы в Терминале, такие как Vim или Emacs?

Если вам когда-либо было любопытно или вас задел этот отрывок, то вы не должны пропустить эту статью!

задний план

Из этой статьи вы можете узнать:

  1. Что такое Escape-коды Ansi и что они делают?
  2. Некоторые расширенные приложения кодов побега Ansi.
  3. Использование Jshell в JDK9.

Заранее эта статья в основном относится к:Ууууууууу.com/post/build тоже удачи…. Первоначальный текст ясен в мыслях, ярок в деле и отлично в наборе, это работа на совесть. Однако, поскольку исходный текст написан на английском языке и использует Python в качестве демонстрации, маленький новичок бэкенда беззастенчиво переведет его и использует Jshell JDK9 в качестве демонстрации, что удобно для изучения большинству Javaers.

Весь код в этой статье был отправлен на Github по адресу:GitHub.com/love LCP/Нет…. Настоятельно рекомендуется клонировать код и запустить его, чтобы увидеть эффект и усилить впечатление.

окрестности

  • Операционная система Mac или Linux или WIn10.Системы Windows, отличные от Win10, в настоящее время не поддерживают Escape-коды Ansi.
  • Поскольку в этой статье Jshell используется в качестве демонстрационного инструмента, вам необходимо установить недавно официально выпущенный JDK9.

В ПОРЯДКЕ! Все готово, приступим!

богатый текст

Самое простое использование Escape-кодов Ansi — вывод текста, отображаемого в консоли, в виде форматированного текста, например установка цвета шрифта, цвета фона и различных стилей. Давайте сначала узнаем, как установить цвет шрифта, вместо того, чтобы мириться со скучным черно-белым!

Цвет шрифта

Раскрашивание консольного текста с помощью команд Ansi (т. е. управляющих кодов Ansi) является наиболее распространенной операцией. Например:

  • Красный:\u001b[31m
  • перезагрузить:\u001b[0m

Большинство кодов выхода Ansi начинаются с\u001bначало. Выведем кусок красного цвета через Java-кодHello World:

System.out.print("\u001b[31mHello World");

Из приведенного выше рисунка видно, что не толькоHello Worldстановится красным, а следующийjshell>Подсказка также стала красной. Фактически, независимо от того, какие символы вы вводите дальше, их цвет шрифта будет красным. Пока вы не введете команду Ansi для другого цвета или не введете команду сброса, цвет шрифта больше не будет красным.

Попробуем ввести команду сброса, чтобы восстановить цвет шрифта:

System.out.print("\u001b[0m");

очень хороший!jshell>Подсказка снова станет белой. Таким образом, рекомендуется добавлять команду сброса в конце всех управляющих кодов Ansi, которые изменяют цвет или стиль шрифта, чтобы избежать непредвиденных последствий. Например:

System.out.print("\u001b[31mHello World\u001b[0m");

Конечно, команду сброса можно добавить куда угодно, например мы можем вставить ее вHello WorldсерединаHelloкрасный, ноWorldбелый:

System.out.print("\u001b[31mHello\u001b[0m World");

8 цветов

только что мы представили红色а также重置Заказ. Практически все консоли поддерживают следующие 8 цветов:

  • чернить:\u001b[30m
  • Красный:\u001b[31m
  • зеленый:\u001b[32m
  • желтый:\u001b[33m
  • синий:\u001b[34m
  • Пурпурный:\u001b[35m
  • синий:\u001b[36m
  • Белый:\u001b[37m
  • перезагрузить:\u001b[0m

Давайте посмотрим на вывод их всех:

System.out.print("\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m");
System.out.print("\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m");

Уведомление,AПоскольку он черный, он сливается с консолью.

16 цветов

Большинство консолей, помимо поддержки только что упомянутых 8 цветов, могут выводить еще 8 более ярких цветов:

  • Яркий черный:\u001b[30;1m
  • Ярко-красный:\u001b[31;1m
  • ярко зеленый:\u001b[32;1m
  • Ярко-желтый:\u001b[33;1m
  • ярко-голубой:\u001b[34;1m
  • Яркий пурпурный:\u001b[35;1m
  • Яркий голубой:\u001b[36;1m
  • Ярко-белый:\u001b[37;1m

Яркие цветные инструкции добавляются в середине оригинальных соответствующих цветовых инструкций соответственно.;1. Мы напечатаем все 16 цветов на консоли, чтобы все могли сравнить:

System.out.print("\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m");
System.out.print("\u001b[34m E \u001b[35m F \u001b[36m G \u001b[37m H \u001b[0m");
System.out.print("\u001b[30;1m A \u001b[31;1m B \u001b[32;1m C \u001b[33;1m D \u001b[0m");
System.out.print("\u001b[34;1m E \u001b[35;1m F \u001b[36;1m G \u001b[37;1m H \u001b[0m");

На картинке ясно видно, что нижние 8 цветов выглядят ярче, чем верхние 8 цветов. Например, оригинальный черныйA, он почти не заметен на черном фоне консоли, но как только он выводится через ярко-черный, контраст становится выше, и он становится более разборчивым.

256 цветов

Наконец, некоторые консоли поддерживают вывод 256 цветов в дополнение к 16 цветам. Форма инструкции следующая:

  • \u001b[38;5;${ID}m

Выведем 256-цветную матрицу:

for (int i = 0; i < 16; i++) {
    for (int j = 0; j < 16; j++) {
        int code = i * 16 + j;
        System.out.printf("\u001b[38;5;%dm%-4d", code, code);
    }
    System.out.println("\u001b[0m");
}

Здесь мы вводим цвет шрифта, а затем давайте введем цвет фона.

фоновый цвет

Только что упомянутый цвет шрифта можно в совокупности назвать цветом переднего плана. Так что, конечно, мы можем установить цвет фона текста:

  • черный фон:\u001b[40m
  • Красный фон:\u001b[41m
  • Зеленый фон:\u001b[42m
  • Желтый фон:\u001b[43m
  • Синий фон:\u001b[44m
  • Пурпурный фон:\u001b[45m
  • Голубой фон:\u001b[46m
  • Белый фон:\u001b[47m

Соответствующая яркая версия:

  • Яркий черный фон:\u001b[40;1m
  • Яркий красный фон:\u001b[41;1m
  • Яркий зеленый фон:\u001b[42;1m
  • Яркий желтый фон:\u001b[43;1m
  • Яркий синий фон:\u001b[44;1m
  • Яркий пурпурный фон:\u001b[45;1m
  • Яркий голубой фон:\u001b[46;1m
  • Яркий белый фон:\u001b[47;1m

Сначала давайте посмотрим на 16-цветный фон:

System.out.print("\u001b[40m A \u001b[41m B \u001b[42m C \u001b[43m D \u001b[0m");
System.out.print("\u001b[44m A \u001b[45m B \u001b[46m C \u001b[47m D \u001b[0m");
System.out.print("\u001b[40;1m A \u001b[41;1m B \u001b[42;1m C \u001b[43;1m D \u001b[0m");
System.out.print("\u001b[44;1m A \u001b[45;1m B \u001b[46;1m C \u001b[47;1m D \u001b[0m");

Стоит отметить, что яркий фон не делает цвет фона ярче, но делает соответствующий цвет переднего плана ярче. Хотя это немного неинтуитивно, это то, как это выглядит на самом деле.

Давайте снова попробуем цвет фона 256, первая команда выглядит следующим образом:

  • \u001b[48;5;${ID}m

Также выведите 256-цветную матрицу:

for (int i = 0; i < 16; i++) {
    for (int j = 0; j < 16; j++) {
        int code = i * 16 + j;
        System.out.printf("\u001b[48;5;%dm%-4d", code, code);
    }
    System.out.println("\u001b[0m");
}

Я чувствую, что ослепну! Пока с настройками цвета познакомились, перейдем к настройкам стиля.

стиль

Помимо раскрашивания текста, мы также можем стилизовать текст:

  • Смелый:\u001b[1m
  • Подчеркивать:\u001b[4m
  • Инвертировать цвет:\u001b[7m

Эффекты используемых стилей соответственно:

System.out.print("\u001b[1m BOLD \u001b[0m\u001b[4m Underline \u001b[0m\u001b[7m Reversed \u001b[0m");

или в сочетании с:

System.out.print("\u001b[1m\u001b[4m\u001b[7m BOLD Underline Reversed \u001b[0m");

Его даже можно сочетать с цветами:

System.out.print("\u001b[1m\u001b[31m Red Bold \u001b[0m");
System.out.print("\u001b[4m\u001b[44m Blue Background Underline \u001b[0m");

Разве это не легко, разве это не круто! Изучив их, мы смогли написать очень классные сценарии командной строки. Но если мы хотим реализовать более сложные функции (например, индикаторы выполнения), нам также необходимо освоить более мощные инструкции управления курсором!

управление курсором

Более сложной командой в Ansi Escape Code является управление курсором. С помощью этих команд мы можем свободно перемещать курсор в любом месте экрана. Например, в командном режиме Vim мы можем использоватьH/J/K/LЭти четыре клавиши перемещают курсор вверх, вниз, влево и вправо.

Самые основные команды управления курсором следующие:

  • начальство:\u001b[{n}A
  • Вниз:\u001b[{n}B
  • правильно:\u001b[{n}C
  • Левый:\u001b[{n}D

Благодаря функциям управления курсором мы можем реализовать множество интересных и крутых функций. Во-первых, давайте посмотрим, как реализовать индикатор выполнения.

Цифровой дисплей прогресса

В качестве индикатора выполнения, как может не отображаться цифровое отображение прогресса? Итак, давайте сначала реализуем обновление номера прогресса индикатора выполнения:

void loading() throws InterruptedException {
    System.out.println("Loading...");
    for (int i = 1; i <= 100; i++) {
        Thread.sleep(100);
        System.out.print("\u001b[1000D" + i + "%");
    }
}

На картинке видно, что прогресс продолжает обновляться от 1% до 100% в одной и той же строке. Для того, чтобы показывать прогресс только на одной строке, мы использовали в кодеSystem.out.printвместоSystem.out.println. Перед печатью каждого прогресса мы использовали\u001b[1000DЦель состоит в том, чтобы переместить курсор в крайнее левое положение текущей строки, то есть в начало строки. Затем перепечатайте новый прогресс, новый номер прогресса перезапишет предыдущий номер прогресса, и цикл повторится, что позволит достичь эффекта, показанного выше.

PS:\u001b[1000DУказывает на перемещение курсора на 1000 символов влево. 1000 здесь представляет расстояние, на которое перемещается курсор.Если вы можете гарантировать, что курсор может перемещаться в крайнее левое положение, вы можете установить любое число, например 2000.

Для того, чтобы всем было проще понять движение курсора, давайте замедлим частоту обновления индикатора выполнения:

void loading() throws InterruptedException {
    System.out.println("Loading...");
    for (int i = 1; i <= 100; i++) {
        System.out.print("\u001b[1000D");
        Thread.sleep(1000);
        System.out.print(i + "%");
        Thread.sleep(1000);
    }
}

Теперь мы ясно видим:

  1. Прогресс печатается слева направо, а курсор перемещается в конец строки.
  2. Курсор переместится в начало строки, а исходный номер прогресса все еще там.
  3. Новый прогресс печатается слева направо, новые цифры перезаписываются поверх старых. Курсор перемещается в конец строки.
  4. цикл взад и вперед.

Индикатор выполнения Ascii

Что ж, теперь мы знаем, как отображать и обновлять цифры прогресса через Ansi Escape Code, а остальное — реализовать полосу чтения прогресса. Не много ерунды, перейдем непосредственно к коду и рендерам:

void loading() throws InterruptedException {
    System.out.println("Loading...");
    for (int i = 1; i <= 100; i++) {
        int width = i / 4;
        String left = "[" + String.join("", Collections.nCopies(width, "#"));
        String right = String.join("", Collections.nCopies(25 - width, " ")) + "]";
        System.out.print("\u001b[1000D" + left + right);
        Thread.sleep(100);
    }
}

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

Давай что-нибудь покруче! Воспользуйтесь преимуществами курсора Ансивверха такжевнизкомандой, мы также можем распечатать несколько индикаторов выполнения одновременно:

void loading(int count) throws InterruptedException {
    System.out.print(String.join("", Collections.nCopies(count, "\n"))); // 初始化进度条所占的空间
    List<Integer> allProgress = new ArrayList<>(Collections.nCopies(count, 0));
    while (true) {
        Thread.sleep(10);

        // 随机选择一个进度条,增加进度
        List<Integer> unfinished = new LinkedList<>();
        for (int i = 0; i < allProgress.size(); i++) {
            if (allProgress.get(i) < 100) {
                unfinished.add(i);
            }
        }
        if (unfinished.isEmpty()) {
            break;
        }
        int index = unfinished.get(new Random().nextInt(unfinished.size()));
        allProgress.set(index, allProgress.get(index) + 1); // 进度+1

        // 绘制进度条
        System.out.print("\u001b[1000D"); // 移动到最左边
        System.out.print("\u001b[" + count + "A"); // 往上移动
        for (Integer progress : allProgress) {
            int width = progress / 4;
            String left = "[" + String.join("", Collections.nCopies(width, "#"));
            String right = String.join("", Collections.nCopies(25 - width, " ")) + "]";
            System.out.println(left + right);
        }
    }
}

В приведенном выше коде:

  • Сначала мы выполняемSystem.out.print(String.join("", Collections.nCopies(count, "\n")));Распечатайте несколько пустых строк, чтобы у нас было достаточно места для печати индикатора выполнения.
  • Затем мы случайным образом увеличиваем прогресс индикатора выполнения и распечатываем все индикаторы выполнения.
  • Наконец мы звонимвверхкоманду, переместите курсор обратно наверх и продолжайте следующий цикл, пока все индикаторы выполнения не достигнут 100%.

Фактический эффект выглядит следующим образом:

Эффект действительно отличный! Остальная работа по объединению показаний и чисел остается за читателем. Изучив этот трюк, в следующий раз, когда вы захотите сделать небольшой инструмент для загрузки файлов в командной строке, эти знания вам пригодятся!

сделать командную строку

Наконец, самое крутое — использовать коды Escape Ansi для реализации персонализированной командной строки. Bash, который мы обычно используем, и некоторые интерпретируемые языки, такие как Python, Ruby и т. д., имеют собственную командную строку REPL. Далее давайте демистифицируем их и разберемся в принципах их реализации.

PS: Поскольку некоторые специальные клавиши, такие как клавиши со стрелками и клавиша возврата, имеют в Jshell свои собственные функции, следующий шаг нельзя продемонстрировать в Jshell. Вам нужно вручную скомпилировать и запустить код, чтобы увидеть реальный эффект.

простая командная строка

Во-первых, давайте реализуем простейшую командную строку, состоящую из следующих двух функций:

  • Когда пользователь вводит печатный символ, такой как abcd и т. д., он отображается на консоли.
  • Когда пользователь вводит возврат каретки, начните новую строку, выведите все символы, введенные пользователем только что, а затем начните новую строку, чтобы продолжить принимать ввод пользователя.

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

import java.io.IOException;

public class CommandLine {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 设置命令行为raw模式,否则会自动解析方向键以及后退键,并且直到按下回车read方法才会返回
        String[] cmd = { "/bin/sh", "-c", "stty raw </dev/tty" };
        Runtime.getRuntime()
               .exec(cmd)
               .waitFor();
        while (true) {
            String input = "";
            while (true) {
                char ch = (char) System.in.read();
                if (ch == 3) {
                    // CTRL-C
                    return;
                }
                else if (ch >= 32 && ch <= 126) {
                    // 普通字符
                    input += ch;
                }
                else if (ch == 10 || ch == 13) {
                    // 回车
                    System.out.println();
                    System.out.print("\u001b[1000D");
                    System.out.println("echo: " + input);
                    input = "";
                }

                System.out.print("\u001b[1000D"); // 首先将光标移动到最左侧
                System.out.print(input); // 重新输出input
                System.out.flush();
            }
        }
    }
}

Хорошо, давайте проиллюстрируем ключевые моменты в коде:

  1. Первая и самая важная вещь заключается в том, что нам нужно установить нашу командную строку в необработанный режим, что может избежать JVM, анализирующего клавиши со стрелками, клавишу «назад» и буферизующую пользовательский ввод для нас. Можете попробовать не ставить сырой режим и посмотреть эффект, вы сможете понять, что я сказал.

  2. пройти черезSystem.in.read()метод принимает пользовательский ввод, а затем анализирует его значение ascii.

  3. Если обнаруживается, что пользователь ввел возврат каретки, нам нужно напечатать все символы, которые пользователь только что ввел. Но нужно обратить внимание, что так как установлен необработанный режим, то если печатать напрямую, не перемещая курсор, позиция курсора не сдвинется в начало строки, как показано ниже:

    Так что здесь вам нужно снова позвонитьSystem.out.print("\u001b[1000D");Переместите курсор в начало строки.

Что ж, посмотрим на эффект:

Это сработало! Но есть недостаток, то есть командная строка не разбирает клавиши со стрелками, а вместо этого начинается с[D[A[C[Bвывод (см. анимацию). Таким образом, мы можем писать только сзади и не можем перемещать курсор вперед, чтобы добиться эффекта вставки. Так что давайте добавим в командную строку функцию разбора стрелок!

движение курсора

Для простоты нам нужно только управлять курсором для перемещения влево и вправо при нажатии левой и правой клавиш клавиш со стрелками. Коды ascii, соответствующие левой и правой клавишам,27 91 68и27 91 67. Поэтому нам нужно только добавить в код синтаксический анализ этих двух строк кодов ascii:

import java.io.IOException;

public class CommandLine {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 设置命令行为raw模式,否则会自动解析方向键以及后退键,并且直到按下回车read方法才会返回
        String[] cmd = { "/bin/sh", "-c", "stty raw </dev/tty" };
        Runtime.getRuntime()
               .exec(cmd)
               .waitFor();
        while (true) {
            String input = "";
            int index = 0;
            while (true) {
                char ch = (char) System.in.read();
                if (ch == 3) {
                    // CTRL-C
                    return;
                }
                else if (ch >= 32 && ch <= 126) {
                    // 普通字符
                    input = input.substring(0, index) + ch + input.substring(index, input.length());
                    index++;
                }
                else if (ch == 10 || ch == 13) {
                    // 回车
                    System.out.println();
                    System.out.print("\u001b[1000D");
                    System.out.println("echo: " + input);
                    input = "";
                    index = 0;
                }
                else if (ch == 27) {
                    // 左右方向键
                    char next1 = (char) System.in.read();
                    char next2 = (char) System.in.read();
                    if (next1 == 91) {
                        if (next2 == 68) {
                            // 左方向键
                            index = Math.max(0, index - 1);
                        }
                        else if (next2 == 67) {
                            // 右方向键
                            index = Math.min(input.length(), index + 1);
                        }
                    }
                }

                System.out.print("\u001b[1000D"); // 将光标移动到最左侧
                System.out.print(input);
                System.out.print("\u001b[1000D"); // 再次将光标移动到最左侧
                if (index > 0) {
                    System.out.print("\u001b[" + index + "C"); // 将光标移动到index处
                }
                System.out.flush();
            }
        }
    }
}

Эффект следующий:

Оно работает! Но эта командная строка пока не поддерживает удаление, мы не можем пройтиBackspaceклавиша для удаления ошибочно введенных символов. Имея опыт, реализовать функцию удаления очень просто!

Удалить

По идее только что, мы можем добавить следующий код в место, где обрабатывается пользовательский ввод:

else if (ch == 127) {
    // 删除
    if (index > 0) {
        input = input.substring(0, index - 1) + input.substring(index, input.length());
        index -= 1;
    }
}

Но с этим кодом есть проблема, давайте посмотрим на рендеринг:

Из рисунка мы видим:

  • Первый раз, когда я набрал11234566, а затем продолжайте нажимать клавишу удаления, хотите удалить34566, но вернулся только курсор, символы не удаляются. Затем снова нажимаю клавишу ввода, и через эхо-строку обнаруживаем, что удаление действительно прошло успешно, но с отображением консоли что-то не так.
  • Второй раз я впервые вхожу123456, затем нажмите клавишу удаления, чтобы удалить456, курсор вернется к3. Затем я продолжаю печатать0, мы находим, что с0перезаписывает оригинал456отображаемое местоположение.

Таким образом, удаление имеет эффект, но нам нужно решить ошибку, из-за которой удаленные символы все еще отображаются. Для того, чтобы добиться эффекта удаления, давайте сначала узнаем о команде удаления в Ansi:

  • Очистить экран:\u001b[{n}Jдля инструкции.
    • n=0: Удаляет все символы от курсора до конца экрана.
    • n=1: Удаляет все символы от начала экрана до курсора.
    • n=2: Удаляет символы со всего экрана.
  • Четкая линия:\u001b[{n}Kдля инструкции.
    • n=0: Удаляет все символы от курсора до конца текущей строки.
    • n=1: Удаляет все символы от текущей строки до курсора.
    • n=2: очистить текущую строку.

Итак, наша идея заключается в том, что независимо от того, что вводит пользователь, мы сначала используемSystem.out.print("\u001b[0K");Очистите текущую строку, в это время курсор вернется в начало строки, а затем выведите правильный символ. Полный код выглядит следующим образом:

import java.io.IOException;

public class CommandLine {
    public static void main(String[] args) throws IOException, InterruptedException {
        // 设置命令行为raw模式,否则会自动解析方向键以及后退键,并且直到按下回车read方法才会返回
        String[] cmd = { "/bin/sh", "-c", "stty raw </dev/tty" };
        Runtime.getRuntime()
               .exec(cmd)
               .waitFor();
        while (true) {
            String input = "";
            int index = 0;
            while (true) {
                char ch = (char) System.in.read();
                if (ch == 3) {
                    // CTRL-C
                    return;
                }
                else if (ch >= 32 && ch <= 126) {
                    // 普通字符
                    input = input.substring(0, index) + ch + input.substring(index, input.length());
                    index++;
                }
                else if (ch == 10 || ch == 13) {
                    // 回车
                    System.out.println();
                    System.out.print("\u001b[1000D");
                    System.out.println("echo: " + input);
                    input = "";
                    index = 0;
                }
                else if (ch == 27) {
                    // 左右方向键
                    char next1 = (char) System.in.read();
                    char next2 = (char) System.in.read();
                    if (next1 == 91) {
                        if (next2 == 68) {
                            // 左方向键
                            index = Math.max(0, index - 1);
                        }
                        else if (next2 == 67) {
                            // 右方向键
                            index = Math.min(input.length(), index + 1);
                        }
                    }
                }
                else if (ch == 127) {
                    // 删除
                    if (index > 0) {
                        input = input.substring(0, index - 1) + input.substring(index, input.length());
                        index -= 1;
                    }
                }
                System.out.print("\u001b[1000D"); // 将光标移动到最左侧
                System.out.print("\u001b[0K"); // 清除光标所在行的全部内容
                System.out.print(input);
                System.out.print("\u001b[1000D"); // 再次将光标移动到最左侧
                if (index > 0) {
                    System.out.print("\u001b[" + index + "C"); // 将光标移动到index处
                }
                System.out.flush();
            }
        }
    }
}

Давайте посмотрим на эффект:

Хорошо, это сработало! На данный момент мы реализовали минимальную командную строку, которая может поддерживать ввод пользователем, перемещать курсор влево и вправо и удалять ненужные символы. Но в нем также отсутствуют многие функции командной строки, такие как отсутствие поддержки синтаксического анализа, напримерAlt-f,Ctrl-rи т.д. общийгорячая клавиша, также не поддерживает ввод символов Unicode и т. д. Однако, пока у нас есть знания прямо сейчас, эти функции могут быть легко реализованы. Например, мы можем прямо сейчас добавить в командную строку простую подсветку синтаксиса — если в конце есть лишние пробелы, отметьте эти пробелы красным цветом, эффект будет следующим:

Реализованный код также очень прост, вы можете обратиться к классу CustomizedCommandLine в проекте Github.

Наконец, некоторые другие полезные коды выхода Ansi:

  • Переместите курсор вверх:\u001b[{n}Aпереместить курсор вверхnсетка.
  • Переместите курсор вниз:\u001b[{n}Bпереместить курсор внизnсетка.
  • Переместите курсор вправо:\u001b[{n}Cпереместите курсор вправоnсетка.
  • Переместите курсор влево:\u001b[{n}Dпереместите курсор влевоnсетка.
  • Курсор перемещается вниз построчно:\u001b[{n}Eпереместить курсор внизnстроку и переместите курсор в начало строки.
  • Курсор перемещается вверх построчно:\u001b[{n}Fпереместить курсор вверхnстроку и переместите курсор в начало строки.
  • Установите столбец курсора:\u001b[{n}Gпереместите курсор наnСтолбцы (количество строк такое же, как и в текущей строке).
  • Установите положение курсора:\u001b[{n};{m}Hпереместите курсор наnРядmСтолбец, начало координат начинается с левого верхнего угла экрана.
  • Сохраните текущую позицию курсора:\u001b[{s}.
  • Прочитайте последнюю сохраненную позицию курсора:\u001b[{u}.

Код теста для перемещения курсора по строке относится к классу LineMovementTest в проекте Github, а код теста для установки позиции курсора относится к классу PositionTest в проекте Github. Если вы хотите узнать больше об управляющих кодах Ansi, см.Википедия.

Суммировать

Изучив эту статью, я считаю, что каждый освоил, как реализовать расширенный текстовый вывод консоли и настраиваемое перемещение курсора консоли с помощью кодов Escape Ansi. Итак, у вас уже есть ответы на четыре вопроса в начале статьи? Наконец, настоятельно рекомендуется, чтобы учащиеся, хорошо владеющие английским языком, прочитали исходный текст:Ууууууууу.com/post/build тоже удачи…. Желаю хороших выходных!

Эта статья была впервые опубликована впоцелуй с.org/2017/11/25/…
Комментарии и перепечатки приветствуются!
Подпишитесь на общедоступную учетную запись WeChat ниже, чтобы получать информацию из первых рук!