Compare commits

...

16 Commits
v47.0 ... main

Author SHA1 Message Date
Sonny Piers
730729b2f1 f 2025-07-06 18:08:09 +02:00
Sonny Piers
b5d2e7806f Prepare v48 2025-04-18 14:02:31 +02:00
Sonny Piers
a48d234c56 Use GNOME 48 2025-04-18 14:02:31 +02:00
Angelo Verlain Shema
34fbe9f018
fix: HoverProvider get_iter crashing (#1003) 2025-03-24 20:54:55 +01:00
Sonny Piers
dc0c931917 Update troll 2025-03-13 14:50:26 +01:00
Sonny Piers
af32c09966 cli: Add Interrupt to simplify control flow 2025-03-13 14:50:26 +01:00
Sonny Piers
584b9e440e cli: Deduplicate code with a diagnose fn 2025-03-13 14:50:26 +01:00
Sonny Piers
2a65be9e33 cli: Split by lang 2025-03-11 17:53:51 +01:00
Sonny Piers
630dbb486f Minor changes 2025-03-11 17:53:51 +01:00
Sonny
8ec88e697b
Reformat files for Blueprint 0.16 (#1001) 2025-03-08 21:26:19 +01:00
Sonny
987a9d4587
Update dependencies (#1000) 2025-03-08 20:05:40 +01:00
Sonny Piers
42c5e6c1d7 v47.1 2025-01-24 15:45:34 +01:00
UrtsiSantsi
39f6eb9b51
Use CSS variables instead of GTK-specific syntax (#997) 2025-01-24 13:47:41 +01:00
Sonny Piers
156186b1c9 Fix permissions dialog
Closes https://github.com/workbenchdev/Workbench/issues/996
2025-01-24 13:40:55 +01:00
Sonny Piers
e97114eee2 Update libportal to 0.9.0 2025-01-24 13:40:23 +01:00
Sonny Piers
0719075808 Update Blueprint to 0.16.0 2025-01-24 13:39:31 +01:00
48 changed files with 2328 additions and 2164 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ install
__pycache__ __pycache__
*.pyc *.pyc
*.gresource *.gresource
.frun
# IDEs / editors # IDEs / editors
.idea .idea

View File

@ -29,5 +29,11 @@
"build", "build",
"builddir" "builddir"
], ],
"vala.languageServerPath": "${workspaceFolder}/.flatpak/vala-language-server.sh" "vala.languageServerPath": "${workspaceFolder}/.flatpak/vala-language-server.sh",
"[meson]": {
"editor.defaultFormatter": "mesonbuild.mesonbuild"
},
"mesonbuild.configureOnOpen": false,
"mesonbuild.buildFolder": "_build",
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh"
} }

View File

@ -4,7 +4,7 @@ SHELL:=/bin/bash -O globstar
setup: setup:
flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install --or-update --user --noninteractive flathub org.gnome.Sdk//47 org.flatpak.Builder org.freedesktop.Sdk.Extension.rust-stable//24.08 org.freedesktop.Sdk.Extension.vala//24.08 org.freedesktop.Sdk.Extension.llvm18//24.08 org.freedesktop.Sdk.Extension.node20//24.08 org.freedesktop.Sdk.Extension.typescript//24.08 flatpak install --or-update --user --noninteractive flathub org.gnome.Sdk//48 org.flatpak.Builder org.freedesktop.Sdk.Extension.rust-stable//24.08 org.freedesktop.Sdk.Extension.vala//24.08 org.freedesktop.Sdk.Extension.llvm18//24.08 org.freedesktop.Sdk.Extension.node20//24.08 org.freedesktop.Sdk.Extension.typescript//24.08
# flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo # flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo
# flatpak remote-add --user --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo # flatpak remote-add --user --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo
# flatpak install --or-update --user --noninteractive gnome-nightly org.gnome.Sdk//master # flatpak install --or-update --user --noninteractive gnome-nightly org.gnome.Sdk//master
@ -43,8 +43,8 @@ lint:
# CSS # CSS
./build-aux/fun workbench-cli check css src/**/*.css ./build-aux/fun workbench-cli check css src/**/*.css
# Flatpak manifests # Flatpak manifests
flatpak run --user --command=flatpak-builder-lint org.flatpak.Builder manifest --exceptions build-aux/re.sonny.Workbench.json flatpak run --user --command=flatpak-builder-lint org.flatpak.Builder manifest --exceptions --user-exceptions ./build-aux/exceptions.json build-aux/re.sonny.Workbench.json
flatpak run --user --command=flatpak-builder-lint org.flatpak.Builder manifest --exceptions build-aux/re.sonny.Workbench.Devel.json flatpak run --user --command=flatpak-builder-lint org.flatpak.Builder manifest --exceptions --user-exceptions ./build-aux/exceptions.json build-aux/re.sonny.Workbench.Devel.json
unit: unit:
./build-aux/fun gjs -m ./troll/tst/bin.js test/*.test.js ./build-aux/fun gjs -m ./troll/tst/bin.js test/*.test.js

View File

@ -31,9 +31,9 @@ Among other things, Workbench comes with
| | Formatter | Linter | Library demos[1] | | | Formatter | Linter | Library demos[1] |
| ---------- | --------- | ------ | ---------------- | | ---------- | --------- | ------ | ---------------- |
| JavaScript | ✅ | ✅ | 99 | | JavaScript | ✅ | ✅ | 103 |
| Python | ✅ | ✅ | 95 | | Python | ✅ | ✅ | 98 |
| Vala | ✅ | ✅ | 91 | | Vala | ✅ | ✅ | 92 |
| Rust | ✅ | ✅ | 52 | | Rust | ✅ | ✅ | 52 |
| Blueprint | ✅ | ✅ | | | Blueprint | ✅ | ✅ | |
| CSS | ✅ | ✅ | | | CSS | ✅ | ✅ | |
@ -45,7 +45,7 @@ Among other things, Workbench comes with
<details> <details>
<summary>Disable code formatting</summary> <summary>Disable code formatting</summary>
[JavaScript](https://docs.rome.tools/formatter/#ignoring-code) [JavaScript](https://biomejs.dev/formatter/#ignore-code)
[CSS](https://prettier.io/docs/en/ignore.html#css) [CSS](https://prettier.io/docs/en/ignore.html#css)

@ -1 +1 @@
Subproject commit 8e10fcf8692108b9d4ab78f41086c5d7773ef864 Subproject commit 04ef0944db56ab01307a29aaa7303df6067cb3c0

View File

@ -0,0 +1,4 @@
{
"re.sonny.Workbench": ["external-gitmodule-url-found"],
"re.sonny.Workbench.Devel": ["external-gitmodule-url-found"]
}

View File

@ -21,8 +21,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/jsonrpc-glib/3.44/jsonrpc-glib-3.44.0.tar.xz", "url": "https://download.gnome.org/sources/jsonrpc-glib/3.44/jsonrpc-glib-3.44.1.tar.xz",
"sha256": "69406a0250d0cc5175408cae7eca80c0c6bfaefc4ae1830b354c0433bcd5ce06" "sha256": "1361d17e9c805646afe5102e59baf8ca450238600fcabd01586c654b78bb30df"
} }
] ]
} }

View File

@ -12,8 +12,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/flatpak/libportal/releases/download/0.8.1/libportal-0.8.1.tar.xz", "url": "https://github.com/flatpak/libportal/releases/download/0.9.1/libportal-0.9.1.tar.xz",
"sha256": "281e54e4f8561125a65d20658f1462ab932b2b1258c376fed2137718441825ac" "sha256": "de801ee349ed3c255a9af3c01b1a401fab5b3fc1c35eb2fd7dfb35d4b8194d7f"
} }
] ]
} }

View File

@ -1,12 +1,12 @@
{ {
"name": "libshumate", "name": "libshumate",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": ["--libdir=/app/lib", "-Dgtk_doc=false"], "config-opts": ["--libdir=/app/lib", "-Ddemos=false", "-Dgtk_doc=false"],
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libshumate/1.3/libshumate-1.3.0.tar.xz", "url": "https://download.gnome.org/sources/libshumate/1.4/libshumate-1.4.rc.tar.xz",
"sha256": "8227a6e8281cde12232894fef83760d44fa66b39ef033c61ed934a86c6dc75d4" "sha256": "a57b97dbbda55bcb07c6f0197ff006128518c2b2c88fbee8bea5168acbc9baee"
} }
], ],
"modules": [ "modules": [
@ -29,8 +29,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.5.0/protobuf-c-1.5.0.tar.gz", "url": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.0/protobuf-c-1.4.0.tar.gz",
"sha256": "7b404c63361ed35b3667aec75cc37b54298d56dd2bcf369de3373212cc06fd98" "sha256": "26d98ee9bf18a6eba0d3f855ddec31dbe857667d269bc0b6017335572f85bbcb"
} }
] ]
} }

View File

@ -5,8 +5,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libspelling/0.4/libspelling-0.4.5.tar.xz", "url": "https://download.gnome.org/sources/libspelling/0.4/libspelling-0.4.6.tar.xz",
"sha256": "ec0372d83f42b65aee3734248ef8e2ffbfba4ea91268419c98ea44a00ef3e83f" "sha256": "3248a9b5336ea2f727d2db912d2f0083accc0505ce707679b3d9b8266c0101f5"
} }
] ]
} }

View File

@ -12,8 +12,21 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/vte/0.78/vte-0.78.2.tar.xz", "url": "https://download.gnome.org/sources/vte/0.79/vte-0.79.91.tar.xz",
"sha256": "35d7bcde07356846b4a12881c8e016705b70a9004a9082285eee5834ccc49890" "sha256": "adca667d40ae1839ba258b63701cd05fba249303d72258711cc69294b2cb8646"
}
],
"modules": [
{
"name": "fast_float",
"buildsystem": "cmake-ninja",
"sources": [
{
"type": "archive",
"url": "https://github.com/fastfloat/fast_float/archive/refs/tags/v6.1.6.tar.gz",
"sha256": "4458aae4b0eb55717968edda42987cabf5f7fc737aee8fede87a70035dba9ab0"
}
]
} }
] ]
} }

View File

@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json", "$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json",
"id": "re.sonny.Workbench.Devel", "id": "re.sonny.Workbench.Devel",
"runtime": "org.gnome.Sdk", "runtime": "org.gnome.Sdk",
"runtime-version": "47", "runtime-version": "48",
"sdk": "org.gnome.Sdk", "sdk": "org.gnome.Sdk",
"sdk-extensions": [ "sdk-extensions": [
"org.freedesktop.Sdk.Extension.vala", "org.freedesktop.Sdk.Extension.vala",

View File

@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json", "$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json",
"id": "re.sonny.Workbench", "id": "re.sonny.Workbench",
"runtime": "org.gnome.Sdk", "runtime": "org.gnome.Sdk",
"runtime-version": "47", "runtime-version": "48",
"sdk": "org.gnome.Sdk", "sdk": "org.gnome.Sdk",
"sdk-extensions": [ "sdk-extensions": [
"org.freedesktop.Sdk.Extension.vala", "org.freedesktop.Sdk.Extension.vala",

View File

@ -27,7 +27,7 @@ console.debug(argv);
const [manifest_path] = argv._; const [manifest_path] = argv._;
if (!manifest_path) { if (!manifest_path) {
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
print(`${programInvocationName} [--verbose] [--debug] MANIFEST`); print(`${programInvocationName} [--verbose] [--debug] MANIFEST [-- command]`);
exit(0); exit(0);
} }
@ -100,6 +100,7 @@ if (!exists(`${path}/.flatpak/flatpak-builder`)) {
// builds workbench // builds workbench
if (!exists(`${path}/_build`)) { if (!exists(`${path}/_build`)) {
await buildModules();
await buildCommand([ await buildCommand([
"meson", "meson",
"--prefix", "--prefix",
@ -224,7 +225,7 @@ async function exec(argv, { cancellable = null /*, verbose = false*/ }) {
return arg.toString(); return arg.toString();
}); });
console.debug(`$ ${argv}`); console.debug(`$ ${argv.join(" ")}`);
let cancelId = 0; let cancelId = 0;

