Step 200: startup and performance improvements
This commit is contained in:
@@ -547,4 +547,5 @@ Sprint 5 in progress. Step 141 (Emacs daemon with user config) done. Next: Step
|
|||||||
| 2026-02-10 | Codex | Step 197: Keyboard navigation audit (F6 panel cycle, Esc focus return, focus ring defaults, nav focus enabled on panels). 1/1 tests pass (step197_test). |
|
| 2026-02-10 | Codex | Step 197: Keyboard navigation audit (F6 panel cycle, Esc focus return, focus ring defaults, nav focus enabled on panels). 1/1 tests pass (step197_test). |
|
||||||
| 2026-02-10 | Codex | Step 198: Virtual scrolling for large files (viewport + buffered rendering, fold hiding optimized). 1/1 tests pass (step198_test). |
|
| 2026-02-10 | Codex | Step 198: Virtual scrolling for large files (viewport + buffered rendering, fold hiding optimized). 1/1 tests pass (step198_test). |
|
||||||
| 2026-02-10 | Codex | Step 199: Large file handling (size thresholds, text-mode fallback, large file prompt, highlight disable, memory indicator). 1/1 tests pass (step199_test). |
|
| 2026-02-10 | Codex | Step 199: Large file handling (size thresholds, text-mode fallback, large file prompt, highlight disable, memory indicator). 1/1 tests pass (step199_test). |
|
||||||
|
| 2026-02-10 | Codex | Step 200: Startup/perf (LSP & highlight debounce, deferred AST sync on session restore, debug frame budget warnings). 1/1 tests pass (step200_test). |
|
||||||
| 2026-02-10 | Codex | Step 166: Extract main.cpp into panel headers marked complete (already implemented). step166_test passes; file_limits_test 4/4 passes. |
|
| 2026-02-10 | Codex | Step 166: Extract main.cpp into panel headers marked complete (already implemented). step166_test passes; file_limits_test 4/4 passes. |
|
||||||
|
|||||||
@@ -1136,6 +1136,9 @@ target_include_directories(step198_test PRIVATE src)
|
|||||||
|
|
||||||
add_executable(step199_test tests/step199_test.cpp)
|
add_executable(step199_test tests/step199_test.cpp)
|
||||||
target_include_directories(step199_test PRIVATE src)
|
target_include_directories(step199_test PRIVATE src)
|
||||||
|
|
||||||
|
add_executable(step200_test tests/step200_test.cpp)
|
||||||
|
target_include_directories(step200_test PRIVATE src)
|
||||||
find_package(SDL2 CONFIG REQUIRED)
|
find_package(SDL2 CONFIG REQUIRED)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
find_package(glad CONFIG REQUIRED)
|
find_package(glad CONFIG REQUIRED)
|
||||||
|
|||||||
@@ -158,6 +158,9 @@ struct BufferState {
|
|||||||
size_t fileSizeBytes = 0;
|
size_t fileSizeBytes = 0;
|
||||||
bool largeFileMode = false;
|
bool largeFileMode = false;
|
||||||
bool disableSyntaxHighlight = false;
|
bool disableSyntaxHighlight = false;
|
||||||
|
double highlightRequestTime = 0.0;
|
||||||
|
bool pendingAstSync = false;
|
||||||
|
double pendingAstStart = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EditorState {
|
struct EditorState {
|
||||||
@@ -205,6 +208,9 @@ struct EditorState {
|
|||||||
bool completionVisible = false;
|
bool completionVisible = false;
|
||||||
int completionSelected = 0;
|
int completionSelected = 0;
|
||||||
double completionLastChange = 0.0;
|
double completionLastChange = 0.0;
|
||||||
|
bool lspChangePending = false;
|
||||||
|
double lspChangeLast = 0.0;
|
||||||
|
std::string lspChangePath;
|
||||||
bool hoverPending = false;
|
bool hoverPending = false;
|
||||||
double hoverLastMove = 0.0;
|
double hoverLastMove = 0.0;
|
||||||
ImVec2 hoverLastMouse = ImVec2(-1.0f, -1.0f);
|
ImVec2 hoverLastMouse = ImVec2(-1.0f, -1.0f);
|
||||||
@@ -213,6 +219,7 @@ struct EditorState {
|
|||||||
int definitionRequestLine = 0;
|
int definitionRequestLine = 0;
|
||||||
int definitionRequestCol = 0;
|
int definitionRequestCol = 0;
|
||||||
std::string definitionRequestPath;
|
std::string definitionRequestPath;
|
||||||
|
double lastFrameBudgetWarning = 0.0;
|
||||||
LSPClient::DefinitionLocation definitionPreview;
|
LSPClient::DefinitionLocation definitionPreview;
|
||||||
bool definitionPreviewValid = false;
|
bool definitionPreviewValid = false;
|
||||||
Pipeline pipeline;
|
Pipeline pipeline;
|
||||||
@@ -592,7 +599,8 @@ struct EditorState {
|
|||||||
BufferManager::BufferMode mode = BufferManager::BufferMode::Structured,
|
BufferManager::BufferMode mode = BufferManager::BufferMode::Structured,
|
||||||
size_t fileSizeBytes = 0,
|
size_t fileSizeBytes = 0,
|
||||||
bool largeFileMode = false,
|
bool largeFileMode = false,
|
||||||
bool disableSyntaxHighlight = false) {
|
bool disableSyntaxHighlight = false,
|
||||||
|
bool deferAstSync = false) {
|
||||||
BufferManager::BufferMode effectiveMode = mode;
|
BufferManager::BufferMode effectiveMode = mode;
|
||||||
if (language == "org") effectiveMode = BufferManager::BufferMode::Text;
|
if (language == "org") effectiveMode = BufferManager::BufferMode::Text;
|
||||||
if (buffers.hasBuffer(path)) {
|
if (buffers.hasBuffer(path)) {
|
||||||
@@ -611,9 +619,14 @@ struct EditorState {
|
|||||||
state->generatedMode.setLanguage(language);
|
state->generatedMode.setLanguage(language);
|
||||||
state->editor.setContent(content, language);
|
state->editor.setContent(content, language);
|
||||||
if (effectiveMode == BufferManager::BufferMode::Structured) {
|
if (effectiveMode == BufferManager::BufferMode::Structured) {
|
||||||
state->sync.setText(content, language);
|
if (deferAstSync) {
|
||||||
state->sync.syncNow();
|
state->pendingAstSync = true;
|
||||||
state->incrementalOptimizer.setRoot(state->sync.getAST());
|
state->pendingAstStart = ImGui::GetTime();
|
||||||
|
} else {
|
||||||
|
state->sync.setText(content, language);
|
||||||
|
state->sync.syncNow();
|
||||||
|
state->incrementalOptimizer.setRoot(state->sync.getAST());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state->editBuf = content;
|
state->editBuf = content;
|
||||||
state->highlightsDirty = true;
|
state->highlightsDirty = true;
|
||||||
@@ -924,7 +937,7 @@ struct EditorState {
|
|||||||
}
|
}
|
||||||
ui.layoutPreset = LayoutManager::presetFromName(session.layoutPreset);
|
ui.layoutPreset = LayoutManager::presetFromName(session.layoutPreset);
|
||||||
for (const auto& buf : session.buffers) {
|
for (const auto& buf : session.buffers) {
|
||||||
doOpen(buf.path, bufferModeFromString(buf.mode));
|
doOpen(buf.path, bufferModeFromString(buf.mode), true);
|
||||||
auto it = bufferStates.find(buf.path);
|
auto it = bufferStates.find(buf.path);
|
||||||
if (it != bufferStates.end()) {
|
if (it != bufferStates.end()) {
|
||||||
auto* bs = it->second.get();
|
auto* bs = it->second.get();
|
||||||
@@ -960,6 +973,44 @@ struct EditorState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void queueLspDidChange() {
|
||||||
|
if (!lsp || !active()) return;
|
||||||
|
if (active()->path.rfind("(untitled", 0) == 0) return;
|
||||||
|
active()->lspVersion += 1;
|
||||||
|
lspChangePending = true;
|
||||||
|
lspChangeLast = ImGui::GetTime();
|
||||||
|
lspChangePath = active()->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushLspDidChange(double nowSeconds) {
|
||||||
|
if (!lsp || !lspChangePending) return;
|
||||||
|
double delay = settings.getLspDebounceMs() / 1000.0;
|
||||||
|
if ((nowSeconds - lspChangeLast) < delay) return;
|
||||||
|
auto it = bufferStates.find(lspChangePath);
|
||||||
|
if (it == bufferStates.end()) {
|
||||||
|
lspChangePending = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* buf = it->second.get();
|
||||||
|
lsp->didChange(toFileUri(buf->path), buf->editBuf, buf->lspVersion);
|
||||||
|
lspChangePending = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flushDeferredAstSync(double nowSeconds) {
|
||||||
|
(void)nowSeconds;
|
||||||
|
for (auto& kv : bufferStates) {
|
||||||
|
auto* buf = kv.second.get();
|
||||||
|
if (!buf->pendingAstSync) continue;
|
||||||
|
buf->sync.setText(buf->editBuf, buf->language);
|
||||||
|
buf->sync.syncNow();
|
||||||
|
buf->incrementalOptimizer.setRoot(buf->sync.getAST());
|
||||||
|
buf->pendingAstSync = false;
|
||||||
|
buf->highlightsDirty = true;
|
||||||
|
buf->generatedHighlightsDirty = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool hasSidePanels() const {
|
bool hasSidePanels() const {
|
||||||
if (ui.showOutline) return true;
|
if (ui.showOutline) return true;
|
||||||
if (library.showDependencyPanel) return true;
|
if (library.showDependencyPanel) return true;
|
||||||
@@ -1791,12 +1842,10 @@ struct EditorState {
|
|||||||
}
|
}
|
||||||
active()->orchestratorDirty = false;
|
active()->orchestratorDirty = false;
|
||||||
active()->highlightsDirty = true;
|
active()->highlightsDirty = true;
|
||||||
|
active()->highlightRequestTime = ImGui::GetTime();
|
||||||
active()->generatedHighlightsDirty = true;
|
active()->generatedHighlightsDirty = true;
|
||||||
active()->modified = true;
|
active()->modified = true;
|
||||||
if (lsp && active()->path.rfind("(untitled", 0) != 0) {
|
queueLspDidChange();
|
||||||
active()->lspVersion += 1;
|
|
||||||
lsp->didChange(toFileUri(active()->path), active()->editBuf, active()->lspVersion);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerCommand(const std::string& id,
|
void registerCommand(const std::string& id,
|
||||||
@@ -2176,12 +2225,10 @@ struct EditorState {
|
|||||||
}
|
}
|
||||||
active()->orchestratorDirty = true;
|
active()->orchestratorDirty = true;
|
||||||
active()->highlightsDirty = true;
|
active()->highlightsDirty = true;
|
||||||
|
active()->highlightRequestTime = ImGui::GetTime();
|
||||||
active()->generatedHighlightsDirty = true;
|
active()->generatedHighlightsDirty = true;
|
||||||
active()->modified = true;
|
active()->modified = true;
|
||||||
if (lsp && active()->path.rfind("(untitled", 0) != 0) {
|
queueLspDidChange();
|
||||||
active()->lspVersion += 1;
|
|
||||||
lsp->didChange(toFileUri(active()->path), active()->editBuf, active()->lspVersion);
|
|
||||||
}
|
|
||||||
events.publish(UIEventType::FileModified, active()->path, {}, ImGui::GetTime());
|
events.publish(UIEventType::FileModified, active()->path, {}, ImGui::GetTime());
|
||||||
events.publishDebounced(UIEventType::ASTChanged,
|
events.publishDebounced(UIEventType::ASTChanged,
|
||||||
active()->path,
|
active()->path,
|
||||||
@@ -2408,7 +2455,8 @@ struct EditorState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void doOpen(const std::string& path,
|
void doOpen(const std::string& path,
|
||||||
BufferManager::BufferMode modeOverride = BufferManager::BufferMode::Structured) {
|
BufferManager::BufferMode modeOverride = BufferManager::BufferMode::Structured,
|
||||||
|
bool deferAstSync = false) {
|
||||||
std::error_code sizeErr;
|
std::error_code sizeErr;
|
||||||
size_t fileSizeBytes = 0;
|
size_t fileSizeBytes = 0;
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
@@ -2455,7 +2503,7 @@ struct EditorState {
|
|||||||
else if (path.size() > 4 && path.substr(path.size() - 4) == ".org")
|
else if (path.size() > 4 && path.substr(path.size() - 4) == ".org")
|
||||||
language = "org";
|
language = "org";
|
||||||
createBuffer(path, content, language, effectiveMode,
|
createBuffer(path, content, language, effectiveMode,
|
||||||
fileSizeBytes, largeFileMode, disableHighlight);
|
fileSizeBytes, largeFileMode, disableHighlight, deferAstSync);
|
||||||
welcome.addRecentFile(path, language, bufferModeToString(effectiveMode));
|
welcome.addRecentFile(path, language, bufferModeToString(effectiveMode));
|
||||||
saveRecentFiles();
|
saveRecentFiles();
|
||||||
if (autoText && modeOverride == BufferManager::BufferMode::Structured) {
|
if (autoText && modeOverride == BufferManager::BufferMode::Structured) {
|
||||||
@@ -2489,6 +2537,7 @@ struct EditorState {
|
|||||||
buf->incrementalOptimizer.setRoot(buf->sync.getAST());
|
buf->incrementalOptimizer.setRoot(buf->sync.getAST());
|
||||||
}
|
}
|
||||||
buf->highlightsDirty = true;
|
buf->highlightsDirty = true;
|
||||||
|
buf->highlightRequestTime = ImGui::GetTime();
|
||||||
buf->generatedHighlightsDirty = true;
|
buf->generatedHighlightsDirty = true;
|
||||||
buf->modified = false;
|
buf->modified = false;
|
||||||
notify(NotificationLevel::Info, "Reloaded: " + path);
|
notify(NotificationLevel::Info, "Reloaded: " + path);
|
||||||
@@ -2511,6 +2560,12 @@ struct EditorState {
|
|||||||
void updateHighlights() {
|
void updateHighlights() {
|
||||||
if (!active()) return;
|
if (!active()) return;
|
||||||
if (!active()->highlightsDirty) return;
|
if (!active()->highlightsDirty) return;
|
||||||
|
double now = ImGui::GetTime();
|
||||||
|
double delay = settings.getHighlightDebounceMs() / 1000.0;
|
||||||
|
if (active()->highlightRequestTime > 0.0 &&
|
||||||
|
(now - active()->highlightRequestTime) < delay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (active()->disableSyntaxHighlight) {
|
if (active()->disableSyntaxHighlight) {
|
||||||
active()->highlights.clear();
|
active()->highlights.clear();
|
||||||
active()->highlightsDirty = false;
|
active()->highlightsDirty = false;
|
||||||
@@ -2599,11 +2654,9 @@ struct EditorState {
|
|||||||
active()->editBuf = active()->sync.getText();
|
active()->editBuf = active()->sync.getText();
|
||||||
active()->editor.setContent(active()->editBuf, active()->language);
|
active()->editor.setContent(active()->editBuf, active()->language);
|
||||||
active()->highlightsDirty = true;
|
active()->highlightsDirty = true;
|
||||||
|
active()->highlightRequestTime = ImGui::GetTime();
|
||||||
active()->modified = true;
|
active()->modified = true;
|
||||||
if (lsp && active()->path.rfind("(untitled", 0) != 0) {
|
queueLspDidChange();
|
||||||
active()->lspVersion += 1;
|
|
||||||
lsp->didChange(toFileUri(active()->path), active()->editBuf, active()->lspVersion);
|
|
||||||
}
|
|
||||||
analysisPending = true;
|
analysisPending = true;
|
||||||
analysisLastChange = ImGui::GetTime();
|
analysisLastChange = ImGui::GetTime();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ public:
|
|||||||
void setLargeFileTextMB(int value) { largeFileTextMB_ = value; }
|
void setLargeFileTextMB(int value) { largeFileTextMB_ = value; }
|
||||||
int getLargeFileDisableHighlightMB() const { return largeFileDisableHighlightMB_; }
|
int getLargeFileDisableHighlightMB() const { return largeFileDisableHighlightMB_; }
|
||||||
void setLargeFileDisableHighlightMB(int value) { largeFileDisableHighlightMB_ = value; }
|
void setLargeFileDisableHighlightMB(int value) { largeFileDisableHighlightMB_ = value; }
|
||||||
|
int getLspDebounceMs() const { return lspDebounceMs_; }
|
||||||
|
void setLspDebounceMs(int value) { lspDebounceMs_ = value; }
|
||||||
|
int getDiagnosticsDebounceMs() const { return diagnosticsDebounceMs_; }
|
||||||
|
void setDiagnosticsDebounceMs(int value) { diagnosticsDebounceMs_ = value; }
|
||||||
|
int getHighlightDebounceMs() const { return highlightDebounceMs_; }
|
||||||
|
void setHighlightDebounceMs(int value) { highlightDebounceMs_ = value; }
|
||||||
const std::string& getLayoutPreset() const { return layoutPreset_; }
|
const std::string& getLayoutPreset() const { return layoutPreset_; }
|
||||||
void setLayoutPreset(const std::string& name) { layoutPreset_ = name; }
|
void setLayoutPreset(const std::string& name) { layoutPreset_ = name; }
|
||||||
const std::string& getKeybindingProfile() const { return keybindingProfile_; }
|
const std::string& getKeybindingProfile() const { return keybindingProfile_; }
|
||||||
@@ -98,6 +104,9 @@ public:
|
|||||||
largeFileWarnMB_ = j.value("largeFileWarnMB", largeFileWarnMB_);
|
largeFileWarnMB_ = j.value("largeFileWarnMB", largeFileWarnMB_);
|
||||||
largeFileTextMB_ = j.value("largeFileTextMB", largeFileTextMB_);
|
largeFileTextMB_ = j.value("largeFileTextMB", largeFileTextMB_);
|
||||||
largeFileDisableHighlightMB_ = j.value("largeFileDisableHighlightMB", largeFileDisableHighlightMB_);
|
largeFileDisableHighlightMB_ = j.value("largeFileDisableHighlightMB", largeFileDisableHighlightMB_);
|
||||||
|
lspDebounceMs_ = j.value("lspDebounceMs", lspDebounceMs_);
|
||||||
|
diagnosticsDebounceMs_ = j.value("diagnosticsDebounceMs", diagnosticsDebounceMs_);
|
||||||
|
highlightDebounceMs_ = j.value("highlightDebounceMs", highlightDebounceMs_);
|
||||||
layoutPreset_ = j.value("layoutPreset", layoutPreset_);
|
layoutPreset_ = j.value("layoutPreset", layoutPreset_);
|
||||||
keybindingProfile_ = j.value("keybindingProfile", keybindingProfile_);
|
keybindingProfile_ = j.value("keybindingProfile", keybindingProfile_);
|
||||||
emacsConfigPath_ = j.value("emacsConfigPath", emacsConfigPath_);
|
emacsConfigPath_ = j.value("emacsConfigPath", emacsConfigPath_);
|
||||||
@@ -141,6 +150,9 @@ public:
|
|||||||
j["largeFileWarnMB"] = largeFileWarnMB_;
|
j["largeFileWarnMB"] = largeFileWarnMB_;
|
||||||
j["largeFileTextMB"] = largeFileTextMB_;
|
j["largeFileTextMB"] = largeFileTextMB_;
|
||||||
j["largeFileDisableHighlightMB"] = largeFileDisableHighlightMB_;
|
j["largeFileDisableHighlightMB"] = largeFileDisableHighlightMB_;
|
||||||
|
j["lspDebounceMs"] = lspDebounceMs_;
|
||||||
|
j["diagnosticsDebounceMs"] = diagnosticsDebounceMs_;
|
||||||
|
j["highlightDebounceMs"] = highlightDebounceMs_;
|
||||||
j["layoutPreset"] = layoutPreset_;
|
j["layoutPreset"] = layoutPreset_;
|
||||||
j["keybindingProfile"] = keybindingProfile_;
|
j["keybindingProfile"] = keybindingProfile_;
|
||||||
j["emacsConfigPath"] = emacsConfigPath_;
|
j["emacsConfigPath"] = emacsConfigPath_;
|
||||||
@@ -221,6 +233,9 @@ private:
|
|||||||
int largeFileWarnMB_ = 1;
|
int largeFileWarnMB_ = 1;
|
||||||
int largeFileTextMB_ = 5;
|
int largeFileTextMB_ = 5;
|
||||||
int largeFileDisableHighlightMB_ = 10;
|
int largeFileDisableHighlightMB_ = 10;
|
||||||
|
int lspDebounceMs_ = 120;
|
||||||
|
int diagnosticsDebounceMs_ = 500;
|
||||||
|
int highlightDebounceMs_ = 120;
|
||||||
std::string layoutPreset_ = "VSCode";
|
std::string layoutPreset_ = "VSCode";
|
||||||
std::string keybindingProfile_ = "VSCode";
|
std::string keybindingProfile_ = "VSCode";
|
||||||
|
|
||||||
|
|||||||
@@ -330,12 +330,22 @@ int main(int, char**) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.pollLspMessages();
|
state.pollLspMessages();
|
||||||
|
state.flushLspDidChange(ImGui::GetTime());
|
||||||
|
state.flushDeferredAstSync(ImGui::GetTime());
|
||||||
state.processLibraryIndexResponses();
|
state.processLibraryIndexResponses();
|
||||||
if (state.emacsState.emacsFunctionIndexDirty) {
|
if (state.emacsState.emacsFunctionIndexDirty) {
|
||||||
state.updateEmacsFunctionIndex();
|
state.updateEmacsFunctionIndex();
|
||||||
}
|
}
|
||||||
state.refreshEmacsModeLine(ImGui::GetTime());
|
state.refreshEmacsModeLine(ImGui::GetTime());
|
||||||
state.events.tick(ImGui::GetTime());
|
state.events.tick(ImGui::GetTime());
|
||||||
|
#ifdef _DEBUG
|
||||||
|
double now = ImGui::GetTime();
|
||||||
|
if (io.DeltaTime > 0.016 && (now - state.lastFrameBudgetWarning) > 1.0) {
|
||||||
|
state.notify(NotificationLevel::Warning,
|
||||||
|
"[perf] Frame time exceeded 16ms budget.");
|
||||||
|
state.lastFrameBudgetWarning = now;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
themes.refreshWatchedThemes();
|
themes.refreshWatchedThemes();
|
||||||
if (state.fontsDirty) {
|
if (state.fontsDirty) {
|
||||||
reloadFonts();
|
reloadFonts();
|
||||||
|
|||||||
@@ -372,7 +372,8 @@ static void renderEditorPanel(EditorState& state) {
|
|||||||
state.symbolsPending = false;
|
state.symbolsPending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.analysisPending && (now - state.analysisLastChange) > 0.5) {
|
double diagDelay = state.settings.getDiagnosticsDebounceMs() / 1000.0;
|
||||||
|
if (state.analysisPending && (now - state.analysisLastChange) > diagDelay) {
|
||||||
if (state.isStructured()) {
|
if (state.isStructured()) {
|
||||||
auto result = state.pipeline.run(state.active()->editBuf,
|
auto result = state.pipeline.run(state.active()->editBuf,
|
||||||
state.active()->language,
|
state.active()->language,
|
||||||
|
|||||||
@@ -381,6 +381,27 @@ static void renderSettingsPanel(EditorState& state) {
|
|||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::TextUnformatted("Debounce (ms)");
|
||||||
|
int lspDebounce = state.settings.getLspDebounceMs();
|
||||||
|
if (ImGui::InputInt("LSP Change", &lspDebounce)) {
|
||||||
|
lspDebounce = std::max(0, lspDebounce);
|
||||||
|
state.settings.setLspDebounceMs(lspDebounce);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
int diagDebounce = state.settings.getDiagnosticsDebounceMs();
|
||||||
|
if (ImGui::InputInt("Diagnostics", &diagDebounce)) {
|
||||||
|
diagDebounce = std::max(0, diagDebounce);
|
||||||
|
state.settings.setDiagnosticsDebounceMs(diagDebounce);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
int highlightDebounce = state.settings.getHighlightDebounceMs();
|
||||||
|
if (ImGui::InputInt("Highlighting", &highlightDebounce)) {
|
||||||
|
highlightDebounce = std::max(0, highlightDebounce);
|
||||||
|
state.settings.setHighlightDebounceMs(highlightDebounce);
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
LayoutPreset preset = state.ui.layoutPreset;
|
LayoutPreset preset = state.ui.layoutPreset;
|
||||||
int presetIndex = 0;
|
int presetIndex = 0;
|
||||||
if (preset == LayoutPreset::Emacs) presetIndex = 1;
|
if (preset == LayoutPreset::Emacs) presetIndex = 1;
|
||||||
|
|||||||
37
editor/tests/step200_test.cpp
Normal file
37
editor/tests/step200_test.cpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Step 200: Startup and panel performance.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
static std::string readFile(const std::string& path) {
|
||||||
|
std::ifstream f(path);
|
||||||
|
if (!f.is_open()) return {};
|
||||||
|
return std::string((std::istreambuf_iterator<char>(f)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assertContains(const std::string& text, const std::string& needle) {
|
||||||
|
assert(text.find(needle) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const std::string settings = readFile("src/SettingsManager.h");
|
||||||
|
const std::string editorState = readFile("src/EditorState.h");
|
||||||
|
const std::string mainSrc = readFile("src/main.cpp");
|
||||||
|
const std::string editorPanel = readFile("src/panels/EditorPanel.h");
|
||||||
|
|
||||||
|
assertContains(settings, "getLspDebounceMs");
|
||||||
|
assertContains(settings, "getDiagnosticsDebounceMs");
|
||||||
|
assertContains(settings, "getHighlightDebounceMs");
|
||||||
|
|
||||||
|
assertContains(editorState, "flushDeferredAstSync");
|
||||||
|
assertContains(editorState, "flushLspDidChange");
|
||||||
|
assertContains(editorState, "pendingAstSync");
|
||||||
|
|
||||||
|
assertContains(editorPanel, "getDiagnosticsDebounceMs");
|
||||||
|
assertContains(mainSrc, "Frame time exceeded 16ms");
|
||||||
|
|
||||||
|
printf("step200_test: all assertions passed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -424,7 +424,7 @@ Make Whetstone usable by everyone and fast with large files.
|
|||||||
- "Reopen in Structured Mode" option if user wants full features
|
- "Reopen in Structured Mode" option if user wants full features
|
||||||
*Modifies:* buffer opening logic, `panels/StatusBarPanel.h`
|
*Modifies:* buffer opening logic, `panels/StatusBarPanel.h`
|
||||||
|
|
||||||
- [ ] **Step 200: Startup and panel performance**
|
- [x] **Step 200: Startup and panel performance**
|
||||||
Faster startup and smoother runtime:
|
Faster startup and smoother runtime:
|
||||||
- Lazy-load panels: only parse/render on first show
|
- Lazy-load panels: only parse/render on first show
|
||||||
- Background grammar loading (don't block editor open for tree-sitter init)
|
- Background grammar loading (don't block editor open for tree-sitter init)
|
||||||
|
|||||||
Reference in New Issue
Block a user