Commit Graph

302 Commits

Author SHA1 Message Date
Levi Neely 4a29efc121 prompts: add tools-image.md for image_read tool 2026-07-16 20:13:33 +02:00
Levi Neely 5eb8f49d15 Activate the existing Ollie GUI instance 2026-07-16 19:58:15 +02:00
Levi Neely 9e0e5cb0f4 Improve KDE GUI file and command handling 2026-07-16 19:42:21 +02:00
Levi Neely 483981a9cd fix(gui): include emojis.js in Qt6 resource bundle
qt_add_resources was only bundling main.qml, causing ollie-gui to fail
at startup with 'Script qrc:/gui/emojis.js unavailable'.
2026-07-16 17:26:06 +02:00
Levi Neely 167e70531a gui: add copy button to call and tool blocks 2026-07-16 16:23:56 +02:00
Levi Neely 378ea83de7 kate: add kill session button in upper right 2026-07-16 14:50:47 +02:00
Levi Neely e2d02152e4 kate: fix chat scroll not pinning to bottom
setHtml() resets the document layout. sb->setValue(sb->maximum()) was
reading a stale maximum before relayout completed. Use moveCursor(End)
+ ensureCursorVisible() which forces layout and scrolls reliably.

Also: fix session list state updates destroying delegates (rename fix)
already included in previous commit.
2026-07-16 14:45:26 +02:00
Levi Neely f45cb8199d gui: close-to-tray option + fix session list disrupting rename
- Add configurable close-to-tray (Settings > System Tray)
  - QSystemTrayIcon with show/hide toggle and quit action
  - closeToTray property persisted in theme.conf
  - Window hides instead of quitting when enabled

- Fix session rename being interrupted by state changes
  - onStateChanged no longer calls refreshSessions()
  - State updates in-place via sessionStateUpdated signal
  - Delegates track state locally, preserving rename TextField
2026-07-16 14:34:14 +02:00
Levi Neely 1d646f7fab gui: fix flickering, add code exec button, fix bubble width, improve scroll
- Replace Qt.callLater scroll debounce with Timer (16ms) to coalesce
  rapid contentHeight changes and eliminate scroll flickering
- Add execute button (play icon) on code blocks for scripted languages
  (bash, python, perl, ruby, etc.) — launches in terminal
- Fix assistant bubble width: always use 95% of available width
- Add minimum width (280px) to code fence blocks
- Move emoji popup into prompt RowLayout so it appears near input
- Disable wheel scroll inertia (direct contentY) while keeping flick
  inertia intact
- Apply all fixes to both KF5 and KF6 QML files
2026-07-16 13:20:08 +02:00
Levi Neely 2929bb6b04 kde: visual enhancements, emoji completion, scroll/layout fixes
ollie-gui:
- Structured chat blocks (user/assistant bubbles, tool/call with left borders)
- Tool/call blocks always visible (not collapsible), whitespace preserved
- User interrupt blocks (amber warning style)
- Copy buttons on bubbles (32x32, hover-visible)
- Emoji completion with popup selector + quick emoticons
- Backend/model display in header bar
- Session state updates on switch
- Scroll flicker fix (debounced, guarded)
- Null guards on delegate block properties
- Binding loop fixes

Kate plugin:
- Diff viewer integration via Kate DiffWidget (libkateprivate)
- Diff mode config (unified/side-by-side/raw)
- Emoji processing in prompt input (quick emoticons + :shortcode:)
- Increased chat font size
- Scroll position preservation

Dbus client:
- activeModel/activeBackend properties from GetConfig
2026-07-16 11:19:22 +02:00
Levi Neely d3c8aece38 kate: extract chat_renderer, simplify kate plugin 2026-07-16 08:57:55 +02:00
Levi Neely 59285cda9f gitignore: add CMakeFiles/ 2026-07-16 08:44:23 +02:00
Levi Neely f6b218bef7 kf5: sync gui with kf6 features, fix install paths
- main-kf5.qml: port all KF6 gui enhancements (chat bubbles, structured
  blocks, markdown, syntax highlighting, diff coloring, collapsible
  call/tool blocks, lazy-load scrolling)
- CMakeLists.txt: add chatblockmodel.cpp and KF5::SyntaxHighlighting to
  KF5 gui target; fix Kate plugin INSTALL_NAMESPACE (ktexteditor, not
  kf5/ktexteditor or kf6/ktexteditor)
- Makefile: fix KF6 kate install path; add icon+desktop to kf5-install
- main.qml + main-kf5.qml: fix prose font size (use root.font.pointSize
  instead of Qt.application.font.pixelSize)