View File

@ -8,6 +8,6 @@ Type=Application
Categories=WebDevelopment;Development;IDE;GNOME;GTK; Categories=WebDevelopment;Development;IDE;GNOME;GTK;
Icon=@app_id@ Icon=@app_id@
# TRANSLATORS: Don't translate # TRANSLATORS: Don't translate
Keywords=CSS;JavaScript;GJS;Blueprint;builder;Vala;GTK;libadwaita;Python;PyGObject;Rust;doc;playground;code; Keywords=CSS;JavaScript;GJS;Blueprint;builder;Vala;GTK;libadwaita;Python;PyGObject;Rust;doc;playground;code;TypeScript;
DBusActivatable=true DBusActivatable=true
StartupNotify=true StartupNotify=true

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<schemalist gettext-domain="@app_id@"> <schemalist>
<enum id="re.sonny.Workbench.UserInterfaceLanguage"> <enum id="re.sonny.Workbench.UserInterfaceLanguage">
<value nick="blueprint" value="0"/> <value nick="blueprint" value="0"/>
<value nick="xml" value="1"/> <value nick="xml" value="1"/>
@ -59,16 +59,16 @@
<key name="edited" type="b"> <key name="edited" type="b">
<default>false</default> <default>false</default>
</key> </key>
<key name="width" type="i"> <key name="window-width" type="i">
<default>0</default> <default>0</default>
</key> </key>
<key name="height" type="i"> <key name="window-height" type="i">
<default>0</default> <default>0</default>
</key> </key>
<key name="maximized" type="b"> <key name="window-maximized" type="b">
<default>false</default> <default>false</default>
</key> </key>
<key name="fullscreened" type="b"> <key name="window-fullscreened" type="b">
<default>false</default> <default>false</default>
</key> </key>
</schema> </schema>

View File

@ -43,6 +43,41 @@
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="48.0" date="2025-04-xx">
<description translatable="no">
<ul>
<li>Use GNOME 48</li>
</ul>
<p>Library:</p>
<ul>
<li>Add "Shortcuts Window" demo</li>
</ul>
<p>Dependencies:</p>
<ul>
<!-- <li>Update Jsonrpc-GLib to 3.44.1</li> -->
<li>Update libportal to 0.9.1</li>
<li>Update libshumate to 1.4</li>
<li>Update libspelling to 0.4.6</li>
<li>Update vte to 0.80.0</li>
</ul>
</description>
</release>
<release version="47.1" date="2025-01-24">
<description translatable="no">
<ul>
<li>Fix permissions dialog</li>
<li>Update Blueprint to 0.16.0</li>
<li>Update libportal to 0.9.0</li>
</ul>
<p>Library:</p>
<ul>
<li>Replace GTK syntax with CSS variables</li>
<li>Fix year sorting in "Column View" Python</li>
</ul>
</description>
</release>
<release version="47.0" date="2024-12-11"> <release version="47.0" date="2024-12-11">
<description translatable="no"> <description translatable="no">
<ul> <ul>

