Code quality, safety, stability, and cleanups.

- Replace header include guards with `#pragma once` and perform minor optimizations.
- Replaced traditional include guards with `#pragma once` for simplicity and to reduce boilerplate in all headers.
- Improved CLI line number handling with clamping and error messaging.
- Enhanced `chdir` error handling for macOS GUI builds.
- Removed redundant logic for GUI builds.
- Adjusted font constructor and registry to handle `const` data pointers consistently.
This commit is contained in:
2025-12-03 14:02:54 -08:00
parent 389dcf9cc7
commit 45b2b88623
29 changed files with 100 additions and 188 deletions

View File

@@ -1,8 +1,7 @@
/*
* AppendBuffer.h - selector header to choose GapBuffer or PieceTable
*/
#ifndef KTE_APPENDBUFFER_H
#define KTE_APPENDBUFFER_H
#pragma once
#ifdef KTE_USE_PIECE_TABLE
#include "PieceTable.h"
@@ -10,6 +9,4 @@ using AppendBuffer = PieceTable;
#else
#include "GapBuffer.h"
using AppendBuffer = GapBuffer;
#endif
#endif // KTE_APPENDBUFFER_H
#endif

View File

@@ -1,8 +1,7 @@
/*
* Buffer.h - editor buffer representing an open document
*/
#ifndef KTE_BUFFER_H
#define KTE_BUFFER_H
#pragma once
#include <cstddef>
#include <memory>
@@ -466,6 +465,4 @@ private:
bool syntax_enabled_ = true;
std::string filetype_;
std::unique_ptr<kte::HighlighterEngine> highlighter_;
};
#endif // KTE_BUFFER_H
};

View File

@@ -1,8 +1,7 @@
/*
* Command.h - command model and registry for editor actions
*/
#ifndef KTE_COMMAND_H
#define KTE_COMMAND_H
#pragma once
#include <functional>
#include <string>
@@ -155,6 +154,4 @@ void InstallDefaultCommands();
// Returns true if the command executed successfully.
bool Execute(Editor &ed, CommandId id, const std::string &arg = std::string(), int count = 0);
bool Execute(Editor &ed, const std::string &name, const std::string &arg = std::string(), int count = 0);
#endif // KTE_COMMAND_H
bool Execute(Editor &ed, const std::string &name, const std::string &arg = std::string(), int count = 0);

View File

@@ -1,9 +1,7 @@
/*
* Editor.h - top-level editor state and buffer management
*/
#ifndef KTE_EDITOR_H
#define KTE_EDITOR_H
#pragma once
#include <cstddef>
#include <ctime>
#include <string>
@@ -561,6 +559,4 @@ public:
private:
std::string replace_find_tmp_;
std::string replace_with_tmp_;
};
#endif // KTE_EDITOR_H
};

View File

@@ -1,9 +1,7 @@
/*
* Frontend.h - top-level container that couples Input + Renderer and runs the loop
*/
#ifndef KTE_FRONTEND_H
#define KTE_FRONTEND_H
#pragma once
class Editor;
class InputHandler;
@@ -21,6 +19,4 @@ public:
// Shutdown/cleanup
virtual void Shutdown() = 0;
};
#endif // KTE_FRONTEND_H
};

View File

@@ -1,8 +1,7 @@
/*
* GUIConfig - loads simple GUI configuration from $HOME/.config/kte/kge.ini
*/
#ifndef KTE_GUI_CONFIG_H
#define KTE_GUI_CONFIG_H
#pragma once
#include <string>
@@ -31,6 +30,4 @@ public:
// Load from explicit path. Returns true if file existed and was parsed.
bool LoadFromFile(const std::string &path);
};
#endif // KTE_GUI_CONFIG_H
};

View File

@@ -1,9 +1,7 @@
/*
* GUIFrontend - couples GUIInputHandler + GUIRenderer and owns SDL2/ImGui lifecycle
*/
#ifndef KTE_GUI_FRONTEND_H
#define KTE_GUI_FRONTEND_H
#pragma once
#include "Frontend.h"
#include "GUIConfig.h"
#include "GUIInputHandler.h"
@@ -35,6 +33,4 @@ private:
SDL_GLContext gl_ctx_ = nullptr;
int width_ = 1280;
int height_ = 800;
};
#endif // KTE_GUI_FRONTEND_H
};

