Всем привет! Хочу поделиться своим опытом написания кроссплатформенного проекта на C++ для интеграции автодополнения в CLI приложения, усаживайтесь поудобнее. Сразу предупрежу, использовать будем C++17 Предлагаю перейти к делу. Очевидно, так как наш проект кроссплатформенный, необходимо написать простенький макрос для определения текущей платформы. Также сделаем небольшую заготовку: Так как мы нацелены на CLI проекты, и терминалы Linux и macOS имеют одинаковый API, объединим их в один define OS_POSIX. Windows, как всегда, стоит в стороне, вынесем для нее отдельный define OS_WINDOWS. Следующим шагом мы должны понять, как будут выглядеть автодополнения. С самого начала я был вдохновлен Redis CLI, поэтому будем просто выводить посказки другим нейтральным цветом. Но это не помешает нам в итоге использовать любые цвета. Следовательно, требуется написать функцию установки нужного цвета для вывода в консоль: Опять таки из-за разницы API приходится искать компромисс, будем всегда возвращать строку для того, чтобы можно было использовать функцию после оператора вывода << для повышения читаемости кода. Для тех, кому интересно, как именно работает API для цвета в Posix и Windows, и какие цветовые профили вообще бывают, предлагаю почитать ответы добрых людей на stackoverflow: Так как нам придется постоянно перерисовывать строку из-за подсказок, необходимо написать функцию для "стирания" строки. На Posix платформах все просто, достаточно вывести в консоль \033[2K, но естественно в Windows нет аналогов, конкретно я не смог найти, приходится писать свою реализацию.  Осталось понять, как осуществлять ввод символов пользователем. Обычный cin явно не подойдет, в процессе считывания не получится выводить предсказания. Тут приходит на ум функция _getch(), доступная в Windows, которая получает код символа нажатой клавиши на клавиатуре — это именно то, что нам надо. Но в этот раз с Posix платформами все плохо, увы, но придется писать свою реализацию. Отлично. Теперь придумаем, как мы будем задавать правила для автодополнения. Предлагаю получать их из текстового файла следующей структуры: Идея такая. За каждым словом могут идти слова на расстоянии 1 табуляции от него. Т.е. после слова git могут идти слова config, init и global. После слова config могут идти слова --global, user.name и user.email и т.д. Также введем возможность указывать опциональные слова, в моем случае это слова внутри символов [] (вместо этих слов пользователь должен вводить свои данные). Хранить правила будем в ассоциативном массиве, где ключ будет выступать строкой, а значения — вектор слов, которые могут идти после ключа-строки. Давайте напишем функцию для парсинга файла с правилами. Разберемся с накопившимися вопросами. Функция просто отрезает лишнее пространство слева и справа у строки Хорошо. У нас есть словарь с правилами, а что дальше? Осталось сделать само автодополнение.
Представим, что пользователь вводит что-то с клавиатуры. Что мы имеем? Одно или несколько введенных слов. Давайте научимся получать последнее слово из строки. Но давайте вспомним, чтобы предугадать, что хочет пользователь, нам надо знать не только последнее слово, которое мы пытаемся угадать, но и то, что шло до него. Давайте научимся получать предпоследнее слово из строки. Что же мы забыли? Функцию для нахождения слов, которые начинаются также, как и последнее слово в строке. А что по поводу проверки орфографии? Мы же хотели ее добавить? Давайте сделаем это. Теперь у нас есть все, чтобы предсказать слово по введенной пользователем строке.
Давайте решим эту задачу. Осталось одно из самых сложных заданий. Написать саму функцию ввода с клавиатуры. В принципе, все готово. Давайте проверим наш код в деле. Код был проверен на macOS, Linux, Windows. Все работает отлично. Как вы видите, писать кроссплатформенный код довольно не просто (в нашем случае пришлось писать, то что есть на Windows из коробки для Linux вручную и наоборот), однако это очень интересно и сам факт, что это все работает на всех трех ОС, крайне доставляет. Надеюсь, я был кому-нибудь полезен. Если вам есть что дополнить, буду внимательно слушать в комментариях. Исходный код можно взять тут.
Пользуйтесь на здоровье. Software Engineer