2
demos

@ -1 +1 @@
Subproject commit a63852e11f84f77907a699cc6ec4c09cf4ef921b Subproject commit cd8b209df99294c72a5846ead00797db0bafa862

View File

@ -1,9 +1,13 @@
project('Workbench', ['vala', 'c', 'rust'], project(
version: '47.0', 'Workbench',
meson_version: '>= 0.64.0', ['vala', 'c', 'rust'],
version: '48.0',
meson_version: '>= 1.0.0',
license: 'GPL-3.0-only', license: 'GPL-3.0-only',
default_options : [ default_options: [
'libdir=lib', 'libdir=lib',
'warning_level=2',
'werror=false',
], ],
) )
@ -33,5 +37,5 @@ subdir('src')
gnome.post_install( gnome.post_install(
glib_compile_schemas: true, glib_compile_schemas: true,
gtk_update_icon_cache: true, gtk_update_icon_cache: true,
update_desktop_database: true update_desktop_database: true,
) )

14
package-lock.json generated
View File

@ -17,7 +17,7 @@
"events": "^3.3.0", "events": "^3.3.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^14.0.1", "lint-staged": "^14.0.1",
"ltx": "git://github.com/xmppjs/ltx.git#d351ffa26ef1c5f2fbee7888d0bcd5047eb8a988", "ltx": "git://github.com/xmppjs/ltx.git#072690a43a51254ddd17b082131a8b9115586e8a",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"prettier": "3.0.3", "prettier": "3.0.3",
"rollup": "^2.76.0", "rollup": "^2.76.0",
@ -2921,9 +2921,9 @@
} }
}, },
"node_modules/ltx": { "node_modules/ltx": {
"version": "3.0.0", "version": "3.1.2",
"resolved": "git+ssh://git@github.com/xmppjs/ltx.git#d351ffa26ef1c5f2fbee7888d0bcd5047eb8a988", "resolved": "git+ssh://git@github.com/xmppjs/ltx.git#072690a43a51254ddd17b082131a8b9115586e8a",
"integrity": "sha512-niPDXqeoCqzZZVatSN1iT2ggttETmxV91GQbIThz1NBWqxJEaoMVU1dy5ec0Qy0BNLZlaKmylP0pSLP1S6u/Zg==", "integrity": "sha512-AsQ9ifqUtYTZU79mjlgoeVYPfVxLfqrJHvKaDZwZPEA7bWey4uhMMxfI1NIIxfyX5A/KUOkXl3sbUqR4u6Y/zQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -6366,10 +6366,10 @@
} }
}, },
"ltx": { "ltx": {
"version": "git+ssh://git@github.com/xmppjs/ltx.git#d351ffa26ef1c5f2fbee7888d0bcd5047eb8a988", "version": "git+ssh://git@github.com/xmppjs/ltx.git#072690a43a51254ddd17b082131a8b9115586e8a",
"integrity": "sha512-niPDXqeoCqzZZVatSN1iT2ggttETmxV91GQbIThz1NBWqxJEaoMVU1dy5ec0Qy0BNLZlaKmylP0pSLP1S6u/Zg==", "integrity": "sha512-AsQ9ifqUtYTZU79mjlgoeVYPfVxLfqrJHvKaDZwZPEA7bWey4uhMMxfI1NIIxfyX5A/KUOkXl3sbUqR4u6Y/zQ==",
"dev": true, "dev": true,
"from": "ltx@git://github.com/xmppjs/ltx.git#d351ffa26ef1c5f2fbee7888d0bcd5047eb8a988" "from": "ltx@git://github.com/xmppjs/ltx.git#072690a43a51254ddd17b082131a8b9115586e8a"
}, },
"magic-string": { "magic-string": {
"version": "0.25.7", "version": "0.25.7",

View File

@ -13,7 +13,7 @@
"events": "^3.3.0", "events": "^3.3.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^14.0.1", "lint-staged": "^14.0.1",
"ltx": "git://github.com/xmppjs/ltx.git#d351ffa26ef1c5f2fbee7888d0bcd5047eb8a988", "ltx": "git://github.com/xmppjs/ltx.git#072690a43a51254ddd17b082131a8b9115586e8a",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"prettier": "3.0.3", "prettier": "3.0.3",
"rollup": "^2.76.0", "rollup": "^2.76.0",

View File

@ -21,7 +21,7 @@ template $Extension: ListBoxRow {
icon-name: "re.sonny.Workbench-test-pass-symbolic"; icon-name: "re.sonny.Workbench-test-pass-symbolic";
styles [ styles [
"success" "success",
] ]
} }
} }
@ -39,7 +39,7 @@ template $Extension: ListBoxRow {
label: _("Run the following command"); label: _("Run the following command");
styles [ styles [
"dim-label" "dim-label",
] ]
} }
@ -52,7 +52,7 @@ template $Extension: ListBoxRow {
xalign: 0; xalign: 0;
styles [ styles [
"command_snippet" "command_snippet",
] ]
} }
} }

View File

@ -38,7 +38,7 @@ Adw.Dialog dialog {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
$Extension { $Extension {
@ -72,7 +72,7 @@ Adw.Dialog dialog {
wrap: true; wrap: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
@ -83,7 +83,7 @@ Adw.Dialog dialog {
wrap: true; wrap: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
} }

View File

@ -28,7 +28,7 @@ template $EntryRow: Adw.ActionRow {
Label description_label { Label description_label {
styles [ styles [
"dim-label", "dim-label",
"caption" "caption",
] ]
xalign: 0; xalign: 0;

View File

@ -46,7 +46,7 @@ Adw.Window window {
label: _("Learn, Test, Remix"); label: _("Learn, Test, Remix");
styles [ styles [
"title-1" "title-1",
] ]
} }
@ -79,7 +79,7 @@ Adw.Window window {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
} }
@ -100,7 +100,7 @@ Adw.Window window {
label: _("No results"); label: _("No results");
styles [ styles [
"title-3" "title-3",
] ]
} }
@ -109,7 +109,7 @@ Adw.Window window {
halign: center; halign: center;
styles [ styles [
"pill" "pill",
] ]
} }
} }
@ -119,7 +119,7 @@ Adw.Window window {
use-markup: true; use-markup: true;
styles [ styles [
"caption" "caption",
] ]
} }
} }

View File

@ -37,7 +37,7 @@ Adw.Dialog dialog {
label: _("Permissions Needed"); label: _("Permissions Needed");
styles [ styles [
"title-1" "title-1",
] ]
} }
@ -55,7 +55,7 @@ Adw.Dialog dialog {
xalign: 0; xalign: 0;
styles [ styles [
"command_snippet" "command_snippet",
] ]
} }
@ -71,7 +71,7 @@ Adw.Dialog dialog {
hexpand: true; hexpand: true;
styles [ styles [
"heading" "heading",
] ]
} }
@ -79,7 +79,7 @@ Adw.Dialog dialog {
icon-name: "re.sonny.Workbench-external-link-symbolic"; icon-name: "re.sonny.Workbench-external-link-symbolic";
styles [ styles [
"flat" "flat",
] ]
} }
} }
@ -88,7 +88,7 @@ Adw.Dialog dialog {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
Adw.ActionRow { Adw.ActionRow {
@ -101,7 +101,7 @@ Adw.Dialog dialog {
subtitle: _("Grant for your account only"); subtitle: _("Grant for your account only");
styles [ styles [
"property" "property",
] ]
} }
@ -115,7 +115,7 @@ Adw.Dialog dialog {
subtitle: _("Network access"); subtitle: _("Network access");
styles [ styles [
"property" "property",
] ]
} }
@ -129,7 +129,7 @@ Adw.Dialog dialog {
subtitle: _("Record and play audio"); subtitle: _("Record and play audio");
styles [ styles [
"property" "property",
] ]
} }
@ -143,7 +143,7 @@ Adw.Dialog dialog {
subtitle: _("Access to input device such as gamepads"); subtitle: _("Access to input device such as gamepads");
styles [ styles [
"property" "property",
] ]
} }
} }

