Skip to content

Commit 9cd0441

Browse files
fix(lint): resolve clang-tidy performance warnings in mini-apps code
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4f76aa4 commit 9cd0441

36 files changed

Lines changed: 2870 additions & 4 deletions

src/ApplicationSettings.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,30 @@ void ApplicationSettings::setWorkspaceTasksJson(const QString &json)
221221
{
222222
setValue(QLatin1String(kWorkspaceTasksJsonKey), json);
223223
}
224+
225+
// --- Mini Apps settings ----------------------------------------------------------
226+
227+
static const char kMiniAppsGlobalJsonKey[] = "MiniApps/GlobalAppsJson";
228+
static const char kMiniAppsWorkspaceJsonKey[] = "MiniApps/WorkspaceAppsJson";
229+
230+
QString ApplicationSettings::miniAppsGlobalJson() const
231+
{
232+
return value(QLatin1String(kMiniAppsGlobalJsonKey), QString()).toString();
233+
}
234+
235+
void ApplicationSettings::setMiniAppsGlobalJson(const QString &json)
236+
{
237+
setValue(QLatin1String(kMiniAppsGlobalJsonKey), json);
238+
emit miniAppsGlobalJsonChanged(json);
239+
}
240+
241+
QString ApplicationSettings::miniAppsWorkspaceJson() const
242+
{
243+
return value(QLatin1String(kMiniAppsWorkspaceJsonKey), QString()).toString();
244+
}
245+
246+
void ApplicationSettings::setMiniAppsWorkspaceJson(const QString &json)
247+
{
248+
setValue(QLatin1String(kMiniAppsWorkspaceJsonKey), json);
249+
emit miniAppsWorkspaceJsonChanged(json);
250+
}

src/ApplicationSettings.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ class ApplicationSettings : public QSettings
143143
public slots:
144144
void setWorkspaceTasksJson(const QString &json);
145145

146+
// Mini Apps persistence. Global apps stored as a JSON array; workspace
147+
// apps stored as a JSON object keyed by normalized workspace path.
148+
public:
149+
QString miniAppsGlobalJson() const;
150+
QString miniAppsWorkspaceJson() const;
151+
public slots:
152+
void setMiniAppsGlobalJson(const QString &json);
153+
void setMiniAppsWorkspaceJson(const QString &json);
154+
signals:
155+
void miniAppsGlobalJsonChanged(const QString &json);
156+
void miniAppsWorkspaceJsonChanged(const QString &json);
157+
146158
DEFINE_SETTING(SyntaxHighlightDiffEnabled, syntaxHighlightDiffEnabled, bool)
147159

148160
// Files-tab git decoration master toggle. When false, the workspace