View File

@@ -1,9 +1,7 @@
/*
* GUIInputHandler - ImGui/SDL2-based input mapping for GUI mode
*/
#ifndef KTE_GUI_INPUT_HANDLER_H
#define KTE_GUI_INPUT_HANDLER_H
#pragma once
#include <mutex>
#include <queue>
@@ -41,6 +39,4 @@ private:
bool uarg_had_digits_ = false; // whether any digits were supplied
int uarg_value_ = 0; // current absolute value (>=0)
std::string uarg_text_; // raw digits/minus typed for status display
};
#endif // KTE_GUI_INPUT_HANDLER_H
};

View File

@@ -1,9 +1,7 @@
/*
* GUIRenderer - ImGui-based renderer for GUI mode
*/
#ifndef KTE_GUI_RENDERER_H
#define KTE_GUI_RENDERER_H
#pragma once
#include "Renderer.h"
class GUIRenderer final : public Renderer {
@@ -13,6 +11,4 @@ public:
~GUIRenderer() override = default;
void Draw(Editor &ed) override;
};
#endif // KTE_GUI_RENDERER_H
};

View File

@@ -1,9 +1,7 @@
/*
* GapBuffer.h - C++ replacement for abuf append/prepend buffer utilities
*/
#ifndef KTE_GAPBUFFER_H
#define KTE_GAPBUFFER_H
#pragma once
#include <cstddef>
@@ -75,6 +73,4 @@ private:
char *buffer_ = nullptr;
std::size_t size_ = 0; // number of valid bytes (excluding terminator)
std::size_t capacity_ = 0; // capacity of buffer_ excluding space for terminator
};
#endif // KTE_GAPBUFFER_H
};

View File

@@ -1,9 +1,7 @@
/*
* HelpText.h - embedded/customizable help content
*/
#ifndef KTE_HELPTEXT_H
#define KTE_HELPTEXT_H
#pragma once
#include <string>
class HelpText {
@@ -12,6 +10,4 @@ public:
// Project maintainers can customize the returned string below
// (in HelpText.cc) without touching the help command logic.
static std::string Text();
};
#endif // KTE_HELPTEXT_H
};

View File

@@ -1,9 +1,7 @@
/*
* InputHandler.h - input abstraction and mapping to commands
*/
#ifndef KTE_INPUT_HANDLER_H
#define KTE_INPUT_HANDLER_H
#pragma once
#include <string>
#include "Command.h"
@@ -24,6 +22,4 @@ public:
// Poll for input and translate it to a command. Non-blocking.
// Returns true if a command is available in 'out'. Returns false if no input.
virtual bool Poll(MappedInput &out) = 0;
};
#endif // KTE_INPUT_HANDLER_H
};

View File

@@ -1,9 +1,7 @@
/*
* KKeymap.h - mapping for k-command (C-k prefix) keys to CommandId
*/
#ifndef KTE_KKEYMAP_H
#define KTE_KKEYMAP_H
#pragma once
#include "Command.h"
@@ -29,6 +27,4 @@ KLowerAscii(const int key)
if (key >= 'A' && key <= 'Z')
return key + ('a' - 'A');
return key;
}
#endif // KTE_KKEYMAP_H
}

View File

@@ -1,7 +1,5 @@
// OptimizedSearch.h - BoyerMoore (bad character) based substring search
#ifndef KTE_OPTIMIZED_SEARCH_H
#define KTE_OPTIMIZED_SEARCH_H
#pragma once
#include <array>
#include <cstddef>
#include <string>
@@ -22,6 +20,4 @@ private:
std::string last_pat_;
void build_bad_char(const std::string &pattern);
};
#endif // KTE_OPTIMIZED_SEARCH_H
};

View File