View File

@ -13,6 +13,8 @@ import {
isDeviceInputOverrideAvailable, isDeviceInputOverrideAvailable,
} from "../flatpak.js"; } from "../flatpak.js";
const device = isDeviceInputOverrideAvailable() ? "input" : "all";
const action_permissions = new Gio.SimpleAction({ const action_permissions = new Gio.SimpleAction({
name: "permissions", name: "permissions",
parameter_type: null, parameter_type: null,
@ -29,7 +31,6 @@ export function Permissions({ window }) {
picture_illustration.set_resource(illustration); picture_illustration.set_resource(illustration);
const device = isDeviceInputOverrideAvailable() ? "input" : "all";
label_command.label = `flatpak override --user --share=network --socket=pulseaudio --device=${device} ${getFlatpakId()}`; label_command.label = `flatpak override --user --share=network --socket=pulseaudio --device=${device} ${getFlatpakId()}`;
action_row_device.title = `--input=${device}`; action_row_device.title = `--input=${device}`;
@ -57,7 +58,7 @@ const missing_permissions = (() => {
return ( return (
!shared.includes("network") || !shared.includes("network") ||
!sockets.includes("pulseaudio") || !sockets.includes("pulseaudio") ||
!devices.includes("all") !devices.includes(device)
); );
})(); })();

View File

@ -12,8 +12,7 @@ class WorkbenchHoverProvider extends GObject.Object {
} }
findDiagnostics(context) { findDiagnostics(context) {
const iter = new Gtk.TextIter(); const [, iter] = context.get_iter();
context.get_iter(iter);
const line = iter.get_line(); const line = iter.get_line();
// Looks like line_offset starts at 0 // Looks like line_offset starts at 0

View File

@ -104,5 +104,5 @@ function getValaVersion() {
} }
function getBlueprintVersion() { function getBlueprintVersion() {
return "Blueprint d47955c5"; return "Blueprint 0.16.0";
} }

View File

@ -1,7 +1,6 @@
#!@GJS@ -m #!@GJS@ -m
import { exit, programArgs } from "system"; import { exit, programArgs } from "system";
import GLib from "gi://GLib";
import { setConsoleLogDomain } from "console"; import { setConsoleLogDomain } from "console";
import Xdp from "gi://Xdp"; import Xdp from "gi://Xdp";
@ -14,7 +13,6 @@ imports.package.init({
datadir: "@datadir@", datadir: "@datadir@",
}); });
setConsoleLogDomain(pkg.name); setConsoleLogDomain(pkg.name);
GLib.set_application_name("Workbench");
if (!Xdp.Portal.running_under_flatpak()) { if (!Xdp.Portal.running_under_flatpak()) {
console.error( console.error(

97
src/cli/blueprint.js Normal file
View File

@ -0,0 +1,97 @@
/* eslint-disable no-restricted-globals */
import Gtk from "gi://Gtk";
import { getLanguage } from "../common.js";
import { parse } from "../langs/xml/xml.js";
import { LSPError } from "../lsp/LSP.js";
import { checkFile, diagnose } from "./util.js";
const languageId = "blueprint";
export default async function blueprint({ file, lspc }) {
print(` ${file.get_path()}`);
await diagnose({
file,
lspc,
languageId,
filter(diagnostic) {
// No replacements yet
return ![
"Gtk.ShortcutsShortcut is deprecated\nhint: This widget will be removed in GTK 5",
"Gtk.ShortcutLabel is deprecated\nhint: This widget will be removed in GTK 5",
"Gtk.ShortcutsWindow is deprecated\nhint: This widget will be removed in GTK 5",
"Gtk.ShortcutsGroup is deprecated\nhint: This widget will be removed in GTK 5",
"Gtk.ShortcutsSection is deprecated\nhint: This widget will be removed in GTK 5",
].includes(diagnostic.message);
},
});
const { xml } = await lspc._request("textDocument/x-blueprint-compile", {
textDocument: {
uri: file.get_uri(),
},
});
print(` ✅ compiles`);
try {
await lspc._request("x-blueprint/decompile", {
text: xml,
});
print(" ✅ decompiles");
} catch (err) {
if (!(err instanceof LSPError)) throw err;
if (
![
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/128
"unsupported XML tag: <condition>",
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/139
"unsupported XML tag: <items>",
].includes(err.message)
) {
throw err;
}
}
await checkFile({
lspc,
file,
lang: getLanguage(languageId),
uri: file.get_uri(),
});
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
const tree = parse(xml);
const template_el = tree.getChild("template");
let template;
const builder = new Gtk.Builder();
const blueprint_object_ids = [];
if (template_el) {
template = tree.toString();
} else {
builder.add_from_string(xml, -1);
print(` ✅ instantiates`);
getXMLObjectIds(tree, blueprint_object_ids);
}
return { template, builder, blueprint_object_ids };
}
function getXMLObjectIds(tree, object_ids) {
for (const object of tree.getChildren("object")) {
if (object.attrs.id) object_ids.push(object.attrs.id);
// <child> or <property name="child">
for (const child of object.getChildElements()) {
getXMLObjectIds(child, object_ids);
}
}
}

25
src/cli/css.js Normal file
View File

@ -0,0 +1,25 @@
/* eslint-disable no-restricted-globals */
import { getLanguage } from "../common.js";
import { checkFile, diagnose } from "./util.js";
const languageId = "css";
export default async function css({ file, lspc }) {
print(` ${file.get_path()}`);
await diagnose({ file, lspc, languageId });
await checkFile({
lspc,
file,
lang: getLanguage(languageId),
uri: file.get_uri(),
});
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
}

56
src/cli/javascript.js Normal file
View File

@ -0,0 +1,56 @@
/* eslint-disable no-restricted-globals */
import { getLanguage } from "../common.js";
import { checkFile, getCodeObjectIds, diagnose, Interrupt } from "./util.js";
const languageId = "javascript";
export default async function javascript({
file,
lspc,
blueprint_object_ids,
demo_dir,
application,
builder,
template,
window,
}) {
print(` ${file.get_path()}`);
const text = await diagnose({ file, lspc, languageId });
await checkFile({
lspc: lspc,
file: file,
lang: getLanguage("javascript"),
uri: file.get_uri(),
});
const js_object_ids = getCodeObjectIds(text);
for (const object_id of js_object_ids) {
if (!blueprint_object_ids.includes(object_id)) {
print(` ❌ Reference to inexistant object id "${object_id}"`);
throw new Interrupt();
}
}
globalThis.workbench = {
window,
application,
builder,
template,
resolve(path) {
return demo_dir.resolve_relative_path(path).get_uri();
},
preview() {},
};
await import(`file://${file.get_path()}`);
print(" ✅ runs");
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
}

View File

@ -4,6 +4,7 @@ import Gio from "gi://Gio";
import { formatting } from "./format.js"; import { formatting } from "./format.js";
import { diagnostic_severities } from "../lsp/LSP.js"; import { diagnostic_severities } from "../lsp/LSP.js";
import { waitForDiagnostics } from "./util.js";
export default async function lint({ filenames, lang, lspc, ci }) { export default async function lint({ filenames, lang, lspc, ci }) {
let success = true; let success = true;
@ -47,19 +48,6 @@ export default async function lint({ filenames, lang, lspc, ci }) {
return success; return success;
} }
export function waitForDiagnostics({ uri, lspc }) {
return new Promise((resolve) => {
const handler_id = lspc.connect(
"notification::textDocument/publishDiagnostics",
(_self, params) => {
if (uri !== params.uri) return;
lspc.disconnect(handler_id);
resolve(params.diagnostics);
},
);
});
}
function serializeDiagnostics({ file, diagnostics }) { function serializeDiagnostics({ file, diagnostics }) {
return ( return (
`\n${file.get_path()}\n` + `\n${file.get_path()}\n` +

View File

@ -5,23 +5,23 @@ import "../init.js";
import GLib from "gi://GLib"; import GLib from "gi://GLib";
import Gio from "gi://Gio"; import Gio from "gi://Gio";
import Gtk from "gi://Gtk";
import Adw from "gi://Adw"; import Adw from "gi://Adw";
import GObject from "gi://GObject"; import GObject from "gi://GObject";
import Shumate from "gi://Shumate"; import Shumate from "gi://Shumate";
import WebKit from "gi://WebKit"; import WebKit from "gi://WebKit";
import { parse } from "../langs/xml/xml.js"; import { createLSPClient, languages, PYTHON_LSP_CONFIG } from "../common.js";
import { LSPError, diagnostic_severities } from "../lsp/LSP.js"; import lint from "./lint.js";
import format from "./format.js";
import { import blueprint from "./blueprint.js";
createLSPClient, import css from "./css.js";
languages, import javascript from "./javascript.js";
getLanguage, import typescript from "./typescript.js";
PYTHON_LSP_CONFIG, import vala from "./vala.js";
} from "../common.js"; import python from "./python.js";
import lint, { waitForDiagnostics } from "./lint.js"; import rust from "./rust.js";
import format, { formatting } from "./format.js"; import { Interrupt } from "./util.js";
GObject.type_ensure(Shumate.SimpleMap); GObject.type_ensure(Shumate.SimpleMap);
GObject.type_ensure(WebKit.WebView); GObject.type_ensure(WebKit.WebView);
@ -31,8 +31,16 @@ export async function main([action, ...args]) {
if (action === "ci") { if (action === "ci") {
const filenames = args; const filenames = args;
const success = await ci({ filenames }); try {
return success ? 0 : 1; await ci({ filenames });
return 0;
} catch (err) {
if (err instanceof Interrupt) {
return 1;
} else {
throw err;
}
}
} }
const [language_id, ...filenames] = args; const [language_id, ...filenames] = args;
@ -67,19 +75,27 @@ export async function main([action, ...args]) {
}); });
} }
let success = false; try {
if (action === "lint") {
if (action === "lint") { await lint({ filenames, lang, lspc, ci: false });
success = await lint({ filenames, lang, lspc, ci: false }); return 0;
} else if (action === "check") { } else if (action === "check") {
success = await lint({ filenames, lang, lspc, ci: true }); await lint({ filenames, lang, lspc, ci: true });
} else if (action === "format") { return 0;
success = await format({ filenames, lang, lspc }); } else if (action === "format") {
} else { await format({ filenames, lang, lspc });
printerr(`Unknown action "${action}"}`); return 0;
} else {
printerr(`Unknown action "${action}"}`);
return 1;
}
} catch (err) {
if (err instanceof Interrupt) {
return 1;
} else {
throw err;
}
} }
return success ? 0 : 1;
} }
const application = new Adw.Application(); const application = new Adw.Application();
@ -107,27 +123,6 @@ function createLSPClients({ root_uri }) {
); );
} }
async function checkFile({ lspc, file, lang, uri }) {
const [contents] = await file.load_contents_async(null);
const text = new TextDecoder().decode(contents);
const buffer = new Gtk.TextBuffer({ text });
const buffer_tmp = new Gtk.TextBuffer({ text: buffer.text });
await formatting({ buffer: buffer_tmp, uri, lang, lspc });
if (buffer_tmp.text === buffer.text) {
print(` ✅ checks`);
return true;
} else {
printerr(
` ❌ formatting differs - open and run ${file
.get_parent()
.get_basename()} with Workbench to fix`,
);
return false;
}
}
async function ci({ filenames }) { async function ci({ filenames }) {
for (const filename of filenames) { for (const filename of filenames) {
const demo_dir = Gio.File.new_for_path(filename); const demo_dir = Gio.File.new_for_path(filename);
@ -150,449 +145,63 @@ async function ci({ filenames }) {
); );
let template = null; let template = null;
const builder = new Gtk.Builder(); let builder = null;
const blueprint_object_ids = []; let blueprint_object_ids = null;
let xml = null;
const file_blueprint = demo_dir.get_child("main.blp"); const file_blueprint = demo_dir.get_child("main.blp");
if (file_blueprint.query_exists(null)) { if (file_blueprint.query_exists(null)) {
print(` ${file_blueprint.get_path()}`); ({ template, builder, blueprint_object_ids } = await blueprint({
const uri = file_blueprint.get_uri();
const languageId = "blueprint";
let version = 0;
const [contents] = await file_blueprint.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.blueprint._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.blueprint,
});
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
({ xml } = await lsp_clients.blueprint._request(
"textDocument/x-blueprint-compile",
{
textDocument: {
uri,
},
},
));
print(` ✅ compiles`);
try {
await lsp_clients.blueprint._request("x-blueprint/decompile", {
text: xml,
});
print(" ✅ decompiles");
} catch (err) {
if (!(err instanceof LSPError)) throw err;
if (
![
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/128
"unsupported XML tag: <condition>",
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/139
"unsupported XML tag: <items>",
].includes(err.message)
) {
throw err;
}
}
const checks = await checkFile({
lspc: lsp_clients.blueprint,
file: file_blueprint, file: file_blueprint,
lang: getLanguage("blueprint"), lspc: lsp_clients.blueprint,
uri, }));
});
if (!checks) return false;
await lsp_clients.blueprint._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
const tree = parse(xml);
const template_el = tree.getChild("template");
if (template_el) {
template = tree.toString();
} else {
builder.add_from_string(xml, -1);
print(` ✅ instantiates`);
getXMLObjectIds(tree, blueprint_object_ids);
}
} }
const file_css = demo_dir.get_child("main.css"); const file_css = demo_dir.get_child("main.css");
if (file_css.query_exists(null)) { if (file_css.query_exists(null)) {
print(` ${file_css.get_path()}`); await css({ file: file_css, lspc: lsp_clients.css });
const uri = file_css.get_uri();
const languageId = "css";
let version = 0;
const [contents] = await file_css.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.css._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.css,
});
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.css,
file: file_css,
lang: getLanguage("css"),
uri,
});
if (!checks) return false;
await lsp_clients.css._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
} }
const file_javascript = demo_dir.get_child("main.js"); const file_javascript = demo_dir.get_child("main.js");
if (file_javascript.query_exists(null)) { if (file_javascript.query_exists(null)) {
print(` ${file_javascript.get_path()}`); await javascript({
const uri = file_javascript.get_uri();
const languageId = "javascript";
let version = 0;
const [contents] = await file_javascript.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.javascript._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.javascript,
});
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.javascript,
file: file_javascript, file: file_javascript,
lang: getLanguage("javascript"), lspc: lsp_clients.javascript,
uri, blueprint_object_ids,
}); demo_dir,
if (!checks) return false;
const js_object_ids = getCodeObjectIds(text);
for (const object_id of js_object_ids) {
if (!blueprint_object_ids.includes(object_id)) {
print(` ❌ Reference to inexistant object id "${object_id}"`);
return false;
}
}
globalThis.workbench = {
window,
application, application,
builder, builder,
template, template,
resolve(path) { window,
return demo_dir.resolve_relative_path(path).get_uri();
},
preview() {},
};
await import(`file://${file_javascript.get_path()}`);
print(" ✅ runs");
await lsp_clients.javascript._notify("textDocument/didClose", {
textDocument: {
uri,
},
}); });
} }
const file_typescript = demo_dir.get_child("main.ts"); const file_typescript = demo_dir.get_child("main.ts");
if (file_typescript.query_exists(null)) { if (file_typescript.query_exists(null)) {
print(` ${file_typescript.get_path()}`); await typescript({
const uri = file_typescript.get_uri();
const languageId = "typescript";
let version = 0;
const [contents] = await file_typescript.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.typescript._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.typescript,
});
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.typescript,
file: file_typescript, file: file_typescript,
lang: getLanguage("typescript"), lspc: lsp_clients.typescript,
uri, blueprint_object_ids,
}); demo_dir,
if (!checks) return false;
const js_object_ids = getCodeObjectIds(text);
for (const object_id of js_object_ids) {
if (!blueprint_object_ids.includes(object_id)) {
print(` ❌ Reference to inexistant object id "${object_id}"`);
return false;
}
}
globalThis.workbench = {
window,
application, application,
builder, builder,
template, template,
resolve(path) { window,
return demo_dir.resolve_relative_path(path).get_uri();
},
preview() {},
};
await import(`file://${file_typescript.get_path()}`);
print(" ✅ runs");
await lsp_clients.typescript._notify("textDocument/didClose", {
textDocument: {
uri,
},
}); });
} }
const file_vala = demo_dir.get_child("main.vala"); const file_vala = demo_dir.get_child("main.vala");
if (file_vala.query_exists(null)) { if (file_vala.query_exists(null)) {
print(` ${file_vala.get_path()}`); await vala({ file: file_vala, lspc: lsp_clients.vala, demo_dir });
const uri = file_vala.get_uri();
const languageId = "vala";
let version = 0;
const file_api = Gio.File.new_for_path(pkg.pkgdatadir).get_child(
"workbench.vala",
);
file_api.copy(
demo_dir.get_child("workbench.vala"),
Gio.FileCopyFlags.OVERWRITE,
null,
null,
);
const [contents] = await file_vala.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.vala._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
let diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.vala,
});
// FIXME: deprecated features, no replacement?
if (demo_dir.get_basename() === "Text Fields") {
const ignore_for_text_fields = [
"`Gtk.EntryCompletion' has been deprecated since 4.10",
"`Gtk.Entry.completion' has been deprecated since 4.10",
"`Gtk.ListStore' has been deprecated since 4.10",
"`Gtk.TreeIter' has been deprecated since 4.10",
];
diagnostics = diagnostics.filter((diagnostic) => {
return !ignore_for_text_fields.includes(diagnostic.message);
});
// Gtk.StyleContext class is deprecated but not the following methods
// gtk_style_context_add_provider_for_display
// gtk_style_context_remove_provider_for_display
} else if (demo_dir.get_basename() === "CSS Gradients") {
diagnostics = diagnostics.filter((diagnostic) => {
return (
diagnostic.message !==
"`Gtk.StyleContext' has been deprecated since 4.10"
);
});
}
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.vala,
file: file_vala,
lang: getLanguage("vala"),
uri,
});
if (!checks) return false;
await lsp_clients.vala._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
} }
const file_python = demo_dir.get_child("main.py"); const file_python = demo_dir.get_child("main.py");
if (file_python.query_exists(null)) { if (file_python.query_exists(null)) {
print(` ${file_python.get_path()}`); await python({ file: file_python, lspc: lsp_clients.python });
const uri = file_python.get_uri();
const languageId = "python";
let version = 0;
const [contents] = await file_python.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.python._request("workspace/didChangeConfiguration", {
settings: PYTHON_LSP_CONFIG,
});
await lsp_clients.python._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.python,
});
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
return false;
}
print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.python,
file: file_python,
lang: getLanguage("python"),
uri,
});
if (!checks) return false;
await lsp_clients.python._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
} }
const file_rust = demo_dir.get_child("code.rs"); const file_rust = demo_dir.get_child("code.rs");
if (file_rust.query_exists(null)) { if (file_rust.query_exists(null)) {
print(` ${file_rust.get_path()}`); await rust({ file: file_rust, lspc: lsp_clients.rust });
const uri = file_rust.get_uri();
const languageId = "rust";
let version = 0;
const [contents] = await file_rust.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lsp_clients.rust._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
// FIXME: rust analyzer doesn't publish diagnostics if there are none
// probably we should switch to pulling diagnostics but unknown if supported
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_pullDiagnostics
// const diagnostics = await waitForDiagnostics({
// uri,
// lspc: lsp_clients.rust,
// });
// if (diagnostics.length > 0) {
// printerr(serializeDiagnostics({ diagnostics }));
// return false;
// }
// print(` ✅ lints`);
const checks = await checkFile({
lspc: lsp_clients.rust,
file: file_rust,
lang: getLanguage("rust"),
uri,
});
if (!checks) return false;
await lsp_clients.rust._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
} }
await Promise.all( await Promise.all(
@ -601,45 +210,6 @@ async function ci({ filenames }) {
}), }),
); );
} }
return true;
}
function getXMLObjectIds(tree, object_ids) {
for (const object of tree.getChildren("object")) {
if (object.attrs.id) object_ids.push(object.attrs.id);
// <child> or <property name="child">
for (const child of object.getChildElements()) {
getXMLObjectIds(child, object_ids);
}
}
}
function getCodeObjectIds(text) {
const object_ids = [];
for (const match of text.matchAll(/get_object\("(.+)"\)/g)) {
object_ids.push(match[1]);
}
return object_ids;
}
function serializeDiagnostics({ diagnostics }) {
return (
diagnostics
.map(({ severity, range, message }) => {
return (
" ❌ " +
diagnostic_severities[severity] +
" " +
range.start.line +
":" +
range.start.character +
" " +
message.split("\n")[0]
);
})
.join("\n") + "\n"
);
} }
const key_file = new GLib.KeyFile(); const key_file = new GLib.KeyFile();

