Reformat code.

This commit is contained in:
2026-02-17 13:44:36 -08:00
parent 95a588b0df
commit 337b585ba0
114 changed files with 32253 additions and 16316 deletions

View File

@@ -1109,33 +1109,34 @@ cmd_theme_set_by_name(const CommandContext &ctx)
static bool static bool
cmd_theme_set_by_name(CommandContext &ctx) cmd_theme_set_by_name(CommandContext &ctx)
{ {
# if defined(KTE_BUILD_GUI) && defined(KTE_USE_QT) # if defined(KTE_BUILD_GUI) && defined(KTE_USE_QT)
// Qt GUI build: schedule theme change for frontend // Qt GUI build: schedule theme change for frontend
std::string name = ctx.arg; std::string name = ctx.arg;
// trim spaces // trim spaces
auto ltrim = [](std::string &s) { auto ltrim = [](std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch); return !std::isspace(ch);
})); }));
}; };
auto rtrim = [](std::string &s) { auto rtrim = [](std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch); return !std::isspace(ch);
}).base(), s.end()); }).base(), s.end());
}; };
ltrim(name); ltrim (name);
rtrim(name); rtrim (name);
if (name.empty()) { if (name.empty()) {
ctx.editor.SetStatus("theme: provide a name (e.g., nord, solarized-dark, gruvbox-light, eink)"); ctx.editor.SetStatus("theme: provide a name (e.g., nord, solarized-dark, gruvbox-light, eink)");
return true; return true;
} }
kte::gThemeChangeRequest = name; kte::gThemeChangeRequest= name;
kte::gThemeChangePending = true; kte::gThemeChangePending=true;
ctx.editor.SetStatus(std::string("Theme requested: ") + name); ctx.editor.SetStatus (std::string("Theme requested: ") + name);
return true; return true;
# else # else
(void) ctx; (void) ctx;
// No-op in terminal build // No-op in terminal build
return true; return true;
# endif # endif
} }

View File

