// Display images inside a terminal
// Copyright (C) 2023 JustKidding
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
#include
#include
#include
#include
#include
#include
#include
#if (CLI11_VERSION_MAJOR >= 3) || (CLI11_VERSION_MAJOR == 2 && CLI11_VERSION_MINOR >= 6)
// CLI11 2.6.0 and beyond requires this header file for the CLI::IsMember validator.
# include
#endif
#include "application.hpp"
#include "flags.hpp"
#include "tmux.hpp"
#include "util.hpp"
void signal_handler(const int signal)
{
Application::stop_flag = true;
const auto logger = spdlog::get("main");
if (!logger) {
return;
}
switch (signal) {
case SIGINT:
logger->error("SIGINT received, exiting...");
break;
case SIGTERM:
logger->error("SIGTERM received, exiting...");
break;
case SIGHUP:
logger->error("SIGHUP received, exiting...");
break;
default:
logger->error("UNKNOWN({}) signal received, exiting...", signal);
break;
}
}
auto main(int argc, char *argv[]) -> int
{
// handle signals
struct sigaction sga;
sga.sa_handler = signal_handler;
sigemptyset(&sga.sa_mask);
sga.sa_flags = 0;
sigaction(SIGINT, &sga, nullptr);
sigaction(SIGTERM, &sga, nullptr);
sigaction(SIGHUP, &sga, nullptr);
sigaction(SIGCHLD, nullptr, nullptr);
spdlog::cfg::load_env_levels();
std::shared_ptr flags;
try {
flags = Flags::instance();
} catch (const std::exception &e) {
std::cerr << "Could not parse config file: " << e.what() << std::endl;
return 1;
}
CLI::App program("Display images in the terminal", "ueberzug");
program.add_flag("-V,--version", flags->print_version, "Print version information.");
auto *layer_command = program.add_subcommand("layer", "Display images on the terminal.");
layer_command->add_flag("-s,--silent", flags->silent, "Print stderr to /dev/null.");
layer_command
->add_flag("--use-escape-codes", flags->use_escape_codes, "Use escape codes to get terminal capabilities.")
->default_val(false);
layer_command->add_option("--pid-file", flags->pid_file, "Output file where to write the daemon PID.");
layer_command->add_flag("--no-stdin", flags->no_stdin, "Do not listen on stdin for commands.")->needs("--pid-file");
layer_command->add_flag("--no-cache", flags->no_cache, "Disable caching of resized images.");
layer_command->add_flag("--no-opencv", flags->no_opencv, "Do not use OpenCV, use Libvips instead.");
layer_command->add_option("-o,--output", flags->output, "Image output method")
->check(CLI::IsMember({"x11", "wayland", "sixel", "kitty", "iterm2", "chafa"}));
layer_command->add_flag("--origin-center", flags->origin_center, "Location of the origin wrt the image");
layer_command->add_option("-p,--parser", nullptr, "**UNUSED**, only present for backwards compatibility.");
layer_command->add_option("-l,--loader", nullptr, "**UNUSED**, only present for backwards compatibility.");
auto *cmd_comand = program.add_subcommand("cmd", "Send a command to a running ueberzugpp instance.");
cmd_comand->add_option("-s,--socket", flags->cmd_socket, "UNIX socket of running instance");
cmd_comand->add_option("-i,--identifier", flags->cmd_id, "Preview identifier");
cmd_comand->add_option("-a,--action", flags->cmd_action, "Action to send");
cmd_comand->add_option("-f,--file", flags->cmd_file_path, "Path of image file");
cmd_comand->add_option("-x,--xpos", flags->cmd_x, "X position of preview");
cmd_comand->add_option("-y,--ypos", flags->cmd_y, "Y position of preview");
cmd_comand->add_option("--max-width", flags->cmd_max_width, "Max width of preview");
cmd_comand->add_option("--max-height", flags->cmd_max_height, "Max height of preview");
auto *tmux_command = program.add_subcommand("tmux", "Handle tmux hooks. Used internaly.");
tmux_command->allow_extras();
auto *query_win_command =
program.add_subcommand("query_windows", "**UNUSED**, only present for backwards compatibility.");
query_win_command->allow_extras();
CLI11_PARSE(program, argc, argv);
if (query_win_command->parsed()) {
return 0;
}
if (flags->print_version) {
Application::print_version();
return 0;
}
if (!layer_command->parsed() && !tmux_command->parsed() && !cmd_comand->parsed()) {
program.exit(CLI::CallForHelp());
return 1;
}
if (layer_command->parsed()) {
Application application(argv[0]);
application.command_loop();
}
if (tmux_command->parsed()) {
try {
const auto positionals = tmux_command->remaining();
tmux::handle_hook(positionals.at(0), std::stoi(positionals.at(1)));
} catch (const std::out_of_range &oor) {
}
}
if (cmd_comand->parsed()) {
util::send_command(*flags);
}
return 0;
}