30
src/cli/python.js Normal file
View File

@ -0,0 +1,30 @@
/* eslint-disable no-restricted-globals */
import { PYTHON_LSP_CONFIG, getLanguage } from "../common.js";
import { checkFile, diagnose } from "./util.js";
const languageId = "python";
export default async function python({ file, lspc }) {
print(` ${file.get_path()}`);
await lspc._request("workspace/didChangeConfiguration", {
settings: PYTHON_LSP_CONFIG,
});
await diagnose({ file, lspc, languageId });
await checkFile({
lspc,
file,
lang: getLanguage(languageId),
uri: file.get_uri(),
});
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
}

48
src/cli/rust.js Normal file
View File

@ -0,0 +1,48 @@
/* eslint-disable no-restricted-globals */
import { getLanguage } from "../common.js";
import { checkFile } from "./util.js";
const languageId = "rust";
export default async function rust({ file, lspc }) {
print(` ${file.get_path()}`);
const uri = file.get_uri();
let version = 0;
const [contents] = await file.load_contents_async(null);
const text = new TextDecoder().decode(contents);
await lspc._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
// FIXME: rust analyzer doesn't publish diagnostics if there are none
// probably we should switch to pulling diagnostics but unknown if supported
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_pullDiagnostics
// await diagnose({
// file,
// lspc,
// languageId,
// });
await checkFile({
lspc,
file,
lang: getLanguage(languageId),
uri,
});
await lspc._notify("textDocument/didClose", {
textDocument: {
uri,
},
});
}

