3 Commits

Author SHA1 Message Date
35e957b326 Fix void crash in kge.
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
Release / Build Linux amd64 (push) Has been cancelled
Release / Build Linux arm64 (push) Has been cancelled
Release / Build macOS arm64 (.app) (push) Has been cancelled
Release / Create GitHub Release (push) Has been cancelled
2025-11-30 21:51:03 -08:00
e7eb35626c NixOS build 2025-11-30 21:07:41 -08:00
f9128a336d better support for smaller screens
Some checks failed
Release / Bump Homebrew formula (push) Has been cancelled
Release / Build Linux amd64 (push) Has been cancelled
Release / Build Linux arm64 (push) Has been cancelled
Release / Build macOS arm64 (.app) (push) Has been cancelled
Release / Create GitHub Release (push) Has been cancelled
editor_prompt should replace the status line when active
2025-11-30 20:25:53 -08:00
8 changed files with 208 additions and 128 deletions

9
.idea/workspace.xml generated
View File

@@ -34,8 +34,9 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Actually add the screenshot."> <list default="true" id="e1fe3ab0-3650-4fca-8664-a247d5dfa457" name="Changes" comment="Actually add the screenshot.">
<change beforePath="$PROJECT_DIR$/.github/workflows/release.yml" beforeDir="false" afterPath="$PROJECT_DIR$/.github/workflows/release.yml" 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$/CMakeLists.txt" beforeDir="false" afterPath="$PROJECT_DIR$/CMakeLists.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/GUIRenderer.cc" beforeDir="false" afterPath="$PROJECT_DIR$/GUIRenderer.cc" 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" />
@@ -128,9 +129,9 @@
</key> </key>
</component> </component>
<component name="RunManager" selected="CMake Application.kge"> <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"> <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="CLION.EXTERNAL.BUILD" enabled="true" /> <option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method> </method>
</configuration> </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"> <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">
@@ -169,7 +170,7 @@
<workItem from="1764539556448" duration="156000" /> <workItem from="1764539556448" duration="156000" />
<workItem from="1764539725338" duration="1075000" /> <workItem from="1764539725338" duration="1075000" />
<workItem from="1764542392763" duration="3512000" /> <workItem from="1764542392763" duration="3512000" />
<workItem from="1764548345516" duration="9962000" /> <workItem from="1764548345516" duration="12773000" />
</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" />

View File

@@ -4,7 +4,7 @@ project(kte)
include(GNUInstallDirs) include(GNUInstallDirs)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(KTE_VERSION "1.0.2") set(KTE_VERSION "1.0.4")
# 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.

View File

@@ -1,5 +1,7 @@
#include <algorithm>
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <filesystem> #include <filesystem>
#include <limits> #include <limits>
#include <string> #include <string>
@@ -182,6 +184,10 @@ GUIRenderer::Draw(Editor &ed)
if (px < 0.0f) if (px < 0.0f)
px = 0.0f; px = 0.0f;
// Empty buffer guard: if there are no lines yet, just move to 0:0
if (lines.empty()) {
Execute(ed, CommandId::MoveCursorTo, std::string("0:0"));
} else {
// Convert pixel X to a render-column target including horizontal col offset // Convert pixel X to a render-column target including horizontal col offset
// Use our own tab expansion of width 8 to match command layer logic. // Use our own tab expansion of width 8 to match command layer logic.
const std::string &line_clicked = lines[by]; const std::string &line_clicked = lines[by];
@@ -231,6 +237,7 @@ GUIRenderer::Draw(Editor &ed)
char tmp[64]; char tmp[64];
std::snprintf(tmp, sizeof(tmp), "%zu:%zu", by, best_col); std::snprintf(tmp, sizeof(tmp), "%zu:%zu", by, best_col);
Execute(ed, CommandId::MoveCursorTo, std::string(tmp)); Execute(ed, CommandId::MoveCursorTo, std::string(tmp));
}
} }
// Cache current horizontal offset in rendered columns // Cache current horizontal offset in rendered columns
const std::size_t coloffs_now = buf->Coloffs(); const std::size_t coloffs_now = buf->Coloffs();
@@ -283,7 +290,6 @@ GUIRenderer::Draw(Editor &ed)
// Status bar spanning full width // Status bar spanning full width
ImGui::Separator(); ImGui::Separator();
// Build three segments: left (app/version/buffer/dirty), middle (message), right (cursor/mark)
// Compute full content width and draw a filled background rectangle // Compute full content width and draw a filled background rectangle
ImVec2 win_pos = ImGui::GetWindowPos(); ImVec2 win_pos = ImGui::GetWindowPos();
ImVec2 cr_min = ImGui::GetWindowContentRegionMin(); ImVec2 cr_min = ImGui::GetWindowContentRegionMin();
@@ -296,6 +302,38 @@ GUIRenderer::Draw(Editor &ed)
ImVec2 p1(x1, cursor.y + bar_h); ImVec2 p1(x1, cursor.y + bar_h);
ImU32 bg_col = ImGui::GetColorU32(ImGuiCol_HeaderActive); ImU32 bg_col = ImGui::GetColorU32(ImGuiCol_HeaderActive);
ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, bg_col); ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, bg_col);
// If a prompt is active, replace the entire status bar with the prompt text
if (ed.PromptActive()) {
std::string msg = ed.PromptLabel();
if (!msg.empty()) msg += ": ";
std::string ptext = ed.PromptText();
auto kind = ed.CurrentPromptKind();
if (kind == Editor::PromptKind::OpenFile || kind == Editor::PromptKind::SaveAs ||
kind == Editor::PromptKind::Chdir) {
const char *home_c = std::getenv("HOME");
if (home_c && *home_c) {
std::string home(home_c);
if (ptext.rfind(home, 0) == 0) {
std::string rest = ptext.substr(home.size());
if (rest.empty())
ptext = "~";
else if (!rest.empty() && (rest[0] == '/' || rest[0] == '\\'))
ptext = std::string("~") + rest;
}
}
}
msg += ptext;
float pad = 6.f;
ImVec2 msg_sz = ImGui::CalcTextSize(msg.c_str());
float left_x = p0.x + pad;
ImGui::PushClipRect(ImVec2(p0.x, p0.y), ImVec2(p1.x, p1.y), true);
ImGui::SetCursorScreenPos(ImVec2(left_x, p0.y + (bar_h - msg_sz.y) * 0.5f));
ImGui::TextUnformatted(msg.c_str());
ImGui::PopClipRect();
// Advance cursor to after the bar to keep layout consistent
ImGui::Dummy(ImVec2(x1 - x0, bar_h));
} else {
// Build left text // Build left text
std::string left; std::string left;
left.reserve(256); left.reserve(256);
@@ -402,6 +440,7 @@ GUIRenderer::Draw(Editor &ed)
} }
// Advance cursor to after the bar to keep layout consistent // Advance cursor to after the bar to keep layout consistent
ImGui::Dummy(ImVec2(x1 - x0, bar_h)); ImGui::Dummy(ImVec2(x1 - x0, bar_h));
}
} }
ImGui::End(); ImGui::End();

