Remove packaging.cmake, deprecate test_undo setup, and add new testing infrastructure.
- Delete `packaging.cmake` to streamline build system. - Deprecate `test_undo` in CMake setup; condition builds on `BUILD_TESTS`. - Introduce `TestFrontend`, `TestRenderer`, and `TestInputHandler` for structured testing. - Update `GUIInputHandler` and `Command` for enhanced buffer save handling and overwrite confirmation. - Enhance kill ring operations and new prompt workflows in `Editor`.
This commit is contained in:
47
.idea/workspace.xml
generated
47
.idea/workspace.xml
generated
@@ -25,7 +25,6 @@
|
|||||||
<config projectName="kte" targetName="kte" />
|
<config projectName="kte" targetName="kte" />
|
||||||
<config projectName="kte" targetName="imgui" />
|
<config projectName="kte" targetName="imgui" />
|
||||||
<config projectName="kte" targetName="kge" />
|
<config projectName="kte" targetName="kge" />
|
||||||
<config projectName="kte" targetName="test_undo" />
|
|
||||||
</generated>
|
</generated>
|
||||||
</component>
|
</component>
|
||||||
<component name="CMakeSettings" AUTO_RELOAD="true">
|
<component name="CMakeSettings" AUTO_RELOAD="true">
|
||||||
@@ -34,26 +33,17 @@
|
|||||||
</configurations>
|
</configurations>
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Add non-linear undo/redo design documentation and improve `UndoSystem` with backspace batching and GUI integration fixes.">
|
<list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Add `TestFrontend` documentation and `UndoSystem` buffer reference update. - Document `TestFrontend` for programmatic testing, including examples and usage details. - Add `UpdateBufferReference` to `UndoSystem` to support updating buffer associations.">
|
||||||
<change afterPath="$PROJECT_DIR$/TestFrontend.cc" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/TestFrontend.h" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/TestInputHandler.cc" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/TestInputHandler.h" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/TestRenderer.cc" afterDir="false" />
|
<change afterPath="$PROJECT_DIR$/TestRenderer.h" afterDir="false" />
|
||||||
<change afterPath="$PROJECT_DIR$/docs/TestFrontend.md" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/test_undo.cc" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Buffer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/Buffer.cc" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Buffer.h" beforeDir="false" afterPath="$PROJECT_DIR$/Buffer.h" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/CMakeLists.txt" beforeDir="false" afterPath="$PROJECT_DIR$/CMakeLists.txt" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/CMakeLists.txt" beforeDir="false" afterPath="$PROJECT_DIR$/CMakeLists.txt" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Command.cc" beforeDir="false" afterPath="$PROJECT_DIR$/Command.cc" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Command.cc" beforeDir="false" afterPath="$PROJECT_DIR$/Command.cc" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Command.h" beforeDir="false" afterPath="$PROJECT_DIR$/Command.h" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Editor.h" beforeDir="false" afterPath="$PROJECT_DIR$/Editor.h" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/GUIFrontend.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIFrontend.cc" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/GUIInputHandler.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIInputHandler.cc" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/KKeymap.cc" beforeDir="false" afterPath="$PROJECT_DIR$/KKeymap.cc" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/TerminalInputHandler.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalInputHandler.cc" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/TerminalInputHandler.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalInputHandler.cc" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/UndoSystem.cc" beforeDir="false" afterPath="$PROJECT_DIR$/UndoSystem.cc" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/cmake/packaging.cmake" beforeDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/UndoSystem.h" beforeDir="false" afterPath="$PROJECT_DIR$/UndoSystem.h" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/docs/ke.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/ke.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/docs/undo-state.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/undo-state.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/fonts/brassmono.h" beforeDir="false" afterPath="$PROJECT_DIR$/fonts/brassmono.h" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -147,7 +137,7 @@
|
|||||||
<recent name="$PROJECT_DIR$/docs" />
|
<recent name="$PROJECT_DIR$/docs" />
|
||||||
</key>
|
</key>
|
||||||
</component>
|
</component>
|
||||||
<component name="RunManager" selected="CMake Application.test_undo">
|
<component name="RunManager" selected="CMake Application.imgui">
|
||||||
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true">
|
<configuration default="true" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true">
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
@@ -168,16 +158,10 @@
|
|||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="test_undo" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="kte" TARGET_NAME="test_undo" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="kte" RUN_TARGET_NAME="test_undo">
|
|
||||||
<method v="2">
|
|
||||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
<list>
|
<list>
|
||||||
<item itemvalue="CMake Application.imgui" />
|
<item itemvalue="CMake Application.imgui" />
|
||||||
<item itemvalue="CMake Application.kge" />
|
<item itemvalue="CMake Application.kge" />
|
||||||
<item itemvalue="CMake Application.kte" />
|
<item itemvalue="CMake Application.kte" />
|
||||||
<item itemvalue="CMake Application.test_undo" />
|
|
||||||
</list>
|
</list>
|
||||||
</component>
|
</component>
|
||||||
<component name="TaskManager">
|
<component name="TaskManager">
|
||||||
@@ -187,7 +171,7 @@
|
|||||||
<option name="number" value="Default" />
|
<option name="number" value="Default" />
|
||||||
<option name="presentableId" value="Default" />
|
<option name="presentableId" value="Default" />
|
||||||
<updated>1764457173148</updated>
|
<updated>1764457173148</updated>
|
||||||
<workItem from="1764457174208" duration="41399000" />
|
<workItem from="1764457174208" duration="42780000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Add undo/redo infrastructure and buffer management additions.">
|
<task id="LOCAL-00001" summary="Add undo/redo infrastructure and buffer management additions.">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -229,7 +213,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1764496151303</updated>
|
<updated>1764496151303</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="6" />
|
<task id="LOCAL-00006" summary="Add `TestFrontend` documentation and `UndoSystem` buffer reference update. - Document `TestFrontend` for programmatic testing, including examples and usage details. - Add `UpdateBufferReference` to `UndoSystem` to support updating buffer associations.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1764500200942</created>
|
||||||
|
<option name="number" value="00006" />
|
||||||
|
<option name="presentableId" value="LOCAL-00006" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1764500200942</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="7" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -248,7 +240,8 @@
|
|||||||
<MESSAGE value="Enable installation targets." />
|
<MESSAGE value="Enable installation targets." />
|
||||||
<MESSAGE value="Add `UndoSystem` implementation and refactor `UndoNode` for simplicity." />
|
<MESSAGE value="Add `UndoSystem` implementation and refactor `UndoNode` for simplicity." />
|
||||||
<MESSAGE value="Add non-linear undo/redo design documentation and improve `UndoSystem` with backspace batching and GUI integration fixes." />
|
<MESSAGE value="Add non-linear undo/redo design documentation and improve `UndoSystem` with backspace batching and GUI integration fixes." />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Add non-linear undo/redo design documentation and improve `UndoSystem` with backspace batching and GUI integration fixes." />
|
<MESSAGE value="Add `TestFrontend` documentation and `UndoSystem` buffer reference update. - Document `TestFrontend` for programmatic testing, including examples and usage details. - Add `UpdateBufferReference` to `UndoSystem` to support updating buffer associations." />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Add `TestFrontend` documentation and `UndoSystem` buffer reference update. - Document `TestFrontend` for programmatic testing, including examples and usage details. - Add `UpdateBufferReference` to `UndoSystem` to support updating buffer associations." />
|
||||||
</component>
|
</component>
|
||||||
<component name="XSLT-Support.FileAssociations.UIState">
|
<component name="XSLT-Support.FileAssociations.UIState">
|
||||||
<expand />
|
<expand />
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ project(kte)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(KTE_VERSION "0.0.1")
|
set(KTE_VERSION "0.1.0")
|
||||||
|
|
||||||
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
||||||
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
||||||
set(BUILD_GUI OFF CACHE BOOL "Enable building the graphical version.")
|
set(BUILD_GUI OFF CACHE BOOL "Enable building the graphical version.")
|
||||||
|
set(BUILD_TESTS OFF CACHE BOOL "Enable building test programs.")
|
||||||
option(KTE_USE_PIECE_TABLE "Use PieceTable instead of GapBuffer implementation" OFF)
|
option(KTE_USE_PIECE_TABLE "Use PieceTable instead of GapBuffer implementation" OFF)
|
||||||
set(KTE_FONT_SIZE "18.0" CACHE STRING "Default font size for GUI")
|
set(KTE_FONT_SIZE "18.0" CACHE STRING "Default font size for GUI")
|
||||||
|
|
||||||
@@ -103,18 +104,21 @@ install(TARGETS kte
|
|||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
# test_undo executable for testing undo/redo system
|
if (BUILD_TESTS)
|
||||||
add_executable(test_undo
|
# test_undo executable for testing undo/redo system
|
||||||
|
add_executable(test_undo
|
||||||
test_undo.cc
|
test_undo.cc
|
||||||
${COMMON_SOURCES}
|
${COMMON_SOURCES}
|
||||||
${COMMON_HEADERS}
|
${COMMON_HEADERS}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (KTE_USE_PIECE_TABLE)
|
if (KTE_USE_PIECE_TABLE)
|
||||||
target_compile_definitions(test_undo PRIVATE KTE_USE_PIECE_TABLE=1)
|
target_compile_definitions(test_undo PRIVATE KTE_USE_PIECE_TABLE=1)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_link_libraries(test_undo ${CURSES_LIBRARIES})
|
|
||||||
|
target_link_libraries(test_undo ${CURSES_LIBRARIES})
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (${BUILD_GUI})
|
if (${BUILD_GUI})
|
||||||
target_sources(kte PRIVATE
|
target_sources(kte PRIVATE
|
||||||
@@ -142,7 +146,27 @@ if (${BUILD_GUI})
|
|||||||
target_compile_definitions(kge PRIVATE KTE_BUILD_GUI=1 KTE_DEFAULT_GUI=1 KTE_FONT_SIZE=${KTE_FONT_SIZE})
|
target_compile_definitions(kge PRIVATE KTE_BUILD_GUI=1 KTE_DEFAULT_GUI=1 KTE_FONT_SIZE=${KTE_FONT_SIZE})
|
||||||
target_link_libraries(kge ${CURSES_LIBRARIES} imgui)
|
target_link_libraries(kge ${CURSES_LIBRARIES} imgui)
|
||||||
|
|
||||||
|
# On macOS, build kge as a proper .app bundle
|
||||||
|
if (APPLE)
|
||||||
|
# Configure Info.plist with version and identifiers
|
||||||
|
set(KGE_BUNDLE_ID "dev.kyle.kge")
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/cmake/Info.plist.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/kge-Info.plist
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
set_target_properties(kge PROPERTIES
|
||||||
|
MACOSX_BUNDLE TRUE
|
||||||
|
MACOSX_BUNDLE_GUI_IDENTIFIER ${KGE_BUNDLE_ID}
|
||||||
|
MACOSX_BUNDLE_BUNDLE_NAME "kge"
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/kge-Info.plist")
|
||||||
|
|
||||||
|
install(TARGETS kge
|
||||||
|
BUNDLE DESTINATION .
|
||||||
|
)
|
||||||
|
else()
|
||||||
install(TARGETS kge
|
install(TARGETS kge
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
48
Command.cc
48
Command.cc
@@ -1,4 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
#include "Editor.h"
|
#include "Editor.h"
|
||||||
@@ -418,6 +419,14 @@ cmd_save(CommandContext &ctx)
|
|||||||
// non-existent path (not yet file-backed but has a filename).
|
// non-existent path (not yet file-backed but has a filename).
|
||||||
if (!buf->IsFileBacked()) {
|
if (!buf->IsFileBacked()) {
|
||||||
if (!buf->Filename().empty()) {
|
if (!buf->Filename().empty()) {
|
||||||
|
// If first-time save to an existing path, confirm overwrite
|
||||||
|
if (std::filesystem::exists(buf->Filename())) {
|
||||||
|
ctx.editor.StartPrompt(Editor::PromptKind::Confirm, "Overwrite", "");
|
||||||
|
ctx.editor.SetPendingOverwritePath(buf->Filename());
|
||||||
|
ctx.editor.SetStatus(
|
||||||
|
std::string("Overwrite existing file '") + buf->Filename() + "'? (y/N)");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
if (!buf->SaveAs(buf->Filename(), err)) {
|
if (!buf->SaveAs(buf->Filename(), err)) {
|
||||||
ctx.editor.SetStatus(err);
|
ctx.editor.SetStatus(err);
|
||||||
return false;
|
return false;
|
||||||
@@ -426,6 +435,7 @@ cmd_save(CommandContext &ctx)
|
|||||||
ctx.editor.SetStatus("Saved " + buf->Filename());
|
ctx.editor.SetStatus("Saved " + buf->Filename());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// If buffer has no name, prompt for a filename
|
// If buffer has no name, prompt for a filename
|
||||||
ctx.editor.StartPrompt(Editor::PromptKind::SaveAs, "Save as", "");
|
ctx.editor.StartPrompt(Editor::PromptKind::SaveAs, "Save as", "");
|
||||||
ctx.editor.SetStatus("Save as: ");
|
ctx.editor.SetStatus("Save as: ");
|
||||||
@@ -932,6 +942,14 @@ cmd_newline(CommandContext &ctx)
|
|||||||
Buffer *buf = ctx.editor.CurrentBuffer();
|
Buffer *buf = ctx.editor.CurrentBuffer();
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
ctx.editor.SetStatus("No buffer to save");
|
ctx.editor.SetStatus("No buffer to save");
|
||||||
|
} else {
|
||||||
|
// If this is a first-time save (unnamed/non-file-backed) and the
|
||||||
|
// target exists, ask for confirmation before overwriting.
|
||||||
|
if (!buf->IsFileBacked() && std::filesystem::exists(value)) {
|
||||||
|
ctx.editor.StartPrompt(Editor::PromptKind::Confirm, "Overwrite", "");
|
||||||
|
ctx.editor.SetPendingOverwritePath(value);
|
||||||
|
ctx.editor.SetStatus(
|
||||||
|
std::string("Overwrite existing file '") + value + "'? (y/N)");
|
||||||
} else {
|
} else {
|
||||||
std::string err;
|
std::string err;
|
||||||
if (!buf->SaveAs(value, err)) {
|
if (!buf->SaveAs(value, err)) {
|
||||||
@@ -945,6 +963,34 @@ cmd_newline(CommandContext &ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (kind == Editor::PromptKind::Confirm) {
|
||||||
|
// Confirmation for potentially destructive operations (e.g., overwrite on save-as)
|
||||||
|
Buffer *buf = ctx.editor.CurrentBuffer();
|
||||||
|
const std::string target = ctx.editor.PendingOverwritePath();
|
||||||
|
if (!target.empty() && buf) {
|
||||||
|
bool yes = false;
|
||||||
|
if (!value.empty()) {
|
||||||
|
char c = value[0];
|
||||||
|
yes = (c == 'y' || c == 'Y');
|
||||||
|
}
|
||||||
|
if (yes) {
|
||||||
|
std::string err;
|
||||||
|
if (!buf->SaveAs(target, err)) {
|
||||||
|
ctx.editor.SetStatus(err);
|
||||||
|
} else {
|
||||||
|
buf->SetDirty(false);
|
||||||
|
ctx.editor.SetStatus("Saved as " + target);
|
||||||
|
if (auto *u = buf->Undo())
|
||||||
|
u->mark_saved();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.editor.SetStatus("Save canceled");
|
||||||
|
}
|
||||||
|
ctx.editor.ClearPendingOverwritePath();
|
||||||
|
} else {
|
||||||
|
ctx.editor.SetStatus("Nothing to confirm");
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// In search mode, Enter accepts the current match and exits search
|
// In search mode, Enter accepts the current match and exits search
|
||||||
@@ -1924,7 +1970,7 @@ cmd_delete_word_prev(CommandContext &ctx)
|
|||||||
ensure_cursor_visible(ctx.editor, *buf);
|
ensure_cursor_visible(ctx.editor, *buf);
|
||||||
if (!killed_total.empty()) {
|
if (!killed_total.empty()) {
|
||||||
if (ctx.editor.KillChain())
|
if (ctx.editor.KillChain())
|
||||||
ctx.editor.KillRingAppend(killed_total);
|
ctx.editor.KillRingPrepend(killed_total);
|
||||||
else
|
else
|
||||||
ctx.editor.KillRingPush(killed_total);
|
ctx.editor.KillRingPush(killed_total);
|
||||||
ctx.editor.SetKillChain(true);
|
ctx.editor.SetKillChain(true);
|
||||||
|
|||||||
32
Editor.h
32
Editor.h
@@ -99,6 +99,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void KillRingPrepend(const std::string &text)
|
||||||
|
{
|
||||||
|
if (text.empty())
|
||||||
|
return;
|
||||||
|
if (kill_ring_.empty()) {
|
||||||
|
KillRingPush(text);
|
||||||
|
} else {
|
||||||
|
kill_ring_.front() = text + kill_ring_.front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] std::string KillRingHead() const
|
[[nodiscard]] std::string KillRingHead() const
|
||||||
{
|
{
|
||||||
return kill_ring_.empty() ? std::string() : kill_ring_.front();
|
return kill_ring_.empty() ? std::string() : kill_ring_.front();
|
||||||
@@ -349,6 +361,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Overwrite confirmation (save-as on existing file) ---
|
||||||
|
void SetPendingOverwritePath(const std::string &path)
|
||||||
|
{
|
||||||
|
pending_overwrite_path_ = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ClearPendingOverwritePath()
|
||||||
|
{
|
||||||
|
pending_overwrite_path_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string &PendingOverwritePath() const
|
||||||
|
{
|
||||||
|
return pending_overwrite_path_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string &PromptLabel() const
|
[[nodiscard]] const std::string &PromptLabel() const
|
||||||
{
|
{
|
||||||
return prompt_label_;
|
return prompt_label_;
|
||||||
@@ -441,6 +472,7 @@ private:
|
|||||||
PromptKind prompt_kind_ = PromptKind::None;
|
PromptKind prompt_kind_ = PromptKind::None;
|
||||||
std::string prompt_label_;
|
std::string prompt_label_;
|
||||||
std::string prompt_text_;
|
std::string prompt_text_;
|
||||||
|
std::string pending_overwrite_path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KTE_EDITOR_H
|
#endif // KTE_EDITOR_H
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
#include "GUIInputHandler.h"
|
#include "GUIInputHandler.h"
|
||||||
#include "KKeymap.h"
|
#include "KKeymap.h"
|
||||||
@@ -26,7 +27,10 @@ map_key(const SDL_Keycode key,
|
|||||||
// If previous key was ESC, interpret this as Meta via ESC keymap
|
// If previous key was ESC, interpret this as Meta via ESC keymap
|
||||||
if (esc_meta) {
|
if (esc_meta) {
|
||||||
int ascii_key = 0;
|
int ascii_key = 0;
|
||||||
if (key >= SDLK_a && key <= SDLK_z) {
|
if (key == SDLK_BACKSPACE) {
|
||||||
|
// ESC BACKSPACE: map to DeleteWordPrev using ncurses KEY_BACKSPACE constant
|
||||||
|
ascii_key = KEY_BACKSPACE;
|
||||||
|
} else if (key >= SDLK_a && key <= SDLK_z) {
|
||||||
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
||||||
} else if (key == SDLK_COMMA) {
|
} else if (key == SDLK_COMMA) {
|
||||||
ascii_key = '<';
|
ascii_key = '<';
|
||||||
@@ -99,13 +103,6 @@ map_key(const SDL_Keycode key,
|
|||||||
case SDLK_ESCAPE:
|
case SDLK_ESCAPE:
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
esc_meta = true; // next key will be treated as Meta
|
esc_meta = true; // next key will be treated as Meta
|
||||||
// Cancel any universal argument collection
|
|
||||||
uarg_active = false;
|
|
||||||
uarg_collecting = false;
|
|
||||||
uarg_negative = false;
|
|
||||||
uarg_had_digits = false;
|
|
||||||
uarg_value = 0;
|
|
||||||
uarg_text.clear();
|
|
||||||
out.hasCommand = false; // no immediate command for bare ESC in GUI
|
out.hasCommand = false; // no immediate command for bare ESC in GUI
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@@ -222,7 +219,10 @@ map_key(const SDL_Keycode key,
|
|||||||
// Alt/Meta bindings (ESC f/b equivalent)
|
// Alt/Meta bindings (ESC f/b equivalent)
|
||||||
if (is_alt) {
|
if (is_alt) {
|
||||||
int ascii_key = 0;
|
int ascii_key = 0;
|
||||||
if (key >= SDLK_a && key <= SDLK_z) {
|
if (key == SDLK_BACKSPACE) {
|
||||||
|
// Alt BACKSPACE: map to DeleteWordPrev using ncurses KEY_BACKSPACE constant
|
||||||
|
ascii_key = KEY_BACKSPACE;
|
||||||
|
} else if (key >= SDLK_a && key <= SDLK_z) {
|
||||||
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
ascii_key = static_cast<int>('a' + (key - SDLK_a));
|
||||||
} else if (key == SDLK_COMMA) {
|
} else if (key == SDLK_COMMA) {
|
||||||
ascii_key = '<';
|
ascii_key = '<';
|
||||||
|
|||||||
@@ -87,13 +87,6 @@ map_key_to_command(const int ch,
|
|||||||
// ESC
|
// ESC
|
||||||
k_prefix = false;
|
k_prefix = false;
|
||||||
esc_meta = true; // next key will be considered meta-modified
|
esc_meta = true; // next key will be considered meta-modified
|
||||||
// Cancel any universal argument collection
|
|
||||||
uarg_active = false;
|
|
||||||
uarg_collecting = false;
|
|
||||||
uarg_negative = false;
|
|
||||||
uarg_had_digits = false;
|
|
||||||
uarg_value = 0;
|
|
||||||
uarg_text.clear();
|
|
||||||
out.hasCommand = false; // no command yet
|
out.hasCommand = false; // no command yet
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
41
TestFrontend.h
Normal file
41
TestFrontend.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* TestFrontend.h - headless frontend for testing with programmable input
|
||||||
|
*/
|
||||||
|
#ifndef KTE_TEST_FRONTEND_H
|
||||||
|
#define KTE_TEST_FRONTEND_H
|
||||||
|
|
||||||
|
#include "Frontend.h"
|
||||||
|
#include "TestInputHandler.h"
|
||||||
|
#include "TestRenderer.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TestFrontend final : public Frontend {
|
||||||
|
public:
|
||||||
|
TestFrontend() = default;
|
||||||
|
|
||||||
|
~TestFrontend() override = default;
|
||||||
|
|
||||||
|
bool Init(Editor &ed) override;
|
||||||
|
|
||||||
|
void Step(Editor &ed, bool &running) override;
|
||||||
|
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
|
||||||
|
TestInputHandler &Input()
|
||||||
|
{
|
||||||
|
return input_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestRenderer &Renderer()
|
||||||
|
{
|
||||||
|
return renderer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TestInputHandler input_{};
|
||||||
|
TestRenderer renderer_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KTE_TEST_FRONTEND_H
|
||||||
33
TestInputHandler.h
Normal file
33
TestInputHandler.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* TestInputHandler.h - programmable input handler for testing
|
||||||
|
*/
|
||||||
|
#ifndef KTE_TEST_INPUT_HANDLER_H
|
||||||
|
#define KTE_TEST_INPUT_HANDLER_H
|
||||||
|
|
||||||
|
#include "InputHandler.h"
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
|
||||||
|
class TestInputHandler : public InputHandler {
|
||||||
|
public:
|
||||||
|
TestInputHandler() = default;
|
||||||
|
|
||||||
|
~TestInputHandler() override = default;
|
||||||
|
|
||||||
|
bool Poll(MappedInput &out) override;
|
||||||
|
|
||||||
|
void QueueCommand(CommandId id, const std::string &arg = "", int count = 0);
|
||||||
|
|
||||||
|
void QueueText(const std::string &text);
|
||||||
|
|
||||||
|
|
||||||
|
bool IsEmpty() const
|
||||||
|
{
|
||||||
|
return queue_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::queue<MappedInput> queue_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KTE_TEST_INPUT_HANDLER_H
|
||||||
35
TestRenderer.h
Normal file
35
TestRenderer.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* TestRenderer.h - minimal renderer for testing (no actual display)
|
||||||
|
*/
|
||||||
|
#ifndef KTE_TEST_RENDERER_H
|
||||||
|
#define KTE_TEST_RENDERER_H
|
||||||
|
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
|
||||||
|
class TestRenderer : public Renderer {
|
||||||
|
public:
|
||||||
|
TestRenderer() = default;
|
||||||
|
|
||||||
|
~TestRenderer() override = default;
|
||||||
|
|
||||||
|
void Draw(Editor &ed) override;
|
||||||
|
|
||||||
|
|
||||||
|
std::size_t GetDrawCount() const
|
||||||
|
{
|
||||||
|
return draw_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ResetDrawCount()
|
||||||
|
{
|
||||||
|
draw_count_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t draw_count_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KTE_TEST_RENDERER_H
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# Packaging support
|
|
||||||
include(InstallRequiredSystemLibraries)
|
|
||||||
|
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEBUG ON)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(CPACK_PACKAGE_VENDOR "Shimmering Clarity")
|
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "kyle's editor")
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
|
||||||
|
|
||||||
###################
|
|
||||||
### DEBIANESQUE ###
|
|
||||||
###################
|
|
||||||
if (${BUILD_GUI})
|
|
||||||
set(CPACK_COMPONENTS_ALL gui nox)
|
|
||||||
else ()
|
|
||||||
set(CPACK_COMPONENTS_ALL nox)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
|
|
||||||
set(CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS ON)
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_SECTION universe/editors)
|
|
||||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
|
||||||
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "K. Isom")
|
|
||||||
set(CPACK_PACKAGE_nox_DESCRIPTION_SUMMARY "kyle's editor")
|
|
||||||
set(CPACK_PACKAGE_nox_DESCRIPTION ${CPACK_PACKAGE_DESCRIPTION})
|
|
||||||
set(CPACK_PACKAGE_nox_PACKAGE_NAME "kte")
|
|
||||||
set(CPACK_DEBIAN_nox_PACKAGE_NAME "ke")
|
|
||||||
|
|
||||||
if (BUILD_GUI)
|
|
||||||
set(CPACK_PACKAGE_gui_PACKAGE_NAME "kge")
|
|
||||||
set(CPACK_DEBIAN_gui_PACKAGE_NAME "kge")
|
|
||||||
set(CPACK_PACKAGE_gui_DESCRIPTION_SUMMARY " graphical front-end for kyle's editor")
|
|
||||||
set(CPACK_PACKAGE_gui_DESCRIPTION "graphical front-end for ${CPACK_PACKAGE_DESCRIPTION} ")
|
|
||||||
endif ()
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
|
||||||
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS ON)
|
|
||||||
|
|
||||||
|
|
||||||
if (LINUX)
|
|
||||||
set(CPACK_GENERATOR "DEB;STGZ;TGZ")
|
|
||||||
elseif (APPLE)
|
|
||||||
set(CPACK_GENERATOR "productbuild;TGZ")
|
|
||||||
elseif (MSVC OR MSYS OR MINGW)
|
|
||||||
set(CPACK_GENERATOR "NSIS;ZIP")
|
|
||||||
else ()
|
|
||||||
set(CPACK_GENERATOR "ZIP")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP ")
|
|
||||||
set(CPACK_SOURCE_IGNORE_FILES
|
|
||||||
/.git
|
|
||||||
/.idea
|
|
||||||
/dist
|
|
||||||
/.*build.*)
|
|
||||||
|
|
||||||
include(CPack)
|
|
||||||
cpack_add_component(gui DEPENDS nox)
|
|
||||||
Reference in New Issue
Block a user