@@ -1,9 +1,7 @@
/*
* PieceTable.h - Alternative to GapBuffer using a piece table representation
*/
#ifndef KTE_PIECETABLE_H
#define KTE_PIECETABLE_H
#pragma once
#include <cstddef>
#include <string>
#include <vector>
@@ -93,6 +91,4 @@ private:
mutable std::string materialized_;
mutable bool dirty_ = true;
std::size_t total_size_ = 0;
};
#endif // KTE_PIECETABLE_H
};

View File

@@ -1,9 +1,7 @@
/*
* Renderer.h - rendering abstraction
*/
#ifndef KTE_RENDERER_H
#define KTE_RENDERER_H
#pragma once
class Editor;
@@ -12,6 +10,4 @@ public:
virtual ~Renderer() = default;
virtual void Draw(Editor &ed) = 0;
};
#endif // KTE_RENDERER_H
};

View File

@@ -1,9 +1,7 @@
/*
* TerminalFrontend - couples TerminalInputHandler + TerminalRenderer and owns ncurses lifecycle
*/
#ifndef KTE_TERMINAL_FRONTEND_H
#define KTE_TERMINAL_FRONTEND_H
#pragma once
#include <termios.h>
#include "Frontend.h"
@@ -31,6 +29,4 @@ private:
// Saved terminal attributes to restore on shutdown
bool have_orig_tio_ = false;
struct termios orig_tio_{};
};
#endif // KTE_TERMINAL_FRONTEND_H
};

View File

@@ -1,9 +1,7 @@
/*
* TerminalInputHandler - ncurses-based input handling for terminal mode
*/
#ifndef KTE_TERMINAL_INPUT_HANDLER_H
#define KTE_TERMINAL_INPUT_HANDLER_H
#pragma once
#include "InputHandler.h"
@@ -30,6 +28,4 @@ private:
bool uarg_had_digits_ = false; // whether any digits were supplied
int uarg_value_ = 0; // current absolute value (>=0)
std::string uarg_text_; // raw digits/minus typed for status display
};
#endif // KTE_TERMINAL_INPUT_HANDLER_H
};

View File

@@ -1,9 +1,7 @@
/*
* TerminalRenderer - ncurses-based renderer for terminal mode
*/
#ifndef KTE_TERMINAL_RENDERER_H
#define KTE_TERMINAL_RENDERER_H
#pragma once
#include "Renderer.h"
@@ -14,6 +12,4 @@ public:
~TerminalRenderer() override;
void Draw(Editor &ed) override;
};
#endif // KTE_TERMINAL_RENDERER_H
};

View File

@@ -1,9 +1,7 @@
/*
* TestFrontend.h - headless frontend for testing with programmable input
*/
#ifndef KTE_TEST_FRONTEND_H
#define KTE_TEST_FRONTEND_H
#pragma once
#include "Frontend.h"
#include "TestInputHandler.h"
#include "TestRenderer.h"
@@ -36,6 +34,4 @@ public:
private:
TestInputHandler input_{};
TestRenderer renderer_{};
};
#endif // KTE_TEST_FRONTEND_H
};

View File

@@ -1,9 +1,7 @@
/*
* TestInputHandler.h - programmable input handler for testing
*/
#ifndef KTE_TEST_INPUT_HANDLER_H
#define KTE_TEST_INPUT_HANDLER_H
#pragma once
#include <queue>
#include "InputHandler.h"
@@ -29,6 +27,4 @@ public:
private:
std::queue<MappedInput> queue_;
};
#endif // KTE_TEST_INPUT_HANDLER_H
};

View File

@@ -1,9 +1,7 @@
/*
* TestRenderer.h - minimal renderer for testing (no actual display)
*/
#ifndef KTE_TEST_RENDERER_H
#define KTE_TEST_RENDERER_H
#pragma once
#include <cstddef>
#include "Renderer.h"
@@ -31,6 +29,4 @@ public:
private:
std::size_t draw_count_ = 0;
};
#endif // KTE_TEST_RENDERER_H
};

View File