View File

@@ -1,6 +1,7 @@
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <filesystem> #include <filesystem>
#include <cstdlib>
#include <ncurses.h> #include <ncurses.h>
#include <string> #include <string>
@@ -149,7 +150,7 @@ TerminalRenderer::Draw(Editor &ed)
mvaddstr(0, 0, "[no buffer]"); mvaddstr(0, 0, "[no buffer]");
} }
// Status line (inverse) — left: app/version/buffer/dirty, middle: message, right: cursor/mark // Status line (inverse)
move(rows - 1, 0); move(rows - 1, 0);
attron(A_REVERSE); attron(A_REVERSE);
@@ -157,6 +158,43 @@ TerminalRenderer::Draw(Editor &ed)
for (int i = 0; i < cols; ++i) for (int i = 0; i < cols; ++i)
addch(' '); addch(' ');
// If a prompt is active, replace the status bar with the full prompt text
if (ed.PromptActive()) {
// Build prompt text: "Label: text" and shorten HOME path for file-related prompts
std::string msg = ed.PromptLabel();
if (!msg.empty())
msg += ": ";
std::string ptext = ed.PromptText();
auto kind = ed.CurrentPromptKind();
if (kind == Editor::PromptKind::OpenFile || kind == Editor::PromptKind::SaveAs ||
kind == Editor::PromptKind::Chdir) {
const char *home_c = std::getenv("HOME");
if (home_c && *home_c) {
std::string home(home_c);
// Ensure we match only at the start
if (ptext.rfind(home, 0) == 0) {
std::string rest = ptext.substr(home.size());
if (rest.empty())
ptext = "~";
else if (rest[0] == '/' || rest[0] == '\\')
ptext = std::string("~") + rest;
}
}
}
msg += ptext;
// Draw left-aligned, clipped to width
if (!msg.empty())
mvaddnstr(rows - 1, 0, msg.c_str(), std::max(0, cols));
// End status rendering for prompt mode
attroff(A_REVERSE);
// Restore logical cursor position in content area
if (saved_cur_y >= 0 && saved_cur_x >= 0)
move(saved_cur_y, saved_cur_x);
return;
}
// Build left segment // Build left segment
std::string left; std::string left;
{ {

View File

@@ -45,6 +45,8 @@ stdenv.mkDerivation {
installManPage ../docs/kte.1 installManPage ../docs/kte.1
installManPage ../docs/kge.1 installManPage ../docs/kge.1
mkdir -p $out/share/icons
cp ../kge.png $out/share/icons/
runHook postInstall runHook postInstall
''; '';

View File

@@ -45,6 +45,9 @@ stdenv.mkDerivation {
installManPage ../docs/kte.1 installManPage ../docs/kte.1
installManPage ../docs/kge.1 installManPage ../docs/kge.1
mkdir -p $out/share/icons
cp ../kge.png $out/share/icons/
runHook postInstall runHook postInstall
''; '';
} }

10
flake.lock generated
View File

@@ -2,15 +2,15 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1764242076, "lastModified": 1764517877,
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=", "narHash": "sha256-pp3uT4hHijIC8JUK5MEqeAWmParJrgBVzHLNfJDZxg4=",
"owner": "nixos", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4", "rev": "2d293cbfa5a793b4c50d17c05ef9e385b90edf6c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"

View File

@@ -1,21 +1,18 @@
{ {
description = "Kyle's Text Editor"; description = "kyle's text editor";
inputs = { inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = outputs = inputs @ { self, nixpkgs, ... }:
{ self, nixpkgs }:
let let
pkgs = import nixpkgs { system = "x86_64-linux"; }; eachSystem = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
in pkgsFor = system: import nixpkgs { inherit system; };
{ in {
packages.x86_64-linux = { packages = eachSystem (system: {
default = pkgs.callPackage ./default-nogui.nix { }; default = (pkgsFor system).callPackage ./default-nogui.nix { };
kge = pkgs.callPackage ./default-gui.nix { }; kge = (pkgsFor system).callPackage ./default-gui.nix { };
kte = pkgs.callPackage ./default-nogui.nix { }; kte = (pkgsFor system).callPackage ./default-nogui.nix { };
full = pkgs.callPackage ./default.nix { }; full = (pkgsFor system).callPackage ./default.nix { };
}; });
}; };
} }