3 Commits

Author SHA1 Message Date
de32a524da docs: testium_assist install instructions (Open VSX / VSCode)
Manual (modes.rst) and README: install the extension from Open VSX in
VSCodium/Cursor/etc., and as a .vsix by hand in Microsoft VSCode; note
that testium must be on PATH or set via testium.serverPath.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 23:56:34 +02:00
2515213b14 release preparation 2026-05-31 16:15:52 +02:00
0376b77494 fix(gui): show the testium icon in the GNOME task bar (Wayland)
Set the app id via setDesktopFileName so the window stops inheriting the
launcher's class ("python3" under the AppImage), which is what GNOME was
keying the wrong icon off. On native Wayland the task-bar icon comes from
an installed desktop file matched to the app id (setWindowIcon is
ignored there), so on Linux drop an idempotent desktop entry + 256px icon
under ~/.local/share. Flatpak keeps its own id/desktop; Windows / macOS
use the window icon. No-op off Linux.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:14:04 +02:00
6 changed files with 163 additions and 1 deletions

View File

@@ -129,6 +129,22 @@ A VSCode / VSCodium client extension (`testium_assist`) wraps `testium lsp`;
the schema is built from testium itself, so new item types and parameters the schema is built from testium itself, so new item types and parameters
appear in the editor on the next testium upgrade with no client change. appear in the editor on the next testium upgrade with no client change.
It is published on [Open VSX](https://open-vsx.org/extension/testium/testium-assist),
so in **VSCodium, Cursor, Windsurf, Theia and code-server** it installs from the
Extensions view (search `testium-assist`) or with
`codium --install-extension testium.testium-assist`.
**Microsoft VSCode** does not list Open VSX extensions, so install the `.vsix`
by hand — download it from the Open VSX page above, then *Extensions → ⋯ →
Install from VSIX…* or:
```sh
code --install-extension testium-assist-0.1.0.vsix
```
The extension runs `testium lsp`, so `testium` must be on the `PATH` (otherwise
point the `testium.serverPath` setting at the binary/AppImage).
## Troubleshooting ## Troubleshooting
### `wl_proxy_marshal_flags` symbol error ### `wl_proxy_marshal_flags` symbol error

View File

@@ -67,3 +67,36 @@ dependencies:
:caption: enable the language server for a wheel / source install :caption: enable the language server for a wheel / source install
pip install 'testium[lsp]' pip install 'testium[lsp]'
Installing the VSCode / VSCodium extension
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The *testium_assist* client extension is published on `Open VSX
<https://open-vsx.org/extension/testium/testium-assist>`_, the registry used by
VSCodium, Cursor, Windsurf, Eclipse Theia and code-server. In those editors,
open the Extensions view and search ``testium-assist``, or install it from the
command line:
.. code-block:: text
:caption: install in VSCodium and other Open VSX editors
codium --install-extension testium.testium-assist
Microsoft *VSCode* uses a different marketplace that does not list Open VSX
extensions, so install the packaged ``.vsix`` by hand. Download it from the
Open VSX page linked above, then either choose *Extensions**⋯*
*Install from VSIX…* in the UI, or run:
.. code-block:: text
:caption: install the .vsix in Microsoft VSCode
code --install-extension testium-assist-0.1.0.vsix
The extension launches ``testium lsp``, so the ``testium`` command must be on
the ``PATH``. If *testium* is installed elsewhere — a specific binary or an
AppImage — point the ``testium.serverPath`` setting at it instead.
Once installed, open a ``.tum`` file: completion of item types, hover
documentation and the outline view become available. If nothing happens, check
that no ``files.associations`` entry forces ``*.tum`` to another language (it
must stay the ``tum`` language the extension provides).

Binary file not shown.

View File

@@ -1 +1 @@
0.2 0.2.1

View File

@@ -0,0 +1,95 @@
"""Install a desktop entry + icon under the user's data dir so desktop shells
show the testium icon in the task bar / dock.
On a native Wayland session GNOME takes a window's task-bar icon from the
``.desktop`` file whose name (or ``StartupWMClass``) matches the window
``app_id`` — ``QGuiApplication.setWindowIcon`` is ignored there. The portable
channels (source checkout, PyInstaller binary, AppImage) install no system
desktop file, so we drop an idempotent one in ``~/.local/share``. The window
``app_id`` is set to ``testium`` (see ``QApplication.setDesktopFileName`` in
``testium_win``), which is exactly this file's base name.
Flatpak ships its own ``org.testium.Testium.desktop`` and keeps its own app id,
so the caller skips this integration there.
"""
import os
import sys
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
# Must match QApplication.setDesktopFileName(...) for the GUI, and is used as
# both the desktop-file base name and the StartupWMClass.
APP_ID = "testium"
def _launch_command():
"""Best-effort Exec= for the menu entry. Not needed for icon matching, but
makes the entry actually launchable when possible."""
appimage = os.environ.get("APPIMAGE")
if appimage:
return f'"{appimage}"'
if getattr(sys, "frozen", False):
return f'"{os.path.abspath(sys.executable)}"'
argv0 = os.path.abspath(sys.argv[0]) if sys.argv and sys.argv[0] else ""
if argv0 and os.path.exists(argv0):
return f'"{os.path.abspath(sys.executable)}" "{argv0}"'
return f'"{os.path.abspath(sys.executable)}" -m testium'
def ensure_desktop_entry():
"""Create (or refresh) ~/.local/share icon + desktop entry. Best-effort:
any failure is swallowed so it can never take the GUI down.
Freedesktop-only: a no-op off Linux (Windows / macOS use the window icon)."""
if not sys.platform.startswith("linux"):
return
try:
data_home = os.environ.get("XDG_DATA_HOME") or os.path.join(
os.path.expanduser("~"), ".local", "share"
)
icon_dir = os.path.join(data_home, "icons", "hicolor", "256x256", "apps")
app_dir = os.path.join(data_home, "applications")
icon_path = os.path.join(icon_dir, f"{APP_ID}.png")
desktop_path = os.path.join(app_dir, f"{APP_ID}.desktop")
os.makedirs(icon_dir, exist_ok=True)
os.makedirs(app_dir, exist_ok=True)
# Icon: render the bundled Qt resource to a PNG once. Requires a live
# QGuiApplication (the caller creates it before calling us).
if not os.path.isfile(icon_path):
pixmap = QPixmap(u":/black/testium_logo.png")
if not pixmap.isNull():
pixmap = pixmap.scaled(
256, 256,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
pixmap.save(icon_path, "PNG")
# Absolute Icon= path so the shell resolves it without an icon-cache
# refresh; StartupWMClass lets X11 / XWayland match too.
desktop = (
"[Desktop Entry]\n"
"Type=Application\n"
"Name=Testium\n"
"Comment=Test sequencer\n"
f"Icon={icon_path}\n"
f"Exec={_launch_command()} %f\n"
"Terminal=false\n"
f"StartupWMClass={APP_ID}\n"
"Categories=Utility;Development;\n"
)
# Write only when missing or changed, to avoid needless menu churn.
current = None
if os.path.isfile(desktop_path):
with open(desktop_path, "r") as fh:
current = fh.read()
if current != desktop:
with open(desktop_path, "w") as fh:
fh.write(desktop)
except Exception:
# Desktop integration is a nicety, never a hard requirement.
pass

View File

@@ -678,6 +678,24 @@ def MainWin(
debug=False, debug=False,
): ):
app = QApplication(sys.argv) app = QApplication(sys.argv)
# Application identity so desktop shells (GNOME, ...) show the testium
# icon in the task bar / dock instead of a generic one. On Wayland this
# sets the surface app_id; on X11/XWayland it sets WM_CLASS, so the window
# stops inheriting the launcher's class (e.g. "python3" under the AppImage,
# which is what GNOME was keying the wrong icon off) and the window icon
# below is used as the fallback. In Flatpak the id must be the Flatpak app
# id so it matches the installed desktop file.
app.setApplicationName("Testium")
app.setApplicationDisplayName("Testium")
app.setDesktopFileName(os.environ.get("FLATPAK_ID", "testium"))
app.setWindowIcon(QIcon(u":/black/testium_logo.png"))
# On native Wayland the task-bar icon comes from an installed desktop file
# matched to the app_id, not from setWindowIcon(). Flatpak ships its own;
# for the other Linux channels drop an idempotent one under ~/.local/share.
# Windows / macOS use the window icon set above, so this is Linux-only.
if sys.platform.startswith("linux") and not os.environ.get("FLATPAK_ID"):
from main_win.desktop_integration import ensure_desktop_entry
ensure_desktop_entry()
ui = MainWindow( ui = MainWindow(
test_file, test_file,
config_files, config_files,