@@ -1,6 +1,4 @@
#ifndef KTE_UNDONODE_H
#define KTE_UNDONODE_H
#pragma once
#include <cstdint>
#include <string>
@@ -20,7 +18,4 @@ struct UndoNode {
std::string text;
UndoNode *child = nullptr; // next in current timeline
UndoNode *next = nullptr; // redo branch
};
#endif // KTE_UNDONODE_H
};

View File

@@ -1,6 +1,4 @@
#ifndef KTE_UNDONODEPOOL_H
#define KTE_UNDONODEPOOL_H
#pragma once
#include <stack>
#include <vector>
#include <memory>
@@ -60,6 +58,4 @@ private:
std::size_t block_size_;
std::vector<std::unique_ptr<UndoNode[]> > blocks_;
std::stack<UndoNode *> available_;
};
#endif // KTE_UNDONODEPOOL_H
};

View File

@@ -1,6 +1,4 @@
#ifndef KTE_UNDOSYSTEM_H
#define KTE_UNDOSYSTEM_H
#pragma once
#include <string_view>
#include <cstddef>
#include <cstdint>
@@ -54,6 +52,4 @@ private:
UndoTree &tree_;
// Internal hint for Delete batching: whether next Append() should prepend
bool pending_prepend_ = false;
};
#endif // KTE_UNDOSYSTEM_H
};

View File

@@ -1,6 +1,4 @@
#ifndef KTE_UNDOTREE_H
#define KTE_UNDOTREE_H
#pragma once
#include "UndoNode.h"
@@ -9,7 +7,4 @@ struct UndoTree {
UndoNode *current = nullptr; // current state of buffer
UndoNode *saved = nullptr; // points to node matching last save (for dirty flag)
UndoNode *pending = nullptr; // in-progress batch (detached)
};
#endif // KTE_UNDOTREE_H
};

View File

@@ -12,7 +12,7 @@ inline const unsigned int *DefaultFontData = BrassMonoCode::DefaultFontBoldCompr
class Font {
public:
Font(std::string name, unsigned int *data, const unsigned int size)
Font(std::string name, const unsigned int *data, const unsigned int size)
: name_(std::move(name)),
data_(data),
size_(size) {}
@@ -28,7 +28,7 @@ public:
private:
std::string name_;
unsigned int *data_{nullptr};
const unsigned int *data_{nullptr};
unsigned int size_{0};
};
}

View File

@@ -7,87 +7,87 @@ InstallDefaultFonts()
{
FontRegistry::Instance().Register(std::make_unique<Font>(
"default",
const_cast<unsigned int *>(BrassMono::DefaultFontBoldCompressedData),
BrassMono::DefaultFontBoldCompressedData,
BrassMono::DefaultFontBoldCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"b612",
const_cast<unsigned int *>(B612Mono::DefaultFontRegularCompressedData),
B612Mono::DefaultFontRegularCompressedData,
B612Mono::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"brassmono",
const_cast<unsigned int *>(BrassMono::DefaultFontBoldCompressedData),
BrassMono::DefaultFontBoldCompressedData,
BrassMono::DefaultFontBoldCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"brassmonocode",
const_cast<unsigned int *>(BrassMonoCode::DefaultFontBoldCompressedData),
BrassMonoCode::DefaultFontBoldCompressedData,
BrassMonoCode::DefaultFontBoldCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"fira",
const_cast<unsigned int *>(FiraCode::DefaultFontRegularCompressedData),
FiraCode::DefaultFontRegularCompressedData,
FiraCode::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"go",
const_cast<unsigned int *>(Go::DefaultFontRegularCompressedData),
Go::DefaultFontRegularCompressedData,
Go::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"ibm",
const_cast<unsigned int *>(IBMPlexMono::DefaultFontRegularCompressedData),
IBMPlexMono::DefaultFontRegularCompressedData,
IBMPlexMono::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"idealist",
const_cast<unsigned int *>(Idealist::DefaultFontRegularCompressedData),
Idealist::DefaultFontRegularCompressedData,
Idealist::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"inconsolata",
const_cast<unsigned int *>(Inconsolata::DefaultFontRegularCompressedData),
Inconsolata::DefaultFontRegularCompressedData,
Inconsolata::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"inconsolataex",
const_cast<unsigned int *>(InconsolataExpanded::DefaultFontRegularCompressedData),
InconsolataExpanded::DefaultFontRegularCompressedData,
InconsolataExpanded::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"iosevka",
const_cast<unsigned int *>(Iosoveka::DefaultFontRegularCompressedData),
Iosoveka::DefaultFontRegularCompressedData,
Iosoveka::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"iosevkaex",
const_cast<unsigned int *>(IosevkaExtended::DefaultFontRegularCompressedData),
IosevkaExtended::DefaultFontRegularCompressedData,
IosevkaExtended::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"sharetech",
const_cast<unsigned int *>(ShareTech::DefaultFontRegularCompressedData),
ShareTech::DefaultFontRegularCompressedData,
ShareTech::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"space",
const_cast<unsigned int *>(SpaceMono::DefaultFontRegularCompressedData),
SpaceMono::DefaultFontRegularCompressedData,
SpaceMono::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"syne",
const_cast<unsigned int *>(Syne::DefaultFontRegularCompressedData),
Syne::DefaultFontRegularCompressedData,
Syne::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"triplicate",
const_cast<unsigned int *>(Triplicate::DefaultFontRegularCompressedData),
Triplicate::DefaultFontRegularCompressedData,
Triplicate::DefaultFontRegularCompressedSize
));
FontRegistry::Instance().Register(std::make_unique<Font>(
"unispace",
const_cast<unsigned int *>(Unispace::DefaultFontRegularCompressedData),
Unispace::DefaultFontRegularCompressedData,
Unispace::DefaultFontRegularCompressedSize
));
}