56
src/cli/typescript.js Normal file
View File

@ -0,0 +1,56 @@
/* eslint-disable no-restricted-globals */
import { getLanguage } from "../common.js";
import { checkFile, getCodeObjectIds, diagnose, Interrupt } from "./util.js";
const languageId = "typescript";
export default async function typescript({
file,
lspc,
blueprint_object_ids,
demo_dir,
application,
builder,
template,
window,
}) {
print(` ${file.get_path()}`);
const text = await diagnose({ file, lspc, languageId });
await checkFile({
lspc,
file,
lang: getLanguage(languageId),
uri: file.get_uri(),
});
const js_object_ids = getCodeObjectIds(text);
for (const object_id of js_object_ids) {
if (!blueprint_object_ids.includes(object_id)) {
print(` ❌ Reference to inexistant object id "${object_id}"`);
throw new Interrupt();
}
}
globalThis.workbench = {
window,
application,
builder,
template,
resolve(path) {
return demo_dir.resolve_relative_path(path).get_uri();
},
preview() {},
};
await import(`file://${file.get_path()}`);
print(" ✅ runs");
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
}

111
src/cli/util.js Normal file
View File

@ -0,0 +1,111 @@
/* eslint-disable no-restricted-globals */
import Gtk from "gi://Gtk";
import { diagnostic_severities } from "../lsp/LSP.js";
import { formatting } from "./format.js";
export class Interrupt extends Error {
constructor(...args) {
super(...args);
Error.captureStackTrace?.(this, Interrupt);
}
}
export async function diagnose({
file,
lspc,
languageId,
filter = (_diagnostic) => {
return true;
},
}) {
const [contents] = await file.load_contents_async(null);
const text = new TextDecoder().decode(contents);
const uri = file.get_uri();
let version = 0;
await lspc._notify("textDocument/didOpen", {
textDocument: {
uri,
languageId,
version: version++,
text,
},
});
let diagnostics = await waitForDiagnostics({
uri,
lspc,
});
diagnostics = diagnostics.filter(filter);
if (diagnostics.length > 0) {
printerr(serializeDiagnostics({ diagnostics }));
throw new Interrupt();
}
print(` ✅ lints`);
return text;
}
export function serializeDiagnostics({ diagnostics }) {
return (
diagnostics
.map(({ severity, range, message }) => {
return (
" ❌ " +
diagnostic_severities[severity] +
" " +
range.start.line +
":" +
range.start.character +
" " +
message.split("\n")[0]
);
})
.join("\n") + "\n"
);
}
export async function checkFile({ lspc, file, lang, uri }) {
const [contents] = await file.load_contents_async(null);
const text = new TextDecoder().decode(contents);
const buffer = new Gtk.TextBuffer({ text });
const buffer_tmp = new Gtk.TextBuffer({ text: buffer.text });
await formatting({ buffer: buffer_tmp, uri, lang, lspc });
if (buffer_tmp.text === buffer.text) {
print(` ✅ checks`);
} else {
printerr(
` ❌ formatting differs - open and run ${file
.get_parent()
.get_basename()} with Workbench to fix`,
);
throw new Interrupt();
}
}
export function getCodeObjectIds(text) {
const object_ids = [];
for (const match of text.matchAll(/get_object\("(.+)"\)/g)) {
object_ids.push(match[1]);
}
return object_ids;
}
export function waitForDiagnostics({ uri, lspc }) {
return new Promise((resolve) => {
const handler_id = lspc.connect(
"notification::textDocument/publishDiagnostics",
(_self, params) => {
if (uri !== params.uri) return;
lspc.disconnect(handler_id);
resolve(params.diagnostics);
},
);
});
}

