Step 357: Status Bar (12/12 tests)

This commit is contained in:
Bill
2026-02-16 09:13:18 -07:00
parent 4c2b5fffcd
commit de795bf6e6
4 changed files with 284 additions and 0 deletions

View File

@@ -2122,4 +2122,8 @@ add_executable(step356_test tests/step356_test.cpp)
target_include_directories(step356_test PRIVATE src)
target_link_libraries(step356_test PRIVATE nlohmann_json::nlohmann_json)
add_executable(step357_test tests/step357_test.cpp)
target_include_directories(step357_test PRIVATE src)
target_link_libraries(step357_test PRIVATE nlohmann_json::nlohmann_json)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -0,0 +1,90 @@
#pragma once
// Step 357: Status bar model.
// Headless representation used for UI rendering/tests.
#include <string>
#include "../ThemeData.h"
struct StatusBarInput {
std::string language = "python";
std::string filePath;
int line = 1;
int column = 1;
std::string encoding = "UTF-8";
std::string lineEnding = "LF";
bool workflowActive = false;
int workflowCurrent = 0;
int workflowTotal = 0;
bool mcpConnected = false;
int errorCount = 0;
int warningCount = 0;
int infoCount = 0;
int hintCount = 0;
};
struct StatusBarModel {
std::string languageBadge;
std::string leftText;
std::string centerText;
std::string rightText;
std::string workflowBadge;
std::string diagnosticsText;
std::string mcpText;
bool overflow = false;
Color4 bgColor;
Color4 textColor;
Color4 dimTextColor;
Color4 languageBadgeColor;
Color4 diagnosticsColor;
Color4 workflowColor;
};
inline Color4 statusLanguageColor(const std::string& language, const WhetstoneTheme& theme) {
if (language == "python") return theme.syntaxFunction;
if (language == "cpp") return theme.syntaxType;
if (language == "kotlin") return theme.syntaxAnnotation;
if (language == "rust") return theme.accent;
if (language == "go") return theme.syntaxKeyword;
return theme.textAccent;
}
inline StatusBarModel buildStatusBar(const StatusBarInput& in,
const WhetstoneTheme& theme,
size_t maxChars = 140) {
StatusBarModel m;
m.bgColor = theme.bgPanel;
m.textColor = theme.text;
m.dimTextColor = theme.textDim;
m.languageBadgeColor = statusLanguageColor(in.language, theme);
m.workflowColor = theme.textAccent;
m.diagnosticsColor = (in.errorCount > 0) ? theme.diagError :
(in.warningCount > 0 ? theme.diagWarning : theme.diagInfo);
m.languageBadge = in.language;
m.leftText = in.language + " " + in.filePath;
m.centerText = "Ln " + std::to_string(in.line) + ", Col " + std::to_string(in.column) +
" | " + in.encoding + " | " + in.lineEnding;
m.diagnosticsText = std::to_string(in.errorCount) + " errors, " +
std::to_string(in.warningCount) + " warnings";
m.mcpText = in.mcpConnected ? "MCP: connected" : "MCP: offline";
if (in.workflowActive && in.workflowTotal > 0) {
m.workflowBadge = "Executing " + std::to_string(in.workflowCurrent) +
"/" + std::to_string(in.workflowTotal);
} else {
m.workflowBadge = "";
}
m.rightText = m.diagnosticsText;
if (!m.workflowBadge.empty()) m.rightText += " | " + m.workflowBadge;
m.rightText += " | " + m.mcpText;
const size_t total = m.leftText.size() + m.centerText.size() + m.rightText.size();
m.overflow = total > maxChars;
return m;
}
inline std::string statusBarClickDiagnosticsTarget() {
return "diagnostics";
}

View File

