summaryrefslogtreecommitdiff
path: root/src/main.cpp
blob: dbc83a8e0d66c45369b8089f63f157c09b5ec37f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// 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 <https://www.gnu.org/licenses/>.

#include <csignal>

#include <CLI/App.hpp>
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>
#include <spdlog/cfg/env.h>
#include <spdlog/spdlog.h>

#include <CLI/Version.hpp>
#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 <CLI/ExtraValidators.hpp>
#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> 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;
}