@@ -158,17 +158,17 @@ map_key(const SDL_Keycode key,
ascii_key = static_cast<int>(key); ascii_key = static_cast<int>(key);
} }
bool ctrl2 = (mod & KMOD_CTRL) != 0; bool ctrl2 = (mod & KMOD_CTRL) != 0;
// If user typed a literal 'C' (uppercase) or '^' as a control qualifier, keep k-prefix active // If user typed a literal 'C' (uppercase) or '^' as a control qualifier, keep k-prefix active
// Do NOT treat lowercase 'c' as a qualifier; 'c' is a valid k-command (BufferClose). // Do NOT treat lowercase 'c' as a qualifier; 'c' is a valid k-command (BufferClose).
if (ascii_key == 'C' || ascii_key == '^') { if (ascii_key == 'C' || ascii_key == '^') {
k_ctrl_pending = true; k_ctrl_pending = true;
// Keep waiting for the next suffix; show status and suppress ensuing TEXTINPUT // Keep waiting for the next suffix; show status and suppress ensuing TEXTINPUT
if (ed) if (ed)
ed->SetStatus("C-k C _"); ed->SetStatus("C-k C _");
suppress_textinput_once = true; suppress_textinput_once = true;
out.hasCommand = false; out.hasCommand = false;
return true; return true;
} }
// Otherwise, consume the k-prefix now for the actual suffix // Otherwise, consume the k-prefix now for the actual suffix
k_prefix = false; k_prefix = false;
if (ascii_key != 0) { if (ascii_key != 0) {
@@ -298,7 +298,7 @@ ImGuiInputHandler::ProcessSDLEvent(const SDL_Event &e)
// High-resolution trackpads can deliver fractional wheel deltas. Accumulate // High-resolution trackpads can deliver fractional wheel deltas. Accumulate
// precise values and emit one scroll step per whole unit. // precise values and emit one scroll step per whole unit.
float dy = 0.0f; float dy = 0.0f;
#if SDL_VERSION_ATLEAST(2,0,18) #if SDL_VERSION_ATLEAST(2, 0, 18)
dy = e.wheel.preciseY; dy = e.wheel.preciseY;
#else #else
dy = static_cast<float>(e.wheel.y); dy = static_cast<float>(e.wheel.y);
@@ -308,7 +308,7 @@ ImGuiInputHandler::ProcessSDLEvent(const SDL_Event &e)
dy = -dy; dy = -dy;
#endif #endif
if (dy != 0.0f) { if (dy != 0.0f) {
wheel_accum_y_ += dy; wheel_accum_y_ += dy;
float abs_accum = wheel_accum_y_ >= 0.0f ? wheel_accum_y_ : -wheel_accum_y_; float abs_accum = wheel_accum_y_ >= 0.0f ? wheel_accum_y_ : -wheel_accum_y_;
int steps = static_cast<int>(abs_accum); int steps = static_cast<int>(abs_accum);
if (steps > 0) { if (steps > 0) {
@@ -439,14 +439,12 @@ ImGuiInputHandler::ProcessSDLEvent(const SDL_Event &e)
} }
// If editor universal argument is active, consume digit TEXTINPUT // If editor universal argument is active, consume digit TEXTINPUT
if (ed_ &&ed_ if (ed_ && ed_
->
-> UArg() != 0
UArg() != 0 ) {
)
{
const char *txt = e.text.text; const char *txt = e.text.text;
if (txt && *txt) { if (txt && *txt) {
unsigned char c0 = static_cast<unsigned char>(txt[0]); unsigned char c0 = static_cast<unsigned char>(txt[0]);
@@ -473,16 +471,16 @@ ImGuiInputHandler::ProcessSDLEvent(const SDL_Event &e)
ascii_key = static_cast<int>(c0); ascii_key = static_cast<int>(c0);
} }
if (ascii_key != 0) { if (ascii_key != 0) {
// Qualifier via TEXTINPUT: uppercase 'C' or '^' only // Qualifier via TEXTINPUT: uppercase 'C' or '^' only
if (ascii_key == 'C' || ascii_key == '^') { if (ascii_key == 'C' || ascii_key == '^') {
k_ctrl_pending_ = true; k_ctrl_pending_ = true;
if (ed_) if (ed_)
ed_->SetStatus("C-k C _"); ed_->SetStatus("C-k C _");
// Keep k-prefix active; do not emit a command // Keep k-prefix active; do not emit a command
k_prefix_ = true; k_prefix_ = true;
produced = true; produced = true;
break; break;
} }
// Map via k-prefix table; do not pass Ctrl for TEXTINPUT case // Map via k-prefix table; do not pass Ctrl for TEXTINPUT case
CommandId id; CommandId id;
bool pass_ctrl = k_ctrl_pending_; bool pass_ctrl = k_ctrl_pending_;

View File

@@ -283,12 +283,11 @@ QtInputHandler::ProcessKeyEvent(const QKeyEvent &e)
const bool ctrl_like = (mods & Qt::ControlModifier); const bool ctrl_like = (mods & Qt::ControlModifier);
// 1) Universal argument digits (when active), consume digits without enqueuing commands // 1) Universal argument digits (when active), consume digits without enqueuing commands
if (ed_ &&ed_ if (ed_ && ed_
-> ->
UArg() != 0 UArg() != 0
) ) {
{
if (!(mods & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { if (!(mods & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) {
if (e.key() >= Qt::Key_0 && e.key() <= Qt::Key_9) { if (e.key() >= Qt::Key_0 && e.key() <= Qt::Key_9) {
int d = e.key() - Qt::Key_0; int d = e.key() - Qt::Key_0;
@@ -379,10 +378,9 @@ QtInputHandler::ProcessKeyEvent(const QKeyEvent &e)
// ESC/meta chords: on macOS, do NOT treat Meta as ESC; only Alt (Option) should trigger. // ESC/meta chords: on macOS, do NOT treat Meta as ESC; only Alt (Option) should trigger.
#if defined(__APPLE__) #if defined(__APPLE__)
if (esc_meta_ || (mods & Qt::AltModifier)) { if (esc_meta_ || (mods & Qt::AltModifier)) {
#else #else
if (esc_meta_ || (mods & (Qt::AltModifier | Qt::MetaModifier))) { if (esc_meta_ || (mods & (Qt::AltModifier | Qt::MetaModifier))) {
#endif #endif
int ascii_key = 0; int ascii_key = 0;
if (e.key() == Qt::Key_Backspace) { if (e.key() == Qt::Key_Backspace) {

25741
fonts/Go.h

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -195,12 +195,11 @@ main(int argc, char *argv[])
} else if (req_term) { } else if (req_term) {
use_gui = false; use_gui = false;
} else { } else {
// Default depends on build target: kge defaults to GUI, kte to terminal
// Default depends on build target: kge defaults to GUI, kte to terminal
#if defined(KTE_DEFAULT_GUI) #if defined(KTE_DEFAULT_GUI)
use_gui = true; use_gui = true;
#else #else
use_gui = false; use_gui = false;
#endif #endif
} }
#endif #endif

View File

@@ -143,7 +143,7 @@ CppHighlighter::HighlightLineStateful(const Buffer &buf,
bool closed = false; bool closed = false;
while (j + 1 <= n) { while (j + 1 <= n) {
if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') { if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') {
j += 2; j += 2;
closed = true; closed = true;
break; break;
} }

View File

@@ -75,7 +75,7 @@ GoHighlighter::HighlightLine(const Buffer &buf, int row, std::vector<HighlightSp
bool closed = false; bool closed = false;
while (j + 1 <= n) { while (j + 1 <= n) {
if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') { if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') {
j += 2; j += 2;
closed = true; closed = true;
break; break;
} }

View File

@@ -72,7 +72,7 @@ RustHighlighter::HighlightLine(const Buffer &buf, int row, std::vector<Highlight
bool closed = false; bool closed = false;
while (j + 1 <= n) { while (j + 1 <= n) {
if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') { if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') {
j += 2; j += 2;
closed = true; closed = true;
break; break;
} }

View File

@@ -75,7 +75,7 @@ SqlHighlighter::HighlightLine(const Buffer &buf, int row, std::vector<HighlightS
bool closed = false; bool closed = false;
while (j + 1 <= n) { while (j + 1 <= n) {
if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') { if (j + 1 < n && s[j] == '*' && s[j + 1] == '/') {
j += 2; j += 2;
closed = true; closed = true;
break; break;
} }

View File

@@ -44,7 +44,7 @@ CreateTreeSitterHighlighter(const char *filetype,
const void * (*get_lang)()) const void * (*get_lang)())
{ {
const auto *lang = reinterpret_cast<const TSLanguage *>(get_lang ? get_lang() : nullptr); const auto *lang = reinterpret_cast<const TSLanguage *>(get_lang ? get_lang() : nullptr);
return std::make_unique < TreeSitterHighlighter > (lang, filetype ? std::string(filetype) : std::string()); return std::make_unique<TreeSitterHighlighter>(lang, filetype ? std::string(filetype) : std::string());
} }
} // namespace kte } // namespace kte

View File

@@ -8,49 +8,61 @@
#include <sstream> #include <sstream>
namespace ktet { namespace ktet {
struct TestCase { struct TestCase {
std::string name; std::string name;
std::function<void()> fn; std::function<void()> fn;
}; };
inline std::vector<TestCase>& registry() {
static std::vector<TestCase> r; inline std::vector<TestCase> &
return r; registry()
{
static std::vector<TestCase> r;
return r;
} }
struct Registrar { struct Registrar {
Registrar(const char* name, std::function<void()> fn) { Registrar(const char *name, std::function<void()> fn)
registry().push_back(TestCase{std::string(name), std::move(fn)}); {
} registry().push_back(TestCase{std::string(name), std::move(fn)});
}
}; };
// Assertions // Assertions
struct AssertionFailure { struct AssertionFailure {
std::string msg; std::string msg;
}; };
inline void expect(bool cond, const char* expr, const char* file, int line) {
if (!cond) { inline void
std::cerr << file << ":" << line << ": EXPECT failed: " << expr << "\n"; expect(bool cond, const char *expr, const char *file, int line)
} {
if (!cond) {
std::cerr << file << ":" << line << ": EXPECT failed: " << expr << "\n";
}
} }
inline void assert_true(bool cond, const char* expr, const char* file, int line) {
if (!cond) { inline void
throw AssertionFailure{std::string(file) + ":" + std::to_string(line) + ": ASSERT failed: " + expr}; assert_true(bool cond, const char *expr, const char *file, int line)
} {
if (!cond) {
throw AssertionFailure{std::string(file) + ":" + std::to_string(line) + ": ASSERT failed: " + expr};
}
} }
template<typename A, typename B> template<typename A, typename B>
inline void assert_eq_impl(const A& a, const B& b, const char* ea, const char* eb, const char* file, int line) { inline void
if (!(a == b)) { assert_eq_impl(const A &a, const B &b, const char *ea, const char *eb, const char *file, int line)
std::ostringstream oss; {
oss << file << ":" << line << ": ASSERT_EQ failed: " << ea << " == " << eb; if (!(a == b)) {
throw AssertionFailure{oss.str()}; std::ostringstream oss;
} oss << file << ":" << line << ": ASSERT_EQ failed: " << ea << " == " << eb;
throw AssertionFailure{oss.str()};
}
} }
} // namespace ktet } // namespace ktet
#define TEST(name) \ #define TEST(name) \

View File

@@ -2,32 +2,35 @@
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
int main() {
using namespace std::chrono; int
auto &reg = ktet::registry(); main()
std::cout << "kte unit tests: " << reg.size() << " test(s)\n"; {
int failed = 0; using namespace std::chrono;
auto t0 = steady_clock::now(); auto &reg = ktet::registry();
for (const auto &tc : reg) { std::cout << "kte unit tests: " << reg.size() << " test(s)\n";
auto ts = steady_clock::now(); int failed = 0;
try { auto t0 = steady_clock::now();
tc.fn(); for (const auto &tc: reg) {
auto te = steady_clock::now(); auto ts = steady_clock::now();
auto ms = duration_cast<milliseconds>(te - ts).count(); try {
std::cout << "[ OK ] " << tc.name << " (" << ms << " ms)\n"; tc.fn();
} catch (const ktet::AssertionFailure &e) { auto te = steady_clock::now();
++failed; auto ms = duration_cast<milliseconds>(te - ts).count();
std::cerr << "[FAIL] " << tc.name << " -> " << e.msg << "\n"; std::cout << "[ OK ] " << tc.name << " (" << ms << " ms)\n";
} catch (const std::exception &e) { } catch (const ktet::AssertionFailure &e) {
++failed; ++failed;
std::cerr << "[EXCP] " << tc.name << " -> " << e.what() << "\n"; std::cerr << "[FAIL] " << tc.name << " -> " << e.msg << "\n";
} catch (...) { } catch (const std::exception &e) {
++failed; ++failed;
std::cerr << "[EXCP] " << tc.name << " -> unknown exception\n"; std::cerr << "[EXCP] " << tc.name << " -> " << e.what() << "\n";
} } catch (...) {
} ++failed;
auto t1 = steady_clock::now(); std::cerr << "[EXCP] " << tc.name << " -> unknown exception\n";
auto total_ms = duration_cast<milliseconds>(t1 - t0).count(); }
std::cout << "Done in " << total_ms << " ms. Failures: " << failed << "\n"; }
return failed == 0 ? 0 : 1; auto t1 = steady_clock::now();
auto total_ms = duration_cast<milliseconds>(t1 - t0).count();
std::cout << "Done in " << total_ms << " ms. Failures: " << failed << "\n";
return failed == 0 ? 0 : 1;
} }

View File

@@ -4,76 +4,85 @@
#include <string> #include <string>
#include "Buffer.h" #include "Buffer.h"
static std::string read_all(const std::string &path) {
std::ifstream in(path, std::ios::binary); static std::string
return std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>()); read_all(const std::string &path)
{
std::ifstream in(path, std::ios::binary);
return std::string((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
} }
TEST(Buffer_SaveAs_and_Save_new_file) {
const std::string path = "./.kte_ut_buffer_io_1.tmp";
std::remove(path.c_str());
Buffer b; TEST(Buffer_SaveAs_and_Save_new_file)
// insert two lines {
b.insert_text(0, 0, std::string("Hello, world!\n")); const std::string path = "./.kte_ut_buffer_io_1.tmp";
b.insert_text(1, 0, std::string("Second line\n")); std::remove(path.c_str());
std::string err; Buffer b;
ASSERT_TRUE(b.SaveAs(path, err)); // insert two lines
ASSERT_EQ(err.empty(), true); b.insert_text(0, 0, std::string("Hello, world!\n"));
b.insert_text(1, 0, std::string("Second line\n"));
// append another line then Save() std::string err;
b.insert_text(2, 0, std::string("Third\n")); ASSERT_TRUE(b.SaveAs(path, err));
b.SetDirty(true); ASSERT_EQ(err.empty(), true);
ASSERT_TRUE(b.Save(err));
ASSERT_EQ(err.empty(), true);
std::string got = read_all(path); // append another line then Save()
ASSERT_EQ(got, std::string("Hello, world!\nSecond line\nThird\n")); b.insert_text(2, 0, std::string("Third\n"));
b.SetDirty(true);
ASSERT_TRUE(b.Save(err));
ASSERT_EQ(err.empty(), true);
std::remove(path.c_str()); std::string got = read_all(path);
ASSERT_EQ(got, std::string("Hello, world!\nSecond line\nThird\n"));
std::remove(path.c_str());
} }
TEST(Buffer_Save_after_Open_existing) {
const std::string path = "./.kte_ut_buffer_io_2.tmp";
std::remove(path.c_str());
{
std::ofstream out(path, std::ios::binary);
out << "abc\n123\n";
}
Buffer b; TEST(Buffer_Save_after_Open_existing)
std::string err; {
ASSERT_TRUE(b.OpenFromFile(path, err)); const std::string path = "./.kte_ut_buffer_io_2.tmp";
ASSERT_EQ(err.empty(), true); std::remove(path.c_str());
{
std::ofstream out(path, std::ios::binary);
out << "abc\n123\n";
}
b.insert_text(2, 0, std::string("tail\n")); Buffer b;
b.SetDirty(true); std::string err;
ASSERT_TRUE(b.Save(err)); ASSERT_TRUE(b.OpenFromFile(path, err));
ASSERT_EQ(err.empty(), true); ASSERT_EQ(err.empty(), true);
std::string got = read_all(path); b.insert_text(2, 0, std::string("tail\n"));
ASSERT_EQ(got, std::string("abc\n123\ntail\n")); b.SetDirty(true);
std::remove(path.c_str()); ASSERT_TRUE(b.Save(err));
ASSERT_EQ(err.empty(), true);
std::string got = read_all(path);
ASSERT_EQ(got, std::string("abc\n123\ntail\n"));
std::remove(path.c_str());
} }
TEST(Buffer_Open_nonexistent_then_SaveAs) {
const std::string path = "./.kte_ut_buffer_io_3.tmp";
std::remove(path.c_str());
Buffer b; TEST(Buffer_Open_nonexistent_then_SaveAs)
std::string err; {
ASSERT_TRUE(b.OpenFromFile(path, err)); const std::string path = "./.kte_ut_buffer_io_3.tmp";
ASSERT_EQ(err.empty(), true); std::remove(path.c_str());
ASSERT_EQ(b.IsFileBacked(), false);
b.insert_text(0, 0, std::string("hello, world")); Buffer b;
b.insert_text(0, 12, std::string("\n")); std::string err;
b.SetDirty(true); ASSERT_TRUE(b.OpenFromFile(path, err));
ASSERT_TRUE(b.SaveAs(path, err)); ASSERT_EQ(err.empty(), true);
ASSERT_EQ(err.empty(), true); ASSERT_EQ(b.IsFileBacked(), false);
std::string got = read_all(path); b.insert_text(0, 0, std::string("hello, world"));
ASSERT_EQ(got, std::string("hello, world\n")); b.insert_text(0, 12, std::string("\n"));
std::remove(path.c_str()); b.SetDirty(true);
ASSERT_TRUE(b.SaveAs(path, err));
ASSERT_EQ(err.empty(), true);
std::string got = read_all(path);
ASSERT_EQ(got, std::string("hello, world\n"));
std::remove(path.c_str());
} }

View File

@@ -82,7 +82,7 @@ check_buffer_matches_model(const Buffer &b, const std::string &model)
} }
TEST (Buffer_RowsCache_MultiLineEdits_StayConsistent) TEST(Buffer_RowsCache_MultiLineEdits_StayConsistent)
{ {
Buffer b; Buffer b;
std::string model; std::string model;

View File

@@ -5,7 +5,7 @@
using ktet::TestHarness; using ktet::TestHarness;
TEST (CommandSemantics_KillToEOL_KillChain_And_Yank) TEST(CommandSemantics_KillToEOL_KillChain_And_Yank)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();
@@ -34,7 +34,7 @@ TEST (CommandSemantics_KillToEOL_KillChain_And_Yank)
} }
TEST (CommandSemantics_ToggleMark_JumpToMark) TEST(CommandSemantics_ToggleMark_JumpToMark)
{ {
TestHarness h; TestHarness h;
Buffer &b = h.Buf(); Buffer &b = h.Buf();
@@ -59,7 +59,7 @@ TEST (CommandSemantics_ToggleMark_JumpToMark)
} }
TEST (CommandSemantics_CtrlGRefresh_ClearsMark_WhenNothingElseToCancel) TEST(CommandSemantics_CtrlGRefresh_ClearsMark_WhenNothingElseToCancel)
{ {
TestHarness h; TestHarness h;
Buffer &b = h.Buf(); Buffer &b = h.Buf();
@@ -78,7 +78,7 @@ TEST (CommandSemantics_CtrlGRefresh_ClearsMark_WhenNothingElseToCancel)
} }
TEST (CommandSemantics_CopyRegion_And_KillRegion) TEST(CommandSemantics_CopyRegion_And_KillRegion)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();

View File

@@ -3,7 +3,7 @@
#include "tests/TestHarness.h" #include "tests/TestHarness.h"
TEST (DailyDriverHarness_Smoke_CanCreateBufferAndInsertText) TEST(DailyDriverHarness_Smoke_CanCreateBufferAndInsertText)
{ {
ktet::TestHarness h; ktet::TestHarness h;

View File

@@ -40,7 +40,7 @@ buffer_bytes_via_views(const Buffer &b)
} }
TEST (DailyWorkflow_OpenEditSave_Transcript) TEST(DailyWorkflow_OpenEditSave_Transcript)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -77,7 +77,7 @@ TEST (DailyWorkflow_OpenEditSave_Transcript)
} }
TEST (DailyWorkflow_MultiBufferSwitchClose_Transcript) TEST(DailyWorkflow_MultiBufferSwitchClose_Transcript)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -123,7 +123,7 @@ TEST (DailyWorkflow_MultiBufferSwitchClose_Transcript)
} }
TEST (DailyWorkflow_CrashRecovery_SwapReplay_Transcript) TEST(DailyWorkflow_CrashRecovery_SwapReplay_Transcript)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();

View File

@@ -5,7 +5,7 @@
#include <ncurses.h> #include <ncurses.h>
TEST (KKeymap_KPrefix_CanonicalChords) TEST(KKeymap_KPrefix_CanonicalChords)
{ {
CommandId id{}; CommandId id{};
@@ -37,7 +37,7 @@ TEST (KKeymap_KPrefix_CanonicalChords)
} }
TEST (KKeymap_CtrlChords_CanonicalChords) TEST(KKeymap_CtrlChords_CanonicalChords)
{ {
CommandId id{}; CommandId id{};
@@ -60,7 +60,7 @@ TEST (KKeymap_CtrlChords_CanonicalChords)
} }
TEST (KKeymap_EscChords_CanonicalChords) TEST(KKeymap_EscChords_CanonicalChords)
{ {
CommandId id{}; CommandId id{};

View File

@@ -34,7 +34,7 @@ LineContentFor(const std::string &s, std::size_t line_num)
} }
TEST (PieceTable_Insert_Delete_LineCount) TEST(PieceTable_Insert_Delete_LineCount)
{ {
PieceTable pt; PieceTable pt;
// start empty // start empty
@@ -61,7 +61,7 @@ TEST (PieceTable_Insert_Delete_LineCount)
} }
TEST (PieceTable_LineCol_Conversions) TEST(PieceTable_LineCol_Conversions)
{ {
PieceTable pt; PieceTable pt;
std::string s = "hello\nworld\n"; // two lines with trailing NL std::string s = "hello\nworld\n"; // two lines with trailing NL
@@ -84,7 +84,7 @@ TEST (PieceTable_LineCol_Conversions)
} }
TEST (PieceTable_ReferenceModel_RandomEdits_Deterministic) TEST(PieceTable_ReferenceModel_RandomEdits_Deterministic)
{ {
PieceTable pt; PieceTable pt;
std::string model; std::string model;

View File

@@ -20,7 +20,7 @@ to_string_rows(const Buffer &buf)
} }
TEST (ReflowParagraph_IndentedBullets_PreserveStructure) TEST(ReflowParagraph_IndentedBullets_PreserveStructure)
{ {
InstallDefaultCommands(); InstallDefaultCommands();

View File

@@ -20,7 +20,7 @@ to_string_rows(const Buffer &buf)
} }
TEST (ReflowParagraph_NumberedList_HangingIndent) TEST(ReflowParagraph_NumberedList_HangingIndent)
{ {
InstallDefaultCommands(); InstallDefaultCommands();

View File

@@ -3,34 +3,44 @@
#include <string> #include <string>
#include <vector> #include <vector>
static std::vector<std::size_t> ref_find_all(const std::string &text, const std::string &pat) {
std::vector<std::size_t> res; static std::vector<std::size_t>
if (pat.empty()) return res; ref_find_all(const std::string &text, const std::string &pat)
std::size_t from = 0; {
while (true) { std::vector<std::size_t> res;
auto p = text.find(pat, from); if (pat.empty())
if (p == std::string::npos) break; return res;
res.push_back(p); std::size_t from = 0;
from = p + pat.size(); while (true) {
} auto p = text.find(pat, from);
return res; if (p == std::string::npos)
break;
res.push_back(p);
from = p + pat.size();
}
return res;
} }
TEST(OptimizedSearch_basic_cases) {
OptimizedSearch os; TEST(OptimizedSearch_basic_cases)
struct Case { std::string text; std::string pat; } cases[] = { {
{"", ""}, OptimizedSearch os;
{"", "a"}, struct Case {
{"a", ""}, std::string text;
{"a", "a"}, std::string pat;
{"aaaaa", "aa"}, } cases[] = {
{"hello world", "world"}, {"", ""},
{"abcabcabc", "abc"}, {"", "a"},
{"the quick brown fox", "fox"}, {"a", ""},
}; {"a", "a"},
for (auto &c : cases) { {"aaaaa", "aa"},
auto got = os.find_all(c.text, c.pat, 0); {"hello world", "world"},
auto ref = ref_find_all(c.text, c.pat); {"abcabcabc", "abc"},
ASSERT_EQ(got, ref); {"the quick brown fox", "fox"},
} };
for (auto &c: cases) {
auto got = os.find_all(c.text, c.pat, 0);
auto ref = ref_find_all(c.text, c.pat);
ASSERT_EQ(got, ref);
}
} }

View File

@@ -7,7 +7,7 @@ using ktet::TestHarness;
// These tests intentionally drive the prompt-based search/replace UI headlessly // These tests intentionally drive the prompt-based search/replace UI headlessly
// via `Execute(Editor&, CommandId, ...)` to lock down behavior without ncurses. // via `Execute(Editor&, CommandId, ...)` to lock down behavior without ncurses.
TEST (SearchFlow_FindStart_Success_LeavesCursorOnMatch_And_ClearsSearchState) TEST(SearchFlow_FindStart_Success_LeavesCursorOnMatch_And_ClearsSearchState)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();
@@ -39,7 +39,7 @@ TEST (SearchFlow_FindStart_Success_LeavesCursorOnMatch_And_ClearsSearchState)
} }
TEST (SearchFlow_FindStart_NotFound_RestoresOrigin_And_ClearsSearchState) TEST(SearchFlow_FindStart_NotFound_RestoresOrigin_And_ClearsSearchState)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();
@@ -71,7 +71,7 @@ TEST (SearchFlow_FindStart_NotFound_RestoresOrigin_And_ClearsSearchState)
} }
TEST (SearchFlow_SearchReplace_EmptyFind_DoesNotMutateBuffer_And_ClearsState) TEST(SearchFlow_SearchReplace_EmptyFind_DoesNotMutateBuffer_And_ClearsState)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();
@@ -101,7 +101,7 @@ TEST (SearchFlow_SearchReplace_EmptyFind_DoesNotMutateBuffer_And_ClearsState)
} }
TEST (SearchFlow_RegexFind_InvalidPattern_FailsSafely_And_ClearsStateOnEnter) TEST(SearchFlow_RegexFind_InvalidPattern_FailsSafely_And_ClearsStateOnEnter)
{ {
TestHarness h; TestHarness h;
Editor &ed = h.EditorRef(); Editor &ed = h.EditorRef();

View File

@@ -23,7 +23,7 @@ write_file_bytes(const std::string &path, const std::string &bytes)
} }
TEST (SwapCleanup_ResetJournalOnSave) TEST(SwapCleanup_ResetJournalOnSave)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -82,7 +82,7 @@ TEST (SwapCleanup_ResetJournalOnSave)
} }
TEST (SwapCleanup_PruneSwapDir_ByAge) TEST(SwapCleanup_PruneSwapDir_ByAge)
{ {
const fs::path xdg_root = fs::temp_directory_path() / const fs::path xdg_root = fs::temp_directory_path() /
(std::string("kte_ut_xdg_state_swap_prune_") + std::to_string((int) ::getpid())); (std::string("kte_ut_xdg_state_swap_prune_") + std::to_string((int) ::getpid()));

View File

@@ -25,7 +25,7 @@ write_file_bytes(const std::string &path, const std::string &bytes)
// Simulate git editor workflow: open file, edit, save, edit more, close. // Simulate git editor workflow: open file, edit, save, edit more, close.
// The swap file should be deleted on close, not left behind. // The swap file should be deleted on close, not left behind.
TEST (SwapCleanup_GitEditorWorkflow) TEST(SwapCleanup_GitEditorWorkflow)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();

View File

@@ -50,7 +50,7 @@ public:
} // namespace } // namespace
TEST (SwapRecorder_InsertABC) TEST(SwapRecorder_InsertABC)
{ {
Buffer b; Buffer b;
FakeSwapRecorder rec; FakeSwapRecorder rec;
@@ -66,7 +66,7 @@ TEST (SwapRecorder_InsertABC)
} }
TEST (SwapRecorder_InsertNewline) TEST(SwapRecorder_InsertNewline)
{ {
Buffer b; Buffer b;
FakeSwapRecorder rec; FakeSwapRecorder rec;
@@ -82,7 +82,7 @@ TEST (SwapRecorder_InsertNewline)
} }
TEST (SwapRecorder_DeleteSpanningNewline) TEST(SwapRecorder_DeleteSpanningNewline)
{ {
Buffer b; Buffer b;
// Prepare content without a recorder (should be no-op) // Prepare content without a recorder (should be no-op)

View File

@@ -71,7 +71,7 @@ struct ScopedXdgStateHome {
} // namespace } // namespace
TEST (SwapRecoveryPrompt_Recover_ReplaysSwap) TEST(SwapRecoveryPrompt_Recover_ReplaysSwap)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -127,7 +127,7 @@ TEST (SwapRecoveryPrompt_Recover_ReplaysSwap)
} }
TEST (SwapRecoveryPrompt_Discard_DeletesSwapAndOpensClean) TEST(SwapRecoveryPrompt_Discard_DeletesSwapAndOpensClean)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -178,7 +178,7 @@ TEST (SwapRecoveryPrompt_Discard_DeletesSwapAndOpensClean)
} }
TEST (SwapRecoveryPrompt_Cancel_AbortsOpen) TEST(SwapRecoveryPrompt_Cancel_AbortsOpen)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();
@@ -228,7 +228,7 @@ TEST (SwapRecoveryPrompt_Cancel_AbortsOpen)
} }
TEST (SwapRecoveryPrompt_CorruptSwap_OffersDelete) TEST(SwapRecoveryPrompt_CorruptSwap_OffersDelete)
{ {
ktet::InstallDefaultCommandsOnce(); ktet::InstallDefaultCommandsOnce();

View File

@@ -63,7 +63,7 @@ record_types_from_bytes(const std::string &bytes)
} }
TEST (SwapReplay_RecordFlushReopenReplay_ExactBytesMatch) TEST(SwapReplay_RecordFlushReopenReplay_ExactBytesMatch)
{ {
const std::string path = "./.kte_ut_swap_replay_1.txt"; const std::string path = "./.kte_ut_swap_replay_1.txt";
std::remove(path.c_str()); std::remove(path.c_str());
@@ -103,7 +103,7 @@ TEST (SwapReplay_RecordFlushReopenReplay_ExactBytesMatch)
} }
TEST (SwapReplay_TruncatedLog_FailsSafely) TEST(SwapReplay_TruncatedLog_FailsSafely)
{ {
const std::string path = "./.kte_ut_swap_replay_2.txt"; const std::string path = "./.kte_ut_swap_replay_2.txt";
std::remove(path.c_str()); std::remove(path.c_str());
@@ -140,7 +140,7 @@ TEST (SwapReplay_TruncatedLog_FailsSafely)
} }
TEST (SwapReplay_Checkpoint_Midstream_ExactBytesMatch) TEST(SwapReplay_Checkpoint_Midstream_ExactBytesMatch)
{ {
const std::string path = "./.kte_ut_swap_replay_chkpt_1.txt"; const std::string path = "./.kte_ut_swap_replay_chkpt_1.txt";
std::remove(path.c_str()); std::remove(path.c_str());
@@ -177,7 +177,7 @@ TEST (SwapReplay_Checkpoint_Midstream_ExactBytesMatch)
} }
TEST (SwapCompaction_RewritesToSingleCheckpoint) TEST(SwapCompaction_RewritesToSingleCheckpoint)
{ {
const std::string path = "./.kte_ut_swap_compact_1.txt"; const std::string path = "./.kte_ut_swap_compact_1.txt";
std::remove(path.c_str()); std::remove(path.c_str());

View File

@@ -65,7 +65,7 @@ crc32(const std::uint8_t *data, std::size_t len, std::uint32_t seed = 0)
} // namespace } // namespace
TEST (SwapWriter_Header_Records_And_CRC) TEST(SwapWriter_Header_Records_And_CRC)
{ {
const std::filesystem::path xdg_root = std::filesystem::temp_directory_path() / const std::filesystem::path xdg_root = std::filesystem::temp_directory_path() /
(std::string("kte_ut_xdg_state_") + std::to_string((int) ::getpid())); (std::string("kte_ut_xdg_state_") + std::to_string((int) ::getpid()));
@@ -166,7 +166,7 @@ TEST (SwapWriter_Header_Records_And_CRC)
} }
TEST (SwapWriter_NoStomp_SameBasename) TEST(SwapWriter_NoStomp_SameBasename)
{ {
const std::filesystem::path xdg_root = std::filesystem::temp_directory_path() / const std::filesystem::path xdg_root = std::filesystem::temp_directory_path() /
(std::string("kte_ut_xdg_state_nostomp_") + std::to_string( (std::string("kte_ut_xdg_state_nostomp_") + std::to_string(

View File

@@ -10,6 +10,7 @@
#if defined(KTE_TESTS) #if defined(KTE_TESTS)
#include <unordered_set> #include <unordered_set>
static void static void
validate_undo_subtree(const UndoNode *node, const UndoNode *expected_parent, validate_undo_subtree(const UndoNode *node, const UndoNode *expected_parent,
std::unordered_set<const UndoNode *> &seen) std::unordered_set<const UndoNode *> &seen)
@@ -56,7 +57,7 @@ validate_undo_tree(const UndoSystem &u)
// The undo suite aims to cover invariants with a small, adversarial test matrix. // The undo suite aims to cover invariants with a small, adversarial test matrix.
TEST (Undo_InsertRun_Coalesces_OneStep) TEST(Undo_InsertRun_Coalesces_OneStep)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -80,7 +81,7 @@ TEST (Undo_InsertRun_Coalesces_OneStep)
} }
TEST (Undo_InsertRun_BreaksOnNonAdjacentCursor) TEST(Undo_InsertRun_BreaksOnNonAdjacentCursor)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -108,7 +109,7 @@ TEST (Undo_InsertRun_BreaksOnNonAdjacentCursor)
} }
TEST (Undo_BackspaceRun_Coalesces_OneStep) TEST(Undo_BackspaceRun_Coalesces_OneStep)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -142,7 +143,7 @@ TEST (Undo_BackspaceRun_Coalesces_OneStep)
} }
TEST (Undo_DeleteKeyRun_Coalesces_OneStep) TEST(Undo_DeleteKeyRun_Coalesces_OneStep)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -175,7 +176,7 @@ TEST (Undo_DeleteKeyRun_Coalesces_OneStep)
} }
TEST (Undo_Newline_IsStandalone) TEST(Undo_Newline_IsStandalone)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -210,7 +211,7 @@ TEST (Undo_Newline_IsStandalone)
} }
TEST (Undo_ExplicitGroup_UndoesAsUnit) TEST(Undo_ExplicitGroup_UndoesAsUnit)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -238,7 +239,7 @@ TEST (Undo_ExplicitGroup_UndoesAsUnit)
} }
TEST (Undo_Branching_RedoBranchSelectionDeterministic) TEST(Undo_Branching_RedoBranchSelectionDeterministic)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -282,7 +283,7 @@ TEST (Undo_Branching_RedoBranchSelectionDeterministic)
} }
TEST (Undo_DirtyFlag_CrossesMarkSaved) TEST(Undo_DirtyFlag_CrossesMarkSaved)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();
@@ -311,7 +312,7 @@ TEST (Undo_DirtyFlag_CrossesMarkSaved)
} }
TEST (Undo_RoundTrip_Lossless_RandomEdits) TEST(Undo_RoundTrip_Lossless_RandomEdits)
{ {
Buffer b; Buffer b;
UndoSystem *u = b.Undo(); UndoSystem *u = b.Undo();

View File

@@ -33,7 +33,7 @@ dump_bytes(const std::string &s)
} }
TEST (VisualLineMode_BroadcastInsert) TEST(VisualLineMode_BroadcastInsert)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -65,7 +65,7 @@ TEST (VisualLineMode_BroadcastInsert)
} }
TEST (VisualLineMode_BroadcastInsert_UndoRedo) TEST(VisualLineMode_BroadcastInsert_UndoRedo)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -108,7 +108,7 @@ TEST (VisualLineMode_BroadcastInsert_UndoRedo)
} }
TEST (VisualLineMode_BroadcastBackspace) TEST(VisualLineMode_BroadcastBackspace)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -135,7 +135,7 @@ TEST (VisualLineMode_BroadcastBackspace)
} }
TEST (VisualLineMode_BroadcastBackspace_UndoRedo) TEST(VisualLineMode_BroadcastBackspace_UndoRedo)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -175,7 +175,7 @@ TEST (VisualLineMode_BroadcastBackspace_UndoRedo)
} }
TEST (VisualLineMode_CancelWithCtrlG) TEST(VisualLineMode_CancelWithCtrlG)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -208,7 +208,7 @@ TEST (VisualLineMode_CancelWithCtrlG)
} }
TEST (Yank_ClearsMarkAndVisualLine) TEST(Yank_ClearsMarkAndVisualLine)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -241,7 +241,7 @@ TEST (Yank_ClearsMarkAndVisualLine)
} }
TEST (VisualLineMode_Yank_BroadcastsToBOL_AndUndo) TEST(VisualLineMode_Yank_BroadcastsToBOL_AndUndo)
{ {
InstallDefaultCommands(); InstallDefaultCommands();
@@ -298,7 +298,7 @@ TEST (VisualLineMode_Yank_BroadcastsToBOL_AndUndo)
} }
TEST (VisualLineMode_Highlight_IsPerLineCursorSpot) TEST(VisualLineMode_Highlight_IsPerLineCursorSpot)
{ {
Buffer b; Buffer b;
// Note: buffers that end with a trailing '\n' have an extra empty row. // Note: buffers that end with a trailing '\n' have an extra empty row.