Step 94: Whetstone diagnostics layer

This commit is contained in:
Bill
2026-02-09 10:05:58 -07:00
parent ede4166af3
commit 360a9fa26a
6 changed files with 170 additions and 1 deletions

View File

@@ -25,6 +25,8 @@
#include "DragDropHandler.h"
#include "FileWatcher.h"
#include "LSPClient.h"
#include "Pipeline.h"
#include "Diagnostics.h"
#include "ast/Generator.h"
#include <cstdio>
@@ -94,6 +96,10 @@ struct EditorState {
bool hoverPending = false;
double hoverLastMove = 0.0;
ImVec2 hoverLastMouse = ImVec2(-1.0f, -1.0f);
Pipeline pipeline;
bool analysisPending = false;
double analysisLastChange = 0.0;
std::vector<EditorDiagnostic> whetstoneDiagnostics;
BufferState* active() { return activeBuffer; }
@@ -1003,11 +1009,29 @@ int main(int, char**) {
avail.y -= 4; // small margin
state.updateHighlights();
std::vector<int> errorLines;
std::vector<int> warningLines;
std::string activeUri = EditorState::toFileUri(buf->path);
if (state.lsp) {
auto lspDiags = state.lsp->getDiagnosticsForUri(activeUri);
for (const auto& d : lspDiags) {
if (d.severity == 1) errorLines.push_back(d.range.start.line);
else if (d.severity == 2) warningLines.push_back(d.range.start.line);
}
}
for (const auto& d : state.whetstoneDiagnostics) {
if (d.uri != activeUri) continue;
if (d.severity == 1) errorLines.push_back(d.line);
else if (d.severity == 2) warningLines.push_back(d.line);
}
CodeEditorOptions opts;
opts.showWhitespace = state.showWhitespace;
opts.mode = &buf->mode;
opts.enableFolding = true;
opts.showMinimap = state.showMinimap;
opts.errorLines = &errorLines;
opts.warningLines = &warningLines;
CodeEditorResult res = buf->widget.render("##editor",
buf->editBuf, buf->highlights, opts, avail, monoFont);
@@ -1030,6 +1054,8 @@ int main(int, char**) {
state.lsp->clearSignatureHelp();
}
}
state.analysisPending = true;
state.analysisLastChange = ImGui::GetTime();
}
double now = ImGui::GetTime();
@@ -1043,6 +1069,23 @@ int main(int, char**) {
state.completionPending = false;
}
if (state.analysisPending && (now - state.analysisLastChange) > 0.5) {
if (state.active()) {
auto result = state.pipeline.run(state.active()->editBuf,
state.active()->language,
state.active()->language);
if (result.success) {
state.whetstoneDiagnostics =
collectWhetstoneDiagnostics(result.validationDiags,
result.violations,
EditorState::toFileUri(state.active()->path));
} else {
state.whetstoneDiagnostics.clear();
}
}
state.analysisPending = false;
}
if (state.lsp && state.active()) {
auto items = state.lsp->getCompletionItems();
int cursor = state.active()->widget.getCursor();
@@ -1177,7 +1220,8 @@ int main(int, char**) {
ImGui::PushFont(monoFont);
ImGui::BeginChild("##problemsScroll", ImVec2(0, 0), false);
auto diags = state.lsp ? state.lsp->getDiagnostics() : std::vector<LSPClient::Diagnostic>{};
if (diags.empty()) {
const auto& whetDiags = state.whetstoneDiagnostics;
if (diags.empty() && whetDiags.empty()) {
ImGui::TextDisabled("(no diagnostics)");
} else {
for (const auto& d : diags) {
@@ -1199,6 +1243,24 @@ int main(int, char**) {
}
}
}
for (const auto& d : whetDiags) {
const char* sev = "Unknown";
if (d.severity == 1) sev = "Error";
else if (d.severity == 2) sev = "Warning";
else if (d.severity == 3) sev = "Info";
std::string path = EditorState::fromFileUri(d.uri);
std::string label = "[" + std::string(sev) + "] " + d.message +
" (" + path + ":" + std::to_string(d.line + 1) +
":" + std::to_string(d.character + 1) + ")";
if (ImGui::Selectable(label.c_str())) {
if (!path.empty()) {
if (state.buffers.hasBuffer(path)) state.switchToBuffer(path);
else state.doOpen(path);
state.jumpTo(state.active(), d.line, d.character);
}
}
}
}
ImGui::EndChild();
ImGui::PopFont();