Создание своего терминала на C++ и Qt: Часть 1
Привет, хабр! Сегодня мы создадим свой собственный терминал на языке программирования C++. Я являюсь фанатом Linux, и пользуюсь минималистичными терминальными программами — от Vim как IDE до чатов. Есть множество терминалов, у каждого из них есть плюсы и минусы. Наш терминал не будет претендовать на место серьезного проекта, но если вы хотите улучшить код, который мы сегодня напишем — то вы молодцы, можете без проблем развить наш терминал.
Это будет небольшой, минималистичный терминал для Linux. Он будет на основе фреймворка Qt 5 и библиотеки qtermwidget5
Не буду долго тянуть, вперед! Исходный код будет в моем репозитории.
Что нам сегодня будет нужно:
Итак, для начала нам нужно установить все зависимости, которые я привел сверху.
# Arch
sudo pacman -Sy qtermwidget basedevel qt5-base
# Для других дистрибутивов смотрите в их репозиториях
Основа нашего терминала — Qt-виджет qtermwidget.
Работающий минимум
Для начала создаем проект:
qmake -project
После в файл <названиеПроекта>.pro помещаем следующий код (не забудьте заменить имена):
######################################################################
# Automatically generated by qmake (3.1) Mon Nov 27 18:10:42 2023
######################################################################
TEMPLATE = app
TARGET = bin/LiTerm
INCLUDEPATH += .
INCLUDEPATH += /usr/include/qtermwidget5
# You can make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# Please consult the documentation of the deprecated API in order to know
# how to port your code away from it.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# Input
SOURCES += src/literm.cpp
TEMPLATE += app
QT += gui widgets
unix:!macx: LIBS += -lqtermwidget5
Дальше при помощи qmake мы создаем Makefile:
qmake -makefile
И здесь мы создаем файл кода С++ и пишем в него следующее:
#include
#include
#include "qtermwidget.h"
int main(int argc, char *argv[]) {
// Создаем окно и приложение
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
// Создаем объект консоли
QTermWidget *console = new QTermWidget();
// Добавляем шрифт терминала
QFont font = QApplication::font();
font.setFamily("Monospace"); // задаем шрифт monospace
font.setPointSize(14); // задаем размер шрифта в pt
console->setTerminalFont(font); // задаем наши характеристики шрифта в консоль
// Показ окна
QObject::connect(console, SIGNAL(finished()), mainWindow, SLOT(close()));
mainWindow->setCentralWidget(console);
mainWindow->show();
return app.exec();
}
Мы включаем нужные нам библиотеки, создаем приложение и создаем виджет терминала. После мы задаем ему шрифт. В конце подключаем терминал и главное окно (то есть закрытие одного окна/виджета заставит закрыться другое окно/виджет), а после показываем окно.
Компиляция
На протяжении всего туториала — компиляция будет состоять из одной строчки:
make
Цветовые схемы
Добавим немного цветов в наш терминал.
#include
#include
#include "qtermwidget.h"
int main(int argc, char *argv[]) {
// Создаем окно и приложение
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
// Создаем объект консоли
QTermWidget *console = new QTermWidget();
// Добавляем шрифт терминала
QFont font = QApplication::font();
font.setFamily("Monospace"); // задаем шрифт monospace
font.setPointSize(14); // задаем размер шрифта в pt
console->setTerminalFont(font); // задаем наши характеристики шрифта в консоль
// Задаем цветовую схему. Существующие можно посмотреть в /usr/share/qtermwidget5/color-schemes
console->setColorScheme("Tango");
// Показ окна
QObject::connect(console, SIGNAL(finished()), mainWindow, SLOT(close()));
mainWindow->setCentralWidget(console);
mainWindow->show();
return app.exec();
}
Мы добавляем в наш предыдущий код всего одну функцию — console->setColorScheme("Tango");
Эта волшебная функция заставляет принять наш терминал цветовую схему Tango (остальные можно посмотреть в /usr/share/qtermwidget5/color-schemes/
Копипаста!
Что-же за терминал такой, в котором даже не работает копирование и вставка текста? Давайте это исправим. Мы добавим кейбинды!
#include
#include
#include // добавляем новую библиотеку
#include "qtermwidget.h"
int main(int argc, char *argv[]) {
// Создаем окно и приложение
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
// Создаем объект консоли
QTermWidget *console = new QTermWidget();
// Добавляем шрифт терминала
QFont font = QApplication::font();
font.setFamily("Monospace"); // задаем шрифт monospace
font.setPointSize(14); // задаем размер шрифта в pt
console->setTerminalFont(font); // задаем наши характеристики шрифта в консоль
// Задаем цветовую схему. Существующие можно посмотреть в /usr/share/qtermwidget5/color-schemes
console->setColorScheme("Tango");
// Подключаем
QObject::connect(console, &QTermWidget::termKeyPressed, mainWindow,
[=](const QKeyEvent *key) -> void { // проверяем нажатия клавиш
if (key->matches(QKeySequence::Copy)) {
console->copyClipboard(); // ctrl+c
} else if (key->matches(QKeySequence::Paste)) {
console->pasteClipboard(); // ctrl+v
}
});
// Показ окна
QObject::connect(console, SIGNAL(finished()), mainWindow, SLOT(close()));
mainWindow->setCentralWidget(console);
mainWindow->show();
return app.exec();
}
Мы получаем нажатия клавиш, и если они равны ctrl+c (копирование) или ctrl+v (вставка) мы копируем или вставляем текст.
Ссылки, ссылки, ссылки…
Давайте создадим еще несколько «плюшек» — возможность активации ссылок, моргающий курсор и внутренние отступы!
#include
#include
#include // добавляем новую библиотеку
#include
#include "qtermwidget.h"
void activateLink(const QUrl &url, bool fromContextMenu) {
/* Функция, которая ничего не возвращает, принимает на вход URL и
fromContextMenu.
Открывает ссылку в доступном браузере */
if (QApplication::keyboardModifiers() & Qt::ControlModifier ||
fromContextMenu) {
QDesktopServices::openUrl(url);
}
}
int main(int argc, char *argv[]) {
// Создаем окно и приложение
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
// Создаем объект консоли
QTermWidget *console = new QTermWidget();
// Добавляем шрифт терминала
QFont font = QApplication::font();
font.setFamily("Monospace"); // задаем шрифт monospace
font.setPointSize(14); // задаем размер шрифта в pt
console->setTerminalFont(font); // задаем наши характеристики шрифта в консоль
console->setBlinkingCursor(true); // мерцающий курсор
// Добавляем внутренние отступы 10 пикселей
console->setMargin(10);
// Задаем цветовую схему. Существующие можно посмотреть в /usr/share/qtermwidget5/color-schemes
console->setColorScheme("Tango");
// Подключаем
QObject::connect(console, &QTermWidget::termKeyPressed, mainWindow,
[=](const QKeyEvent *key) -> void { // проверяем нажатия клавиш
if (key->matches(QKeySequence::Copy)) {
console->copyClipboard(); // ctrl+c
} else if (key->matches(QKeySequence::Paste)) {
console->pasteClipboard(); // ctrl+v
}
});
// Подключаем функцию активации ссылки
QObject::connect(console, &QTermWidget::urlActivated, mainWindow,
activateLink);
// Показ окна
QObject::connect(console, SIGNAL(finished()), mainWindow, SLOT(close()));
mainWindow->setCentralWidget(console);
mainWindow->show();
return app.exec();
}
И компилируя мы получаем…
Вот такой у нас получился терминал. Я использую на скриншотах шрифт не Monospace, а Iosevka Nerd Fonts.
Заключение
В этой части мы реализовали базовые возможности нашего терминала. В следующей части мы создадим больше плюшек — подумаем над созданием конфигуратора, добавим больше функций.
Спасибо за прочтение! Надеюсь вам понравилось!