62
src/cli/vala.js Normal file
View File

@ -0,0 +1,62 @@
/* eslint-disable no-restricted-globals */
import Gio from "gi://Gio";
import { getLanguage } from "../common.js";
import { checkFile, diagnose } from "./util.js";
const languageId = "vala";
export default async function vala({ file, lspc, demo_dir }) {
print(` ${file.get_path()}`);
const file_api = Gio.File.new_for_path(pkg.pkgdatadir).get_child(
"workbench.vala",
);
file_api.copy(
demo_dir.get_child("workbench.vala"),
Gio.FileCopyFlags.OVERWRITE,
null,
null,
);
await diagnose({
file,
lspc,
languageId,
filter(diagnostic) {
// FIXME: deprecated features, no replacement?
if (demo_dir.get_basename() === "Text Fields") {
const ignore_for_text_fields = [
"`Gtk.EntryCompletion' has been deprecated since 4.10",
"`Gtk.Entry.completion' has been deprecated since 4.10",
"`Gtk.ListStore' has been deprecated since 4.10",
"`Gtk.TreeIter' has been deprecated since 4.10",
];
return !ignore_for_text_fields.includes(diagnostic.message);
// Gtk.StyleContext class is deprecated but not the following methods
// gtk_style_context_add_provider_for_display
// gtk_style_context_remove_provider_for_display
} else if (demo_dir.get_basename() === "CSS Gradients") {
return (
diagnostic.message !==
"`Gtk.StyleContext' has been deprecated since 4.10"
);
}
return true;
},
});
await checkFile({
lspc,
file,
lang: getLanguage("vala"),
uri: file.get_uri(),
});
await lspc._notify("textDocument/didClose", {
textDocument: {
uri: file.get_uri(),
},
});
}

View File