2026-07-16 08:43:25 +02:00
Levi Neely f546c8cf69 move You/Ollie labels below bubbles 2026-07-16 07:38:56 +02:00
Levi Neely a0fae46417 chat bubble styling for user and assistant messages
- User messages: right-aligned bubble, accent-tinted (15%), max 85% width
- Assistant messages: left-aligned bubble, subtle text-color tint (6%), max 95% width
- Both have 12px radius, 12px internal padding
- Small "You" / "Ollie" labels above each bubble
- Tool/call/reasoning blocks remain unchanged (collapsed, no bubble)
2026-07-16 07:34:33 +02:00
Levi Neely dfca04e734 all blocks use markdown rendering by default
- Tool blocks: expanded via sub-blocks (same as assistant) so embedded
  diffs and code fences render properly with coloring
- Call blocks: always JSON, use formattedContent (pretty-print + highlight)
- Prose sub-blocks use Text.MarkdownText for native backtick/bold/link support
2026-07-16 07:29:30 +02:00
Levi Neely 7f226e2012 tool blocks: use sub-block rendering (same as assistant)
Tool results often contain markdown with code fences and diffs.
Using formattedContent treated the whole block as raw text.
Now tool blocks expand into parsed sub-blocks (prose, code, diff)
just like assistant blocks, so embedded diffs get colored.
2026-07-16 07:27:33 +02:00
Levi Neely c907aee653 use Qt native MarkdownText for prose blocks
Stop hand-rolling markdown with regex. Qt 6 Text supports
textFormat: Text.MarkdownText natively — handles backticks,
bold, italic, links, lists correctly. Code blocks and diffs
still use our custom KSyntaxHighlighting rendering.
2026-07-16 07:23:41 +02:00
Levi Neely cc24400ba7 fix indentation: wrap highlighted HTML in <pre> with white-space:pre-wrap
HTML RichText collapses multiple spaces, destroying JSON indentation.
Wrap all highlighted output in <pre> tags and use real newlines instead
of <br>. pre-wrap allows wrapping at container width.
2026-07-16 07:20:55 +02:00
Levi Neely 5c093a3bb2 fix syntax highlighting: use AbstractHighlighter directly
QSyntaxHighlighter applies colors to the layout only (not accessible
via QTextBlock iteration). Replace with a custom AbstractHighlighter
subclass (HtmlBuilder) that builds HTML directly in applyFormat().
This actually produces colored output.
2026-07-16 07:19:09 +02:00
Levi Neely 9f365f49b0 fix backtick regex: prevent matching across newlines 2026-07-16 07:09:16 +02:00
Levi Neely 93c9bd995e move call/tool formatting entirely to C++ via formattedContent role
QML scope issues made JS-based formatting unreliable. New approach:
- FormattedContentRole in the model computes pretty-printed HTML in C++
- Call blocks: always prettyJson()
- Tool blocks: detect JSON/diff and format, otherwise escaped HTML
- QML just binds text: block.formattedContent || ""
2026-07-16 07:07:51 +02:00
Levi Neely 7cd46337a3 render inline \`code\` in monospace with subtle background 2026-07-16 07:04:46 +02:00
Levi Neely c2ff88e8e6 fix: String() conversion for block.blockContent, avoid ES2019 methods
blockContent from QVariant needs explicit String() conversion.
Use charAt/indexOf instead of startsWith (ES6 compat).
2026-07-16 07:03:40 +02:00
Levi Neely 38df1a8e32 fix TypeError: guard against undefined blockContent in tool/call delegates 2026-07-16 07:02:04 +02:00
Levi Neely c39e0f2723 fix call/tool pretty-print: use C++ prettyJson() with QJsonDocument
The onVisibleChanged approach failed because block.blockContent could
not resolve through the Loader scope. Now using direct binding:
- call blocks: text bound to chatModel.prettyJson(block.blockContent)
- tool blocks: detect JSON/diff, format accordingly
- prettyJson() uses QJsonDocument for proper indentation + KSyntaxHighlighting
- Only evaluated when visible (lazy)
2026-07-16 07:00:40 +02:00
Levi Neely ee3a0a1e76 pretty-print + syntax highlight call/tool blocks
Call blocks: always pretty-print JSON + highlight on expand.
Tool blocks: detect JSON/diff and highlight accordingly.
2026-07-16 06:56:14 +02:00
Levi Neely 481f7f9d76 toggle arrow direction on collapsible blocks (▶/▼) 2026-07-16 06:54:06 +02:00
Levi Neely d7a66f1827 replace ListView with Flickable+Column+Repeater
ListView.positionViewAtEnd() causes freezes by forcing instantiation
of all delegates to measure total height. Flickable+Column avoids this
- contentHeight is computed directly from Column.implicitHeight
- Scroll to bottom is just contentY = contentHeight - height
- No virtualization needed with only 20 blocks
- Eliminates all positionViewAtEnd and _scrolling guard complexity
2026-07-16 06:51:37 +02:00
Levi Neely 79656596e4 fix startup freeze: async highlighting + reduce initial blocks to 20
- Code blocks show plain text immediately, highlight via Timer after
  150ms (prevents blocking the render thread during initial load)
- Reduced initial blocks from 40 to 20
- Detect append vs full reset in setRawText for better session switch
2026-07-16 06:49:20 +02:00
Levi Neely f122a69bce reverse-scroll chat: start at bottom, lazy-load on scroll up
- Model shows last 40 blocks initially, positioned at end
- Scrolling near top triggers loadEarlier() which prepends 30 blocks
- Scroll position maintained after prepend via contentY adjustment
- All blocks still parsed (for searching later) but only tail rendered
- Reduced initial render cost significantly
2026-07-16 06:46:47 +02:00
Levi Neely f1a045077b limit visible blocks to 80 + reduce cacheBuffer for startup perf
With 300KB+ chat logs producing hundreds of blocks, instantiating all
delegates was causing unresponsiveness. Cap the model at the last 80
blocks and set cacheBuffer: 200 to limit off-screen rendering.
2026-07-16 06:44:11 +02:00
Levi Neely 6f351b77e4 fix performance: cache subBlocks and syntax highlighting
- Cache parseSubBlocks per block (only reparse when content changes)
- Cache highlightedHtml results (code+language key)
- Prevents expensive KSyntaxHighlighting and regex on every render
- Also fixes scroll loop with _scrolling guard
2026-07-16 06:42:11 +02:00
Levi Neely a6a1a227c3 fix scroll: incremental model updates + prevent scroll loop
- ChatBlockModel::reparse() now does incremental diffs instead of
  beginResetModel which destroys all delegates and resets scroll
- ListView scroll uses _scrolling guard to prevent infinite loop
  from positionViewAtEnd triggering contentHeightChanged
2026-07-16 06:38:37 +02:00
Levi Neely 0783c7dda3 fix scroll height and prose line breaks in rich output
- Loader delegate: set explicit height from item.implicitHeight so
  ListView can calculate correct contentHeight for scrolling
- Prose sub-blocks: escape HTML, convert newlines to <br> before
  linkifying paths (RichText ignores bare newlines)
2026-07-16 06:36:00 +02:00
Levi Neely 9e10bf30db fix: Text has no background property, wrap diff lines in Rectangle 2026-07-16 06:31:02 +02:00
Levi Neely 6e03064d0f rich output rendering for ollie-gui
Replace flat TextArea chat view with structured ListView:
- ChatBlockModel parses raw chat text into typed blocks (user,
  assistant, reasoning, call, tool, error, info)
- Sub-blocks parsed from markdown: prose, fenced code, diffs
- Code blocks rendered with KSyntaxHighlighting (auto light/dark theme)
- Diff blocks with red/green line coloring
- Copy button on code and diff blocks
- File paths linkified and clickable (opens with xdg-open)
- Reasoning/call/tool blocks collapsible (click to expand)
- User blocks highlighted with subtle accent background
- Error blocks in red
- Scroll pinning preserved (auto-scroll when at bottom)
2026-07-16 06:29:18 +02:00
Levi Neely 6642ab014b multi-line prompt input across all front-ends
Replace single-line TextField/QLineEdit with multi-line TextArea/QPlainTextEdit.
Enter sends, Shift+Enter and Ctrl+J insert newlines. Max height capped so the
input area does not take over the panel.
2026-07-16 06:19:14 +02:00
Levi Neely 5c51ef3a87 gitignore build directory 2026-07-16 06:10:10 +02:00
Levi Neely 7b8fa5eca4 support arbitrary color schemes in ollie-gui
Scan ~/.local/share/color-schemes/ in addition to /usr/share/color-schemes/
so user-installed themes (e.g. Catppuccin) are discovered. Mode is now any
scheme name rather than just system/light/dark. Settings dialog uses a
ComboBox listing all available schemes plus "System".
2026-07-16 06:08:41 +02:00
Levi Neely fcc3cd2313 kate stop button, sorted sessions, scroll pinning, install fix
- Kate: add always-visible stop button next to prompt input
- All front-ends: sort sessions alphabetically by ID
- All front-ends: only auto-scroll chat if at bottom, show
  floating go-to-bottom button when scrolled away
- CMakeLists: set KDE_INSTALL_PLUGINDIR to QT6_INSTALL_PLUGINS
  so plugins install to lib64/qt6/plugins/ (where Kate looks)
2026-07-16 06:03:15 +02:00
Levi Neely d5e27f1c82 fix kate crash 2026-07-15 17:55:14 +02:00
Levi Neely 455d9c9190 kate: fix use-after-free crash in setupGhostProvider
m_ghost was parented to the view, so Qt parent-child cleanup could
destroy it when a view was replaced. The raw pointer remained non-null,
causing a double-free on the next viewChanged signal.

Fix by using QPointer<OllieGhostProvider> which auto-nulls on destroy.

Also replace qobject_cast with dynamic_cast for KF5 KTextEditor
interfaces to avoid crashes when qt_metacast accesses uninitialized
KateViewConfig during early view activation.
2026-07-15 11:06:20 +02:00
Levi Neely 5d18806ad6 kate: add KF5 preprocessor guards for InlineNote and completion APIs
KF5's KTextEditor uses interface classes (InlineNoteInterface,
CodeCompletionInterface, ConfigInterface) accessed via qobject_cast,
whereas KF6 puts these methods directly on View. Wrap the differences
with #if KTEXTEDITOR_VERSION_MAJOR >= 6 so both build paths compile.

Fixes:
- inlineNotes() return type: QVector<int> (KF5) vs QList<int> (KF6)
- paintInlineNote() signature: 2 params (KF5) vs 3 params (KF6)
- register/unregisterInlineNoteProvider via InlineNoteInterface
- isCompletionActive via CodeCompletionInterface
- configValue via ConfigInterface
2026-07-15 09:59:56 +02:00
Levi Neely e87038ca04 plasmoid: fix highlighted session text unreadable on light themes
Replace KirigamiDelegates.RoundedItemDelegate (not available in all
Kirigami versions) with PlasmaComponents.ItemDelegate. Add explicit
highlightedTextColor bindings to labels and icon in the session list
delegate for both KF5 and KF6 builds.
2026-07-14 15:58:46 +02:00
Levi Neely 1552fce126 kate: fix crash on document close (dangling overlay pointer)
The GhostOverlay is parented to the view widget and gets destroyed by
Qt child cleanup before ~OllieGhostProvider runs. Stop calling
hideOverlay() in destructor, connect destroyed() signal to null the
pointer.
2026-07-14 14:58:40 +02:00
Levi Neely 18402a2be7 kate: config page improvements, status bar dedup, default backend/model
- Add Default Backend / Default Model config for chat sessions
  (overrides OLLIE_BACKEND / OLLIE_MODEL env vars)
- Pass configured backend/model to CreateSession D-Bus call
- Move "Completion enabled on startup" checkbox below text fields
- Deduplicate status bar indicator when multiple views exist
- Make install target depend on build
- Remove Escape-to-dismiss (conflicts with Kate popups)
2026-07-14 14:53:13 +02:00
Levi Neely b67e82dca0 kate: fix ghost text provider, add multi-line overlay and config
- Fix parent not passed to InlineNoteProvider causing provider recreation
  on every viewChanged signal (killed debounce timer, no completions fired)
- Add view() accessor, use it in setupGhostProvider check
- Null-check focusProxy() to prevent crash during early viewChanged
- Multi-line completions: first line as inline note, continuation lines
  rendered via GhostOverlay floating widget
- Guard event filter and signal handlers against active completion popups
- Add suggestion cycling (Meta+O,N / Meta+O,P) with history
- Add Meta+O,C to toggle completions on/off with status bar indicator
- Add Meta+O,D to dismiss current suggestion
- Add Meta+O,Tab to manually trigger a completion
- Add config page for completion backend and model override
- Pass backend/model config via D-Bus Complete context parameter
2026-07-14 13:24:03 +02:00
Levi Neely 16e8fc7a75 feat: ghost-text code completion via InlineNoteProvider
Adds OllieGhostProvider that renders AI completions as translucent
gray text after the cursor. Uses the new Complete D-Bus method with
500ms debounce. Tab accepts, Escape dismisses, any edit clears.
Works on both KF5 and KF6 builds.
2026-07-14 12:30:18 +02:00
Levi Neely bbff78cd7e add .gitignore: exclude __pycache__ 2026-07-14 12:00:43 +02:00