44
main.cc
View File

@@ -1,7 +1,10 @@
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <getopt.h>
#include <iostream>
#include <limits>
#include <memory>
#include <signal.h>
#include <string>
@@ -41,10 +44,10 @@ main(int argc, const char *argv[])
Editor editor;
// CLI parsing using getopt_long
bool req_gui = false;
bool req_term = false;
bool show_help = false;
bool show_version = false;
bool req_gui = false;
[[maybe_unused]] bool req_term = false;
bool show_help = false;
bool show_version = false;
static struct option long_opts[] = {
{"gui", no_argument, nullptr, 'g'},
@@ -86,10 +89,6 @@ main(int argc, const char *argv[])
return 0;
}
#if !defined(KTE_BUILD_GUI)
(void) req_term; // suppress unused warning when GUI is not compiled in
#endif
// Determine frontend
#if !defined(KTE_BUILD_GUI)
if (req_gui) {
@@ -104,11 +103,13 @@ main(int argc, const char *argv[])
} else if (req_term) {
use_gui = false;
} 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)
use_gui = true;
use_gui = true;
#else
use_gui = false;
use_gui = false;
#endif
}
#endif
@@ -134,7 +135,13 @@ main(int argc, const char *argv[])
// Clamp to >=1 later; 0 disables.
try {
unsigned long v = std::stoul(p);
pending_line = static_cast<std::size_t>(v);
if (v > std::numeric_limits<std::size_t>::max()) {
std::cerr <<
"kte: Warning: Line number too large, ignoring\n";
pending_line = 0;
} else {
pending_line = static_cast<std::size_t>(v);
}
} catch (...) {
// Ignore malformed huge numbers
pending_line = 0;
@@ -193,8 +200,15 @@ main(int argc, const char *argv[])
#if defined(KTE_BUILD_GUI) && defined(__APPLE__)
if (use_gui) {
/* likely using the .app, so need to cd */
if (chdir(getenv("HOME")) != 0) {
std::cerr << "kge.app: failed to chdir to HOME" << std::endl;
const char *home = getenv("HOME");
if (!home) {
std::cerr << "kge.app: HOME environment variable not set" << std::endl;
return 1;
}
if (chdir(home) != 0) {
std::cerr << "kge.app: failed to chdir to " << home << ": "
<< std::strerror(errno) << std::endl;
return 1;
}
}
#endif
@@ -212,4 +226,4 @@ main(int argc, const char *argv[])
fe->Shutdown();
return 0;
}
}