@ -12,7 +12,7 @@ export function setup({ document }) {
const lspc = createLSPClient({ const lspc = createLSPClient({
lang: getLanguage("typescript"), lang: getLanguage("typescript"),
root_uri: file.get_parent().get_uri(), root_uri: file.get_parent().get_uri(),
quiet: true, quiet: false,
}); });
lspc.buffer = buffer; lspc.buffer = buffer;
lspc.uri = file.get_uri(); lspc.uri = file.get_uri();
@ -48,9 +48,10 @@ export async function setupTypeScriptProject(destination, document) {
Gio.FileCopyFlags.NONE, Gio.FileCopyFlags.NONE,
); );
// FIXME: hangs
// Notify the language server that the tsconfig file was created // Notify the language server that the tsconfig file was created
// to initialized diagnostics and type checkings // to initialized diagnostics and type checkings
await document.lspc.notify("workspace/didCreateFile", { // await document.lspc.notify("workspace/didCreateFile", {
files: [{ uri: destination_file.get_uri() }], // files: [{ uri: destination_file.get_uri() }],
}); // });
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,6 @@ import {
getNowForFilename, getNowForFilename,
demos_dir, demos_dir,
settings as global_settings, settings as global_settings,
settings,
copyDirectory, copyDirectory,
decode, decode,
removeDirectory, removeDirectory,
@ -40,7 +39,7 @@ export async function getSessions() {
} }
// Projects // Projects
const recent_projects = settings.get_strv("recent-projects"); const recent_projects = global_settings.get_strv("recent-projects");
for (const path of recent_projects) { for (const path of recent_projects) {
const file = Gio.File.new_for_path(path); const file = Gio.File.new_for_path(path);
if ( if (
@ -165,15 +164,15 @@ export class Session {
} }
export function addToRecentProjects(path) { export function addToRecentProjects(path) {
const recent_projects = new Set(settings.get_strv("recent-projects")); const recent_projects = new Set(global_settings.get_strv("recent-projects"));
recent_projects.add(path); recent_projects.add(path);
settings.set_strv("recent-projects", [...recent_projects]); global_settings.set_strv("recent-projects", [...recent_projects]);
} }
export function removeFromRecentProjects(path) { export function removeFromRecentProjects(path) {
const recent_projects = new Set(settings.get_strv("recent-projects")); const recent_projects = new Set(global_settings.get_strv("recent-projects"));
recent_projects.delete(path); recent_projects.delete(path);
settings.set_strv("recent-projects", [...recent_projects]); global_settings.set_strv("recent-projects", [...recent_projects]);
} }
async function buildGResourceIcons(file) { async function buildGResourceIcons(file) {

View File

@ -9,13 +9,12 @@ export default function ShortcutsWindow({ application }) {
const action_shortcuts = new Gio.SimpleAction({ const action_shortcuts = new Gio.SimpleAction({
name: "shortcuts", name: "shortcuts",
parameter_type: null,
}); });
action_shortcuts.connect("activate", () => { action_shortcuts.connect("activate", () => {
if (!window) { if (!window) {
({ window } = build(resource)); ({ window } = build(resource));
window.set_transient_for(application.get_active_window());
} }
window.set_transient_for(application.active_window);
window.present(); window.present();
}); });
application.add_action(action_shortcuts); application.add_action(action_shortcuts);

View File

@ -13,12 +13,12 @@
} }
.command_snippet { .command_snippet {
color: @view_fg_color; color: var(--view-fg-color);
background: @view_bg_color; background: var(--view-bg-color);
font-family: monospace; font-family: monospace;
border-radius: 6px; border-radius: 6px;
padding: 6px; padding: 6px;
border: 1px solid @borders; border: 1px solid var(--border-color);
} }
/* /*
@ -36,7 +36,7 @@ button.pill.small {
#panel_code, #panel_code,
#panel_style, #panel_style,
#panel_ui { #panel_ui {
border-right: solid 1px @borders; border-right: solid 1px var(--border-color);
background-color: #fcfcfc; background-color: #fcfcfc;
} }

View File

@ -11,7 +11,7 @@ template $CodeFind: Revealer {
Box { Box {
styles [ styles [
"toolbar" "toolbar",
] ]
halign: center; halign: center;
@ -63,7 +63,7 @@ template $CodeFind: Revealer {
styles [ styles [
"circular", "circular",
"small" "small",
] ]
clicked => $onClose(); clicked => $onClose();

View File

@ -45,7 +45,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"flat", "flat",
"view-toggler" "view-toggler",
] ]
} }
@ -65,7 +65,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"flat", "flat",
"view-toggler" "view-toggler",
] ]
} }
@ -85,7 +85,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"flat", "flat",
"view-toggler" "view-toggler",
] ]
} }
@ -105,7 +105,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"flat", "flat",
"view-toggler" "view-toggler",
] ]
} }
} }
@ -130,7 +130,7 @@ Adw.ApplicationWindow window {
tooltip-text: _("Run (Ctrl+⏎)"); tooltip-text: _("Run (Ctrl+⏎)");
styles [ styles [
"suggested-action" "suggested-action",
] ]
} }
} }
@ -157,7 +157,7 @@ Adw.ApplicationWindow window {
CenterBox { CenterBox {
styles [ styles [
"toolbar", "toolbar",
"panel_header" "panel_header",
] ]
height-request: 46; height-request: 46;
@ -169,13 +169,13 @@ Adw.ApplicationWindow window {
use-markup: true; use-markup: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
Separator { Separator {
styles [ styles [
"spacer" "spacer",
] ]
} }
@ -241,7 +241,7 @@ Adw.ApplicationWindow window {
CenterBox { CenterBox {
styles [ styles [
"toolbar", "toolbar",
"panel_header" "panel_header",
] ]
height-request: 46; height-request: 46;
@ -252,7 +252,7 @@ Adw.ApplicationWindow window {
use-markup: true; use-markup: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
} }
@ -271,7 +271,7 @@ Adw.ApplicationWindow window {
CenterBox { CenterBox {
styles [ styles [
"toolbar", "toolbar",
"panel_header" "panel_header",
] ]
height-request: 46; height-request: 46;
@ -283,13 +283,13 @@ Adw.ApplicationWindow window {
use-markup: true; use-markup: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
Separator { Separator {
styles [ styles [
"spacer" "spacer",
] ]
} }
@ -341,7 +341,7 @@ Adw.ApplicationWindow window {
CenterBox { CenterBox {
styles [ styles [
"toolbar", "toolbar",
"panel_header" "panel_header",
] ]
height-request: 46; height-request: 46;
@ -353,7 +353,7 @@ Adw.ApplicationWindow window {
label: _("Preview"); label: _("Preview");
styles [ styles [
"flat" "flat",
] ]
menu-model: preview_menu; menu-model: preview_menu;
@ -400,7 +400,7 @@ Adw.ApplicationWindow window {
valign: fill; valign: fill;
styles [ styles [
"background" "background",
] ]
}; };
} }
@ -425,7 +425,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"pill", "pill",
"suggested-action" "suggested-action",
] ]
} }
} }
@ -447,7 +447,7 @@ Adw.ApplicationWindow window {
label: _("Close Preview Window"); label: _("Close Preview Window");
styles [ styles [
"pill" "pill",
] ]
} }
} }
@ -479,7 +479,7 @@ Adw.ApplicationWindow window {
styles [ styles [
"toolbar", "toolbar",
"panel_header" "panel_header",
] ]
[start] [start]
@ -572,7 +572,7 @@ Adw.Dialog dialog_blueprint_experimental {
styles [ styles [
"suggested-action", "suggested-action",
"pill" "pill",
] ]
} }
}; };
@ -752,7 +752,7 @@ Adw.AlertDialog alert_dialog_save_project {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
Adw.EntryRow row_project_name { Adw.EntryRow row_project_name {
@ -767,7 +767,7 @@ Adw.AlertDialog alert_dialog_save_project {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
Adw.ActionRow row_project_location { Adw.ActionRow row_project_location {
@ -785,7 +785,7 @@ Adw.AlertDialog alert_dialog_save_project {
styles [ styles [
"dim-label", "dim-label",
"caption" "caption",
] ]
justify: left; justify: left;
@ -799,7 +799,7 @@ Button button_location {
valign: center; valign: center;
styles [ styles [
"flat" "flat",
] ]
} }

2
troll

@ -1 +1 @@
Subproject commit 1dc72cb295edbc212b4a0952286c7b5cc66db60a Subproject commit bccc2a7fd570d5e9d6845e8fa8e4d838f35f571b