@@ -0,0 +1,154 @@
// Step 357: Status Bar (12 tests)
#include <cassert>
#include <iostream>
#include <string>
#include "panels/StatusBar.h"
int main() {
int passed = 0;
WhetstoneTheme theme = getDefaultDarkTheme();
// Test 1: language badge shows current buffer language
{
StatusBarInput in;
in.language = "python";
in.filePath = "src/main.py";
auto model = buildStatusBar(in, theme);
assert(model.languageBadge == "python");
std::cout << "Test 1 PASSED: language badge\n";
passed++;
}
// Test 2: cursor position updates
{
StatusBarInput in;
in.filePath = "file";
in.line = 42;
in.column = 8;
auto model = buildStatusBar(in, theme);
assert(model.centerText.find("Ln 42, Col 8") != std::string::npos);
std::cout << "Test 2 PASSED: cursor position\n";
passed++;
}
// Test 3: diagnostic count accurate
{
StatusBarInput in;
in.filePath = "file";
in.errorCount = 3;
in.warningCount = 2;
auto model = buildStatusBar(in, theme);
assert(model.diagnosticsText == "3 errors, 2 warnings");
std::cout << "Test 3 PASSED: diagnostics count\n";
passed++;
}
// Test 4: workflow badge shown when active
{
StatusBarInput in;
in.filePath = "file";
in.workflowActive = true;
in.workflowCurrent = 3;
in.workflowTotal = 10;
auto model = buildStatusBar(in, theme);
assert(model.workflowBadge == "Executing 3/10");
std::cout << "Test 4 PASSED: workflow badge active\n";
passed++;
}
// Test 5: click diagnostics focuses diagnostics panel
{
assert(statusBarClickDiagnosticsTarget() == "diagnostics");
std::cout << "Test 5 PASSED: diagnostics click target\n";
passed++;
}
// Test 6: status bar uses theme colors
{
StatusBarInput in;
in.filePath = "file";
auto model = buildStatusBar(in, theme);
assert(model.bgColor.toHex() == theme.bgPanel.toHex());
assert(model.textColor.toHex() == theme.text.toHex());
assert(model.dimTextColor.toHex() == theme.textDim.toHex());
std::cout << "Test 6 PASSED: theme colors\n";
passed++;
}
// Test 7: language changes when switching buffers
{
StatusBarInput py;
py.language = "python";
py.filePath = "a.py";
StatusBarInput cpp;
cpp.language = "cpp";
cpp.filePath = "a.cpp";
auto m1 = buildStatusBar(py, theme);
auto m2 = buildStatusBar(cpp, theme);
assert(m1.languageBadge != m2.languageBadge);
std::cout << "Test 7 PASSED: language switch reflected\n";
passed++;
}
// Test 8: encoding display
{
StatusBarInput in;
in.filePath = "file";
in.encoding = "UTF-16";
auto model = buildStatusBar(in, theme);
assert(model.centerText.find("UTF-16") != std::string::npos);
std::cout << "Test 8 PASSED: encoding display\n";
passed++;
}
// Test 9: all sections fit without overflow for normal input
{
StatusBarInput in;
in.filePath = "src/main.cpp";
auto model = buildStatusBar(in, theme, 200);
assert(!model.overflow);
std::cout << "Test 9 PASSED: no overflow normal case\n";
passed++;
}
// Test 10: overflow flagged for extreme long path
{
StatusBarInput in;
in.filePath = std::string(220, 'a');
auto model = buildStatusBar(in, theme, 80);
assert(model.overflow);
std::cout << "Test 10 PASSED: overflow flagged\n";
passed++;
}
// Test 11: line ending display
{
StatusBarInput in;
in.filePath = "file";
in.lineEnding = "CRLF";
auto model = buildStatusBar(in, theme);
assert(model.centerText.find("CRLF") != std::string::npos);
std::cout << "Test 11 PASSED: line ending display\n";
passed++;
}
// Test 12: MCP indicator states
{
StatusBarInput on;
on.filePath = "file";
on.mcpConnected = true;
StatusBarInput off = on;
off.mcpConnected = false;
auto a = buildStatusBar(on, theme);
auto b = buildStatusBar(off, theme);
assert(a.mcpText == "MCP: connected");
assert(b.mcpText == "MCP: offline");
std::cout << "Test 12 PASSED: MCP indicator states\n";
passed++;
}
std::cout << "\nResults: " << passed << "/12\n";
assert(passed == 12);
return 0;
}

View File

@@ -1899,6 +1899,42 @@ theme-derived colors for consistent visual integration.
- `step355_test` — PASS (8/8) regression coverage
- `step356_test` — PASS (12/12) new step coverage
### Step 357: Status Bar
**Status:** PASS (12/12 tests)
Added a status-bar data model that provides left/center/right sections for
language/file, cursor+encoding+line-ending, and diagnostics/workflow/MCP state.
The model includes theme-driven colors, overflow signaling, and a diagnostics
focus target for click handling.
**Files created:**
- `editor/src/panels/StatusBar.h` — headless status model:
- `StatusBarInput` + `StatusBarModel`
- `buildStatusBar(...)` section construction and overflow check
- language badge color mapping
- diagnostics click target helper
- `editor/tests/step357_test.cpp` — 12 tests covering:
1. language badge
2. cursor position updates
3. diagnostic summary counts
4. workflow badge visibility/content
5. diagnostics click target
6. theme color usage
7. language switch behavior
8. encoding display
9. normal-fit no-overflow case
10. overflow flag on extreme content
11. line-ending display
12. MCP connected/offline indicator
**Files modified:**
- `editor/CMakeLists.txt``step357_test` target
**Verification run:**
- `step355_test` — PASS (8/8) regression coverage
- `step356_test` — PASS (12/12) regression coverage
- `step357_test` — PASS (12/12) new step coverage
# Roadmap Planning — Sprints 12-25+
## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)