kde: remove KF5/Qt5 support, build KF6/Qt6 only

Drop the OLLIE_KF5 CMake option and the entire Qt5/KF5 build branch;
delete KF5-only assets (99-ollie-kf5.sh, ollie-actions-kf5.desktop);
collapse all QT_VERSION_MAJOR and KTEXTEDITOR_VERSION_MAJOR conditionals
to the KF6 path in the KRunner, Kate, KIO, and GUI sources; update
Makefile, README, and docs. Verified: KF6 configure + full build of
ollie-gui, krunner_ollie, ollie_kate, kio_ollie.
This commit is contained in:
Ollie Agent 2026-09-29 16:44:12 +02:00
parent 50b02b7a1e
commit 72239fe3d5
18 changed files with 123 additions and 413 deletions

2
.gitignore vendored
View File

@ -16,8 +16,6 @@ __pycache__/
build/
build-cmake/
build-kf5/
build-kf6/
CMakeFiles/
# Large ML model files (downloaded during install)

View File

@ -64,7 +64,6 @@ make ninep # olliesrv and ollie-9p
make client # native lib9p shared library and header
make tools # compiled tools (code-intel, file, LSP, web)
make kde # KDE KF6 integration
make kde-kf5 # KDE KF5 integration
make install-data # runtime configuration, prompts, skills, scripts, and tools
make test # core and lib9p tests
make test-core # cmd/olliesrv, cmd/toolsrv, shared packages
@ -84,7 +83,7 @@ For direct Go testing, use the packages covered by `make test-core` and `make te
## Language & Conventions
- **Go** (root module): Go 1.25+, standard library preferred, minimal dependencies.
- **C++20/Qt6/KF6** (kde): CMake build, dual Qt5/Qt6 support where noted.
- **C++20/Qt6/KF6** (kde): CMake build.
- **Elisp** (el): single file `ellie.el`.
- **Tool scripts**: Python 3, Bash, or compiled binaries. Must be executable. Metadata lives in a `.meta` sidecar JSON file (see `data/tools/*.meta`).
### Code style
@ -220,7 +219,7 @@ The registry doesn't distinguish between scripts and binaries.
2. If it should be loaded by default, reference it in `data/agents/default.json`
3. Run `make install-data` to install
## KDE development
KDE integration is part of this repository under `kde/`. Build and install it through the root Makefile targets (`make kde` or `make kde-kf5`).
KDE integration is part of this repository under `kde/`. Build and install it through the root Makefile target (`make kde`).
## Key Lessons (Aug 14–17 session)

View File

@ -42,7 +42,7 @@ tools: go
for f in data/tools/*; do [ -f "$$f" ] && [ -x "$$f" ] && cp "$$f" $(BUILD_DIR)/tools/; done; true
cp -a data/tools/_lib $(BUILD_DIR)/tools/
# KDE components (auto-detects KF6/KF5, builds lib9p internally)
# KDE components (KF6/Qt6, builds lib9p internally)
kde:
@if cmake -S kde -B kde/build -DCMAKE_INSTALL_PREFIX=$(PREFIX) 2>/dev/null; then \
cmake --build kde/build -j$(JOBS) || { echo "KDE build failed" >&2; exit 1; }; \
@ -65,8 +65,7 @@ install: build install-data
cmake --install kde/build; \
install -Dm644 kde/gui/org.ollie.gui.desktop $(PREFIX)/share/applications/org.ollie.gui.desktop; \
install -Dm644 kde/gui/ollie.svg $(PREFIX)/share/icons/hicolor/scalable/apps/ollie.svg; \
install -Dm755 kde/dolphin/ollie-actions.desktop $(PREFIX)/share/kio/servicemenus/ollie-actions.desktop 2>/dev/null || \
install -Dm755 kde/dolphin/ollie-actions-kf5.desktop $(PREFIX)/share/kio/servicemenus/ollie-actions.desktop; \
install -Dm755 kde/dolphin/ollie-actions.desktop $(PREFIX)/share/kio/servicemenus/ollie-actions.desktop; \
install -Dm755 kde/dolphin/ollie-ask $(BINDIR)/ollie-ask; \
install -Dm755 kde/dolphin/ollie-session-here $(BINDIR)/ollie-session-here; \
install -m755 kde/lib9p/libollie9p.so $(LIBDIR)/libollie9p.so; \
@ -142,4 +141,4 @@ help:
@echo 'Components:'
@echo ' make go Build Go binaries (olliesrv, ollie-9p, toolsrv)'
@echo ' make tools Build compiled tools'
@echo ' make kde Build KDE components (auto-detects KF6/KF5)'
@echo ' make kde Build KDE components (KF6/Qt6)'

View File

@ -127,8 +127,7 @@ make
```
The top-level Makefile builds the Go services and tools, then delegates KDE/Qt
compatibility to `kde/CMakeLists.txt`. CMake detects KF6 first and falls back
to KF5; use `make kde-kf5` to force the KF5/Qt5 build.
compatibility to `kde/CMakeLists.txt`, which builds against KF6/Qt6.
## Why an Octopus?

View File

@ -44,9 +44,7 @@ Build and install it:
make
```
For KF5/Qt5, use `make kde-kf5` or `make install-kf5`.
The KDE build is delegated to `kde/CMakeLists.txt`. CMake auto-detects KF6 unless `-DOLLIE_KF5=ON` is supplied. Use `make kde-kf5` to force Qt5/KF5.
The KDE build is delegated to `kde/CMakeLists.txt` and targets KF6/Qt6.
Install targets include:
@ -80,6 +78,6 @@ The GUI uses native client code for streaming and session operations. Other inte
| Kate | `kde/kate/` |
| KIO | `kde/kio/` |
| Dolphin actions | `kde/dolphin/` |
| Plasma environment | `kde/99-ollie.sh`, `kde/99-ollie-kf5.sh` |
| Plasma environment | `kde/99-ollie.sh` |
For the public protocol and namespace, see [`architecture-9p.md`](architecture-9p.md). For the core agent runtime, see [`architecture-core.md`](architecture-core.md).

View File

@ -1,2 +0,0 @@
export QT_PLUGIN_PATH=$HOME/.local/lib/qt5/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH}
export QML_IMPORT_PATH=$HOME/.local/lib/x86_64-linux-gnu/qml${QML_IMPORT_PATH:+:$QML_IMPORT_PATH}

View File

@ -1,22 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(kde-ollie VERSION 0.1.0 LANGUAGES CXX)
option(OLLIE_KF5 "Build against KF5/Qt5 (Plasma 5.27)" OFF)
# Auto-detect: if OLLIE_KF5 not explicitly set, try KF6 first, fall back to KF5.
# Note: Gentoo and some distros don't ship a monolithic KF6Config.cmake; check
# individual components directly instead of find_package(KF6 COMPONENTS ...).
if(NOT DEFINED OLLIE_KF5 OR NOT OLLIE_KF5)
find_package(KF6Runner QUIET)
find_package(KF6CoreAddons QUIET)
if(KF6Runner_FOUND AND KF6CoreAddons_FOUND)
set(KF6_FOUND TRUE)
else()
message(STATUS "KF6 not found, falling back to KF5")
set(OLLIE_KF5 ON)
endif()
endif()
# Build lib9p (Go shared library) as part of the cmake build.
set(OLLIE9P_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so")
set(OLLIE9P_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.h")
@ -40,10 +24,6 @@ set_target_properties(ollie9p PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OLLIE9P_INCLUDE_DIR}"
)
if(OLLIE_KF5)
cmake_policy(SET CMP0160 OLD)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
@ -60,222 +40,109 @@ install(FILES "${OLLIE9P_LIBRARY}" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
if(OLLIE_KF5)
# --- Qt5 / KF5 ---
find_package(Qt5 REQUIRED COMPONENTS Core Concurrent Widgets Quick Qml QuickControls2 Network)
# --- Qt6 / KF6 ---
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Quick QuickControls2 Network)
find_package(KF6 REQUIRED COMPONENTS Runner CoreAddons)
find_package(KF6Config REQUIRED)
find_package(KF6KIO REQUIRED)
# Override KDE_INSTALL_PLUGINDIR so kcoreaddons_add_plugin installs under
# CMAKE_INSTALL_PREFIX (e.g. ~/.local/lib/qt5/plugins), not the system dir.
set(KDE_INSTALL_PLUGINDIR "lib/qt5/plugins" CACHE PATH "" FORCE)
find_package(KF5 REQUIRED COMPONENTS
Runner
CoreAddons
Config
KIO
TextEditor
SyntaxHighlighting
)
# KDE's KDE_INSTALL_PLUGINDIR defaults to lib64/plugins/ but Qt6 plugins
# live under lib64/qt6/plugins/. Override so kcoreaddons_add_plugin installs
# to the correct location.
set(KDE_INSTALL_PLUGINDIR "${QT6_INSTALL_PLUGINS}" CACHE PATH "" FORCE)
# --- KRunner Plugin ---
kcoreaddons_add_plugin(krunner_ollie SOURCES krunner/ollie_runner.cpp INSTALL_NAMESPACE "kf5/krunner")
target_link_libraries(krunner_ollie
KF5::Runner
Qt5::Core
Qt5::Widgets
)
# --- KRunner Plugin ---
kcoreaddons_add_plugin(krunner_ollie SOURCES krunner/ollie_runner.cpp INSTALL_NAMESPACE "kf6/krunner")
target_link_libraries(krunner_ollie
KF6::Runner
Qt6::Core
Qt6::Widgets
)
# --- Kate Plugin ---
kcoreaddons_add_plugin(ollie_kate SOURCES
kate/ollie_kate.cpp
kate/ollie_ghost.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "ktexteditor"
)
add_dependencies(ollie_kate lib9p_build)
target_include_directories(ollie_kate PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie_kate
KF5::TextEditor
KF5::SyntaxHighlighting
Qt5::Core
Qt5::Widgets
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- Kate Plugin ---
find_package(KF6TextEditor REQUIRED)
kcoreaddons_add_plugin(ollie_kate SOURCES
kate/ollie_kate.cpp
kate/ollie_ghost.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "kf6/ktexteditor"
)
add_dependencies(ollie_kate lib9p_build)
target_include_directories(ollie_kate PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie_kate
KF6::TextEditor
KF6::SyntaxHighlighting
Qt6::Core
Qt6::Widgets
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- KIO Worker (ollie:// protocol) ---
kcoreaddons_add_plugin(kio_ollie SOURCES
kio/ollie_kio.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "kf5/kio"
)
add_dependencies(kio_ollie lib9p_build)
target_include_directories(kio_ollie PRIVATE
${CMAKE_SOURCE_DIR}/gui
${CMAKE_SOURCE_DIR}/kio
$ENV{HOME}/.local/include
)
target_link_libraries(kio_ollie
KF5::KIOCore
Qt5::Core
Qt5::Network
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
install(FILES kio/ollie.protocol DESTINATION ${KDE_INSTALL_KSERVICESDIR})
# --- KIO Worker (ollie:// protocol) ---
kcoreaddons_add_plugin(kio_ollie SOURCES
kio/ollie_kio.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "kf6/kio"
)
add_dependencies(kio_ollie lib9p_build)
target_include_directories(kio_ollie PRIVATE
${CMAKE_SOURCE_DIR}/gui
${CMAKE_SOURCE_DIR}/kio
$ENV{HOME}/.local/include
)
target_link_libraries(kio_ollie
KF6::KIOCore
Qt6::Core
Qt6::Network
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- GUI App (9P-based) ---
# Strip Qt6-only grouped palette syntax (palette.active.*, palette.inactive.*,
# palette.disabled.*) — Qt5 QML doesn't support color-group qualifiers.
# ThemeManager::applyPalette() sets the application palette which Qt Quick
# Controls 2 picks up automatically.
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/gui/main.qml _QML_SRC)
string(REGEX REPLACE "[ \t]*(//[^\n]*palette[^\n]*\n|palette\\.(active|inactive|disabled)\\.[^\n]*\n)" "" _QML_SRC "${_QML_SRC}")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/main.qml "${_QML_SRC}")
# Copy component QML files (no palette stripping needed - they don't use grouped palette)
configure_file(gui/SettingsDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/SettingsDialog.qml COPYONLY)
configure_file(gui/NewSessionDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/NewSessionDialog.qml COPYONLY)
configure_file(gui/NewAgentDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/NewAgentDialog.qml COPYONLY)
configure_file(gui/GoalDialog.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/GoalDialog.qml COPYONLY)
configure_file(gui/ChatBlockDelegate.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/ChatBlockDelegate.qml COPYONLY)
configure_file(gui/SessionTree.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/SessionTree.qml COPYONLY)
configure_file(gui/ChatPane.qml ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/ChatPane.qml COPYONLY)
configure_file(gui/ollie.svg ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/ollie.svg COPYONLY)
configure_file(gui/qml.qrc ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/qml.qrc COPYONLY)
qt5_add_resources(GUI_KF5_QRC ${CMAKE_CURRENT_BINARY_DIR}/gui-kf5/qml.qrc)
add_executable(ollie-gui
gui/main.cpp
gui/ollie9pclient.cpp
gui/sessionmodel.cpp
gui/lib9pclient.cpp
gui/nativestreamer.cpp
gui/chatblockmodel.cpp
gui/thememanager.cpp
gui/clipboardhelper.cpp
gui/plumber.cpp
${GUI_KF5_QRC}
)
add_dependencies(ollie-gui lib9p_build)
target_include_directories(ollie-gui PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie-gui
Qt5::Core
Qt5::Widgets
Qt5::Quick
Qt5::QuickControls2
Qt5::Network
KF5::ConfigCore
KF5::SyntaxHighlighting
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- GUI App (9P-based, no D-Bus) ---
find_package(KF6SyntaxHighlighting REQUIRED)
add_executable(ollie-gui
gui/main.cpp
gui/ollie9pclient.cpp
gui/sessionmodel.cpp
gui/lib9pclient.cpp
gui/nativestreamer.cpp
gui/chatblockmodel.cpp
gui/thememanager.cpp
gui/clipboardhelper.cpp
gui/plumber.cpp
)
add_dependencies(ollie-gui lib9p_build)
target_include_directories(ollie-gui PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie-gui
Qt6::Core
Qt6::Widgets
Qt6::Quick
Qt6::QuickControls2
Qt6::Network
KF6::ConfigCore
KF6::SyntaxHighlighting
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
qt_add_resources(ollie-gui "gui"
PREFIX "/"
BASE gui
FILES
gui/main.qml
gui/SettingsDialog.qml
gui/NewSessionDialog.qml
gui/NewAgentDialog.qml
gui/GoalDialog.qml
gui/ChatBlockDelegate.qml
gui/SessionTree.qml
gui/ChatPane.qml
)
# --- Install ---
install(TARGETS ollie-gui DESTINATION ${KDE_INSTALL_BINDIR})
# --- Install ---
install(TARGETS ollie-gui DESTINATION ${KDE_INSTALL_BINDIR})
else()
# --- Qt6 / KF6 ---
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Quick QuickControls2 Network)
find_package(KF6 REQUIRED COMPONENTS Runner CoreAddons)
find_package(KF6Config REQUIRED)
find_package(KF6KIO REQUIRED)
# KDE's KDE_INSTALL_PLUGINDIR defaults to lib64/plugins/ but Qt6 plugins
# live under lib64/qt6/plugins/. Override so kcoreaddons_add_plugin installs
# to the correct location.
set(KDE_INSTALL_PLUGINDIR "${QT6_INSTALL_PLUGINS}" CACHE PATH "" FORCE)
# --- KRunner Plugin ---
kcoreaddons_add_plugin(krunner_ollie SOURCES krunner/ollie_runner.cpp INSTALL_NAMESPACE "kf6/krunner")
target_link_libraries(krunner_ollie
KF6::Runner
Qt6::Core
Qt6::Widgets
)
# --- Kate Plugin ---
find_package(KF6TextEditor REQUIRED)
kcoreaddons_add_plugin(ollie_kate SOURCES
kate/ollie_kate.cpp
kate/ollie_ghost.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "kf6/ktexteditor"
)
add_dependencies(ollie_kate lib9p_build)
target_include_directories(ollie_kate PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie_kate
KF6::TextEditor
KF6::SyntaxHighlighting
Qt6::Core
Qt6::Widgets
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- KIO Worker (ollie:// protocol) ---
kcoreaddons_add_plugin(kio_ollie SOURCES
kio/ollie_kio.cpp
gui/lib9pclient.cpp
INSTALL_NAMESPACE "kf6/kio"
)
add_dependencies(kio_ollie lib9p_build)
target_include_directories(kio_ollie PRIVATE
${CMAKE_SOURCE_DIR}/gui
${CMAKE_SOURCE_DIR}/kio
$ENV{HOME}/.local/include
)
target_link_libraries(kio_ollie
KF6::KIOCore
Qt6::Core
Qt6::Network
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
# --- GUI App (9P-based, no D-Bus) ---
find_package(KF6SyntaxHighlighting REQUIRED)
add_executable(ollie-gui
gui/main.cpp
gui/ollie9pclient.cpp
gui/sessionmodel.cpp
gui/lib9pclient.cpp
gui/nativestreamer.cpp
gui/chatblockmodel.cpp
gui/thememanager.cpp
gui/clipboardhelper.cpp
gui/plumber.cpp
)
add_dependencies(ollie-gui lib9p_build)
target_include_directories(ollie-gui PRIVATE
${CMAKE_SOURCE_DIR}/gui
$ENV{HOME}/.local/include
)
target_link_libraries(ollie-gui
Qt6::Core
Qt6::Widgets
Qt6::Quick
Qt6::QuickControls2
Qt6::Network
KF6::ConfigCore
KF6::SyntaxHighlighting
${CMAKE_CURRENT_SOURCE_DIR}/lib9p/libollie9p.so
)
qt_add_resources(ollie-gui "gui"
PREFIX "/"
BASE gui
FILES
gui/main.qml
gui/SettingsDialog.qml
gui/NewSessionDialog.qml
gui/NewAgentDialog.qml
gui/GoalDialog.qml
gui/ChatBlockDelegate.qml
gui/SessionTree.qml
gui/ChatPane.qml
)
# --- Install ---
install(TARGETS ollie-gui DESTINATION ${KDE_INSTALL_BINDIR})
endif()
# The ollie:// KIO protocol description.
install(FILES kio/ollie.protocol DESTINATION ${KDE_INSTALL_KSERVICESDIR})

View File

@ -32,16 +32,14 @@ There is no system-tray component.
## Dependencies
- Qt 6 (Core, Widgets, Quick, QuickControls2, Network), or Qt 5 equivalents when `OLLIE_KF5=ON`
- Qt 6 (Core, Widgets, Quick, QuickControls2, Network)
- ECM (Extra CMake Modules)
- KF6/KF5 Runner and CoreAddons for KRunner
- KF6/KF5 TextEditor and SyntaxHighlighting for Kate
- KF6/KF5 KIO for the `ollie://` worker
- KF6 Runner and CoreAddons for KRunner
- KF6 TextEditor and SyntaxHighlighting for Kate
- KF6 KIO for the `ollie://` worker
- `libollie9p.so` and its header from `kde/lib9p/`
- A 9P CLI named `9p` (KRunner) and `ollie-9p` (Dolphin scripts)
KF6/Qt6 is selected by default when KF6 Runner and CoreAddons are available. Set `-DOLLIE_KF5=ON` to force the KF5/Qt5 build.
## Build
The KDE directory is a CMake project. From `kde/`:
@ -51,18 +49,11 @@ cmake -S . -B build-cmake
cmake --build build-cmake -j
```
For KF5/Qt5:
```sh
cmake -S . -B build-kf5 -DOLLIE_KF5=ON
cmake --build build-kf5 -j
```
The build produces:
- `ollie-gui`
- `lib/kf6/krunner/krunner_ollie.so` and `lib/kf6/ktexteditor/ollie_kate.so` (or `kf5` paths)
- `lib/kf6/kio/kio_ollie.so` (or `kf5` paths)
- `lib/kf6/krunner/krunner_ollie.so` and `lib/kf6/ktexteditor/ollie_kate.so`
- `lib/kf6/kio/kio_ollie.so`
- `libollie9p.so`, installed to `${CMAKE_INSTALL_LIBDIR}` (normally `lib` or `lib64`)
The CMake project installs `ollie-gui` and `libollie9p.so`. The plugins, KIO metadata, desktop files, Dolphin scripts, icon, and Plasma environment files are source-tree assets and must be installed or packaged separately; the `just kde` and `just install-kde` commands described by older documentation are not provided in this repository.
@ -79,13 +70,13 @@ cmake --install build-cmake
That installs `ollie-gui` and `libollie9p.so` to the prefix's KDE bindir and `${CMAKE_INSTALL_LIBDIR}`, respectively. To use the other components, install the matching built plugin and source assets into the locations used by your KDE/Qt installation:
- KRunner: the `kf6/krunner` (or `kf5/krunner`) plugin directory, plus `krunner/metadata.json`
- Kate: the `kf6/ktexteditor` (or `kf5/ktexteditor`) plugin directory, plus `kate/metadata.json`
- KRunner: the `kf6/krunner` plugin directory, plus `krunner/metadata.json`
- Kate: the `kf6/ktexteditor` plugin directory, plus `kate/metadata.json`
- KIO: the corresponding KIO plugin directory, `kio/ollie.protocol`, and `kio/ollie.json`
- Dolphin: `dolphin/*.desktop` in `~/.local/share/kio/servicemenus/` and both helper scripts in `~/.local/bin/`
- GUI integration: `gui/org.ollie.gui.desktop`, `gui/ollie.svg`, and the appropriate `99-ollie*.sh` environment file
- GUI integration: `gui/org.ollie.gui.desktop`, `gui/ollie.svg`, and the `99-ollie.sh` environment file
The exact plugin directories are distribution- and Qt-version-dependent. After installing KDE metadata or plugins, rebuild the relevant service cache (for example `kbuildsycoca6` or `kbuildsycoca5`) and restart the affected KDE application.
The exact plugin directories are distribution-dependent. After installing KDE metadata or plugins, rebuild the service cache (`kbuildsycoca6`) and restart the affected KDE application.
## Usage
@ -162,7 +153,7 @@ Enable the "Ollie" plugin in Settings → Configure Kate → Plugins. The plugin
```text
kde/
├── CMakeLists.txt # Qt5/KF5 and Qt6/KF6 build configuration
├── CMakeLists.txt # Qt6/KF6 build configuration
├── README.md
├── gui/ # ollie-gui (C++/QML) and desktop assets
│ ├── main.cpp, main.qml
@ -177,7 +168,7 @@ kde/
├── kio/ # `ollie://` KIO worker and protocol metadata
├── dolphin/ # service menus and helper scripts
├── lib9p/ # Go-built libollie9p shared library/header
└── 99-ollie*.sh # Qt/KF-specific Plasma environment snippets
└── 99-ollie.sh # Qt/KF Plasma environment snippet
```
`build/` and `build-cmake/` are local build directories and are not source components.
@ -189,13 +180,13 @@ kde/
- The GUI maintains native chat, agent-state, and event streams and polls the daemon heartbeat every 2.5 seconds for recovery.
- The Kate plugin is lightweight: context actions, agent management, and ghost text; it has no chat panel.
- The KIO worker exposes the server's namespace as a mutable virtual filesystem, not as a local mirror.
- CMake supports KF6/Qt6 and KF5/Qt5 via `OLLIE_KF5`.
- CMake targets KF6/Qt6.
- The CMake install target installs `libollie9p.so` to `${CMAKE_INSTALL_LIBDIR}` (`lib` or `lib64`), alongside the executable rather than under the Qt plugin directory.
## Troubleshooting
**Plugins not appearing after installation:**
- Run `kbuildsycoca6` (KF6) or `kbuildsycoca5` (KF5) to rebuild system cache
- Run `kbuildsycoca6` to rebuild the system cache
- Restart Plasma: `plasmashell --replace` or log out/in
**"9p" or "ollie-9p" not found:**
@ -208,7 +199,7 @@ kde/
- The clients resolve the default namespace from `NAMESPACE`, or from `/tmp/ns.$USER.$DISPLAY/ollie` when `NAMESPACE` is unset.
**Kate plugin crashes or is rejected:**
- Check that Kate and the plugin use the same Qt major version (Qt5 vs Qt6).
- Check that Kate and the plugin use Qt6.
- Verify that `libollie9p.so` and its runtime dependencies are discoverable.
**Ghost text not appearing:**

View File

@ -1,16 +0,0 @@
[Desktop Entry]
Type=Service
X-KDE-ServiceTypes=KonqPopupMenu/Plugin
MimeType=all/allfiles;inode/directory;
Actions=askOllie;sessionHere;
X-KDE-AuthorizeAction=shell_access
[Desktop Action askOllie]
Name=Ask Ollie about this
Icon=ollie
Exec=ollie-ask %f
[Desktop Action sessionHere]
Name=Start Ollie session here
Icon=ollie
Exec=ollie-session-here %f

View File

@ -6,9 +6,7 @@
#include <QHash>
#include <QSet>
#include <QTimer>
#if QT_VERSION_MAJOR >= 6
#include <QQmlEngine>
#endif
#include "lib9pclient.h"
#include "nativestreamer.h"
@ -18,10 +16,8 @@
class Ollie9pClient : public QObject
{
Q_OBJECT
#if QT_VERSION_MAJOR >= 6
QML_ELEMENT
QML_SINGLETON
#endif
Q_PROPERTY(QVariantList sessions READ sessions NOTIFY sessionsChanged)
Q_PROPERTY(QString activeSessionId READ activeSessionId WRITE setActiveSessionId NOTIFY activeSessionIdChanged)

View File

@ -3,19 +3,15 @@
#include <QObject>
#include <QProcess>
#if QT_VERSION_MAJOR >= 6
#include <QQmlEngine>
#endif
// Plumber wraps plan9port's plumb command for context-aware actions.
// B3-click on text → plumber routes to appropriate handler (editor, browser, etc.)
class Plumber : public QObject
{
Q_OBJECT
#if QT_VERSION_MAJOR >= 6
QML_ELEMENT
QML_SINGLETON
#endif
public:
explicit Plumber(QObject *parent = nullptr);

View File

@ -1,13 +1,6 @@
#include "ollie_ghost.h"
#include "ollie_kate.h"
#include <ktexteditor_version.h>
#if KTEXTEDITOR_VERSION_MAJOR < 6
#include <KTextEditor/InlineNoteInterface>
#include <KTextEditor/CodeCompletionInterface>
#include <KTextEditor/ConfigInterface>
#endif
#include <QApplication>
#include <QFileInfo>
#include <QPaintEvent>
@ -110,16 +103,7 @@ OllieGhostProvider::OllieGhostProvider(KTextEditor::View *view, OllieKatePlugin
this, &OllieGhostProvider::onTextChanged);
connect(view, &QObject::destroyed, this, [this]() { m_view = nullptr; });
#if KTEXTEDITOR_VERSION_MAJOR >= 6
view->registerInlineNoteProvider(this);
#else
// Use dynamic_cast instead of qobject_cast: during view construction,
// qt_metacast() can access uninitialized KateViewConfig and crash.
// dynamic_cast only needs the vtable which is valid once the C++ ctor runs.
auto *noteIface = dynamic_cast<KTextEditor::InlineNoteInterface *>(view);
if (noteIface)
noteIface->registerInlineNoteProvider(this);
#endif
}
OllieGhostProvider::~OllieGhostProvider()
@ -128,23 +112,13 @@ OllieGhostProvider::~OllieGhostProvider()
// by Qt's child cleanup before we get here — just null it out.
m_overlay = nullptr;
if (m_view) {
#if KTEXTEDITOR_VERSION_MAJOR >= 6
m_view->unregisterInlineNoteProvider(this);
#else
auto *iface = dynamic_cast<KTextEditor::InlineNoteInterface *>(m_view);
if (iface)
iface->unregisterInlineNoteProvider(this);
#endif
}
}
// --- InlineNoteProvider interface ---
#if KTEXTEDITOR_VERSION_MAJOR >= 6
QList<int> OllieGhostProvider::inlineNotes(int line) const
#else
QVector<int> OllieGhostProvider::inlineNotes(int line) const
#endif
{
if (m_suggestionLines.isEmpty() || m_suggestionStartLine < 0)
return {};
@ -177,14 +151,9 @@ QSize OllieGhostProvider::inlineNoteSize(const KTextEditor::InlineNote &note) co
return QSize(qRound(width), note.lineHeight());
}
#if KTEXTEDITOR_VERSION_MAJOR >= 6
void OllieGhostProvider::paintInlineNote(const KTextEditor::InlineNote &note, QPainter &painter, Qt::LayoutDirection direction) const
{
Q_UNUSED(direction);
#else
void OllieGhostProvider::paintInlineNote(const KTextEditor::InlineNote &note, QPainter &painter) const
{
#endif
if (m_suggestionLines.isEmpty())
return;
@ -266,14 +235,8 @@ bool OllieGhostProvider::hasSuggestion() const
void OllieGhostProvider::onCursorPositionChanged()
{
// Don't react to cursor changes while completion popup is active
#if KTEXTEDITOR_VERSION_MAJOR >= 6
if (m_view->isCompletionActive())
return;
#else
auto *ccIface = dynamic_cast<KTextEditor::CodeCompletionInterface *>(m_view);
if (ccIface && ccIface->isCompletionActive())
return;
#endif
if (hasSuggestion()) {
KTextEditor::Cursor cur = m_view->cursorPosition();
@ -431,16 +394,7 @@ void OllieGhostProvider::showOverlay()
QStringList contLines = m_suggestionLines.mid(1);
// Get font from the view's config
#if KTEXTEDITOR_VERSION_MAJOR >= 6
QFont font = m_view->configValue(QStringLiteral("font")).value<QFont>();
#else
QFont font;
auto *cfgIface = dynamic_cast<KTextEditor::ConfigInterface *>(m_view);
if (cfgIface)
font = cfgIface->configValue(QStringLiteral("font")).value<QFont>();
else
font = m_view->font();
#endif
m_overlay->setLines(contLines, font);
// Position the overlay below the cursor line

View File

@ -5,7 +5,6 @@
#include <KTextEditor/View>
#include <KTextEditor/Document>
#include <KTextEditor/Cursor>
#include <ktexteditor_version.h>
#include <QTimer>
#include <QPainter>
@ -41,17 +40,9 @@ public:
~OllieGhostProvider() override;
// InlineNoteProvider interface
#if KTEXTEDITOR_VERSION_MAJOR >= 6
QList<int> inlineNotes(int line) const override;
#else
QVector<int> inlineNotes(int line) const override;
#endif
QSize inlineNoteSize(const KTextEditor::InlineNote &note) const override;
#if KTEXTEDITOR_VERSION_MAJOR >= 6
void paintInlineNote(const KTextEditor::InlineNote &note, QPainter &painter, Qt::LayoutDirection direction) const override;
#else
void paintInlineNote(const KTextEditor::InlineNote &note, QPainter &painter) const override;
#endif
/// Accept the current suggestion (insert into document). Returns true if accepted.
bool accept();

View File

@ -6,10 +6,6 @@
#include <KConfigGroup>
#include <KTextEditor/Document>
#include <KTextEditor/Editor>
#include <ktexteditor_version.h>
#if KTEXTEDITOR_VERSION_MAJOR < 6
#include <KTextEditor/CodeCompletionInterface>
#endif
#include <QApplication>
#include <QCheckBox>
@ -26,7 +22,6 @@ K_PLUGIN_CLASS_WITH_JSON(OllieKatePlugin, "metadata.json")
// --- Plugin ---
#if QT_VERSION_MAJOR >= 6
OllieKatePlugin::OllieKatePlugin(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
: KTextEditor::Plugin(parent)
{
@ -34,14 +29,6 @@ OllieKatePlugin::OllieKatePlugin(QObject *parent, const KPluginMetaData &data, c
Q_UNUSED(args);
loadConfig();
}
#else
OllieKatePlugin::OllieKatePlugin(QObject *parent, const QVariantList &args)
: KTextEditor::Plugin(parent)
{
Q_UNUSED(args);
loadConfig();
}
#endif
QObject *OllieKatePlugin::createView(KTextEditor::MainWindow *mainWindow)
{
@ -166,7 +153,6 @@ OllieKateView::OllieKateView(OllieKatePlugin *plugin, KTextEditor::MainWindow *m
QObject::connect(projectView, SIGNAL(projectChanged()),
this, SLOT(onProjectChanged()));
}
#if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(5, 78, 0)
connect(mainWindow, &KTextEditor::MainWindow::pluginViewCreated,
this, [this](const QString &name, QObject *view) {
if (name == "kateprojectplugin") {
@ -176,7 +162,6 @@ OllieKateView::OllieKateView(OllieKatePlugin *plugin, KTextEditor::MainWindow *m
updateStatusLabel();
}
});
#endif
// Context menu on initial view
if (auto *view = mainWindow->activeView())
@ -623,16 +608,9 @@ bool OllieKateView::eventFilter(QObject *obj, QEvent *event)
if (m_ghost->hasSuggestion()) {
auto *activeView = m_mainWindow->activeView();
#if KTEXTEDITOR_VERSION_MAJOR >= 6
if (QApplication::activePopupWidget() ||
(activeView && activeView->isCompletionActive()))
return QObject::eventFilter(obj, event);
#else
auto *ccIface = activeView ? dynamic_cast<KTextEditor::CodeCompletionInterface *>(activeView) : nullptr;
if (QApplication::activePopupWidget() ||
(ccIface && ccIface->isCompletionActive()))
return QObject::eventFilter(obj, event);
#endif
if (keyEvent->key() == Qt::Key_Tab && keyEvent->modifiers() == Qt::NoModifier) {
if (m_ghost->accept()) {

View File

@ -5,9 +5,7 @@
#include <KTextEditor/ConfigPage>
#include <KTextEditor/MainWindow>
#include <KTextEditor/View>
#if QT_VERSION_MAJOR >= 6
#include <KPluginMetaData>
#endif
#include <QPointer>
#include <QLabel>
@ -25,11 +23,7 @@ class OllieKatePlugin : public KTextEditor::Plugin
Q_OBJECT
public:
#if QT_VERSION_MAJOR >= 6
explicit OllieKatePlugin(QObject *parent, const KPluginMetaData &data, const QVariantList &args = {});
#else
explicit OllieKatePlugin(QObject *parent, const QVariantList &args = {});
#endif
~OllieKatePlugin() override = default;
QObject *createView(KTextEditor::MainWindow *mainWindow) override;

View File

@ -12,7 +12,6 @@
using namespace KIO;
// Plugin factory — KIO loads this .so and calls the appropriate create method
#if QT_VERSION_MAJOR >= 6
class OllieWorkerFactory : public KIO::WorkerFactory
{
Q_OBJECT
@ -24,26 +23,8 @@ public:
return std::make_unique<OllieWorker>(pool, app);
}
};
#else
class OllieWorkerFactory : public KIO::RealWorkerFactory
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.kio.worker.ollie" FILE "ollie.json")
public:
using RealWorkerFactory::RealWorkerFactory;
std::unique_ptr<SlaveBase> createWorker(const QByteArray &pool, const QByteArray &app) override
{
Q_UNUSED(pool); Q_UNUSED(app);
return nullptr; // unused — KIO calls createRealWorker for RealWorkerFactory
}
std::unique_ptr<WorkerBase> createRealWorker(const QByteArray &pool, const QByteArray &app) override
{
return std::make_unique<OllieWorker>(pool, app);
}
};
#endif
// kdemain entry point — KF5 KIO launches workers by calling this
// kdemain entry point — legacy KIO launch path
extern "C" Q_DECL_EXPORT int kdemain(int argc, char **argv)
{
QCoreApplication app(argc, argv);

View File

@ -26,13 +26,8 @@ static QString ollieIconPath()
return path;
}
#if QT_VERSION_MAJOR >= 6
OllieRunner::OllieRunner(QObject *parent, const KPluginMetaData &data)
: AbstractRunner(parent, data)
#else
OllieRunner::OllieRunner(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
: AbstractRunner(parent, data, args)
#endif
{
}

View File

@ -6,22 +6,14 @@
#include <KRunner/QueryMatch>
#include <QProcess>
#if QT_VERSION_MAJOR >= 6
namespace RunnerNS = KRunner;
#else
namespace RunnerNS = Plasma;
#endif
class OllieRunner : public RunnerNS::AbstractRunner
{
Q_OBJECT
public:
#if QT_VERSION_MAJOR >= 6
OllieRunner(QObject *parent, const KPluginMetaData &data);
#else
OllieRunner(QObject *parent, const KPluginMetaData &data, const QVariantList &args);
#endif
void match(RunnerNS::RunnerContext &context) override;
void run(const RunnerNS::RunnerContext &context, const RunnerNS::QueryMatch &match) override;