From f9128a336d01bea49cf1c00155c5559fb254c953 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Sun, 30 Nov 2025 20:25:53 -0800 Subject: [PATCH] better support for smaller screens editor_prompt should replace the status line when active --- CMakeLists.txt | 2 +- GUIRenderer.cc | 79 ++++++++++++++++++++++++++++++++------------- TerminalRenderer.cc | 60 +++++++++++++++++++++++++++------- 3 files changed, 106 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fb24c7..d9fe4b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(kte) include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 17) -set(KTE_VERSION "1.0.2") +set(KTE_VERSION "1.0.3") # Default to terminal-only build to avoid SDL/OpenGL dependency by default. # Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available. diff --git a/GUIRenderer.cc b/GUIRenderer.cc index 12a2d48..2bbf4e5 100644 --- a/GUIRenderer.cc +++ b/GUIRenderer.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -280,28 +281,59 @@ GUIRenderer::Draw(Editor &ed) } ImGui::EndChild(); - // Status bar spanning full width - ImGui::Separator(); + // Status bar spanning full width + 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 - ImVec2 win_pos = ImGui::GetWindowPos(); - ImVec2 cr_min = ImGui::GetWindowContentRegionMin(); - ImVec2 cr_max = ImGui::GetWindowContentRegionMax(); - float x0 = win_pos.x + cr_min.x; - float x1 = win_pos.x + cr_max.x; - ImVec2 cursor = ImGui::GetCursorScreenPos(); - float bar_h = ImGui::GetFrameHeight(); - ImVec2 p0(x0, cursor.y); - ImVec2 p1(x1, cursor.y + bar_h); - ImU32 bg_col = ImGui::GetColorU32(ImGuiCol_HeaderActive); - ImGui::GetWindowDrawList()->AddRectFilled(p0, p1, bg_col); - // Build left text - std::string left; - left.reserve(256); - left += "kge"; // GUI app name - left += " "; - left += KTE_VERSION_STR; + // Compute full content width and draw a filled background rectangle + ImVec2 win_pos = ImGui::GetWindowPos(); + ImVec2 cr_min = ImGui::GetWindowContentRegionMin(); + ImVec2 cr_max = ImGui::GetWindowContentRegionMax(); + float x0 = win_pos.x + cr_min.x; + float x1 = win_pos.x + cr_max.x; + ImVec2 cursor = ImGui::GetCursorScreenPos(); + float bar_h = ImGui::GetFrameHeight(); + ImVec2 p0(x0, cursor.y); + ImVec2 p1(x1, cursor.y + bar_h); + ImU32 bg_col = ImGui::GetColorU32(ImGuiCol_HeaderActive); + 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 + std::string left; + left.reserve(256); + left += "kge"; // GUI app name + left += " "; + left += KTE_VERSION_STR; std::string fname; try { fname = ed.DisplayNameFor(*buf); @@ -400,8 +432,9 @@ GUIRenderer::Draw(Editor &ed) ImGui::PopClipRect(); } } - // Advance cursor to after the bar to keep layout consistent - ImGui::Dummy(ImVec2(x1 - x0, bar_h)); + // Advance cursor to after the bar to keep layout consistent + ImGui::Dummy(ImVec2(x1 - x0, bar_h)); + } } ImGui::End(); diff --git a/TerminalRenderer.cc b/TerminalRenderer.cc index 3ee3be9..110c861 100644 --- a/TerminalRenderer.cc +++ b/TerminalRenderer.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -149,13 +150,50 @@ TerminalRenderer::Draw(Editor &ed) mvaddstr(0, 0, "[no buffer]"); } - // Status line (inverse) — left: app/version/buffer/dirty, middle: message, right: cursor/mark - move(rows - 1, 0); - attron(A_REVERSE); + // Status line (inverse) + move(rows - 1, 0); + attron(A_REVERSE); - // Fill the status line with spaces first - for (int i = 0; i < cols; ++i) - addch(' '); + // Fill the status line with spaces first + for (int i = 0; i < cols; ++i) + 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 std::string left; @@ -243,10 +281,10 @@ TerminalRenderer::Draw(Editor &ed) if (llen > 0) mvaddnstr(rows - 1, 0, left.c_str(), llen); - // Draw right, flush to end - int rstart = std::max(0, cols - rlen); - if (rlen > 0) - mvaddnstr(rows - 1, rstart, right.c_str(), rlen); + // Draw right, flush to end + int rstart = std::max(0, cols - rlen); + if (rlen > 0) + mvaddnstr(rows - 1, rstart, right.c_str(), rlen); // Middle message const std::string &msg = ed.Status(); @@ -262,7 +300,7 @@ TerminalRenderer::Draw(Editor &ed) } } - attroff(A_REVERSE); + attroff(A_REVERSE); // Restore terminal cursor to the content position so a visible caret // remains in the editing area (not on the status line).