-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathterminal_utils.cpp
More file actions
179 lines (163 loc) · 5.41 KB
/
Copy pathterminal_utils.cpp
File metadata and controls
179 lines (163 loc) · 5.41 KB
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "tui/terminal_utils.hpp"
#include <atomic>
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <string>
#include <string_view>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <io.h>
#include <direct.h>
#else
#include <termios.h>
#include <unistd.h>
#include <csignal>
#endif
#include "version.hpp"
#include "config/config.hpp"
#include "utils/logger.hpp"
#include "utils/terminal_title.hpp"
#include "skills/default_skill_seeder.hpp"
#include "session/session_manager.hpp"
#include "tui/chat_scroll.hpp"
namespace acecode { namespace tui {
std::string get_cwd() {
#ifdef _WIN32
char buf[MAX_PATH];
if (_getcwd(buf, sizeof(buf))) return std::string(buf);
#else
char buf[4096];
if (getcwd(buf, sizeof(buf))) return std::string(buf);
#endif
return ".";
}
std::string get_executable_dir_from_argv(int argc, char* argv[]) {
if (argc <= 0 || !argv[0]) return "";
std::error_code ec;
std::filesystem::path exe(argv[0]);
std::filesystem::path abs = std::filesystem::weakly_canonical(exe, ec);
if (!ec) return abs.parent_path().string();
return exe.parent_path().string();
}
void reconcile_default_skills_on_startup(const std::string& argv0_dir) {
auto result = acecode::reconcile_default_global_skills_on_startup(
std::filesystem::path(acecode::get_acecode_dir()),
argv0_dir);
if (!result.attempted) return;
size_t installed = 0;
size_t updated = 0;
size_t unchanged = 0;
size_t preserved = 0;
size_t errors = 0;
const auto count_outcomes = [&](const auto& outcomes) {
for (const auto& outcome : outcomes) {
if (outcome.result == "installed") ++installed;
else if (outcome.result == "updated") ++updated;
else if (outcome.result == "unchanged") ++unchanged;
else if (outcome.result == "preserved_user_modified") ++preserved;
else ++errors;
}
};
count_outcomes(result.outcomes);
count_outcomes(result.expert_outcomes);
count_outcomes(result.hook_outcomes);
if (!result.error.empty()) {
LOG_WARN("[seed] Default resource reconciliation issue: " + result.error);
}
LOG_INFO("[seed] Default resource reconciliation attempted: version=" +
result.bundle_version + " installed=" + std::to_string(installed) +
" updated=" + std::to_string(updated) +
" unchanged=" + std::to_string(unchanged) +
" preserved=" + std::to_string(preserved) +
" errors=" + std::to_string(errors));
}
void write_terminal_control_sequence(std::string_view seq) {
#ifdef _WIN32
auto stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD out_mode = 0;
const bool restore_mode =
stdout_handle != INVALID_HANDLE_VALUE &&
GetConsoleMode(stdout_handle, &out_mode);
if (!restore_mode) return;
constexpr DWORD enable_virtual_terminal_processing = 0x0004;
constexpr DWORD disable_newline_auto_return = 0x0008;
SetConsoleMode(stdout_handle,
out_mode | enable_virtual_terminal_processing |
disable_newline_auto_return);
#endif
std::cout.write(seq.data(), static_cast<std::streamsize>(seq.size()));
std::cout.flush();
#ifdef _WIN32
SetConsoleMode(stdout_handle, out_mode);
#endif
}
void set_ftxui_full_repaint_mode(bool enabled) {
#ifdef _WIN32
_putenv_s("ACECODE_FTXUI_FULL_REPAINT", enabled ? "1" : "0");
#else
if (enabled) setenv("ACECODE_FTXUI_FULL_REPAINT", "1", 1);
else unsetenv("ACECODE_FTXUI_FULL_REPAINT");
#endif
}
void reset_cursor() {
write_terminal_control_sequence("\033[?25h");
}
void flush_terminal_input_buffer() {
#ifdef _WIN32
auto stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
if (stdin_handle == INVALID_HANDLE_VALUE) return;
FlushConsoleInputBuffer(stdin_handle);
#else
if (isatty(STDIN_FILENO)) tcflush(STDIN_FILENO, TCIFLUSH);
#endif
}
// Globals
SessionManager* g_session_manager = nullptr;
std::atomic<ftxui::ScreenInteractive*> g_active_screen{nullptr};
void finalize_session_atexit() {
if (g_session_manager) {
g_session_manager->finalize();
auto sid = g_session_manager->current_session_id();
if (!sid.empty()) {
std::cerr << "\nacecode: session " << sid
<< " saved. Resume with: acecode --resume " << sid << std::endl;
}
}
clear_terminal_title();
}
#ifdef _WIN32
BOOL WINAPI console_ctrl_handler(DWORD ctrl_type) {
auto* s = g_active_screen.load(std::memory_order_acquire);
if (ctrl_type == CTRL_C_EVENT) {
if (s) { s->PostEvent(ftxui::Event::CtrlC); return TRUE; }
finalize_session_atexit();
return FALSE;
}
if (ctrl_type == CTRL_BREAK_EVENT || ctrl_type == CTRL_CLOSE_EVENT) {
if (s) { s->Exit(); return TRUE; }
finalize_session_atexit();
return FALSE;
}
return FALSE;
}
void prepare_windows_ctrl_c_handling_after_ftxui_install() {
auto stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD in_mode = 0;
if (stdin_handle != INVALID_HANDLE_VALUE &&
GetConsoleMode(stdin_handle, &in_mode)) {
SetConsoleMode(stdin_handle, in_mode & ~ENABLE_PROCESSED_INPUT);
}
SetConsoleCtrlHandler(console_ctrl_handler, FALSE);
SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
}
#else
void signal_handler(int /*sig*/) {
finalize_session_atexit();
_exit(1);
}
#endif
}} // namespace acecode::tui