src/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ qt_add_executable(NotepadAI
3434
Finder.h
3535
FocusWatcher.h
3636
HtmlConverter.h
37+
HtmlPreviewWidget.h
3738
IFaceTable.h
3839
MarkdownPreviewWidget.h
3940
MarkdownRenderer.h
@@ -106,6 +107,7 @@ qt_add_executable(NotepadAI
106107
FileWatcher.cpp
107108
Finder.cpp
108109
HtmlConverter.cpp
110+
HtmlPreviewWidget.cpp
109111
IFaceTable.cpp
110112
MarkdownPreviewWidget.cpp
111113
MarkdownRenderer.cpp
@@ -189,6 +191,8 @@ qt_add_executable(NotepadAI
189191
dialogs/SendWithGoalDialog.h
190192
dialogs/EditTasksDialog.cpp
191193
dialogs/EditTasksDialog.h
194+
dialogs/EditMiniAppsDialog.cpp
195+
dialogs/EditMiniAppsDialog.h
192196
dialogs/ColumnEditorDialog.cpp
193197
dialogs/ColumnEditorDialog.h
194198
dialogs/ColumnEditorDialog.ui
@@ -366,6 +370,8 @@ qt_add_executable(NotepadAI
366370
ScintillaSorter.h ScintillaSorter.cpp
367371
widgets/TabsQuickActionsBar.cpp
368372
widgets/TabsQuickActionsBar.h
373+
widgets/WebViewWidget.h
374+
widgets/WebViewWidget.cpp
369375

370376
TerminalAiHelper.h
371377
TerminalAiHelper.cpp
@@ -375,6 +381,13 @@ qt_add_executable(NotepadAI
375381
TerminalManager.cpp
376382
TerminalTaskRegistry.h
377383
TerminalTaskRegistry.cpp
384+
MiniAppDefinition.h
385+
MiniAppRegistry.h
386+
MiniAppRegistry.cpp
387+
MiniAppInstance.h
388+
MiniAppInstance.cpp
389+
MiniAppManager.h
390+
MiniAppManager.cpp
378391
widgets/TerminalColorScheme.h
379392
widgets/TerminalColorScheme.cpp
380393
widgets/ScrollbackBuffer.h
@@ -417,6 +430,16 @@ else()
417430
# libsecret resolved at runtime via QLibrary("secret-1"); no build dep.
418431
endif()
419432

433+
# Platform-conditional WebView widget for Mini Apps.
434+
if(WIN32)
435+
target_sources(NotepadAI PRIVATE widgets/WebViewWidget_win.cpp)
436+
target_link_libraries(NotepadAI PRIVATE webview2)
437+
elseif(APPLE)
438+
enable_language(OBJCXX)
439+
target_sources(NotepadAI PRIVATE widgets/WebViewWidget_mac.mm)
440+
target_link_libraries(NotepadAI PRIVATE "-framework WebKit")
441+
endif()
442+
420443
set_target_properties(NotepadAI PROPERTIES
421444
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/deploy/macos/info.plist
422445
)

src/CrashHandler.cpp

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@
4545
# define WIN32_LEAN_AND_MEAN
4646
# include <windows.h>
4747
# include <dbghelp.h>
48+
# include <psapi.h>
4849
# include <shlobj.h>
4950
# pragma comment(lib, "dbghelp.lib")
51+
# pragma comment(lib, "psapi.lib")
5052
# pragma comment(lib, "shell32.lib")
5153
#else
5254
# include <fcntl.h>
@@ -75,6 +77,9 @@ constexpr std::size_t kRotateBytes = 10 * 1024 * 1024;
7577
constexpr std::size_t kFrameReserve = 1024;
7678
#ifdef _WIN32
7779
constexpr DWORD64 kSymDispMax = 256 * 1024;
80+
constexpr int kMaxModules = 64;
81+
constexpr std::size_t kRawStackBytes = 512;
82+
constexpr int kInsnBytes = 16;
7883
#endif
7984

8085
#ifndef _WIN32
@@ -381,6 +386,8 @@ void writeHeader(CrashFile *cf, const char *kind)
381386
appendStr(b, kSectionBufSize, &p, "\nPID : ");
382387
#ifdef _WIN32
383388
appendU64(b, kSectionBufSize, &p, GetCurrentProcessId());
389+
appendStr(b, kSectionBufSize, &p, "\nTID : ");
390+
appendU64(b, kSectionBufSize, &p, GetCurrentThreadId());
384391
#else
385392
appendU64(b, kSectionBufSize, &p, static_cast<std::uint64_t>(getpid()));
386393
#endif
@@ -475,11 +482,175 @@ bool isFatalSehCode(DWORD code)
475482
}
476483
}
477484

485+
void writeRegisters(CrashFile *cf, CONTEXT *ctx)
486+
{
487+
std::size_t p = 0;
488+
char *b = g_section_buf;
489+
appendStr(b, kSectionBufSize, &p, "Registers:\n");
490+
491+
#if defined(_M_X64) || defined(__x86_64__)
492+
auto reg = [&](const char *name, DWORD64 val) {
493+
appendStr(b, kSectionBufSize, &p, " ");
494+
appendStr(b, kSectionBufSize, &p, name);
495+
appendStr(b, kSectionBufSize, &p, ": 0x");
496+
appendHex64(b, kSectionBufSize, &p, val, 16);
497+
appendChar(b, kSectionBufSize, &p, '\n');
498+
};
499+
reg("RAX", ctx->Rax); reg("RBX", ctx->Rbx);
500+
reg("RCX", ctx->Rcx); reg("RDX", ctx->Rdx);
501+
reg("RSI", ctx->Rsi); reg("RDI", ctx->Rdi);
502+
reg("RBP", ctx->Rbp); reg("RSP", ctx->Rsp);
503+
reg("R8 ", ctx->R8); reg("R9 ", ctx->R9);
504+
reg("R10", ctx->R10); reg("R11", ctx->R11);
505+
reg("R12", ctx->R12); reg("R13", ctx->R13);
506+
reg("R14", ctx->R14); reg("R15", ctx->R15);
507+
reg("RIP", ctx->Rip);
508+
#elif defined(_M_ARM64) || defined(__aarch64__)
509+
appendStr(b, kSectionBufSize, &p, " (ARM64 register dump not implemented)\n");
510+
#else
511+
appendStr(b, kSectionBufSize, &p, " (unsupported arch)\n");
512+
#endif
513+
514+
writeSection(cf, b, &p);
515+
}
516+
517+
bool isMemoryReadable(const void *ptr, std::size_t len)
518+
{
519+
MEMORY_BASIC_INFORMATION mbi{};
520+
if (VirtualQuery(ptr, &mbi, sizeof(mbi)) == 0) return false;
521+
if (mbi.State != MEM_COMMIT) return false;
522+
const DWORD prot = mbi.Protect;
523+
if (prot & (PAGE_NOACCESS | PAGE_GUARD)) return false;
524+
const auto start = reinterpret_cast<std::uintptr_t>(ptr);
525+
const auto regionEnd = reinterpret_cast<std::uintptr_t>(mbi.BaseAddress) + mbi.RegionSize;
526+
return (start + len) <= regionEnd;
527+
}
528+
529+
void writeInsnBytes(CrashFile *cf, void *addr)
530+
{
531+
std::size_t p = 0;
532+
char *b = g_section_buf;
533+
unsigned char insnBuf[kInsnBytes] = {0};
534+
bool insnOk = false;
535+
536+
if (addr && isMemoryReadable(addr, kInsnBytes)) {
537+
memcpy(insnBuf, addr, kInsnBytes);
538+
insnOk = true;
539+
}
540+
541+
appendStr(b, kSectionBufSize, &p, "Insn : ");
542+
if (insnOk) {
543+
for (int i = 0; i < kInsnBytes; ++i) {
544+
if (i > 0) appendChar(b, kSectionBufSize, &p, ' ');
545+
appendHex64(b, kSectionBufSize, &p, insnBuf[i], 2);
546+
}
547+
} else {
548+
appendStr(b, kSectionBufSize, &p, "(unreadable)");
549+
}
550+
appendChar(b, kSectionBufSize, &p, '\n');
551+
writeSection(cf, b, &p);
552+
}
553+
554+
void writeModules(CrashFile *cf)
555+
{
556+
std::size_t p = 0;
557+
char *b = g_section_buf;
558+
appendStr(b, kSectionBufSize, &p, "Modules:\n");
559+
writeSection(cf, b, &p);
560+
561+
HANDLE process = GetCurrentProcess();
562+
HMODULE mods[kMaxModules];
563+
DWORD needed = 0;
564+
if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
565+
return;
566+
567+
const int count = static_cast<int>(needed / sizeof(HMODULE));
568+
const int limit = count < kMaxModules ? count : kMaxModules;
569+
570+
for (int i = 0; i < limit; ++i) {
571+
MODULEINFO mi{};
572+
GetModuleInformation(process, mods[i], &mi, sizeof(mi));
573+
574+
char name[MAX_PATH] = {0};
575+
GetModuleFileNameA(mods[i], name, MAX_PATH);
576+
577+
// Extract just the filename from the full path
578+
const char *basename = name;
579+
for (const char *c = name; *c; ++c) {
580+
if (*c == '\\' || *c == '/') basename = c + 1;
581+
}
582+
583+
p = 0;
584+
appendStr(b, kSectionBufSize, &p, " 0x");
585+
appendHex64(b, kSectionBufSize, &p,
586+
reinterpret_cast<std::uint64_t>(mi.lpBaseOfDll), 16);
587+
appendChar(b, kSectionBufSize, &p, ' ');
588+
appendHex64(b, kSectionBufSize, &p,
589+
static_cast<std::uint64_t>(mi.SizeOfImage), 8);
590+
appendChar(b, kSectionBufSize, &p, ' ');
591+
appendStr(b, kSectionBufSize, &p, basename);
592+
appendChar(b, kSectionBufSize, &p, '\n');
593+
594+
if (kSectionBufSize - p < kFrameReserve) {
595+
writeSection(cf, b, &p);
596+
}
597+
}
598+
writeSection(cf, b, &p);
599+
}
600+
601+
void writeRawStack(CrashFile *cf, CONTEXT *ctx)
602+
{
603+
#if defined(_M_X64) || defined(__x86_64__)
604+
std::size_t p = 0;
605+
char *b = g_section_buf;
606+
appendStr(b, kSectionBufSize, &p, "Raw stack (512 bytes from RSP):\n");
607+
writeSection(cf, b, &p);
608+
609+
unsigned char stackBuf[kRawStackBytes] = {0};
610+
bool ok = false;
611+
void *rspPtr = reinterpret_cast<void *>(ctx->Rsp);
612+
if (rspPtr && isMemoryReadable(rspPtr, kRawStackBytes)) {
613+
memcpy(stackBuf, rspPtr, kRawStackBytes);
614+
ok = true;
615+
}
616+
617+
if (!ok) {
618+
p = 0;
619+
appendStr(b, kSectionBufSize, &p, " (unreadable)\n");
620+
writeSection(cf, b, &p);
621+
return;
622+
}
623+
624+
// Dump as 64-bit qwords, 8 per line
625+
const std::uint64_t *qwords = reinterpret_cast<const std::uint64_t *>(stackBuf);
626+
const int totalQwords = static_cast<int>(kRawStackBytes / 8);
627+
p = 0;
628+
for (int i = 0; i < totalQwords; ++i) {
629+
if (i % 8 == 0) appendStr(b, kSectionBufSize, &p, " ");
630+
appendStr(b, kSectionBufSize, &p, "0x");
631+
appendHex64(b, kSectionBufSize, &p, qwords[i], 16);
632+
if (i % 8 == 7 || i == totalQwords - 1) {
633+
appendChar(b, kSectionBufSize, &p, '\n');
634+
if (kSectionBufSize - p < kFrameReserve) {
635+
writeSection(cf, b, &p);
636+
}
637+
} else {
638+
appendChar(b, kSectionBufSize, &p, ' ');
639+
}
640+
}
641+
writeSection(cf, b, &p);
642+
#else
643+
(void)cf; (void)ctx;
644+
#endif
645+
}
646+
478647
void writeStackTraceWindows(CrashFile *cf, CONTEXT *ctx)
479648
{
480649
HANDLE process = GetCurrentProcess();
481650
HANDLE thread = GetCurrentThread();
482651

652+
SymRefreshModuleList(process);
653+
483654
STACKFRAME64 frame{};
484655
DWORD machine = 0;
485656
#if defined(_M_X64) || defined(__x86_64__)
@@ -633,8 +804,12 @@ bool writeReportSeh(EXCEPTION_POINTERS *info, const char *origin)
633804
writeSection(&cf, b, &p);
634805
}
635806

807+
writeRegisters(&cf, info->ContextRecord);
808+
writeInsnBytes(&cf, info->ExceptionRecord->ExceptionAddress);
636809
writeContextSection(&cf);
810+
writeModules(&cf);
637811
writeStackTraceWindows(&cf, info->ContextRecord);
812+
writeRawStack(&cf, info->ContextRecord);
638813
writeFooter(&cf);
639814
cf.close();
640815
return true;

src/DockedEditor.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "ScintillaNext.h"
2929

3030
#include <QEvent>
31+
#include <QTimer>
3132
#include <QUuid>
3233

3334

@@ -102,10 +103,13 @@ DockedEditor::DockedEditor(QWidget *parent) : QObject(parent)
102103
emit editorOrderChanged();
103104
});
104105

105-
// In theory the order changes when a new dock area is created (e.g. editor is dragged and dropped),
106-
// but the dockAreaCreated() signal is triggered before it is actually added to the CDockManager,
107-
// so interrogating the dock manager during the signal doesn't help.
108-
//emit editorOrderChanged();
106+
// Pin preview editor if it was dragged to create this new area
107+
QTimer::singleShot(0, this, [this, DockArea]() {
108+
if (!m_previewEditor) return;
109+
auto *dw = qobject_cast<ads::CDockWidget *>(m_previewEditor->parentWidget());
110+
if (dw && dw->dockAreaWidget() == DockArea)
111+
pinPreviewEditor();
112+
});
109113
});
110114
}
111115

@@ -254,6 +258,8 @@ void DockedEditor::addPreviewEditor(ScintillaNext *editor)
254258
pinPreviewEditor();
255259
}
256260
});
261+
262+
emit previewEditorSet();
257263
}
258264

259265
ScintillaNext *DockedEditor::previewEditor() const

src/DockedEditor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ private slots:
8585
void editorActivated(ScintillaNext *editor);
8686
void editorOrderChanged();
8787
void previewTabActivated(QWidget *widget);
88+
void previewEditorSet();
8889

8990
void contextMenuRequestedForEditor(ScintillaNext *editor);
9091
void titleBarDoubleClicked();

0 commit comments

Comments
 (0)