Introduce file picker and GUI configuration with enhancements.
- Add visual file picker for GUI with toggle support. - Introduce `GUIConfig` class for loading GUI settings from configuration file. - Refactor window initialization to support dynamic sizing based on configuration. - Add macOS-specific handling for fullscreen behavior. - Improve header inclusion order and minor code cleanup.
77
.idea/workspace.xml
generated
@@ -33,12 +33,58 @@
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Refactor code for consistency and enhanced functionality. - Normalize path handling for buffer operations, supporting tilde expansion and absolute paths. - Introduce `DisplayNameFor` to uniquely resolve buffer display names, minimizing filename clashes. - Add new commands: `ShowWorkingDirectory` and `ChangeWorkingDirectory`. - Refine keybindings and enhance existing commands for improved command flow. - Adjust GUI and terminal renderers to display total line counts alongside filenames. - Update coding style to align with project guidelines.">
|
||||
<list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Add horizontal scrolling support and refactor mouse click handling in GUI. - Introduce horizontal scrolling with column offset synchronization in GUI. - Refactor mouse click handling for improved accuracy and viewport alignment. - Enhance tab expansion and cursor rendering logic for better user experience. - Replace redundant variable declarations in `Buffer` for cleaner code.">
|
||||
<change afterPath="$PROJECT_DIR$/GUIConfig.cc" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/GUIConfig.h" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.icns" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_128x128.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_128x128@2x.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_16x16.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_16x16@2x.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_256x256.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_256x256@2x.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_32x32.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_32x32@2x.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_512x512.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.iconset/icon_512x512@2x.png" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/kge.png" 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$/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.cc" beforeDir="false" afterPath="$PROJECT_DIR$/Editor.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Editor.h" beforeDir="false" afterPath="$PROJECT_DIR$/Editor.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/Frontend.h" beforeDir="false" afterPath="$PROJECT_DIR$/Frontend.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIFrontend.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIFrontend.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIFrontend.h" beforeDir="false" afterPath="$PROJECT_DIR$/GUIFrontend.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIInputHandler.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIInputHandler.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIInputHandler.h" beforeDir="false" afterPath="$PROJECT_DIR$/GUIInputHandler.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIRenderer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIRenderer.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GUIRenderer.h" beforeDir="false" afterPath="$PROJECT_DIR$/GUIRenderer.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GapBuffer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GapBuffer.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/GapBuffer.h" beforeDir="false" afterPath="$PROJECT_DIR$/GapBuffer.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/InputHandler.h" beforeDir="false" afterPath="$PROJECT_DIR$/InputHandler.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/KKeymap.cc" beforeDir="false" afterPath="$PROJECT_DIR$/KKeymap.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/KKeymap.h" beforeDir="false" afterPath="$PROJECT_DIR$/KKeymap.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/PieceTable.h" beforeDir="false" afterPath="$PROJECT_DIR$/PieceTable.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TerminalFrontend.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalFrontend.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TerminalFrontend.h" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalFrontend.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TerminalInputHandler.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalInputHandler.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TerminalInputHandler.h" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalInputHandler.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TerminalRenderer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TerminalRenderer.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TestFrontend.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TestFrontend.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TestInputHandler.h" beforeDir="false" afterPath="$PROJECT_DIR$/TestInputHandler.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TestRenderer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/TestRenderer.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/TestRenderer.h" beforeDir="false" afterPath="$PROJECT_DIR$/TestRenderer.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/UndoNode.h" beforeDir="false" afterPath="$PROJECT_DIR$/UndoNode.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/UndoSystem.cc" beforeDir="false" afterPath="$PROJECT_DIR$/UndoSystem.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/UndoSystem.h" beforeDir="false" afterPath="$PROJECT_DIR$/UndoSystem.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/UndoTree.h" beforeDir="false" afterPath="$PROJECT_DIR$/UndoTree.h" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmake/Info.plist.in" beforeDir="false" afterPath="$PROJECT_DIR$/cmake/Info.plist.in" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/main.cc" beforeDir="false" afterPath="$PROJECT_DIR$/main.cc" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/test_undo.cc" beforeDir="false" afterPath="$PROJECT_DIR$/test_undo.cc" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -59,15 +105,6 @@
|
||||
<component name="HighlightingSettingsPerFile">
|
||||
<setting file="mock:///AIAssistantSnippet.." root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///AIAssistantSnippet.." root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///AIAssistantSnippet.." root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
<setting file="mock:///dummy.cpp" root0="SKIP_HIGHLIGHTING" />
|
||||
</component>
|
||||
<component name="OptimizeOnSaveOptions">
|
||||
<option name="myRunOnSave" value="true" />
|
||||
@@ -134,6 +171,11 @@
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="CMake Application.kge">
|
||||
<configuration default="true" type="CLionExternalRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true">
|
||||
<method v="2">
|
||||
<option name="CLION.EXTERNAL.BUILD" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="imgui" 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="imgui" CONFIG_NAME="Debug">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
@@ -170,7 +212,7 @@
|
||||
<workItem from="1764539556448" duration="156000" />
|
||||
<workItem from="1764539725338" duration="1075000" />
|
||||
<workItem from="1764542392763" duration="3512000" />
|
||||
<workItem from="1764548345516" duration="3453000" />
|
||||
<workItem from="1764548345516" duration="7941000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Add undo/redo infrastructure and buffer management additions.">
|
||||
<option name="closed" value="true" />
|
||||
@@ -252,7 +294,15 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1764550164829</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="11" />
|
||||
<task id="LOCAL-00011" summary="Add horizontal scrolling support and refactor mouse click handling in GUI. - Introduce horizontal scrolling with column offset synchronization in GUI. - Refactor mouse click handling for improved accuracy and viewport alignment. - Enhance tab expansion and cursor rendering logic for better user experience. - Replace redundant variable declarations in `Buffer` for cleaner code.">
|
||||
<option name="closed" value="true" />
|
||||
<created>1764551986561</created>
|
||||
<option name="number" value="00011" />
|
||||
<option name="presentableId" value="LOCAL-00011" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1764551986561</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="12" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -276,7 +326,8 @@
|
||||
<MESSAGE value="Add man pages for `kge` and `kte` with installation targets in CMake. - Introduce `docs/kge.1` and `docs/kte.1` man pages covering usage, options, keybindings, and examples. - Update `CMakeLists.txt` to install man pages under `${CMAKE_INSTALL_MANDIR}/man1`. - Ensure `kge` man page installation is conditional on GUI being built." />
|
||||
<MESSAGE value="Add GUI initialization updates and improve navigation commands. - Implement terminal detachment for GUI mode to enable terminal closure post-launch. - Add `+N` support for opening files at specific line numbers and refine cursor positioning. - Introduce `JumpToLine` command for direct navigation by line number. - Enhance mouse wheel handling for line-wise scrolling." />
|
||||
<MESSAGE value="Refactor code for consistency and enhanced functionality. - Normalize path handling for buffer operations, supporting tilde expansion and absolute paths. - Introduce `DisplayNameFor` to uniquely resolve buffer display names, minimizing filename clashes. - Add new commands: `ShowWorkingDirectory` and `ChangeWorkingDirectory`. - Refine keybindings and enhance existing commands for improved command flow. - Adjust GUI and terminal renderers to display total line counts alongside filenames. - Update coding style to align with project guidelines." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Refactor code for consistency and enhanced functionality. - Normalize path handling for buffer operations, supporting tilde expansion and absolute paths. - Introduce `DisplayNameFor` to uniquely resolve buffer display names, minimizing filename clashes. - Add new commands: `ShowWorkingDirectory` and `ChangeWorkingDirectory`. - Refine keybindings and enhance existing commands for improved command flow. - Adjust GUI and terminal renderers to display total line counts alongside filenames. - Update coding style to align with project guidelines." />
|
||||
<MESSAGE value="Add horizontal scrolling support and refactor mouse click handling in GUI. - Introduce horizontal scrolling with column offset synchronization in GUI. - Refactor mouse click handling for improved accuracy and viewport alignment. - Enhance tab expansion and cursor rendering logic for better user experience. - Replace redundant variable declarations in `Buffer` for cleaner code." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Add horizontal scrolling support and refactor mouse click handling in GUI. - Introduce horizontal scrolling with column offset synchronization in GUI. - Refactor mouse click handling for improved accuracy and viewport alignment. - Enhance tab expansion and cursor rendering logic for better user experience. - Replace redundant variable declarations in `Buffer` for cleaner code." />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "Buffer.h"
|
||||
#include "UndoSystem.h"
|
||||
#include "UndoTree.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "UndoSystem.h"
|
||||
#include "UndoTree.h"
|
||||
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
|
||||
1
Buffer.h
@@ -12,6 +12,7 @@
|
||||
#include "AppendBuffer.h"
|
||||
#include "UndoSystem.h"
|
||||
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer();
|
||||
|
||||
@@ -128,6 +128,8 @@ endif ()
|
||||
if (${BUILD_GUI})
|
||||
target_sources(kte PRIVATE
|
||||
Font.h
|
||||
GUIConfig.cc
|
||||
GUIConfig.h
|
||||
GUIRenderer.cc
|
||||
GUIRenderer.h
|
||||
GUIInputHandler.cc
|
||||
@@ -142,6 +144,8 @@ if (${BUILD_GUI})
|
||||
main.cc
|
||||
${COMMON_SOURCES}
|
||||
${COMMON_HEADERS}
|
||||
GUIConfig.cc
|
||||
GUIConfig.h
|
||||
GUIRenderer.cc
|
||||
GUIRenderer.h
|
||||
GUIInputHandler.cc
|
||||
@@ -153,6 +157,15 @@ if (${BUILD_GUI})
|
||||
|
||||
# On macOS, build kge as a proper .app bundle
|
||||
if (APPLE)
|
||||
# Define the icon file
|
||||
set(MACOSX_BUNDLE_ICON_FILE kge.icns)
|
||||
set(kge_ICON "${CMAKE_CURRENT_SOURCE_DIR}/${MACOSX_BUNDLE_ICON_FILE}")
|
||||
|
||||
# Add icon to the target sources and mark it as a resource
|
||||
target_sources(kge PRIVATE ${kge_ICON})
|
||||
set_source_files_properties(${kge_ICON} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
# Configure Info.plist with version and identifiers
|
||||
set(KGE_BUNDLE_ID "dev.wntrmute.kge")
|
||||
configure_file(
|
||||
@@ -164,6 +177,7 @@ if (${BUILD_GUI})
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER ${KGE_BUNDLE_ID}
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "kge"
|
||||
MACOSX_BUNDLE_ICON_FILE ${MACOSX_BUNDLE_ICON_FILE}
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/kge-Info.plist")
|
||||
|
||||
install(TARGETS kge
|
||||
|
||||
34
Command.cc
@@ -6,14 +6,13 @@
|
||||
#include "Editor.h"
|
||||
#include "Buffer.h"
|
||||
#include "UndoSystem.h"
|
||||
// Note: Command layer must remain UI-agnostic. Do not include frontend/IO headers here.
|
||||
|
||||
|
||||
// Keep buffer viewport offsets so that the cursor stays within the visible
|
||||
// window based on the editor's current dimensions. The bottom row is reserved
|
||||
// for the status line.
|
||||
static std::size_t
|
||||
compute_render_x(const std::string &line, std::size_t curx, std::size_t tabw)
|
||||
compute_render_x(const std::string &line, const std::size_t curx, const std::size_t tabw)
|
||||
{
|
||||
std::size_t rx = 0;
|
||||
for (std::size_t i = 0; i < curx && i < line.size(); ++i) {
|
||||
@@ -474,7 +473,7 @@ cmd_change_working_directory_start(CommandContext &ctx)
|
||||
{
|
||||
std::string initial;
|
||||
try {
|
||||
initial = std::filesystem::current_path().string();
|
||||
initial = std::filesystem::current_path().string() + "/";
|
||||
} catch (...) {
|
||||
initial.clear();
|
||||
}
|
||||
@@ -677,6 +676,30 @@ cmd_open_file_start(CommandContext &ctx)
|
||||
}
|
||||
|
||||
|
||||
// GUI: toggle visual file picker (no-op in terminal; renderer will consume flag)
|
||||
static bool
|
||||
cmd_visual_file_picker_toggle(CommandContext &ctx)
|
||||
{
|
||||
// Toggle visibility
|
||||
bool show = !ctx.editor.FilePickerVisible();
|
||||
ctx.editor.SetFilePickerVisible(show);
|
||||
if (show) {
|
||||
// Initialize directory to current working directory if empty
|
||||
if (ctx.editor.FilePickerDir().empty()) {
|
||||
try {
|
||||
ctx.editor.SetFilePickerDir(std::filesystem::current_path().string());
|
||||
} catch (...) {
|
||||
ctx.editor.SetFilePickerDir(".");
|
||||
}
|
||||
}
|
||||
ctx.editor.SetStatus("Open File (visual)");
|
||||
} else {
|
||||
ctx.editor.SetStatus("Closed file picker");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
cmd_jump_to_line_start(CommandContext &ctx)
|
||||
{
|
||||
@@ -2630,6 +2653,11 @@ InstallDefaultCommands()
|
||||
CommandId::MarkAllAndJumpEnd, "mark-all-jump-end", "Set mark at beginning and jump to end",
|
||||
cmd_mark_all_and_jump_end
|
||||
});
|
||||
// GUI
|
||||
CommandRegistry::Register({
|
||||
CommandId::VisualFilePickerToggle, "file-picker-toggle", "Toggle visual file picker",
|
||||
cmd_visual_file_picker_toggle
|
||||
});
|
||||
// Working directory
|
||||
CommandRegistry::Register({
|
||||
CommandId::ShowWorkingDirectory, "show-working-directory", "Show current working directory",
|
||||
|
||||
@@ -24,6 +24,8 @@ enum class CommandId {
|
||||
KPrefix, // show "C-k _" prompt in status when entering k-command
|
||||
FindStart, // begin incremental search (placeholder)
|
||||
OpenFileStart, // begin open-file prompt
|
||||
// GUI: visual file picker
|
||||
VisualFilePickerToggle,
|
||||
// Buffers
|
||||
BufferSwitchStart, // begin buffer switch prompt
|
||||
BufferClose,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "Editor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <filesystem>
|
||||
|
||||
#include "Editor.h"
|
||||
|
||||
|
||||
Editor::Editor() = default;
|
||||
|
||||
|
||||
29
Editor.h
@@ -441,6 +441,31 @@ public:
|
||||
return buffers_;
|
||||
}
|
||||
|
||||
|
||||
// --- GUI: Visual File Picker state ---
|
||||
void SetFilePickerVisible(bool on)
|
||||
{
|
||||
file_picker_visible_ = on;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] bool FilePickerVisible() const
|
||||
{
|
||||
return file_picker_visible_;
|
||||
}
|
||||
|
||||
|
||||
void SetFilePickerDir(const std::string &path)
|
||||
{
|
||||
file_picker_dir_ = path;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] const std::string &FilePickerDir() const
|
||||
{
|
||||
return file_picker_dir_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t rows_ = 0, cols_ = 0;
|
||||
int mode_ = 0;
|
||||
@@ -478,6 +503,10 @@ private:
|
||||
std::string prompt_label_;
|
||||
std::string prompt_text_;
|
||||
std::string pending_overwrite_path_;
|
||||
|
||||
// GUI-only state (safe no-op in terminal builds)
|
||||
bool file_picker_visible_ = false;
|
||||
std::string file_picker_dir_;
|
||||
};
|
||||
|
||||
#endif // KTE_EDITOR_H
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#ifndef KTE_FRONTEND_H
|
||||
#define KTE_FRONTEND_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
||||
class Editor;
|
||||
class InputHandler;
|
||||
|
||||
107
GUIConfig.cc
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "GUIConfig.h"
|
||||
|
||||
|
||||
static void
|
||||
trim(std::string &s)
|
||||
{
|
||||
auto not_space = [](int ch) {
|
||||
return !std::isspace(ch);
|
||||
};
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), not_space));
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), not_space).base(), s.end());
|
||||
}
|
||||
|
||||
|
||||
static std::string
|
||||
default_config_path()
|
||||
{
|
||||
const char *home = std::getenv("HOME");
|
||||
if (!home || !*home)
|
||||
return std::string();
|
||||
std::string path(home);
|
||||
path += "/.config/kte/kge.ini";
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
GUIConfig
|
||||
GUIConfig::Load()
|
||||
{
|
||||
GUIConfig cfg; // defaults already set
|
||||
std::string path = default_config_path();
|
||||
if (!path.empty()) {
|
||||
cfg.LoadFromFile(path);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GUIConfig::LoadFromFile(const std::string &path)
|
||||
{
|
||||
std::ifstream in(path);
|
||||
if (!in.good())
|
||||
return false;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
// Remove comments starting with '#' or ';'
|
||||
auto hash = line.find('#');
|
||||
if (hash != std::string::npos)
|
||||
line.erase(hash);
|
||||
auto sc = line.find("//");
|
||||
if (sc != std::string::npos)
|
||||
line.erase(sc);
|
||||
// Basic key=value
|
||||
auto eq = line.find('=');
|
||||
if (eq == std::string::npos)
|
||||
continue;
|
||||
std::string key = line.substr(0, eq);
|
||||
std::string val = line.substr(eq + 1);
|
||||
trim(key);
|
||||
trim(val);
|
||||
// Strip trailing semicolon
|
||||
if (!val.empty() && val.back() == ';') {
|
||||
val.pop_back();
|
||||
trim(val);
|
||||
}
|
||||
|
||||
// Lowercase key
|
||||
std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) {
|
||||
return (char) std::tolower(c);
|
||||
});
|
||||
|
||||
if (key == "fullscreen") {
|
||||
fullscreen = (val == "1" || val == "true" || val == "on" || val == "yes");
|
||||
} else if (key == "columns" || key == "cols") {
|
||||
int v = columns;
|
||||
try {
|
||||
v = std::stoi(val);
|
||||
} catch (...) {}
|
||||
if (v > 0)
|
||||
columns = v;
|
||||
} else if (key == "rows") {
|
||||
int v = rows;
|
||||
try {
|
||||
v = std::stoi(val);
|
||||
} catch (...) {}
|
||||
if (v > 0)
|
||||
rows = v;
|
||||
} else if (key == "font_size" || key == "fontsize") {
|
||||
float v = font_size;
|
||||
try {
|
||||
v = std::stof(val);
|
||||
} catch (...) {}
|
||||
if (v > 0.0f)
|
||||
font_size = v;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
27
GUIConfig.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* GUIConfig - loads simple GUI configuration from $HOME/.config/kte/kge.ini
|
||||
*/
|
||||
#ifndef KTE_GUI_CONFIG_H
|
||||
#define KTE_GUI_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef KTE_FONT_SIZE
|
||||
#define KTE_FONT_SIZE 16.0f
|
||||
#endif
|
||||
|
||||
class GUIConfig {
|
||||
public:
|
||||
bool fullscreen = false;
|
||||
int columns = 80;
|
||||
int rows = 42;
|
||||
float font_size = (float) KTE_FONT_SIZE;
|
||||
|
||||
// Load from default path: $HOME/.config/kte/kge.ini
|
||||
static GUIConfig Load();
|
||||
|
||||
// Load from explicit path. Returns true if file existed and was parsed.
|
||||
bool LoadFromFile(const std::string &path);
|
||||
};
|
||||
|
||||
#endif // KTE_GUI_CONFIG_H
|
||||
@@ -1,18 +1,25 @@
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_sdl2.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
#include <imgui.h>
|
||||
#include <backends/imgui_impl_sdl2.h>
|
||||
#include <backends/imgui_impl_opengl3.h>
|
||||
|
||||
#include "Editor.h"
|
||||
#include "Command.h"
|
||||
#include "GUIFrontend.h"
|
||||
#include "Font.h" // embedded default font (DefaultFontRegular)
|
||||
#include "GUIConfig.h"
|
||||
|
||||
|
||||
#ifndef KTE_FONT_SIZE
|
||||
#define KTE_FONT_SIZE 16.0f
|
||||
#endif
|
||||
|
||||
static const char *kGlslVersion = "#version 150"; // GL 3.2 core (macOS compatible)
|
||||
|
||||
@@ -24,6 +31,9 @@ GUIFrontend::Init(Editor &ed)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load GUI configuration (fullscreen, columns/rows, font size)
|
||||
const auto [fullscreen, columns, rows, font_size] = GUIConfig::Load();
|
||||
|
||||
// GL attributes for core profile
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
@@ -33,14 +43,56 @@ GUIFrontend::Init(Editor &ed)
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
// Compute desired window size from config
|
||||
Uint32 win_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
if (fullscreen) {
|
||||
// "Fullscreen": fill the usable bounds of the primary display.
|
||||
// On macOS, do NOT use true fullscreen so the menu/status bar remains visible.
|
||||
SDL_Rect usable{};
|
||||
if (SDL_GetDisplayUsableBounds(0, &usable) == 0) {
|
||||
width_ = usable.w;
|
||||
height_ = usable.h;
|
||||
}
|
||||
#if !defined(__APPLE__)
|
||||
// Non-macOS: desktop fullscreen uses the current display resolution.
|
||||
win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
#endif
|
||||
} else {
|
||||
// Windowed: width = columns * font_size, height = (rows * 2) * font_size
|
||||
int w = static_cast<int>(columns * font_size);
|
||||
int h = static_cast<int>((rows * 2) * font_size);
|
||||
|
||||
// As a safety, clamp to display usable bounds if retrievable
|
||||
SDL_Rect usable{};
|
||||
if (SDL_GetDisplayUsableBounds(0, &usable) == 0) {
|
||||
w = std::min(w, usable.w);
|
||||
h = std::min(h, usable.h);
|
||||
}
|
||||
width_ = std::max(320, w);
|
||||
height_ = std::max(200, h);
|
||||
}
|
||||
|
||||
window_ = SDL_CreateWindow(
|
||||
"kte",
|
||||
"kge - kyle's text editor " KTE_VERSION_STR,
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
width_, height_,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
win_flags);
|
||||
if (!window_)
|
||||
return false;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// macOS: when "fullscreen" is requested, position the window at the
|
||||
// top-left of the usable display area to mimic fullscreen while keeping
|
||||
// the system menu bar visible.
|
||||
if (fullscreen) {
|
||||
SDL_Rect usable{};
|
||||
if (SDL_GetDisplayUsableBounds(0, &usable) == 0) {
|
||||
SDL_SetWindowPosition(window_, usable.x, usable.y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gl_ctx_ = SDL_GL_CreateContext(window_);
|
||||
if (!gl_ctx_)
|
||||
return false;
|
||||
@@ -64,11 +116,23 @@ GUIFrontend::Init(Editor &ed)
|
||||
width_ = w;
|
||||
height_ = h;
|
||||
|
||||
// Initialize GUI font from embedded default
|
||||
#ifndef KTE_FONT_SIZE
|
||||
#define KTE_FONT_SIZE 16.0f
|
||||
#if defined(__APPLE__)
|
||||
// Workaround: On macOS Retina when starting maximized, we sometimes get a
|
||||
// subtle input vs draw alignment mismatch until the first manual resize.
|
||||
// Nudge the window size by 1px and back to trigger a proper internal
|
||||
// recomputation, without visible impact.
|
||||
if (w > 1 && h > 1) {
|
||||
SDL_SetWindowSize(window_, w - 1, h - 1);
|
||||
SDL_SetWindowSize(window_, w, h);
|
||||
// Update cached size in case backend reports immediately
|
||||
SDL_GetWindowSize(window_, &w, &h);
|
||||
width_ = w;
|
||||
height_ = h;
|
||||
}
|
||||
#endif
|
||||
LoadGuiFont_(nullptr, (float) KTE_FONT_SIZE);
|
||||
|
||||
// Initialize GUI font from embedded default (use configured size or compiled default)
|
||||
LoadGuiFont_(nullptr, (float) font_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "GUIInputHandler.h"
|
||||
#include "GUIRenderer.h"
|
||||
|
||||
|
||||
struct SDL_Window;
|
||||
typedef void *SDL_GLContext;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <SDL.h>
|
||||
#include <cstdio>
|
||||
#include <ncurses.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "GUIInputHandler.h"
|
||||
#include "KKeymap.h"
|
||||
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#ifndef KTE_GUI_INPUT_HANDLER_H
|
||||
#define KTE_GUI_INPUT_HANDLER_H
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "InputHandler.h"
|
||||
|
||||
|
||||
union SDL_Event; // fwd decl to avoid including SDL here (SDL defines SDL_Event as a union)
|
||||
|
||||
class GUIInputHandler final : public InputHandler {
|
||||
|
||||
188
GUIRenderer.cc
@@ -1,29 +1,44 @@
|
||||
#include "GUIRenderer.h"
|
||||
|
||||
#include "Editor.h"
|
||||
#include "Buffer.h"
|
||||
#include "Command.h"
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "GUIRenderer.h"
|
||||
#include "Buffer.h"
|
||||
#include "Command.h"
|
||||
#include "Editor.h"
|
||||
|
||||
|
||||
// Version string expected to be provided by build system as KTE_VERSION_STR
|
||||
#ifndef KTE_VERSION_STR
|
||||
# define KTE_VERSION_STR "dev"
|
||||
#endif
|
||||
|
||||
// ImGui compatibility: some bundled ImGui versions (or builds without docking)
|
||||
// don't define ImGuiWindowFlags_NoDocking. Treat it as 0 in that case.
|
||||
#ifndef ImGuiWindowFlags_NoDocking
|
||||
# define ImGuiWindowFlags_NoDocking 0
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
GUIRenderer::Draw(Editor &ed)
|
||||
{
|
||||
// Make the editor window occupy the entire GUI container/viewport
|
||||
ImGuiViewport *vp = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(vp->Pos);
|
||||
ImGui::SetNextWindowSize(vp->Size);
|
||||
// On HiDPI/Retina, snap to integer pixels to prevent any draw vs hit-test
|
||||
// mismatches that can appear on the very first maximized frame.
|
||||
ImVec2 main_pos = vp->Pos;
|
||||
ImVec2 main_sz = vp->Size;
|
||||
main_pos.x = std::floor(main_pos.x + 0.5f);
|
||||
main_pos.y = std::floor(main_pos.y + 0.5f);
|
||||
main_sz.x = std::floor(main_sz.x + 0.5f);
|
||||
main_sz.y = std::floor(main_sz.y + 0.5f);
|
||||
ImGui::SetNextWindowPos(main_pos);
|
||||
ImGui::SetNextWindowSize(main_sz);
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoResize
|
||||
@@ -379,4 +394,153 @@ GUIRenderer::Draw(Editor &ed)
|
||||
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
// --- Visual File Picker overlay (GUI only) ---
|
||||
if (ed.FilePickerVisible()) {
|
||||
// Centered popup-style window that always fits within the current viewport
|
||||
ImGuiViewport *vp2 = ImGui::GetMainViewport();
|
||||
|
||||
// Desired size, min size, and margins
|
||||
const ImVec2 want(800.0f, 500.0f);
|
||||
const ImVec2 min_sz(240.0f, 160.0f);
|
||||
const float margin = 20.0f; // space from viewport edges
|
||||
|
||||
// Compute the maximum allowed size (viewport minus margins) and make sure it's not negative
|
||||
ImVec2 max_sz(std::max(32.0f, vp2->Size.x - 2.0f * margin),
|
||||
std::max(32.0f, vp2->Size.y - 2.0f * margin));
|
||||
|
||||
// Clamp desired size to [min_sz, max_sz]
|
||||
ImVec2 size(std::min(want.x, max_sz.x), std::min(want.y, max_sz.y));
|
||||
size.x = std::max(size.x, std::min(min_sz.x, max_sz.x));
|
||||
size.y = std::max(size.y, std::min(min_sz.y, max_sz.y));
|
||||
|
||||
// Center within the viewport using the final size
|
||||
ImVec2 pos(vp2->Pos.x + std::max(margin, (vp2->Size.x - size.x) * 0.5f),
|
||||
vp2->Pos.y + std::max(margin, (vp2->Size.y - size.y) * 0.5f));
|
||||
|
||||
// On HiDPI displays (macOS Retina), ensure integer pixel alignment to avoid
|
||||
// potential hit-test vs draw mismatches from sub-pixel positions.
|
||||
pos.x = std::floor(pos.x + 0.5f);
|
||||
pos.y = std::floor(pos.y + 0.5f);
|
||||
size.x = std::floor(size.x + 0.5f);
|
||||
size.y = std::floor(size.y + 0.5f);
|
||||
|
||||
ImGui::SetNextWindowPos(pos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(size, ImGuiCond_Always);
|
||||
ImGuiWindowFlags wflags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoDocking;
|
||||
bool open = true;
|
||||
if (ImGui::Begin("File Picker", &open, wflags)) {
|
||||
// Current directory
|
||||
std::string curdir = ed.FilePickerDir();
|
||||
if (curdir.empty()) {
|
||||
try {
|
||||
curdir = std::filesystem::current_path().string();
|
||||
} catch (...) {
|
||||
curdir = ".";
|
||||
}
|
||||
ed.SetFilePickerDir(curdir);
|
||||
}
|
||||
ImGui::TextUnformatted(curdir.c_str());
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Up")) {
|
||||
try {
|
||||
std::filesystem::path p(curdir);
|
||||
if (p.has_parent_path()) {
|
||||
ed.SetFilePickerDir(p.parent_path().string());
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Close")) {
|
||||
ed.SetFilePickerVisible(false);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Header
|
||||
ImGui::TextUnformatted("Name");
|
||||
ImGui::Separator();
|
||||
|
||||
// Scrollable list
|
||||
ImGui::BeginChild("picker-list", ImVec2(0, 0), true);
|
||||
|
||||
// Build entries: directories first then files, alphabetical
|
||||
struct Entry {
|
||||
std::string name;
|
||||
std::filesystem::path path;
|
||||
bool is_dir;
|
||||
};
|
||||
std::vector<Entry> entries;
|
||||
entries.reserve(256);
|
||||
// Optional parent entry
|
||||
try {
|
||||
std::filesystem::path base(curdir);
|
||||
std::error_code ec;
|
||||
for (auto it = std::filesystem::directory_iterator(base, ec);
|
||||
!ec && it != std::filesystem::directory_iterator(); it.increment(ec)) {
|
||||
const auto &p = it->path();
|
||||
std::string nm;
|
||||
try {
|
||||
nm = p.filename().string();
|
||||
} catch (...) {
|
||||
continue;
|
||||
}
|
||||
if (nm == "." || nm == "..")
|
||||
continue;
|
||||
bool is_dir = false;
|
||||
std::error_code ec2;
|
||||
is_dir = it->is_directory(ec2);
|
||||
entries.push_back({nm, p, is_dir});
|
||||
}
|
||||
} catch (...) {
|
||||
// ignore listing errors; show empty
|
||||
}
|
||||
std::sort(entries.begin(), entries.end(), [](const Entry &a, const Entry &b) {
|
||||
if (a.is_dir != b.is_dir)
|
||||
return a.is_dir && !b.is_dir;
|
||||
return a.name < b.name;
|
||||
});
|
||||
|
||||
// Draw rows
|
||||
int idx = 0;
|
||||
for (const auto &e: entries) {
|
||||
ImGui::PushID(idx++); // ensure unique/stable IDs even if names repeat
|
||||
std::string label;
|
||||
label.reserve(e.name.size() + 4);
|
||||
if (e.is_dir)
|
||||
label += "[";
|
||||
label += e.name;
|
||||
if (e.is_dir)
|
||||
label += "]";
|
||||
|
||||
// Render selectable row
|
||||
ImGui::Selectable(label.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick);
|
||||
|
||||
// Activate based strictly on hover + mouse, to avoid any off-by-one due to click routing
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (e.is_dir && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||
// Enter directory on double-click
|
||||
ed.SetFilePickerDir(e.path.string());
|
||||
} else if (!e.is_dir && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
// Open file on single click
|
||||
std::string err;
|
||||
if (!ed.OpenFile(e.path.string(), err)) {
|
||||
ed.SetStatus(std::string("open: ") + err);
|
||||
} else {
|
||||
ed.SetStatus(std::string("Opened: ") + e.name);
|
||||
}
|
||||
ed.SetFilePickerVisible(false);
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::End();
|
||||
if (!open) {
|
||||
ed.SetFilePickerVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "Renderer.h"
|
||||
|
||||
class GUIRenderer : public Renderer {
|
||||
class GUIRenderer final : public Renderer {
|
||||
public:
|
||||
GUIRenderer() = default;
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "GapBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "GapBuffer.h"
|
||||
|
||||
|
||||
GapBuffer::GapBuffer() = default;
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
class GapBuffer {
|
||||
public:
|
||||
GapBuffer();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
|
||||
// Result of translating raw input into an editor command.
|
||||
struct MappedInput {
|
||||
bool hasCommand = false;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "KKeymap.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <ncurses.h>
|
||||
#include <ostream>
|
||||
|
||||
#include "KKeymap.h"
|
||||
|
||||
|
||||
auto
|
||||
KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool
|
||||
@@ -83,6 +83,9 @@ KLookupKCommand(const int ascii_key, const bool ctrl, CommandId &out) -> bool
|
||||
case 'u':
|
||||
out = CommandId::Undo;
|
||||
return true;
|
||||
case 'v':
|
||||
out = CommandId::VisualFilePickerToggle;
|
||||
return true;
|
||||
case 'w':
|
||||
out = CommandId::ShowWorkingDirectory;
|
||||
return true;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
|
||||
// Lookup the command to execute after a C-k prefix.
|
||||
// Parameters:
|
||||
// - ascii_key: ASCII code of the key, preferably lowercased if it's a letter.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class PieceTable {
|
||||
public:
|
||||
PieceTable();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <ncurses.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "Editor.h"
|
||||
#include "Command.h"
|
||||
#include "TerminalFrontend.h"
|
||||
#include "Command.h"
|
||||
#include "Editor.h"
|
||||
|
||||
|
||||
bool
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
#ifndef KTE_TERMINAL_FRONTEND_H
|
||||
#define KTE_TERMINAL_FRONTEND_H
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
#include "Frontend.h"
|
||||
#include "TerminalInputHandler.h"
|
||||
#include "TerminalRenderer.h"
|
||||
#include <termios.h>
|
||||
|
||||
|
||||
class TerminalFrontend final : public Frontend {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <ncurses.h>
|
||||
#include <cstdio>
|
||||
#include <ncurses.h>
|
||||
|
||||
#include "KKeymap.h"
|
||||
#include "TerminalInputHandler.h"
|
||||
#include "KKeymap.h"
|
||||
|
||||
namespace {
|
||||
constexpr int
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#ifndef KTE_TERMINAL_INPUT_HANDLER_H
|
||||
#define KTE_TERMINAL_INPUT_HANDLER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "InputHandler.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
#include "TerminalRenderer.h"
|
||||
|
||||
#include <ncurses.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <ncurses.h>
|
||||
#include <string>
|
||||
|
||||
#include "Editor.h"
|
||||
#include "TerminalRenderer.h"
|
||||
#include "Buffer.h"
|
||||
#include "Editor.h"
|
||||
|
||||
// Version string expected to be provided by build system as KTE_VERSION_STR
|
||||
#ifndef KTE_VERSION_STR
|
||||
# define KTE_VERSION_STR "dev"
|
||||
#endif
|
||||
|
||||
|
||||
TerminalRenderer::TerminalRenderer() = default;
|
||||
|
||||
TerminalRenderer::~TerminalRenderer() = default;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "TestFrontend.h"
|
||||
#include "Editor.h"
|
||||
#include "Command.h"
|
||||
#include <iostream>
|
||||
#include "Editor.h"
|
||||
|
||||
|
||||
bool
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#ifndef KTE_TEST_INPUT_HANDLER_H
|
||||
#define KTE_TEST_INPUT_HANDLER_H
|
||||
|
||||
#include "InputHandler.h"
|
||||
#include <queue>
|
||||
|
||||
#include "InputHandler.h"
|
||||
|
||||
class TestInputHandler : public InputHandler {
|
||||
|
||||
class TestInputHandler final : public InputHandler {
|
||||
public:
|
||||
TestInputHandler() = default;
|
||||
|
||||
@@ -21,7 +22,7 @@ public:
|
||||
void QueueText(const std::string &text);
|
||||
|
||||
|
||||
bool IsEmpty() const
|
||||
[[nodiscard]] bool IsEmpty() const
|
||||
{
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "TestRenderer.h"
|
||||
#include "Editor.h"
|
||||
|
||||
|
||||
void
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
#ifndef KTE_TEST_RENDERER_H
|
||||
#define KTE_TEST_RENDERER_H
|
||||
|
||||
#include "Renderer.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "Renderer.h"
|
||||
|
||||
class TestRenderer : public Renderer {
|
||||
|
||||
class TestRenderer final : public Renderer {
|
||||
public:
|
||||
TestRenderer() = default;
|
||||
|
||||
@@ -17,7 +18,7 @@ public:
|
||||
void Draw(Editor &ed) override;
|
||||
|
||||
|
||||
std::size_t GetDrawCount() const
|
||||
[[nodiscard]] std::size_t GetDrawCount() const
|
||||
{
|
||||
return draw_count_;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#ifndef KTE_UNDONODE_H
|
||||
#define KTE_UNDONODE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ UndoSystem::Begin(UndoType type)
|
||||
if (type == UndoType::Delete) {
|
||||
// Support batching both forward deletes (DeleteChar) and backspace (prepend case)
|
||||
// Forward delete: cursor stays at anchor col; expected == col
|
||||
std::size_t anchor = static_cast<std::size_t>(tree_.pending->col);
|
||||
const auto anchor = static_cast<std::size_t>(tree_.pending->col);
|
||||
if (anchor + tree_.pending->text.size() == static_cast<std::size_t>(col)) {
|
||||
pending_prepend_ = false;
|
||||
return; // keep batching forward delete
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#define KTE_UNDOSYSTEM_H
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "UndoTree.h"
|
||||
|
||||
|
||||
class Buffer;
|
||||
|
||||
class UndoSystem {
|
||||
@@ -39,7 +41,6 @@ private:
|
||||
|
||||
void update_dirty_flag();
|
||||
|
||||
private:
|
||||
Buffer *buf_;
|
||||
UndoTree &tree_;
|
||||
// Internal hint for Delete batching: whether next Append() should prepend
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define KTE_UNDOTREE_H
|
||||
|
||||
#include "UndoNode.h"
|
||||
#include <memory>
|
||||
|
||||
|
||||
struct UndoTree {
|
||||
UndoNode *root = nullptr; // first edit ever
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>kge</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>@MACOSX_BUNDLE_ICON_FILE@</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>@KGE_BUNDLE_ID@</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
@@ -23,4 +25,4 @@
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||
BIN
kge.iconset/icon_128x128.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
kge.iconset/icon_128x128@2x.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
kge.iconset/icon_16x16.png
Normal file
|
After Width: | Height: | Size: 911 B |
BIN
kge.iconset/icon_16x16@2x.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
kge.iconset/icon_256x256.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
kge.iconset/icon_256x256@2x.png
Normal file
|
After Width: | Height: | Size: 483 KiB |
BIN
kge.iconset/icon_32x32.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
kge.iconset/icon_32x32@2x.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
kge.iconset/icon_512x512.png
Normal file
|
After Width: | Height: | Size: 483 KiB |
BIN
kge.iconset/icon_512x512@2x.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
13
main.cc
@@ -1,15 +1,15 @@
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Editor.h"
|
||||
#include "Command.h"
|
||||
#include "Editor.h"
|
||||
#include "Frontend.h"
|
||||
#include "TerminalFrontend.h"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
# define KTE_VERSION_STR "devel"
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
PrintUsage(const char *prog)
|
||||
{
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Command.h"
|
||||
#include "Editor.h"
|
||||
#include "TestFrontend.h"
|
||||
#include "Command.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
|
||||
int
|
||||
|
||||