Compare commits

...

136 Commits
v45.4 ... 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
Sonny
aa93296968
Support Flatpak < 1.15.6 for permissions (#992) 2024-12-11 16:19:09 +01:00
Sonny
5506bf85f9
Release 47 (#991) 2024-12-11 15:52:11 +01:00
Sonny Piers
1b75996fab Use -- to pass custom command to run.js 2024-10-18 12:50:06 +02:00
Sonny
2057f39390
Include freedesktop sdk TypeScript extension (#988)
Closes https://github.com/workbenchdev/Workbench/issues/975

TypeScript is still disabled by default for now but it's just a
gsetting.
2024-10-18 12:08:31 +02:00
Sonny Piers
d9badbe19c Stop using deprecated gtk_show_uri 2024-10-17 22:54:25 +02:00
Sonny Piers
6c173507a5 Fix js override for registerClass signature with a single argument 2024-10-17 22:54:25 +02:00
Sonny Piers
541572809a Update release notes 2024-10-17 22:54:25 +02:00
Nokse22
eafa99f771
Added Nokse in contributors section (#987) 2024-10-10 14:41:19 +02:00
Sonny Piers
48897f71d2 Update to libspelling 0.4.2 2024-10-07 15:52:28 +02:00
Sonny
812895129f
Disable TypeScript by default (#986)
Temporarily until
https://github.com/flathub/org.freedesktop.Sdk.Extension.typescript/issues/29
2024-10-04 14:26:04 +02:00
Sonny
e5c077bd78
Remove unsafe permissions and add dialog (#985)
Fixes https://github.com/workbenchdev/Workbench/issues/915
2024-10-03 23:15:00 +02:00
Sonny Piers
d79bc8c84a Rename extension property enabled to available 2024-10-03 17:39:15 +02:00
Sonny Piers
efb14d9961 Include GOM dependency 2024-09-30 15:27:38 +02:00
Sonny Piers
2e4e318e17 Various improvements to Library 2024-09-26 13:44:16 +02:00
Sonny Piers
26e63a11a5 Fix Library category filtering 2024-09-25 12:37:45 +02:00
Sonny
dfb44ab923
Remove gst-plugin-gtk4 (#984)
Fixes https://github.com/workbenchdev/Workbench/issues/983
2024-09-23 23:03:05 +02:00
Atbrat
7aa97b6cc7
library: Add Language and Category filters (#967) 2024-09-23 14:28:05 +02:00
Sonny Piers
d02b1d1eef Add wip build script 2024-09-23 13:01:14 +02:00
Sonny
020cfec21b
GNOME 47 (#982)
Technically depends on
https://github.com/flathub/org.freedesktop.Sdk.Extension.typescript/issues/29

Without, TypeScript support is broken.
But I'll merge anyway as keeping separate sdk branches is a mess, and we
can move forward and prepare the release.

For now I have re-enabled Biome for JavaScript. 

Hopefully `org.freedesktop.Sdk.Extension.typescript//24.08` will get
released soon.
2024-09-23 11:25:28 +02:00
Atbrat
154f5eaa82
Add dependency for GOM demo (#981)
- Parent PR: https://github.com/workbenchdev/demos/pull/200
2024-09-04 22:42:43 -07:00
Roland Lötscher
2c1dad91de
Add option to create new project (#970)
Fixes #951
2024-07-23 21:56:51 +02:00
Sonny
b66871f6bd
Various improvements (#974) 2024-07-16 15:51:01 +02:00
Sonny
6a1dd637ce
Remove Biome (#973)
We switched to TypeScript Language Server so we don't need it anymore.
2024-07-14 23:13:59 +02:00
Angelo Verlain Shema
3a8e52ceb0
Typechecking with JavaScript (#972)
Using the world-famous `jsconfig.json`
2024-07-14 20:52:44 +02:00
Angelo Verlain Shema
bf5e999a00
Use the node18 SDK Extension instead of 20 (#971)
That's what typescript requires
2024-07-14 14:31:08 +02:00
Diego Iván M.E
2c0a46abf2
extensions: Fix language detection (#968) 2024-07-12 12:06:28 +02:00
Sonny
669d808c89
Switch back devel to 46 again (#966)
Nightly is too broken at this stage
2024-07-11 16:59:20 +02:00
UrtsiSantsi
fa3f77ef51
Fix code search close button behavior (#960)
Fixes #959 

Clear the highlights in the code and remember the last searched word
2024-07-10 21:52:00 +02:00
Brage Fuglseth
05d6c3cf1a
readme: Update Flathub badge (#963)
See https://fosstodon.org/@bragefuglseth/112753049810610017
2024-07-09 16:39:39 +02:00
Sonny
2d9b184bd5
Use org.flatpak.Builder (#962) 2024-07-07 19:40:36 +02:00
Sonny
60cfdb38fb
Use GNOME nightly again (#961) 2024-07-07 16:23:59 +02:00
Atbrat
f4eb0e604b
library: Remove Usage of PreferencesPage and Group (#958) 2024-07-07 01:48:56 +02:00
Angelo Verlain Shema
2b13cf3ce2
Add typechecking for TypeScript (#946)
Co-authored-by: Sonny <sonny@fastmail.net>
2024-07-07 01:23:09 +02:00
Sonny Piers
afea0a5339 Use GNOME 46 for Workbench devel
GNOME nightly is temporarily broken
https://discourse.gnome.org/t/nightly-runtime-updated-to-freedesktop-sdk-24-08/21962
2024-07-05 12:58:33 +02:00
Sonny Piers
be55d5a675 Update Blueprint 2024-07-05 00:31:28 +02:00
Sonny Piers
bdf7bed717 Add make stable and make devel commands 2024-07-03 15:01:32 +02:00
Atbrat
78dbbfbc75
library: Remove usage of Adw.PreferencesRow (#955) 2024-07-03 14:47:31 +02:00
Sonny Piers
dd9a3e87a3 ci: Allow triggering workflows manually 2024-07-02 14:04:27 +02:00
Atbrat
d4066fc32a
library: Add search bar inside library view (#950) 2024-06-30 00:47:45 +02:00
Atbrat
5a29338cce
library: Remove usage of Adw.PreferencesWindow (#949) 2024-06-25 00:58:27 +02:00
Sonny Piers
ea18e429c9 Update language support 2024-06-18 22:42:22 +02:00
Sonny Piers
b16fc2ddec Improve Blueprint completion experience 2024-06-16 23:49:27 +02:00
Sonny Piers
d8f06f1b46 cli: Filter out erronous Vala CSS Gradients deprecations 2024-06-15 00:23:15 +02:00
Angelo Verlain Shema
84f1bfa1cc Add TypeScript support
Squashed commit of the following:

commit 705f0256b155d523f0759081b995b902851f1010
Merge: 915fe997 17e53775
Author: Sonny Piers <sonny@fastmail.net>
Date:   Thu May 30 17:35:46 2024 +0300

    Merge branch 'main' into typescript

commit 915fe997c8c0fa30db061d17cc7849678aa1c681
Author: Angelo Verlain Shema <37999241+vixalien@users.noreply.github.com>
Date:   Tue May 28 11:19:04 2024 +0200

    Compile TypeScript to JavaScript before executing (#941)

    This basically compiles from TypeScript to JavaScript at runtime when
    the "Run" button is clicked.

    However, there are currently 2 issues worth mentioning:

    ### 1. Speed

    Notice that this is noticeably slow because it's using `tsc`. It could
    possibly be improved by using `esbuild`, `swc`, `babel` or something
    similar but then there will be no typechecking when the "Run" button is
    clicked.

    However, I think the above typechecking caveat will not make much sense
    when we have real-time Intellisense in the editor for TypeScript.

    ### 2. Sourcemaps

    Another consideration is the lack of sourcemap support in GJS. While tsc
    can generate sourcemaps, this feature is disabled because GJS won't use
    them. This means that some errors will have the wrong line:column
    information.

    For example:

    ![image](https://github.com/workbenchdev/Workbench/assets/37999241/c6487292-18a9-4e50-85a0-5c8771f107fc)

    Workbench/GJS reports the error is on line number 17 even if it's
    actually on line number 22 because that's where it ends up after it's
    compiled to JavaScript (many compilers will eat up unnecessary line
    breaks even though the minify option is turned off).

    I left some TODOs in here where some decisions need to be made and hope
    to get some feedback

commit 773669f02adb90d59f82a11ba6d16e35bd114a28
Author: Angelo Verlain Shema <37999241+vixalien@users.noreply.github.com>
Date:   Tue May 7 15:53:06 2024 +0200

    Add base TypeScript view to Workbench (#938)
2024-06-06 15:05:24 +03:00
Sonny Piers
17a8e4a6af Various improvements to completion 2024-06-03 22:36:19 +03:00
Sonny Piers
e9748dd79f Fix CSS scoping for CSS variables
```
:root {
  --color: red;
}

label {
  color: var(--color);
}
```
2024-06-03 22:34:06 +03:00
Sonny Piers
a4e1163e13 Fix confusing warning when typing a property
"Argument type may not be null"
2024-06-02 07:55:16 +03:00
Sonny
3a9c3338e0
Completion provider (#155)
Fixes https://github.com/sonnyp/Workbench/issues/257

Works well with CSS and Blueprint for now
We'll need to tweak language servers and fix some issues for
Vala/Python/Rust/JavaScript

---
EDIT: the following is outdated thanks to
https://github.com/sonnyp/Workbench/pull/371

This is blocked by https://gitlab.gnome.org/GNOME/gjs/-/issues/72

https://gitlab.gnome.org/GNOME/gjs/-/issues/255 is a better explanation
of the problem
2024-06-02 06:56:55 +03:00
Sonny Piers
b26fd1d381 Update vte 0.76.2 2024-05-31 11:28:07 +03:00
Sonny Piers
d2c8150675 Update libshumate 1.2.2 2024-05-31 11:27:45 +03:00
Sonny Piers
17e5377587 Fix an async function signature
Argument ready_callback_closure may not be null
2024-05-30 17:11:12 +03:00
Sonny
df4b1d4461
Use org.gnome master for devel (#944)
We are now on gnome nightly
2024-05-28 17:36:22 +03:00
Sonny Piers
89a9f1b348 ci: Checkout submodules for deploy 2024-05-28 15:44:47 +03:00
Sonny
26d48f4fe1
ci: Deploy to gnome-nightly (#942) 2024-05-28 15:24:12 +03:00
Sonny Piers
0b0a0a283c Fix python-previewer formatting 2024-05-14 00:51:47 +02:00
Sonny Piers
b2dc1df6f3 Add Adwaita icon theme to search path 2024-04-30 01:19:52 +02:00
Sonny Piers
563a316695 Do not read icons from host 2024-04-28 18:12:17 +02:00
Sonny Piers
c65bdb49e2 Support icons in projects 2024-04-28 17:14:42 +02:00
Sonny Piers
3ae1c8c611 cli: Skip incompatible demos 2024-04-28 15:09:19 +02:00
Sonny Piers
be124d22d8 Fix Vala and Rust extensions detection on "Run" 2024-04-28 11:53:19 +02:00
Sonny Piers
d8584653ce Update metadata 2024-04-28 11:02:23 +02:00
Sonny Piers
16f4f12810 Ignore incompatible demos 2024-04-27 23:25:01 +02:00
Sonny Piers
fae77d8ea1 Revert "Use Flatter to generate nightly builds (#936)"
This reverts commit d8c79925127a32fe04109684ae8e006dfabb96d6.
2024-04-27 10:44:05 +02:00
Sonny
d8c7992512
Use Flatter to generate nightly builds (#936) 2024-04-27 00:24:06 +02:00
Sonny Piers
2b7a0aa6da Use Adw.Dialog instead of custom Modal widget 2024-04-21 17:09:41 +02:00
Sonny
1ebbe1e391
Remove icon library (#932) 2024-04-21 16:12:29 +02:00
Sonny
f511bc15ec
Load project icons using resources (#934)
Follow up to https://github.com/workbenchdev/Workbench/pull/887

The current solution using file search paths is not ideal.

It requires the following structure in session / demo dirs:
`icons/scalable/actions`
Exposing users to unnecessary jargon which can usually be ignored during
app development since the icon theme is not something we are interested
in.

With the file search paths it's possible to place `library-symbolic.svg`
in `icons` but it won't be considered symbolic no matter what and
therefor won't recolor.

Also by unloading icons, we can avoid conflicts between demos for the
internal previewer.
2024-04-21 15:00:37 +02:00
Sonny Piers
16cda14d9a Save and restore session windows 2024-04-21 12:37:53 +02:00
Sonny
6ee084e1a0
Allow custom icons in projects (#887) 2024-04-16 01:51:39 +02:00
Sonny Piers
4126d00920 Update demos 2024-04-15 22:08:07 +02:00
Jamie Gravendeel
ac5ec74787
Update Bart Gravendeel in contributors (#927)
Change name and update the domain.
2024-04-03 15:27:41 +02:00
Parker Cook
185dfe415a
Removing the install button from Vala in Workbench Extensions (#926)
I have been asked to delete the Install button for Vala in Workbenches extensions due to it having people install a different version of Vala than is needed.

https://github.com/workbenchdev/Workbench/issues/925
2024-04-03 02:33:30 +02:00
Sonny
4c2944e89c
Enable Code Search (#917) 2024-04-03 02:18:39 +02:00
Angelo Verlain Shema
9f6af155b8
Use Reverse-DNS name for developer ID (#921)
Fixes #906
2024-04-01 00:32:12 +02:00
Angelo Verlain Shema
5d442dbe33
Don't use deprecated methods (#924)
This PR utilises the following methods instead of their deprecated
counterparts:

- `Gtk.Widget.get_height` instead of `Gtk.Widget.get_allocated_height` 
- `Gtk.Widget.get_width` instead of `Gtk.Widget.get_allocated_width` 
- `GLib.resource_register` instead of `GLib.Resource._register`

Thanks!
2024-03-30 16:42:12 +01:00
Sonny
011d9d837f
Do not copy build files to the library (#918)
The way we copied `demos` to `pkgdatadir` was
`install_subdir('../demos/src', install_dir : join_paths(pkgdatadir,
'demos'), strip_directory: true)`

But this method would copy all files, including build files so when a
user creates a session from a demo, the build files would be carried
over as well.

Build files are present in `demos` when opening of the demo with
Workbench directly as a folder project.

The presence of `Cargo.lock` in the session caused problems
which this solves.
2024-03-25 00:20:30 +01:00
Sonny
75ce9e32a6
Make it easier to debug lsp (#920) 2024-03-24 18:04:37 +01:00
Sonny Piers
13dccf5b30 Update Blueprint to 0.12.0 2024-03-24 13:53:50 +01:00
Sonny
984cc2c13c
rust: Enable GNOME 46 (#910) 2024-03-20 14:10:59 +01:00
Sonny Piers
5e034880af Clear own logs on start 2024-03-20 11:26:57 +01:00
Sonny
fb6d55abe9
Update VTE 0.76 (#911) 2024-03-20 11:01:49 +01:00
Sonny Piers
b60eac426d 46 2024-03-20 10:36:25 +01:00
Sonny
0df5033f1d
pre 46 maintenance (#909) 2024-03-17 13:58:26 +01:00
Sonny Piers
749c7f3884 Do not build separate locales
We only support English
2024-03-16 22:23:10 +01:00
Sonny Piers
c145dd4a7c cli: Ignore Gtk.TreeIter deprecation in Text Fields 2024-03-16 22:23:10 +01:00
Vladimir Vaskov
53f9d3c62b
Add Rirusha to about.js (#907)
https://github.com/workbenchdev/demos/pull/120
2024-03-15 20:27:22 +01:00
Sonny
34b017b66d
Update dependencies and release notes (#905) 2024-03-08 23:32:54 +01:00
Sonny Piers
aaa8761e4d Adapt to demos moving to src 2024-03-07 09:14:06 +01:00
Jan Fooken
352d3b11e3
Add myself to to the about section (#904)
This commit adds my name to the contributor list for #857 

Thanks so much for the patience and help I received from you @sonnyp
@theCapypara
2024-03-04 23:09:53 +01:00
Sonny
4f0c6ef5a5
cli: Add proper Python support (#903) 2024-03-04 15:23:57 +01:00
Marco Köpcke
6f201f9cf5
Replace Black with Ruff, add LSP plugin for Ruff (#902)
Co-authored-by: Sonny Piers <sonny@fastmail.net>
2024-03-03 23:40:56 +01:00
Sonny
06cce1a912
Use an AdwDialog for Extensions (#900) 2024-03-03 20:23:08 +01:00
Jan Fooken
eb3a1e099a
Add pylsp as the python LSP (#857)
Co-authored-by: Sonny Piers <sonny@fastmail.net>
Co-authored-by: Marco Capypara Köpcke <hello@capypara.de>
2024-03-03 20:22:37 +01:00
Sonny Piers
4a398b0a50 Use Flathub beta 2024-03-01 18:59:19 +01:00
Sonny Piers
1cec46533d Fix appstream to make new Flathub validation pass 2024-03-01 18:09:34 +01:00
Atbrat
64e5db0c06
about: Add as contributor (#898) 2024-02-29 09:57:39 +01:00
Sonny Piers
774af5843a
46 beta (#896) 2024-02-21 20:13:37 +01:00
Hofer-Julian
c4da728abc
docs: Extend contributing section (#895)
`libxmljs` one of our nodejs dependencies requires a C++ compiler
2024-02-21 18:09:21 +01:00
Sonny Piers
e8c4147fe7
Solve brwap dangling process (#893)
Fixes https://github.com/workbenchdev/Workbench/issues/828
2024-02-20 00:22:56 +01:00
Sonny Piers
b9727214a3
Fix extensions detection (#892) 2024-02-18 17:45:39 +01:00
Sonny Piers
9206d0f1f9 Open Workbench windows maximized 2024-02-18 14:53:00 +01:00
Sonny Piers
45f0ba7e1a
Update modules (#891) 2024-02-18 14:51:27 +01:00
Bart Gravendeel
87936379fa
Add Bart Gravendeel to contributors (#890) 2024-02-18 13:17:38 +01:00
Diego Iván M.E
259a61cb1c
flatpak: Remove /app/include from cleanup (#886)
Before this change, Workbench installed via Flatpak was not able to run
Vala demos that required Shumate, Libportal or Libspelling because their
header files were removed by the cleanup process. The versions of
Workbench that are run from Builder or flatpak-vscode can actually
compile and execute this demos because they don't do any clean-up, and
therefore none of the header files are deleted, which is probably why
this issue went unnoticed for quite some time even when porting the
affected demos to Vala.

In order to test this changes and compare them with the current version
of Workbench, it is necessary to export a bundle and install it, so the
cleanup process is actually done.

Closes #885
2024-02-18 10:43:16 +01:00
Sonny Piers
6db6825a61
Use async enumerate_children (#889) 2024-02-18 00:58:14 +01:00
Bart Gravendeel
e5132f05cc
String fixes (#888) 2024-02-18 00:40:31 +01:00
Marco Köpcke
b134c81c86
Python Previewer: Initialize Shumate (#884)
See:
- https://github.com/workbenchdev/demos/pull/94
- https://github.com/workbenchdev/Workbench/pull/879
- https://github.com/workbenchdev/Workbench/issues/738
2024-02-16 09:03:20 +01:00
Sonny Piers
99d35b78c5
Asynchronize file copies (#882) 2024-02-14 17:10:31 +01:00
Sonny Piers
2514485ca4
Add Rust analyzer support (#868)
Fixes #520 

Only supports syntax diagnostics for now. I made a follow up for types
https://github.com/workbenchdev/Workbench/issues/881
2024-02-13 00:44:55 +01:00
Marco Köpcke
deb048d1b3
Python Previewer: Initialize WebView (#879) 2024-02-11 12:57:39 +01:00
Sonny Piers
2af69259fa
Update Rust deps (#878) 2024-02-11 01:02:01 +01:00
Sonny Piers
008877a07b
Support adw dialog preview (#880) 2024-02-10 23:27:54 +01:00
Sonny Piers
cbe33d9fde Set implicit-trailing-newline to false
Prevents unwanted changes to end of files.
This is what GNOME Builder does

https://gnome.pages.gitlab.gnome.org/gtksourceview/gtksourceview5/method.Buffer.set_implicit_trailing_newline.html
250b0951f9/src/libide/code/ide-buffer.c (L329)
2024-02-07 00:34:01 +01:00
Sonny Piers
f6fb4e7323
Use AdwWindow for the previewer (#877) 2024-02-03 01:19:42 +01:00
Lorenz Wildberg
e53da83c00
Extensions: Add button to install Vala SDK extension (#711)
Fixes https://github.com/workbenchdev/Workbench/issues/709

---------

Co-authored-by: Sonny Piers <sonny@fastmail.net>
2024-02-02 10:29:51 +01:00
Sonny Piers
2d1af689a5
cli: Remove unecessary exceptions in ci (#876) 2024-01-30 12:31:44 +01:00
Sonny Piers
a697b2fa25
Replace AdwMessageDialog with AdwAlertDialog (#874)
https://gitlab.gnome.org/jwestman/blueprint-compiler/-/merge_requests/177
2024-01-30 12:00:01 +01:00
Sonny Piers
a8eb24e9a5
GNOME 46 (#867) 2024-01-29 14:13:32 +01:00
Hofer-Julian
02cb5ee3b8
Fix doap file (#871)
- Wrap each person in their own `maintainer` attribute
- Fix my name
2024-01-27 16:52:50 +01:00
UrtsiSantsi
5f322703c3
Remove duplicate code (#869) 2024-01-26 16:32:20 +01:00
187 changed files with 16346 additions and 6416 deletions

View File

@ -4,11 +4,10 @@ env:
parser: "@babel/eslint-parser" parser: "@babel/eslint-parser"
parserOptions: parserOptions:
sourceType: module sourceType: module
ecmaVersion: 2023
requireConfigFile: false requireConfigFile: false
babelOptions: babelOptions:
plugins: plugins:
- "@babel/plugin-syntax-import-assertions" - "@babel/plugin-syntax-import-attributes"
extends: extends:
- eslint:recommended - eslint:recommended
- plugin:import/errors - plugin:import/errors

4
.gitconfig Normal file
View File

@ -0,0 +1,4 @@
[re.sonny.Commit]
title-length-hint=72
body-length-wrap=50
auto-capitalize-title=true

2
.github/CODEOWNERS vendored
View File

@ -4,7 +4,7 @@
/src/langs/vala/ @lw64 /src/langs/vala/ @lw64
*.vala @lw64 *.vala @lw64
/src/langs/rust/ @lw64 /src/langs/rust/ @Hofer-Julian
*.rs @Hofer-Julian *.rs @Hofer-Julian
Cargo.toml @Hofer-Julian Cargo.toml @Hofer-Julian
Cargo.lock @Hofer-Julian Cargo.lock @Hofer-Julian

View File

@ -5,10 +5,11 @@ name: CI
on: on:
pull_request: pull_request:
branches: [main] branches: [main]
workflow_dispatch:
jobs: jobs:
CI: CI:
runs-on: ubuntu-22.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -16,13 +17,12 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 20
cache: "npm" cache: "npm"
- name: Install host dependencies - name: Install host dependencies
run: | run: |
sudo apt-get update sudo apt-get install flatpak mutter flatpak-builder
sudo apt-get install flatpak flatpak-builder mutter
# Restore caches # Restore caches
- name: Restore Flatpak dependencies - name: Restore Flatpak dependencies

32
.github/workflows/deploy.yaml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-nightly
options: --privileged
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
name: "Build"
with:
bundle: re.sonny.Workbench.Devel.flatpak
manifest-path: build-aux/re.sonny.Workbench.Devel.json
cache-key: flatpak-builder-${{ github.sha }}
- uses: flatpak/flatpak-github-actions/flat-manager@v6
name: "Deploy"
with:
repository: nightly
flat-manager-url: https://flat-manager.gnome.org/
token: ${{ secrets.GNOME_NIGHTLY_TOKEN }}

3
.gitignore vendored
View File

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

7
.gitmodules vendored
View File

@ -4,3 +4,10 @@
[submodule "demos"] [submodule "demos"]
path = demos path = demos
url = https://github.com/workbenchdev/demos.git url = https://github.com/workbenchdev/demos.git
[submodule "blueprint-compiler"]
path = blueprint-compiler
url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git
[submodule "src/langs/typescript/template/gi-types"]
path = gi-types
url = https://gitlab.gnome.org/BrainBlasted/gi-typescript-definitions.git
branch = nightly

View File

@ -9,6 +9,6 @@
"prince781.vala", "prince781.vala",
"bodil.blueprint-gtk", "bodil.blueprint-gtk",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"ms-python.black-formatter" "charliermarsh.ruff"
] ]
} }

21
.vscode/settings.json vendored
View File

@ -5,8 +5,8 @@
"files.watcherExclude": { "files.watcherExclude": {
"**/.git/objects/**": true, "**/.git/objects/**": true,
"**/.git/subtree-cache/**": true, "**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true,
"**/.hg/store/**": true, "**/.hg/store/**": true,
"**/node_modules/*/**": true,
"**/.flatpak": true, "**/.flatpak": true,
"**/src/lib": true, "**/src/lib": true,
".flatpak": true, ".flatpak": true,
@ -14,17 +14,26 @@
"_build/**": true "_build/**": true
}, },
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"rust-analyzer.server.path": "${workspaceFolder}/.flatpak/rust-analyzer.sh",
"rust-analyzer.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
"rust-analyzer.files.excludeDirs": [".flatpak"],
"[yaml]": { "[yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[json]": { "[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"rust-analyzer.server.path": "${workspaceFolder}/.flatpak/rust-analyzer.sh",
"rust-analyzer.runnables.command": "${workspaceFolder}/.flatpak/cargo.sh",
"rust-analyzer.files.excludeDirs": [
".flatpak",
".flatpak-builder",
"_build",
"build",
"builddir"
],
"vala.languageServerPath": "${workspaceFolder}/.flatpak/vala-language-server.sh",
"[meson]": {
"editor.defaultFormatter": "mesonbuild.mesonbuild"
},
"mesonbuild.configureOnOpen": false, "mesonbuild.configureOnOpen": false,
"mesonbuild.buildFolder": "_build", "mesonbuild.buildFolder": "_build",
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh", "mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh"
"vala.languageServerPath": "${workspaceFolder}/.flatpak/vala-language-server.sh"
} }

View File

@ -26,13 +26,13 @@ We provide a couple of tools to make the development process pleasant.
```sh ```sh
# Ubuntu requirements # Ubuntu requirements
# sudo apt install flatpak flatpak-builder nodejs make # sudo apt install flatpak flatpak-builder nodejs make gcc g++
# Fedora requirements # Fedora requirements
# sudo dnf install flatpak flatpak-builder nodejs make # sudo dnf install flatpak flatpak-builder nodejs make gcc gcc-c++
cd Workbench cd Workbench
make setup make
``` ```
Before submitting a PR, we recommend running tests locally with Before submitting a PR, we recommend running tests locally with

View File

@ -1,18 +1,30 @@
SHELL:=/bin/bash -O globstar SHELL:=/bin/bash -O globstar
.PHONY: setup build lint unit test ci sandbox flatpak .PHONY: setup build lint unit test ci sandbox flatpak
.DEFAULT_GOAL := test .DEFAULT_GOAL := setup
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//45 org.flatpak.Builder org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.vala//23.08 org.freedesktop.Sdk.Extension.llvm16//23.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
npm install # flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo
make build # 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
git submodule update --init
npm install --no-fund
@echo "✅ You can use "make build" to build Workbench"
build: stable:
# flatpak --user run org.flatpak.Builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.json
flatpak-builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.json
devel:
# flatpak --user run org.flatpak.Builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json
flatpak-builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json flatpak-builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json
build: devel
cli: cli:
./troll/gjspack/bin/gjspack src/cli/main.js --appid=re.sonny.Workbench.cli --prefix=/re/sonny/Workbench --resource-root=src/ --no-executable flatpak/files/share/re.sonny.Workbench.cli/ ./troll/gjspack/bin/gjspack src/cli/main.js --appid=re.sonny.Workbench.cli --prefix=/re/sonny/Workbench --resource-root=src/ --no-executable flatpak/files/share/re.sonny.Workbench.cli/
cp src/cli/bin.js flatpak/files/bin/workbench-cli cp src/cli/bin.js flatpak/files/bin/workbench-cli
lint: lint:
@ -21,7 +33,8 @@ lint:
# Rust # Rust
./build-aux/fun rustfmt --check --edition 2021 src/**/*.rs ./build-aux/fun rustfmt --check --edition 2021 src/**/*.rs
# Python # Python
./build-aux/fun black --check src/**/*.py ./build-aux/fun ruff check --config=src/langs/python/ruff.toml src/**/*.py
./build-aux/fun ruff format --config=src/langs/python/ruff.toml --check src/**/*.py
# Blueprint # Blueprint
./build-aux/fun blueprint-compiler format src/**/*.blp ./build-aux/fun blueprint-compiler format src/**/*.blp
./build-aux/fun workbench-cli check blueprint src/**/*.blp ./build-aux/fun workbench-cli check blueprint src/**/*.blp
@ -30,11 +43,12 @@ 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
#./build-aux/wip/run.js build-aux/re.sonny.Workbench.Devel.json -- gjs -m ./troll/tst/bin.js test/*.test.js
# https://github.com/ximion/appstream/issues/398#issuecomment-1129454985 # https://github.com/ximion/appstream/issues/398#issuecomment-1129454985
# flatpak run org.freedesktop.appstream.cli validate --override=release-time-missing=info --no-net data/app.metainfo.xml # flatpak run org.freedesktop.appstream.cli validate --override=release-time-missing=info --no-net data/app.metainfo.xml
@ -47,25 +61,28 @@ unit:
# flatpak run --env=G_DEBUG=fatal-criticals --command=appstream-util org.flatpak.Builder validate data/app.metainfo.xml # flatpak run --env=G_DEBUG=fatal-criticals --command=appstream-util org.flatpak.Builder validate data/app.metainfo.xml
test: unit lint test: unit lint
./build-aux/fun workbench-cli ci demos/demos/Welcome ./build-aux/fun workbench-cli ci demos/src/Welcome
# ./build-aux/wip/run.js build-aux/re.sonny.Workbench.Devel.json -- workbench-cli ci demos/src/Welcome/
ci: setup test ci: setup build test
./build-aux/fun workbench-cli ci demos/demos/** # See Permissions.js
# flatpak override --user --share=network --socket=pulseaudio --device=input re.sonny.Workbench.Devel
./build-aux/fun workbench-cli ci demos/src/*
# Note that if you have Sdk extensions installed they will be used # Note that if you have Sdk extensions installed they will be used
# make sure to test without the sdk extensions installed # make sure to test without the sdk extensions installed
sandbox: setup sandbox: setup
flatpak-builder --ccache --user --install --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json flatpak run org.flatpak.Builder --ccache --user --install --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json
# flatpak remove --noninteractive org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.vala//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08 # flatpak remove --noninteractive org.freedesktop.Sdk.Extension.rust-stable//24.08 org.freedesktop.Sdk.Extension.vala//24.08 org.freedesktop.Sdk.Extension.llvm18//24.08
flatpak run --command="bash" re.sonny.Workbench.Devel flatpak run --command="bash" re.sonny.Workbench.Devel
flatpak: flatpak:
flatpak-builder --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json flatpak run org.flatpak.Builder --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json
# This is what Flathub does - consider moving to lint # This is what Flathub does - consider moving to lint
flatpak run --env=G_DEBUG=fatal-criticals --command=appstream-util org.flatpak.Builder validate flatpak/files/share/appdata/re.sonny.Workbench.Devel.appdata.xml flatpak run --env=G_DEBUG=fatal-criticals --command=appstream-util org.flatpak.Builder validate flatpak/files/share/appdata/re.sonny.Workbench.Devel.appdata.xml
flatpak run --command="desktop-file-validate" --filesystem=host:ro org.freedesktop.Sdk//23.08 flatpak/files/share/applications/re.sonny.Workbench.Devel.desktop flatpak run --command="desktop-file-validate" --filesystem=host:ro org.freedesktop.Sdk//24.08 flatpak/files/share/applications/re.sonny.Workbench.Devel.desktop
# appstreamcli validate --override=release-time-missing=info /path/to/your/app.metainfo.xml # appstreamcli validate --override=release-time-missing=info /path/to/your/app.metainfo.xml
flatpak-builder --run flatpak build-aux/re.sonny.Workbench.Devel.json bash flatpak run org.flatpak.Builder --run flatpak build-aux/re.sonny.Workbench.Devel.json bash
# Sync with .gitignore # Sync with .gitignore
clean: clean:

View File

@ -6,7 +6,7 @@ Learn and prototype with GNOME technologies
![](data/workbench.gif) ![](data/workbench.gif)
<a href='https://flathub.org/apps/re.sonny.Workbench'><img width='240' height='80' alt='Download on Flathub' src='https://dl.flathub.org/assets/badges/flathub-badge-en.svg'/></a> <a href='https://flathub.org/apps/re.sonny.Workbench'><img width='240' alt='Download on Flathub' src='https://flathub.org/api/badge?svg&locale=en'/></a>
Workbench lets you experiment with GNOME technologies, no matter if tinkering for the first time or building and testing a GTK user interface. Workbench lets you experiment with GNOME technologies, no matter if tinkering for the first time or building and testing a GTK user interface.
@ -14,12 +14,12 @@ Among other things, Workbench comes with
- Live GTK/CSS preview - Live GTK/CSS preview
- Library of 100+ examples - Library of 100+ examples
<!-- - JavaScript, TypeScript, Rust, Python and Vala support -->
- JavaScript, Rust, Python and Vala support - JavaScript, Rust, Python and Vala support
- Declarative user interface syntax - Declarative user interface syntax
- Autosave, sessions and projects - Autosave, sessions and projects
- Code linter and formatter - Code diagnostics, completion and formatter
- Terminal output - Terminal output
- 1000+ icons
Workbench is made possible by Flatpak. Only Flathub Workbench is supported. Workbench is made possible by Flatpak. Only Flathub Workbench is supported.
@ -31,21 +31,21 @@ Among other things, Workbench comes with
| | Formatter | Linter | Library demos[1] | | | Formatter | Linter | Library demos[1] |
| ---------- | --------- | ------ | ---------------- | | ---------- | --------- | ------ | ---------------- |
| JavaScript | ✅ | ✅ | 94 | | JavaScript | ✅ | ✅ | 103 |
| Python | ✅ | | 64 | | Python | ✅ | ✅ | 98 |
| Vala | ✅ | ✅ | 54 | | Vala | ✅ | ✅ | 92 |
| Rust | ✅ | | 45 | | Rust | ✅ | ✅ | 52 |
| Blueprint | ✅ | ✅ | | | Blueprint | ✅ | ✅ | |
| CSS | ✅ | ✅ | | | CSS | ✅ | ✅ | |
[1] As of 2024-01-14 <!--counted with `~/go/bin/scc demos/demos`--> [1] As of 2024-06-16 <!--counted with `~/go/bin/scc demos/src`-->
## Tips and tricks ## Tips and tricks
<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)

View File

@ -9,8 +9,8 @@
<shortdesc>Learn and prototype with GNOME technologies</shortdesc> <shortdesc>Learn and prototype with GNOME technologies</shortdesc>
<description>Workbench goal is to let you experiment with GNOME technologies, no matter if tinkering for the first time or building and testing a custom GTK widget.</description> <description>Workbench goal is to let you experiment with GNOME technologies, no matter if tinkering for the first time or building and testing a custom GTK widget.</description>
<homepage rdf:resource="https://apps.gnome.org/Workbench" /> <homepage rdf:resource="https://workbench.sonny.re" />
<bug-database rdf:resource="https://github.com/workbenchdev/Workbench/issues" /> <bug-database rdf:resource="https://workbench.sonny.re/feedback" />
<programming-language>JavaScript</programming-language> <programming-language>JavaScript</programming-language>
<programming-language>Vala</programming-language> <programming-language>Vala</programming-language>
<programming-language>C</programming-language> <programming-language>C</programming-language>
@ -38,8 +38,10 @@
</foaf:OnlineAccount> </foaf:OnlineAccount>
</foaf:account> </foaf:account>
</foaf:Person> </foaf:Person>
</maintainer>
<maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>julianhofer</foaf:name> <foaf:name>Julian Hofer</foaf:name>
<foaf:mbox rdf:resource="mailto:julianhofer@gnome.org" /> <foaf:mbox rdf:resource="mailto:julianhofer@gnome.org" />
<gnome:userid>julianhofer</gnome:userid> <gnome:userid>julianhofer</gnome:userid>
<foaf:account> <foaf:account>

1
blueprint-compiler Submodule

@ -0,0 +1 @@
Subproject commit 04ef0944db56ab01307a29aaa7303df6067cb3c0

View File

@ -4,34 +4,37 @@ This directory contains the Flatpak Manifest and other build utilities.
## Workbench Flatpak Manifests ## Workbench Flatpak Manifests
### gst-plugin-gtk4 ### Python Modules
```sh The `modules/python-*.json` files contain Flatpak modules to install Python dependencies.
wget https://crates.io/api/v1/crates/gst-plugin-gtk4/0.11.1/download
tar-xf download
cd gst-plugin-gtk4-0.11.1/
~/Projects/flathub/flatpak-builder-tools/cargo/flatpak-cargo-generator.py Cargo.lock
# cp generated-sources.json to gst-plugin-gtk4-sources.json
```
### Python Black Dependency These files are (sometimes partially, see below) auto-generated. Here is how to generate it:
`modules/python-black.json` contains the Flatpak modules to install [https://github.com/psf/black](black), the
uncompromising Python code formatter.
This file is partially auto-generated. Here is how to generate it:
1. Obtain an up-to-date copy of [flatpak-builder-tools](https://github.com/flatpak/flatpak-builder-tools). 1. Obtain an up-to-date copy of [flatpak-builder-tools](https://github.com/flatpak/flatpak-builder-tools).
2. Make sure you have a Python virtualenv activated with the dependencies for the `pip` generator from the repo above. 2. Make sure you have a Python virtualenv activated with the dependencies for the `pip` generator from the repo above.
3. Run `python3 <...>/flatpak-builder-tools/pip/flatpak-pip-generator black -o modules/python-black --build-isolation` 3. Run `python3 <...>/flatpak-builder-tools/pip/flatpak-pip-generator <package> -o modules/python-<package> --build-isolation`
You will notice that Workbench will now not build. This is due to these issues: You will notice that Workbench will not build after auto-generating these files as described above.
This is due to these issues:
- https://github.com/flatpak/flatpak-builder-tools/issues/380 - https://github.com/flatpak/flatpak-builder-tools/issues/380
- https://github.com/pypa/pip/issues/7863 - https://github.com/pypa/pip/issues/7863
This means that the generated JSON file now needs its build dependencies manually added. Check the build dependencies This means that the generated JSON file now needs its build dependencies manually added. Check the build dependencies
of black and their dependencies and add them to the JSON as well. Brute-forcing the build to obtain missing packages of the package and their dependencies and add them to the JSON as well. Brute-forcing the build to obtain missing packages
may help as does referencing old commits of the file. You can also use the generator command to generate dependencies may help as does referencing old commits of the file. You can also use the generator command to generate dependencies
for them and then merge it into the file by hand, but note that you will also need to manually collect their build for them and then merge it into the file by hand, but note that you will also need to manually collect their build
dependencies too. dependencies too.
In some cases you may also need to manually remove some packages the generator adds (such as `packaging` with `rope`,
as the SDK and Runtime already contain a version of these packages that can not be replaced. Make sure the package
you want to install is actually compatible with the version of that dependency in the SDK/Runtime.
#### Python packages with Maturin as build system
Python packages with Maturin as build system need some additional manual steps to get working. You will have to have
Rust enabled for compilation and pull in additional dependencies. See `modules/python-ruff.json` for example.
You can generate Maturin's dependencies with another generator provided by the Flatpak Builder Tools. Clone
the Maturin repo in the corresponding version you need and run:
`python3 <...>/flatpak-builder-tools/cargo/flatpak-cargo-generator.py <...>/Cargo.lock -o modules/cargo-sources-maturin.json`

View File

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

View File

@ -1,75 +0,0 @@
#!/usr/bin/env -S gjs -m
import Gio from "gi://Gio";
import GLib from "gi://GLib";
Gio._promisify(
Gio.File.prototype,
"enumerate_children_async",
"enumerate_children_finish",
);
Gio._promisify(
Gio.File.prototype,
"replace_contents_async",
"replace_contents_finish",
);
const demos_dir = Gio.File.new_for_path(
GLib.getenv("MESON_SOURCE_ROOT"),
).get_child("demos/demos");
const demos = [];
for (const file_info of demos_dir.enumerate_children(
"",
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
null,
)) {
if (file_info.get_file_type() !== Gio.FileType.DIRECTORY) continue;
const demo_name = file_info.get_name();
const demo_dir = demos_dir.get_child(demo_name);
let str;
try {
str = new TextDecoder().decode(
demo_dir.get_child("main.json").load_contents(null)[1],
);
} catch (err) {
console.warn(err);
continue;
}
const demo = JSON.parse(str);
demo.name = file_info.get_name();
const languages = [];
if (demo_dir.get_child("main.js").query_exists(null)) {
languages.push("javascript");
}
if (demo_dir.get_child("main.vala").query_exists(null)) {
languages.push("vala");
}
if (demo_dir.get_child("code.rs").query_exists(null)) {
languages.push("rust");
}
if (demo_dir.get_child("main.py").query_exists(null)) {
languages.push("python");
}
demo.languages = languages;
demos.push(demo);
}
const [pkgdatadir] = ARGV;
GLib.mkdir_with_parents(pkgdatadir, 0o755);
await Gio.File.new_for_path(pkgdatadir)
.get_child("demos/index.json")
.replace_contents_async(
new TextEncoder().encode(JSON.stringify(demos)),
null,
false,
Gio.FileCreateFlags.NONE,
null,
);

250
build-aux/library.js Executable file
View File

@ -0,0 +1,250 @@
#!/usr/bin/env -S gjs -m
import Gio from "gi://Gio";
import GLib from "gi://GLib";
import { programArgs, exit } from "system";
Gio._promisify(
Gio.File.prototype,
"enumerate_children_async",
"enumerate_children_finish",
);
Gio._promisify(
Gio.File.prototype,
"replace_contents_async",
"replace_contents_finish",
);
Gio._promisify(
Gio.File.prototype,
"make_directory_async",
"make_directory_finish",
);
Gio._promisify(Gio.File.prototype, "copy_async", "copy_finish");
const loop = new GLib.MainLoop(null, false);
const [pkgdatadir] = programArgs;
GLib.mkdir_with_parents(
Gio.File.new_for_path(pkgdatadir).get_child("demos").get_path(),
0o755,
);
const demos_dir = Gio.File.new_for_path(
GLib.getenv("MESON_SOURCE_ROOT"),
).get_child("demos/src");
const demos = [];
(async () => {
const enumerator = await demos_dir.enumerate_children_async(
`${Gio.FILE_ATTRIBUTE_STANDARD_NAME},${Gio.FILE_ATTRIBUTE_STANDARD_IS_HIDDEN}`,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
GLib.PRIORITY_DEFAULT,
null,
);
for (const file_info of enumerator) {
if (file_info.get_is_hidden()) continue;
if (file_info.get_file_type() !== Gio.FileType.DIRECTORY) continue;
const demo_dir = enumerator.get_child(file_info);
let str;
try {
str = new TextDecoder().decode(
demo_dir.get_child("main.json").load_contents(null)[1],
);
} catch (err) {
console.warn(err);
continue;
}
const demo = JSON.parse(str);
demo.name = file_info.get_name();
if (!isDemoCompatible(demo)) {
continue;
}
const languages = [];
if (demo_dir.get_child("main.js").query_exists(null)) {
languages.push("javascript");
}
if (demo_dir.get_child("main.ts").query_exists(null)) {
languages.push("typescript");
}
if (demo_dir.get_child("main.vala").query_exists(null)) {
languages.push("vala");
}
if (demo_dir.get_child("code.rs").query_exists(null)) {
languages.push("rust");
}
if (demo_dir.get_child("main.py").query_exists(null)) {
languages.push("python");
}
demo.languages = languages;
await copyDemo(
demo_dir,
Gio.File.new_for_path(pkgdatadir)
.get_child("demos")
.get_child(demo_dir.get_basename()),
);
demos.push(demo);
}
demos.sort((a, b) => {
if (a.name === "Welcome") return -1;
if (b.name === "Welcome") return 1;
if (a.name === "Platform Tools") return -1;
if (b.name === "Platform Tools") return 1;
else return a.name.localeCompare(b.name);
});
await Gio.File.new_for_path(pkgdatadir)
.get_child("demos/index.json")
.replace_contents_async(
new TextEncoder().encode(JSON.stringify(demos)),
null,
false,
Gio.FileCreateFlags.NONE,
null,
);
})()
.catch((err) => {
loop.quit();
console.error(err);
exit(1);
})
.then(() => {
loop.quit();
});
async function copyDemo(source, destination) {
try {
destination.make_directory_with_parents(null);
} catch (err) {
if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) {
throw err;
}
}
const enumerator = await source.enumerate_children_async(
`${Gio.FILE_ATTRIBUTE_STANDARD_NAME},${Gio.FILE_ATTRIBUTE_STANDARD_IS_HIDDEN}`,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
GLib.PRIORITY_DEFAULT,
null,
);
for await (const file_info of enumerator) {
if (file_info.get_is_hidden()) continue;
const child = enumerator.get_child(file_info);
if (
// Sync with demos "make clean" and .gitignore
[
"Cargo.lock",
"Cargo.toml",
"lib.rs",
"workbench.rs",
"workbench.vala",
"libworkbenchcode.so",
"settings",
"main.ui",
"icons.gresource",
"icons.gresource.xml",
].includes(child.get_basename())
) {
continue;
}
const child_dest = destination.get_child(child.get_basename());
if (file_info.get_file_type() === Gio.FileType.DIRECTORY) {
await copyDirectory(child, child_dest);
continue;
}
try {
await child.copy_async(
child_dest, // destination
Gio.FileCopyFlags.NONE, // flags
GLib.PRIORITY_DEFAULT, // priority
null, // cancellable
null, // progress_callback
);
} catch (err) {
if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) {
throw err;
}
}
}
}
async function copyDirectory(source, destination) {
try {
await destination.make_directory_async(GLib.PRIORITY_DEFAULT, null);
} catch (err) {
if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) {
throw err;
}
}
const enumerator = await source.enumerate_children_async(
`${Gio.FILE_ATTRIBUTE_STANDARD_NAME},${Gio.FILE_ATTRIBUTE_STANDARD_IS_HIDDEN}`,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
GLib.PRIORITY_DEFAULT,
null,
);
for await (const file_info of enumerator) {
if (file_info.get_is_hidden()) continue;
const child = enumerator.get_child(file_info);
const child_dest = destination.get_child(child.get_basename());
if (file_info.get_file_type() === Gio.FileType.DIRECTORY) {
await copyDirectory(child, child_dest);
continue;
}
try {
await child.copy_async(
child_dest, // destination
Gio.FileCopyFlags.NONE, // flags
GLib.PRIORITY_DEFAULT, // priority
null, // cancellable
null, // progress_callback
);
} catch (err) {
if (!err.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) {
throw err;
}
}
}
}
const key_file = new GLib.KeyFile();
key_file.load_from_file("/.flatpak-info", GLib.KeyFileFlags.NONE);
// runtime/org.gnome.Sdk/x86_64/master
const [, , , runtime_version] = key_file
.get_string("Application", "runtime")
.split("/");
function isDemoCompatible(demo) {
const demo_runtime_version = demo["runtime-version"];
if (demo_runtime_version === "master") {
return runtime_version === "master";
} else if (runtime_version === "master") {
return true;
} else if (!demo_runtime_version) {
return true;
}
return +runtime_version >= +demo_runtime_version;
}
loop.run();

View File

@ -6,19 +6,23 @@
{ {
"type": "git", "type": "git",
"url": "https://github.com/JCWasmx86/GTKCssLanguageServer", "url": "https://github.com/JCWasmx86/GTKCssLanguageServer",
"commit": "6475047e6d2632467838769332bc849941ab2aaa" "commit": "dcbe75012d2d26fbca2729cee014e4860e31fa53"
} }
], ],
"modules": [ "modules": [
{ {
"name": "jsonrpc-glib", "name": "jsonrpc-glib",
"config-opts": ["--buildtype=release", "-Denable_tests=false"], "config-opts": [
"--libdir=/app/lib",
"--buildtype=release",
"-Denable_tests=false"
],
"buildsystem": "meson", "buildsystem": "meson",
"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

@ -7,15 +7,15 @@
"type": "file", "type": "file",
"dest-filename": "biome", "dest-filename": "biome",
"only-arches": ["aarch64"], "only-arches": ["aarch64"],
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.4.1/biome-linux-arm64", "url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.9.4/biome-linux-arm64",
"sha256": "8f2712e303877594a9401ce392724f8b8c94d533b6f5902d9cbdd149e4fbd794" "sha256": "f0f0f3e7cdec78420a600b05bfc364aa9b804811bd3bbae04e7bf090828ae970"
}, },
{ {
"type": "file", "type": "file",
"dest-filename": "biome", "dest-filename": "biome",
"only-arches": ["x86_64"], "only-arches": ["x86_64"],
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.4.1/biome-linux-x64", "url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.9.4/biome-linux-x64",
"sha256": "2995159aebcb7ddd116b098a1a0a459d1a8681aaa878623fb5390cc0dd0e414a" "sha256": "ce247fb644999ef52e5111dd6fd6e471019669fc9c4a44b5699721e39b7032c3"
} }
] ]
} }

View File

@ -3,9 +3,8 @@
"buildsystem": "meson", "buildsystem": "meson",
"sources": [ "sources": [
{ {
"type": "git", "type": "dir",
"url": "https://gitlab.gnome.org/jwestman/blueprint-compiler.git", "path": "../../blueprint-compiler"
"commit": "80aaee374d332b0c7e04a132cce9c472d6427a1e"
} }
] ]
} }

View File

@ -0,0 +1,12 @@
{
"name": "gom",
"buildsystem": "meson",
"config-opts": ["--libdir=/app/lib", "-Denable-gtk-doc=false"],
"sources": [
{
"type": "archive",
"url": "https://download.gnome.org/sources/gom/0.5/gom-0.5.3.tar.xz",
"sha256": "069d0909fbdc6b4d27edf7a879366194e3ab508b03548bf5b89ff63546d20177"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
{
"name": "gst-plugin-gtk4",
"buildsystem": "simple",
"sources": [
{
"type": "archive",
"url": "https://crates.io/api/v1/crates/gst-plugin-gtk4/0.11.2/download",
"dest-filename": "gst-plugin-gtk4-0.11.2.tar.gz",
"sha256": "33970273495544e54d5f486d761b09d402f0cf8760990e1ea508bd5141f8ebeb"
},
"gst-plugin-gtk4-sources.json"
],
"build-commands": [
"cargo cinstall --offline --release --features=wayland,x11glx,x11egl --library-type=cdylib --prefix=/app"
],
"build-options": {
"env": {
"CARGO_HOME": "/run/build/gst-plugin-gtk4/cargo"
}
}
}

View File

@ -1,40 +0,0 @@
{
"name": "icon-development-kit",
"buildsystem": "simple",
"build-commands": [
"mkdir -p /app/share/icon-development-kit",
"mkdir -p /app/share/icons/hicolor/scalable/actions/",
"yq -o=json _data/icons.yaml > /app/share/icon-development-kit/icons.json",
"cp -r img/symbolic/**/*.svg /app/share/icons/hicolor/scalable/actions/ || true"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/Teams/Design/icon-development-kit-www.git",
"commit": "d6bc308bbf9dab29c719f09ddfd54088b58abf5f"
}
],
"modules": [
{
"name": "yq",
"buildsystem": "simple",
"build-commands": ["chmod +x yq", "cp yq /app/bin/yq"],
"sources": [
{
"type": "file",
"only-arches": ["x86_64"],
"url": "https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_amd64",
"sha256": "4ee662847c588c3ef2fec8bfb304e8739e3dbaba87ccb9a608d691c88f5b64dc",
"dest-filename": "yq"
},
{
"type": "file",
"only-arches": ["aarch64"],
"url": "https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_arm64",
"sha256": "15925a972d268bcb0a7aa2236c7e5925b7a3ba4b5569bb57e943db7e8c6f834f",
"dest-filename": "yq"
}
]
}
]
}

View File

@ -2,6 +2,7 @@
"name": "libportal", "name": "libportal",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": [ "config-opts": [
"--libdir=/app/lib",
"-Dtests=false", "-Dtests=false",
"-Dbackend-gtk3=disabled", "-Dbackend-gtk3=disabled",
"-Dbackend-gtk4=enabled", "-Dbackend-gtk4=enabled",
@ -11,8 +12,8 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/flatpak/libportal/releases/download/0.7.1/libportal-0.7.1.tar.xz", "url": "https://github.com/flatpak/libportal/releases/download/0.9.1/libportal-0.9.1.tar.xz",
"sha256": "297b90b263fad22190a26b8c7e8ea938fe6b18fb936265e588927179920d3805" "sha256": "de801ee349ed3c255a9af3c01b1a401fab5b3fc1c35eb2fd7dfb35d4b8194d7f"
} }
] ]
} }

View File

@ -1,12 +1,38 @@
{ {
"name": "libshumate", "name": "libshumate",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": ["-Dgtk_doc=false", "-Dlibsoup3=true"], "config-opts": ["--libdir=/app/lib", "-Ddemos=false", "-Dgtk_doc=false"],
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libshumate/1.1/libshumate-1.1.2.tar.xz", "url": "https://download.gnome.org/sources/libshumate/1.4/libshumate-1.4.rc.tar.xz",
"sha256": "8f094f6e7e256ab192800516ff96617abeec2363b054aad6aeb17e0088c1fb2c" "sha256": "a57b97dbbda55bcb07c6f0197ff006128518c2b2c88fbee8bea5168acbc9baee"
}
],
"modules": [
{
"name": "protobuf",
"buildsystem": "autotools",
"config-opts": ["DIST_LANG=cpp"],
"cleanup": ["/bin/protoc*", "/lib/libprotoc*", "/lib/libprotobuf-lite*"],
"sources": [
{
"type": "archive",
"url": "https://github.com/protocolbuffers/protobuf/releases/download/v3.17.3/protobuf-all-3.17.3.tar.gz",
"sha256": "77ad26d3f65222fd96ccc18b055632b0bfedf295cb748b712a98ba1ac0b704b2"
}
]
},
{
"name": "protobuf-c",
"buildsystem": "autotools",
"sources": [
{
"type": "archive",
"url": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.0/protobuf-c-1.4.0.tar.gz",
"sha256": "26d98ee9bf18a6eba0d3f855ddec31dbe857667d269bc0b6017335572f85bbcb"
}
]
} }
] ]
} }

View File

@ -1,12 +1,12 @@
{ {
"name": "libspelling", "name": "libspelling",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": ["-Ddocs=false"], "config-opts": ["--libdir=/app/lib", "-Ddocs=false"],
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/libspelling/0.2/libspelling-0.2.0.tar.xz", "url": "https://download.gnome.org/sources/libspelling/0.4/libspelling-0.4.6.tar.xz",
"sha256": "fdc5609e02818eca6fc172ff164caa8e52dba638d7590130af3dfb1f28b53421" "sha256": "3248a9b5336ea2f727d2db912d2f0083accc0505ce707679b3d9b8266c0101f5"
} }
] ]
} }

View File

@ -1,104 +0,0 @@
{
"name": "python3-black",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"black\""
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/36/bf/a462f36723824c60dc3db10528c95656755964279a6a5c287b4f9fd0fa84/black-23.10.1.tar.gz",
"sha256": "1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
"sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl",
"sha256": "4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl",
"sha256": "8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/b4/2a/9b1be29146139ef459188f5e420a66e835dda921208db600b7037093891f/pathspec-0.11.2-py3-none-any.whl",
"sha256": "1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/56/29/3ec311dc18804409ecf0d2b09caa976f3ae6215559306b5b530004e11156/platformdirs-3.11.0-py3-none-any.whl",
"sha256": "e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6b/be/0f2f4a5e8adc114a02b63d92bf8edbfa24db6fc602fca83c885af2479e0e/editables-0.5-py3-none-any.whl",
"sha256": "61e5ffa82629e0d8bfe09bc44a07db3c1ab8ed1ce78a6980732870f19b5e7d4c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/76/56/8ccca673e2c896931722f876bf040c0b6a7d8c1a128be60516a8a55bb27a/hatchling-1.18.0-py3-none-any.whl",
"sha256": "b66dc254931ec42aa68b5febd1d342c58142cc5267b7ff3b12ba3fa5b4900c93"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl",
"sha256": "8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/b4/2a/9b1be29146139ef459188f5e420a66e835dda921208db600b7037093891f/pathspec-0.11.2-py3-none-any.whl",
"sha256": "1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/05/b8/42ed91898d4784546c5f06c60506400548db3f7a4b3fb441cba4e5c17952/pluggy-1.3.0-py3-none-any.whl",
"sha256": "d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/40/05cb2725ca7e6c844c66af626c5749efd254ec4506f17a1d01ba79ae9da6/trove_classifiers-2023.10.18-py3-none-any.whl",
"sha256": "20a3da8e3cb65587cc9f5d5b837bf74edeb480bba9bd8cd4f03ab056d6b06c4c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/00/b1/90cc7881c2e870333eeafa6afb7b27de53418aad1ba5409ad331c96608a1/hatch_vcs-0.3.0-py3-none-any.whl",
"sha256": "60ce59a3fa4664057e4a858b6a96ab0b9dec21bf8f562f836139315bb361be8c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/0e/a3/b9a8b0adfe672bf0df5901707aa929d30a97ee390ba651910186776746d2/setuptools_scm-8.0.4-py3-none-any.whl",
"sha256": "b47844cd2a84b83b3187a5782c71128c28b4c94cad8bfb871da2784a5cb54c4f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/24/21/7d397a4b7934ff4028987914ac1044d3b7d52712f30e2ac7a2ae5bc86dd0/typing_extensions-4.8.0-py3-none-any.whl",
"sha256": "8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6b/74/74a15619861065fa75f6170c649cd2fd5467726bb407ec2017d4a3f92d28/hatch_fancy_pypi_readme-23.1.0-py3-none-any.whl",
"sha256": "9a2c0e5d527611701858083bfb355876f26e04a075342b7d4da725ba5a6dd6ea"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ef/cc/93f7213b2ab5ed383f98ce8020e632ef256b406b8569606c3f160ed8e1c9/setuptools-68.2.2.tar.gz",
"sha256": "4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/a4/99/78c4f3bd50619d772168bec6a0f34379b02c19c9cced0ed833ecd021fd0d/wheel-0.41.2.tar.gz",
"sha256": "0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c4/e6/c1ac50fe3eebb38a155155711e6e864e254ce4b6e17fe2429b4c4d5b9e80/flit_core-3.9.0.tar.gz",
"sha256": "72ad266176c4a3fcfab5f2930d76896059851240570ce9a98733b658cb786eba"
}
]
}

View File

@ -0,0 +1,64 @@
{
"name": "python3-python-lsp-ruff",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-lsp-ruff\""
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e1/c7/247d04257d391251f32a7179cb74b418954022f1e9e276b5933e6ac1d3b1/python_lsp_ruff-2.2.0-py3-none-any.whl",
"sha256": "fe0487c7997b38a59862c44e19cb815e24bb1b2f7cef4f1f32c61cf623a5ce94"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/b3/0d/cd4a4071c7f38385dc5ba91286723b4d1090b87815db48216212c6c6c30e/cattrs-23.2.3-py3-none-any.whl",
"sha256": "0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/8d/37/2351e48cb3309673492d3a8c59d407b75fb6630e560eb27ecd4da03adc9a/lsprotocol-2023.0.1-py3-none-any.whl",
"sha256": "c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/91/f7/3b9c3a588e46bbdc2671d8fd07ecee118a672db50d72656b5726fbeffbcd/python_lsp_server-1.10.0-py3-none-any.whl",
"sha256": "1a9f338bd7cf3cdde5ae85a2bd93fd5be9e55249f6482d88f99fb6227215424a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl",
"sha256": "99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl",
"sha256": "e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/a5/5b/0cc789b59e8cc1bf288b38111d002d8c5917123194d45b29dcdac64723cc/pluggy-1.4.0-py3-none-any.whl",
"sha256": "7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/cb/d9/656659d5b5d5f402b2b174cd0ba9bc827e07ce3c0bf88da65424baf64af8/python_lsp_jsonrpc-1.1.2-py3-none-any.whl",
"sha256": "7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6e/54/6f2bdac7117e89a47de4511c9f01732a283457ab1bf856e1e51aa861619e/ujson-5.9.0.tar.gz",
"sha256": "89cc92e73d5501b8a7f48575eeb14ad27156ad092c2e9fc7e3cf949f07e75532"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c1/cf/4eee59f6c4111b3e80cc32cf6bac483a90646f5c8693e84496c9855e8e38/docstring_to_markdown-0.15-py3-none-any.whl",
"sha256": "27afb3faedba81e34c33521c32bbd258d7fbb79eedf7d29bc4e81080e854aec0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/05/63/8011bd08a4111858f79d2b09aad86638490d62fbf881c44e434a6dfca87b/parso-0.8.3-py2.py3-none-any.whl",
"sha256": "c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"
}
]
}

View File

@ -0,0 +1,69 @@
{
"name": "python3-python-lsp-server",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-lsp-server\""
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/be/4f/1b6eb5a6d92ae52f3798e9fdffd225f1bcd017172bb732743315390a9025/docstring_to_markdown-0.13-py3-none-any.whl",
"sha256": "aa487059d0883e70e54da25c7b230e918d9e4d40f23d6dfaa2b73e4225b2d7dd"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl",
"sha256": "e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/05/63/8011bd08a4111858f79d2b09aad86638490d62fbf881c44e434a6dfca87b/parso-0.8.3-py2.py3-none-any.whl",
"sha256": "c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/05/b8/42ed91898d4784546c5f06c60506400548db3f7a4b3fb441cba4e5c17952/pluggy-1.3.0-py3-none-any.whl",
"sha256": "d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/cb/d9/656659d5b5d5f402b2b174cd0ba9bc827e07ce3c0bf88da65424baf64af8/python_lsp_jsonrpc-1.1.2-py3-none-any.whl",
"sha256": "7339c2e9630ae98903fdaea1ace8c47fba0484983794d6aafd0bd8989be2b03c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/83/49/355783384945708c604f4ad4c773d4ec93bc609b691698e5d8ecfc51d01c/python_lsp_server-1.9.0-py3-none-any.whl",
"sha256": "6b947cf9dc33d7bed9abc936bb173140fcf606b6eb50cf02e27d4cb09f10d3fb"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6e/54/6f2bdac7117e89a47de4511c9f01732a283457ab1bf856e1e51aa861619e/ujson-5.9.0.tar.gz",
"sha256": "89cc92e73d5501b8a7f48575eeb14ad27156ad092c2e9fc7e3cf949f07e75532"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl",
"sha256": "8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/0e/a3/b9a8b0adfe672bf0df5901707aa929d30a97ee390ba651910186776746d2/setuptools_scm-8.0.4-py3-none-any.whl",
"sha256": "b47844cd2a84b83b3187a5782c71128c28b4c94cad8bfb871da2784a5cb54c4f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/b7/f4/6a90020cd2d93349b442bfcb657d0dc91eee65491600b2cb1d388bc98e6b/typing_extensions-4.9.0-py3-none-any.whl",
"sha256": "af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/bb/e1/ed2dd0850446b8697ad28d118df885ad04140c64ace06c4bd559f7c8a94f/setuptools-69.0.2-py3-none-any.whl",
"sha256": "1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c7/c3/55076fc728723ef927521abaa1955213d094933dc36d4a2008d5101e1af5/wheel-0.42.0-py3-none-any.whl",
"sha256": "177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"
}
]
}

View File

@ -0,0 +1,48 @@
{
"name": "python3-ruff",
"buildsystem": "simple",
"build-commands": [
". /usr/lib/sdk/rust-stable/enable.sh && pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"ruff\""
],
"build-options": {
"env": {
"CARGO_HOME": "/run/build/python3-ruff/cargo",
"CARGO_NET_OFFLINE": "true"
}
},
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/20/90/43a3aa35f037e91582ec7516a92084a71f84e89e39ef580813bed072b154/maturin-1.4.0.tar.gz",
"sha256": "ed12e1768094a7adeafc3a74ebdb8dc2201fa64c4e7e31f14cfc70378bf93790"
},
"sources/cargo-sources-maturin.json",
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ef/cc/93f7213b2ab5ed383f98ce8020e632ef256b406b8569606c3f160ed8e1c9/setuptools-68.2.2.tar.gz",
"sha256": "4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c7/c3/55076fc728723ef927521abaa1955213d094933dc36d4a2008d5101e1af5/wheel-0.42.0-py3-none-any.whl",
"sha256": "177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/f7/7f/8b1c33598b03ad612b8ced223f9ca54076b789fabf5a66ce37cc096d9cf7/setuptools_rust-1.9.0-py3-none-any.whl",
"sha256": "409caf49dcf7ad9bd510b4bf4011fbad504e745fae98f57fe1c06f3a97719638"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl",
"sha256": "de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/61/b0/5fb64bc79464823ca94e566c9000143ddc11f9396c6e20202315059dd64f/ruff-0.3.0.tar.gz",
"sha256": "0886184ba2618d815067cf43e005388967b67ab9c80df52b32ec1152ab49f53a"
},
"sources/cargo-sources-ruff.json"
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
"name": "vte", "name": "vte",
"buildsystem": "meson", "buildsystem": "meson",
"config-opts": [ "config-opts": [
"--libdir=/app/lib",
"-Ddocs=false", "-Ddocs=false",
"-Dgtk3=false", "-Dgtk3=false",
"-Dgtk4=true", "-Dgtk4=true",
@ -11,8 +12,21 @@
"sources": [ "sources": [
{ {
"type": "archive", "type": "archive",
"url": "https://download.gnome.org/sources/vte/0.74/vte-0.74.0.tar.xz", "url": "https://download.gnome.org/sources/vte/0.79/vte-0.79.91.tar.xz",
"sha256": "9ae08f777952ba793221152d360550451580f42d3b570e3341ebb6841984c76b" "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

@ -1,19 +0,0 @@
{
"name": "webp-pixbuf-loader",
"buildsystem": "meson",
"config-opts": [
"-Dgdk_pixbuf_moduledir=/app/lib/gdk-pixbuf-2.0/2.10.0/loaders/"
],
"sources": [
{
"type": "git",
"url": "https://github.com/aruiz/webp-pixbuf-loader.git",
"tag": "0.2.4",
"commit": "a35014104a226265e44fe30fcdb4df9305af3466"
}
],
"post-install": [
"GDK_PIXBUF_MODULEDIR=/app/lib/gdk-pixbuf-2.0/2.10.0/loaders/ gdk-pixbuf-query-loaders > /app/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache",
"gdk-pixbuf-query-loaders >> /app/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
]
}

View File

@ -1,28 +1,30 @@
{ {
"$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": "45", "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",
"org.freedesktop.Sdk.Extension.rust-stable", "org.freedesktop.Sdk.Extension.rust-stable",
"org.freedesktop.Sdk.Extension.llvm16" "org.freedesktop.Sdk.Extension.llvm18",
"org.freedesktop.Sdk.Extension.node20",
"org.freedesktop.Sdk.Extension.typescript"
], ],
"build-options": { "build-options": {
"append-path": "/usr/lib/sdk/vala/bin:/usr/lib/sdk/rust-stable/bin", "append-path": "/usr/lib/sdk/vala/bin:/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/node20/bin:/usr/lib/sdk/typescript/bin",
"append-ld-library-path": "/usr/lib/sdk/vala/lib" "append-ld-library-path": "/usr/lib/sdk/vala/lib"
}, },
"command": "workbench", "command": "workbench",
"separate-locales": false,
"finish-args": [ "finish-args": [
"--share=ipc", "--share=ipc",
"--socket=fallback-x11", "--socket=fallback-x11",
"--socket=wayland", "--socket=wayland",
"--device=dri", "--device=dri"
"--share=network",
"--socket=pulseaudio"
], ],
"cleanup": [ "cleanup": [
"/include", "#/include",
"#/lib/pkgconfig", "#/lib/pkgconfig",
"/man", "/man",
"/share/doc", "/share/doc",
@ -34,17 +36,17 @@
"*.a" "*.a"
], ],
"modules": [ "modules": [
"modules/python-black.json",
"modules/blueprint-compiler.json", "modules/blueprint-compiler.json",
"modules/biome.json", "modules/biome.json",
"modules/gst-plugin-gtk4.json",
"modules/vte.json", "modules/vte.json",
"modules/libshumate.json", "modules/libshumate.json",
"modules/libportal.json", "modules/libportal.json",
"modules/libspelling.json", "modules/libspelling.json",
"modules/gom.json",
"modules/GTKCssLanguageServer.json", "modules/GTKCssLanguageServer.json",
"modules/icon-development-kit.json", "modules/python-python-lsp-server.json",
"modules/webp-pixbuf-loader.json", "modules/python-ruff.json",
"modules/python-python-lsp-ruff.json",
{ {
"name": "Workbench", "name": "Workbench",
"buildsystem": "meson", "buildsystem": "meson",

View File

@ -1,28 +1,30 @@
{ {
"$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": "45", "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",
"org.freedesktop.Sdk.Extension.rust-stable", "org.freedesktop.Sdk.Extension.rust-stable",
"org.freedesktop.Sdk.Extension.llvm16" "org.freedesktop.Sdk.Extension.llvm18",
"org.freedesktop.Sdk.Extension.node20",
"org.freedesktop.Sdk.Extension.typescript"
], ],
"build-options": { "build-options": {
"append-path": "/usr/lib/sdk/vala/bin:/usr/lib/sdk/rust-stable/bin", "append-path": "/usr/lib/sdk/vala/bin:/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/node20/bin:/usr/lib/sdk/typescript/bin",
"append-ld-library-path": "/usr/lib/sdk/vala/lib" "append-ld-library-path": "/usr/lib/sdk/vala/lib"
}, },
"command": "workbench", "command": "workbench",
"separate-locales": false,
"finish-args": [ "finish-args": [
"--share=ipc", "--share=ipc",
"--socket=fallback-x11", "--socket=fallback-x11",
"--socket=wayland", "--socket=wayland",
"--device=dri", "--device=dri"
"--share=network",
"--socket=pulseaudio"
], ],
"cleanup": [ "cleanup": [
"/include", "#/include",
"#/lib/pkgconfig", "#/lib/pkgconfig",
"/man", "/man",
"/share/doc", "/share/doc",
@ -34,17 +36,17 @@
"*.a" "*.a"
], ],
"modules": [ "modules": [
"modules/python-black.json",
"modules/blueprint-compiler.json", "modules/blueprint-compiler.json",
"modules/biome.json", "modules/biome.json",
"modules/gst-plugin-gtk4.json",
"modules/vte.json", "modules/vte.json",
"modules/libshumate.json", "modules/libshumate.json",
"modules/libportal.json", "modules/libportal.json",
"modules/libspelling.json", "modules/libspelling.json",
"modules/gom.json",
"modules/GTKCssLanguageServer.json", "modules/GTKCssLanguageServer.json",
"modules/icon-development-kit.json", "modules/python-python-lsp-server.json",
"modules/webp-pixbuf-loader.json", "modules/python-ruff.json",
"modules/python-python-lsp-ruff.json",
{ {
"name": "Workbench", "name": "Workbench",
"buildsystem": "meson", "buildsystem": "meson",

308
build-aux/wip/minimist.js Normal file
View File

@ -0,0 +1,308 @@
/* eslint-disable */
// https://github.com/minimistjs/minimist/blob/bedaa8b9ab5a901fa342aad4494cbbf676b11a21/index.js
function hasKey(obj, keys) {
var o = obj;
keys.slice(0, -1).forEach(function (key) {
o = o[key] || {};
});
var key = keys[keys.length - 1];
return key in o;
}
function isNumber(x) {
if (typeof x === "number") {
return true;
}
if (/^0x[0-9a-f]+$/i.test(x)) {
return true;
}
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
}
function isConstructorOrProto(obj, key) {
return (
(key === "constructor" && typeof obj[key] === "function") ||
key === "__proto__"
);
}
export default function minimist(args, opts) {
if (!opts) {
opts = {};
}
var flags = {
bools: {},
strings: {},
unknownFn: null,
};
if (typeof opts.unknown === "function") {
flags.unknownFn = opts.unknown;
}
if (typeof opts.boolean === "boolean" && opts.boolean) {
flags.allBools = true;
} else {
[]
.concat(opts.boolean)
.filter(Boolean)
.forEach(function (key) {
flags.bools[key] = true;
});
}
var aliases = {};
function isBooleanKey(key) {
if (flags.bools[key]) {
return true;
}
if (!aliases[key]) {
return false;
}
return aliases[key].some(function (x) {
return flags.bools[x];
});
}
Object.keys(opts.alias || {}).forEach(function (key) {
aliases[key] = [].concat(opts.alias[key]);
aliases[key].forEach(function (x) {
aliases[x] = [key].concat(
aliases[key].filter(function (y) {
return x !== y;
}),
);
});
});
[]
.concat(opts.string)
.filter(Boolean)
.forEach(function (key) {
flags.strings[key] = true;
if (aliases[key]) {
[].concat(aliases[key]).forEach(function (k) {
flags.strings[k] = true;
});
}
});
var defaults = opts.default || {};
var argv = { _: [] };
function argDefined(key, arg) {
return (
(flags.allBools && /^--[^=]+$/.test(arg)) ||
flags.strings[key] ||
flags.bools[key] ||
aliases[key]
);
}
function setKey(obj, keys, value) {
var o = obj;
for (var i = 0; i < keys.length - 1; i++) {
var key = keys[i];
if (isConstructorOrProto(o, key)) {
return;
}
if (o[key] === undefined) {
o[key] = {};
}
if (
o[key] === Object.prototype ||
o[key] === Number.prototype ||
o[key] === String.prototype
) {
o[key] = {};
}
if (o[key] === Array.prototype) {
o[key] = [];
}
o = o[key];
}
var lastKey = keys[keys.length - 1];
if (isConstructorOrProto(o, lastKey)) {
return;
}
if (
o === Object.prototype ||
o === Number.prototype ||
o === String.prototype
) {
o = {};
}
if (o === Array.prototype) {
o = [];
}
if (
o[lastKey] === undefined ||
isBooleanKey(lastKey) ||
typeof o[lastKey] === "boolean"
) {
o[lastKey] = value;
} else if (Array.isArray(o[lastKey])) {
o[lastKey].push(value);
} else {
o[lastKey] = [o[lastKey], value];
}
}
function setArg(key, val, arg) {
if (arg && flags.unknownFn && !argDefined(key, arg)) {
if (flags.unknownFn(arg) === false) {
return;
}
}
var value = !flags.strings[key] && isNumber(val) ? Number(val) : val;
setKey(argv, key.split("."), value);
(aliases[key] || []).forEach(function (x) {
setKey(argv, x.split("."), value);
});
}
// Set booleans to false by default.
Object.keys(flags.bools).forEach(function (key) {
setArg(key, false);
});
// Set booleans to user defined default if supplied.
Object.keys(defaults)
.filter(isBooleanKey)
.forEach(function (key) {
setArg(key, defaults[key]);
});
var notFlags = [];
if (args.indexOf("--") !== -1) {
notFlags = args.slice(args.indexOf("--") + 1);
args = args.slice(0, args.indexOf("--"));
}
for (var i = 0; i < args.length; i++) {
var arg = args[i];
var key;
var next;
if (/^--.+=/.test(arg)) {
// Using [\s\S] instead of . because js doesn't support the
// 'dotall' regex modifier. See:
// http://stackoverflow.com/a/1068308/13216
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
key = m[1];
var value = m[2];
if (isBooleanKey(key)) {
value = value !== "false";
}
setArg(key, value, arg);
} else if (/^--no-.+/.test(arg)) {
key = arg.match(/^--no-(.+)/)[1];
setArg(key, false, arg);
} else if (/^--.+/.test(arg)) {
key = arg.match(/^--(.+)/)[1];
next = args[i + 1];
if (
next !== undefined &&
!/^(-|--)[^-]/.test(next) &&
!isBooleanKey(key) &&
!flags.allBools
) {
setArg(key, next, arg);
i += 1;
} else if (/^(true|false)$/.test(next)) {
setArg(key, next === "true", arg);
i += 1;
} else {
setArg(key, flags.strings[key] ? "" : true, arg);
}
} else if (/^-[^-]+/.test(arg)) {
var letters = arg.slice(1, -1).split("");
var broken = false;
for (var j = 0; j < letters.length; j++) {
next = arg.slice(j + 2);
if (next === "-") {
setArg(letters[j], next, arg);
continue;
}
if (/[A-Za-z]/.test(letters[j]) && next[0] === "=") {
setArg(letters[j], next.slice(1), arg);
broken = true;
break;
}
if (
/[A-Za-z]/.test(letters[j]) &&
/-?\d+(\.\d*)?(e-?\d+)?$/.test(next)
) {
setArg(letters[j], next, arg);
broken = true;
break;
}
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
setArg(letters[j], arg.slice(j + 2), arg);
broken = true;
break;
} else {
setArg(letters[j], flags.strings[letters[j]] ? "" : true, arg);
}
}
key = arg.slice(-1)[0];
if (!broken && key !== "-") {
if (
args[i + 1] &&
!/^(-|--)[^-]/.test(args[i + 1]) &&
!isBooleanKey(key)
) {
setArg(key, args[i + 1], arg);
i += 1;
} else if (args[i + 1] && /^(true|false)$/.test(args[i + 1])) {
setArg(key, args[i + 1] === "true", arg);
i += 1;
} else {
setArg(key, flags.strings[key] ? "" : true, arg);
}
}
} else {
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
argv._.push(flags.strings._ || !isNumber(arg) ? arg : Number(arg));
}
if (opts.stopEarly) {
argv._.push.apply(argv._, args.slice(i + 1));
break;
}
}
}
Object.keys(defaults).forEach(function (k) {
if (!hasKey(argv, k.split("."))) {
setKey(argv, k.split("."), defaults[k]);
(aliases[k] || []).forEach(function (x) {
setKey(argv, x.split("."), defaults[k]);
});
}
});
if (opts["--"]) {
argv["--"] = notFlags.slice();
} else {
notFlags.forEach(function (k) {
argv._.push(k);
});
}
return argv;
}

264
build-aux/wip/run.js Executable file
View File

@ -0,0 +1,264 @@
#!/usr/bin/env -S gjs -m
import Gio from "gi://Gio";
import { exit, programArgs, programInvocationName } from "system";
import GLib from "gi://GLib";
import minimist from "./minimist.js";
// export G_MESSAGES_DEBUG=Gjs-Console && ./run.js
Gio._promisify(
Gio.File.prototype,
"load_contents_async",
"load_contents_finish",
);
Gio._promisify(
Gio.Subprocess.prototype,
"wait_check_async",
"wait_check_finish",
);
const path = GLib.get_current_dir();
console.debug(programInvocationName, programArgs);
const argv = minimist(programArgs, { boolean: true, "--": true });
console.debug(argv);
const [manifest_path] = argv._;
if (!manifest_path) {
// eslint-disable-next-line no-restricted-globals
print(`${programInvocationName} [--verbose] [--debug] MANIFEST [-- command]`);
exit(0);
}
const home = GLib.get_home_dir();
const manifest_file = Gio.File.new_for_path(manifest_path);
const [contents] = await manifest_file.load_contents_async(null);
const manifest = JSON.parse(new TextDecoder().decode(contents));
// console.log(JSON.parse(manifest));
const flatpak_id = manifest.id;
// We assume the last module is the app itself
const app_module = manifest.modules.at(-1);
function exists(path) {
const result = Gio.File.new_for_path(path).query_exists(null);
console.debug(`${path} ${result ? "exists" : "non existant"}`);
return result;
}
if (!exists(`${path}/.flatpak/repo`)) {
const { runtime, sdk } = manifest;
const runtime_version = manifest["runtime-version"];
// initializes repo
await run([
"flatpak",
"build-init",
`${path}/.flatpak/repo`,
flatpak_id,
sdk,
runtime,
runtime_version,
]);
}
const prefix = [
"flatpak-builder",
"--ccache",
"--force-clean",
"--disable-updates",
];
const suffix = [
`--state-dir=${path}/.flatpak/flatpak-builder`,
`--stop-at=${app_module.name}`,
`${path}/.flatpak/repo`,
Gio.File.new_for_path(path).get_relative_path(manifest_file),
];
// de-initializes
async function downloadSources() {
await run([...prefix, "--download-only", ...suffix]);
}
// de-initializes
async function buildModules() {
await run([
...prefix,
"--disable-download",
"--build-only",
"--keep-build-dirs",
...suffix,
]);
}
if (!exists(`${path}/.flatpak/flatpak-builder`)) {
await downloadSources();
await buildModules();
}
// builds workbench
if (!exists(`${path}/_build`)) {
await buildModules();
await buildCommand([
"meson",
"--prefix",
"/app",
"_build",
"-Dprofile=development",
]);
}
await buildCommand(["meson", "install", "-C", "_build"]);
// await buildCommand([
// `troll/gjspack/bin/gjspack`,
// `--appid=${flatpak_id}`,
// "--prefix=/re/sonny/Workbench",
// `--project-root=.`,
// `--resource-root=./src`,
// "--blueprint-compiler=/app/bin/blueprint-compiler",
// "--no-executable",
// `${path}/src/main.js`,
// `/app/share/${flatpak_id}.src.gresource`,
// ]);
// starts workbench
const command = argv["--"].length ? argv["--"] : [manifest.command];
await runCommand(command);
function buildCommand(argv) {
let PATH =
"/app/bin:/app/bin:/app/bin:/usr/bin:${home}/.var/app/com.visualstudio.code/data/node_modules/bin:/app/bin:/usr/bin";
const append_path = manifest["build-options"]?.["append-path"];
if (append_path) PATH += `:${append_path}`;
let LD_LIBRARY_PATH = "/app/lib:/app/lib";
const append_ld_library_path =
manifest["build-options"]?.["append-ls-library-path"];
if (append_ld_library_path) LD_LIBRARY_PATH += `:${append_ld_library_path}`;
const PKG_CONFIG_PATH =
"/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig:/app/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig";
return run([
"flatpak",
"build",
"--share=network",
`--filesystem=${path}`,
`--filesystem=${path}/.flatpak/repo`,
`--env=PATH=${PATH}`,
`--env=LD_LIBRARY_PATH=${LD_LIBRARY_PATH}`,
`--env=PKG_CONFIG_PATH=${PKG_CONFIG_PATH}`,
`--filesystem=${path}/_build`,
`${path}/.flatpak/repo`,
...argv,
]);
}
async function runCommand(argv) {
await exec(
[
"flatpak",
"build",
"--with-appdir",
"--allow=devel",
`--bind-mount=/run/user/1000/doc=/run/user/1000/doc/by-app/${flatpak_id}`,
...manifest["finish-args"],
// Non default permissions, see Permissions.js
// consider getting installed overrides instead with
// flatpak override --user --show re.sonny.Workbench.Devel
"--share=network",
"--socket=pulseaudio",
"--device=input",
"--talk-name=org.freedesktop.portal.*",
"--talk-name=org.a11y.Bus",
"--bind-mount=/run/flatpak/at-spi-bus=/run/user/1000/at-spi/bus",
"--env=AT_SPI_BUS_ADDRESS=unix:path=/run/flatpak/at-spi-bus",
...getHostEnv(),
"--bind-mount=/run/host/fonts=/usr/share/fonts",
"--bind-mount=/run/host/fonts-cache=/usr/lib/fontconfig/cache",
`--filesystem=${home}/.local/share/fonts:ro`,
`--filesystem=${home}/.cache/fontconfig:ro`,
`--bind-mount=/run/host/user-fonts-cache=${home}/.cache/fontconfig`,
`--bind-mount=/run/host/font-dirs.xml=${home}/.cache/font-dirs.xml`,
`${path}/.flatpak/repo`,
...argv,
],
{ verbose: true },
);
}
function getHostEnv() {
// https://github.com/bilelmoussaoui/flatpak-vscode/blob/6424e7d8f53924faa33c9043153e08b0aedf6225/src/utils.ts#L88
const forwarded_env_keys = [
"COLORTERM",
"DESKTOP_SESSION",
"LANG",
"WAYLAND_DISPLAY",
"XDG_CURRENT_DESKTOP",
"XDG_SEAT",
"XDG_SESSION_DESKTOP",
"XDG_SESSION_ID",
"XDG_SESSION_TYPE",
"XDG_VTNR",
"AT_SPI_BUS_ADDRESS",
];
const env_vars = [];
forwarded_env_keys.forEach((key) => {
const value = GLib.getenv(key);
if (value === undefined) env_vars.push(key + "=" + value);
});
return env_vars;
}
async function run(_) {
return exec(_, { verbose: argv.verbose });
}
async function exec(argv, { cancellable = null /*, verbose = false*/ }) {
argv = argv.map((arg) => {
return arg.toString();
});
console.debug(`$ ${argv.join(" ")}`);
let cancelId = 0;
// meson uses stdout for logs
// const flags = verbose
// ? Gio.SubprocessFlags.NONE
// : Gio.SubprocessFlags.STDOUT_SILENCE;
const flags = Gio.SubprocessFlags.NONE;
const proc = new Gio.Subprocess({
argv,
flags,
});
proc.init(cancellable);
if (cancellable instanceof Gio.Cancellable)
cancelId = cancellable.connect(() => proc.force_exit());
try {
const success = await proc.wait_check_async(null);
if (!success) {
const status = proc.get_exit_status();
throw new Gio.IOErrorEnum({
code: Gio.IOErrorEnum.FAILED,
message: `Command '${argv}' failed with exit code ${status}`,
});
}
} catch (err) {
console.debug(err);
exit(1);
} finally {
if (cancelId > 0) cancellable.disconnect(cancelId);
}
}

34
build-aux/wip/run.sh Executable file
View File

@ -0,0 +1,34 @@
set -eux
flatpak_id=re.sonny.Workbench.Devel
path=/home/sonny/Projects/Workbench
manifest=$path/build-aux/$flatpak_id.json
module_name=Workbench
command=workbench
function run_build_command {
flatpak build --share=network --filesystem=$path --filesystem=$path/.flatpak/repo --env=PATH=/app/bin:/app/bin:/app/bin:/usr/bin:/home/sonny/.var/app/com.visualstudio.code/data/node_modules/bin:/app/bin:/usr/bin:/usr/lib/sdk/vala/bin:/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/node20/bin:/usr/lib/sdk/typescript/bin --env=LD_LIBRARY_PATH=/app/lib:/app/lib:/usr/lib/sdk/vala/lib --env=PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig:/app/lib/pkgconfig:/app/share/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig --filesystem=$path/_build $path/.flatpak/repo $1
}
if [ ! -d "$path/.flatpak/repo" ]; then
# initializes repo
flatpak build-init $path/.flatpak/repo $flatpak_id org.gnome.Sdk org.gnome.Sdk 47
fi
if [ ! -d "$path/.flatpak/flatpak-builder" ]; then
# downloads sources (de-initializes)
flatpak-builder --ccache --force-clean --disable-updates --download-only --state-dir=$path/.flatpak/flatpak-builder --stop-at=$module_name $path/.flatpak/repo $manifest
# builds modules (de-initializes)
flatpak-builder --ccache --force-clean --disable-updates --disable-download --build-only --keep-build-dirs --state-dir=$path/.flatpak/flatpak-builder --stop-at=$module_name $path/.flatpak/repo $manifest
fi
# builds Workbench module
if [ ! -d "$path/_build" ]; then
run_build_command "meson --prefix /app _build -Dprofile=development"
else
time run_build_command "meson install -C _build"
# time run_build_command "$path/troll/gjspack/bin/gjspack --appid=$flatpak_id --prefix=/re.sonny.Workbench --project-root=$path --resource-root=$path/src --blueprint-compiler=/app/bin/blueprint-compiler --no-executable $path/src/main.js /app/share/$flatpak_id.src.gresource"
fi
# starts workbench
flatpak build --with-appdir --allow=devel --bind-mount=/run/user/1000/doc=/run/user/1000/doc/by-app/$flatpak_id --share=ipc --socket=fallback-x11 --socket=wayland --device=dri --share=network --socket=pulseaudio --talk-name='org.freedesktop.portal.*' --talk-name=org.a11y.Bus --bind-mount=/run/flatpak/at-spi-bus=/run/user/1000/at-spi/bus --env=AT_SPI_BUS_ADDRESS=unix:path=/run/flatpak/at-spi-bus --env=AT_SPI_BUS_ADDRESS=unix:path=/run/flatpak/at-spi-bus --env=COLORTERM=truecolor --env=DESKTOP_SESSION=gnome --env=LANG=en_US.UTF-8 --env=WAYLAND_DISPLAY=wayland-0 --env=XDG_CURRENT_DESKTOP=GNOME --env=XDG_SESSION_DESKTOP=gnome --env=XDG_SESSION_TYPE=wayland --bind-mount=/run/host/fonts=/usr/share/fonts --bind-mount=/run/host/fonts-cache=/usr/lib/fontconfig/cache --filesystem=/home/sonny/.local/share/fonts:ro --filesystem=/home/sonny/.cache/fontconfig:ro --bind-mount=/run/host/user-fonts-cache=/home/sonny/.cache/fontconfig --bind-mount=/run/host/font-dirs.xml=/home/sonny/.cache/font-dirs.xml $path/.flatpak/repo $command

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"/>
@ -12,15 +12,15 @@
<key name="recent-code-language" type="i"> <key name="recent-code-language" type="i">
<default>0</default> <default>0</default>
</key> </key>
<key name="open-extensions" type="b">
<default>false</default>
</key>
<key name="recent-projects" type="as"> <key name="recent-projects" type="as">
<default>[]</default> <default>[]</default>
</key> </key>
<key name="first-run" type="b"> <key name="first-run" type="b">
<default>true</default> <default>true</default>
</key> </key>
<key name="typescript" type="b">
<default>true</default>
</key>
</schema> </schema>
<schema id="@app_id@.Session" path="/re/sonny/Workbench/"> <schema id="@app_id@.Session" path="/re/sonny/Workbench/">
<key name="show-code" type="b"> <key name="show-code" type="b">
@ -59,5 +59,17 @@
<key name="edited" type="b"> <key name="edited" type="b">
<default>false</default> <default>false</default>
</key> </key>
<key name="window-width" type="i">
<default>0</default>
</key>
<key name="window-height" type="i">
<default>0</default>
</key>
<key name="window-maximized" type="b">
<default>false</default>
</key>
<key name="window-fullscreened" type="b">
<default>false</default>
</key>
</schema> </schema>
</schemalist> </schemalist>

View File

@ -3,17 +3,15 @@
<id>@app_id@</id> <id>@app_id@</id>
<launchable type="desktop-id">@app_id@.desktop</launchable> <launchable type="desktop-id">@app_id@.desktop</launchable>
<name translatable="no">Workbench</name> <name translatable="no">Workbench</name>
<!-- developer_name tag deprecated with Appstream 1.0 --> <developer id="re.sonny">
<developer_name translatable="no">Sonny Piers</developer_name>
<developer>
<name translatable="no">Sonny Piers</name> <name translatable="no">Sonny Piers</name>
</developer> </developer>
<update_contact>sonnyp@gnome.org</update_contact> <update_contact>sonnyp@gnome.org</update_contact>
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0</project_license> <project_license>GPL-3.0</project_license>
<summary>Learn and prototype with GNOME technologies</summary> <summary>Prototype with GNOME technologies</summary>
<description> <description>
<p>Workbench lets you experiment with GNOME technologies, no matter if tinkering for the first time or building and testing a GTK user interface.</p> <p>Workbench is for learning and prototyping with GNOME technologies, no matter if tinkering for the first time or building and testing a GTK user interface.</p>
<p>Among other things, Workbench comes with</p> <p>Among other things, Workbench comes with</p>
<ul> <ul>
<li>Live GTK/CSS preview</li> <li>Live GTK/CSS preview</li>
@ -21,31 +19,215 @@
<li>JavaScript, Rust, Python and Vala support</li> <li>JavaScript, Rust, Python and Vala support</li>
<li>Declarative user interface syntax</li> <li>Declarative user interface syntax</li>
<li>Autosave, sessions and projects</li> <li>Autosave, sessions and projects</li>
<li>Code linter and formatter</li> <li>Code diagnostics, completion and formatter</li>
<li>Terminal output</li> <li>Terminal output</li>
<li>1000+ icons</li>
</ul> </ul>
</description> </description>
<url type="homepage">https://apps.gnome.org/Workbench</url> <url type="homepage">https://workbench.sonny.re</url>
<url type="bugtracker">https://github.com/workbenchdev/Workbench/issues</url> <url type="bugtracker">https://workbench.sonny.re/feedback</url>
<url type="donation">https://ko-fi.com/sonnyp</url> <url type="donation">https://workbench.sonny.re/donate</url>
<url type="vcs-browser">https://github.com/workbenchdev/Workbench</url> <url type="vcs-browser">https://workbench.sonny.re/source</url>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot.png</image> <image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/welcome.png</image>
<caption>Welcome screen</caption>
</screenshot> </screenshot>
<screenshot> <screenshot>
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-code.png</image> <image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/code.png</image>
<caption>Drawing Area demo</caption>
</screenshot> </screenshot>
<screenshot> <screenshot>
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-library.png</image> <image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/library.png</image>
</screenshot> <caption>Library window</caption>
<screenshot>
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-extensions.png</image>
</screenshot> </screenshot>
</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">
<description translatable="no">
<ul>
<li>Use GNOME 47</li>
<li>Add code suggestions/completions support</li>
<li>Add Language and Category filters to the Library</li>
<li>Add action to create new blank project</li>
<li>Add experimental TypeScript support</li>
</ul>
<p>Library:</p>
<ul>
<li>Add "Button Row" demo</li>
<li>Add "Gamepad" demo</li>
<li>Add "List View with Sections" demo</li>
<li>Add "List View with a Tree" demo</li>
<li>Add "Bottom Sheet" demo</li>
<li>Add "Database" demo</li>
<li>Update "Spinner" to use AdwSpinner</li>
<li>Port "Dialog" to Python</li>
<li>Port "List View" to Python</li>
<li>Port "Grid View" to Python</li>
<li>Port "Level Bars" to Rust</li>
<li>Port "Text Fields" to Rust</li>
<li>Port "Column View" to Rust</li>
<li>Port "Clamp" to Rust</li>
<li>Port "List View" to Rust</li>
<li>Port "Frame" to Rust</li>
<li>Port "Audio" to Rust</li>
<li>Port "File Monitor" to Vala</li>
<li>Port "Scrolled Window" to Vala</li>
<li>Port "Menu" to Vala</li>
<li>Port "HTTP Server" to Vala</li>
<li>Port "Map" to Vala</li>
<li>Port "Session Monitor and Inhibit" to Vala</li>
<li>Port "Save File" to Vala</li>
<li>Port "Spin Button" to Vala</li>
<li>Port "Progress Bar" to Vala</li>
<li>Port "Label" to Vala</li>
<li>Port "Power Profile Monitor" to Vala</li>
<li>Port "Drawing Area" to Vala</li>
<li>Port "Font Dialog" to Vala</li>
<li>Port "Select Folder" to Vala</li>
<li>Port "Network Monitor" to Vala</li>
<li>Port "Toggle Button" to Vala</li>
<li>Port "Tooltip" to Vala</li>
<li>Port "Spell Checker" to Vala</li>
<li>Port "Popovers" to Vala</li>
<li>Port "Menu Button" to Vala</li>
<li>Port "Frame" to Vala</li>
<li>Port "Actions" to Vala</li>
<li>Port "Dialog" to Vala</li>
<li>Port "CSS Gradients" to Vala</li>
<li>Port "Snapshot" to Vala</li>
</ul>
<p>Dependencies:</p>
<ul>
<!-- <li>Replace Biome with TypeScript Language Server</li> -->
<li>Add GOM dependency 0.5.3</li>
<li>Update Biome to 1.9.4</li>
<li>Update libshumate to 1.3</li>
<li>Update Blueprint to 0.14.0</li>
<li>Update vte to 0.78.2</li>
<li>Update libspelling to 0.4.5</li>
<li>Update libportal to 0.8.1</li>
</ul>
</description>
</release>
<release version="46.1" date="2024-04-30">
<description translatable="no">
<ul>
<li>Add "Find" to search for code in the current editor</li>
<li>Save and restore the session window dimensions</li>
<li>Add "Reveal in Folder" to browse project files</li>
<li>Remove Icon Library, please refer to the "Using Icons" entry</li>
<li>List editor shortcuts in Shortcuts</li>
<li>Fix Vala and Rust extensions detection on "Run"</li>
<li>Library: Add "Using Icons"</li>
<li>Library: Add "SVG"</li>
<li>Library: Split "List View Widget" into "List View" and "Grid View"</li>
<li>Library: Port "Animation" to Python</li>
<li>Library: Port "Radio Buttons" to Vala</li>
<li>Library: Port "Switch" to Vala</li>
<li>Library: Port "Revealer" to Vala</li>
<li>Library: Port "Styling with CSS" to Vala</li>
<li>Library: Port "Separator" to Vala</li>
<li>Library: Port "Level Bars" to Vala</li>
<li>Library: Port "Link Button" to Vala</li>
</ul>
</description>
</release>
<release version="46" date="2024-03-20">
<description translatable="no">
<ul>
<li>Use GNOME 46</li>
<li>Add basic Rust diagnostics</li>
<li>Add basic Python diagnostics</li>
<li>Replace Python formatter Black with Ruff</li>
<li>Support libadwaita dialogs</li>
<li>Stop adding a superfluous newlines to end of files</li>
<li>Optimize opening Library entries</li>
<li>Open project windows maximized</li>
<li>Fix dangling bwrap processes after quitting Workbench</li>
<li>Modernize the Extensions window</li>
<li>Update Biome to 1.6.0</li>
<li>Update libspelling to 0.2.1</li>
<li>Update gst-plugin-gtk4 to 0.12.1</li>
<li>Update libshumate to 1.2</li>
<li>Update VTE to 0.76</li>
<li>Update Blueprint to 0.12.0</li>
<li>Update GTKCssLanguageServer</li>
<li>Update icon-development-kit</li>
<li>Library: Adapt demos to use GNOME 46 features</li>
<li>Library: Add FileFilter example to "Open File" demo</li>
<li>Library: Add "Snapshot" demo</li>
<li>Library: Port "Scrolled Window" demo to Python</li>
<li>Library: Port "HTTP Image" demo to Python</li>
<li>Library: Port "HTTP Request" demo to Python</li>
<li>Library: Port "HTTP Server" demo to Python</li>
<li>Library: Port "Font Dialog" demo to Python</li>
<li>Library: Port "Box" demo to Python</li>
<li>Library: Port "Frame" demo to Python</li>
<li>Library: Port "Grid" demo to Python</li>
<li>Library: Port "Web View" demo to Python</li>
<li>Library: Port "Network Monitor" demo to Python</li>
<li>Library: Port "Navigation View" demo to Python</li>
<li>Library: Port "Launcher" demo to Python</li>
<li>Library: Port "Audio" demo to Python</li>
<li>Library: Port "Map" demo to Python</li>
<li>Library: Port "File Monitor" demo to Python</li>
<li>Library: Port "WebSocket Client" demo to Python</li>
<li>Library: Port "Screencast" demo to Python</li>
<li>Library: Port "Progress Bar" demo to Python</li>
<li>Library: Port "Camera" demo to Python</li>
<li>Library: Port "Location" demo to Python</li>
<li>Library: Port "List Model" demo to Python</li>
<li>Library: Port "Drop Down" demo to Python</li>
<li>Library: Port "Drawing Area" demo to Python</li>
<li>Library: Port "Session Monitor and Inhibit" demo to Python</li>
<li>Library: Port "View Switcher" demo to Python</li>
<li>Library: Port "View Switcher" demo to Python</li>
<li>Library: Port "Checkboxes" demo to Vala</li>
<li>Library: Port "Action Bar" demo to Vala</li>
<li>Library: Port "Clamp" demo to Vala</li>
<li>Library: Port "Banner" demo to Vala</li>
<li>Library: Port "Emoji Chooser" demo to Vala</li>
</ul>
</description>
</release>
<release version="45.4" date="2024-01-14"> <release version="45.4" date="2024-01-14">
<description translatable="no"> <description translatable="no">
<ul> <ul>
@ -53,7 +235,6 @@
<li>Open the Library on start if there are no sessions to restore</li> <li>Open the Library on start if there are no sessions to restore</li>
<li>Restore scroll and cusor positions on format and Run</li> <li>Restore scroll and cusor positions on format and Run</li>
<li>Add "Copy" and "Select All" to Console</li> <li>Add "Copy" and "Select All" to Console</li>
<!-- <li>Add find text support</li> -->
<li>Add Vala formatter support</li> <li>Add Vala formatter support</li>
<li>Add WebP image format support</li> <li>Add WebP image format support</li>
<li>Use Biome instead of prettier as JavaScript formatter</li> <li>Use Biome instead of prettier as JavaScript formatter</li>
@ -214,7 +395,7 @@
</ul> </ul>
</description> </description>
</release> </release>
<release version="45" date="2023-09-22"> <release version="45.0" date="2023-09-22">
<description translatable="no"> <description translatable="no">
<ul> <ul>
<li>Use GNOME 45</li> <li>Use GNOME 45</li>
@ -511,9 +692,15 @@
<kudo>ModernToolkit</kudo> <kudo>ModernToolkit</kudo>
</kudos> </kudos>
<branding> <branding>
<color type="primary">#33d17a</color> <color type="primary" scheme_preference="light">#57e389</color>
<color type="primary" scheme_preference="dark">#26a269</color>
</branding> </branding>
<custom> <requires>
<value key="GnomeSoftware::key-colors">[(51, 209, 122)]</value> <display_length compare="ge">1024</display_length>
</custom> </requires>
<recommends>
<control>keyboard</control>
<control>pointing</control>
<control>touch</control>
</recommends>
</component> </component>

View File

@ -2,49 +2,45 @@ desktop_file = configure_file(
input: 'app.desktop', input: 'app.desktop',
output: '@0@.desktop'.format(app_id), output: '@0@.desktop'.format(app_id),
configuration: { 'app_id': app_id }, configuration: { 'app_id': app_id },
install_dir: join_paths(get_option('datadir'), 'applications') install_dir: get_option('datadir') / 'applications'
) )
desktop_utils = find_program('desktop-file-validate', required: false) desktop_utils = find_program('desktop-file-validate', required: true)
if desktop_utils.found() test('Validate desktop file', desktop_utils,
test('Validate desktop file', desktop_utils, args: [desktop_file]
args: [desktop_file] )
)
endif
configure_file( configure_file(
input: 'app.service', input: 'app.service',
output: '@0@.service'.format(app_id), output: '@0@.service'.format(app_id),
configuration: { 'app_id': app_id, 'bindir': bindir }, configuration: { 'app_id': app_id, 'bindir': bindir },
install_dir: join_paths(get_option('datadir'), 'dbus-1/services') install_dir: get_option('datadir') / 'dbus-1/services'
) )
appstream_file = configure_file( appstream_file = configure_file(
input: 'app.metainfo.xml', input: 'app.metainfo.xml',
output: '@0@.metainfo.xml'.format(app_id), output: '@0@.metainfo.xml'.format(app_id),
configuration: { 'app_id': app_id }, configuration: { 'app_id': app_id },
install_dir: join_paths(get_option('datadir'), 'metainfo') install_dir: get_option('datadir') / 'metainfo'
) )
appstream_cli = find_program('appstreamcli', required: false) appstreamcli = find_program('appstreamcli', required: false)
if appstream_cli.found() test(
test('Validate metainfo file', appstream_cli, 'Validate appstream file',
args: ['validate', '--override=release-time-missing=info', '--no-net', '--explain', appstream_file] appstreamcli,
) args: ['validate', '--no-net', '--explain', appstream_file],
endif )
configure_file( configure_file(
input: 'app.gschema.xml', input: 'app.gschema.xml',
output: '@0@.gschema.xml'.format(app_id), output: '@0@.gschema.xml'.format(app_id),
configuration: { 'app_id': app_id }, configuration: { 'app_id': app_id },
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas') install_dir: get_option('datadir') / 'glib-2.0/schemas'
) )
compile_schemas = find_program('glib-compile-schemas', required: false) compile_schemas = find_program('glib-compile-schemas', required: true)
if compile_schemas.found() test('Validate schema file', compile_schemas,
test('Validate schema file', compile_schemas, args: ['--strict', '--dry-run', meson.current_source_dir()]
args: ['--strict', '--dry-run', meson.current_source_dir()] )
)
endif
install_subdir('icons/hicolor', install_dir : join_paths(get_option('datadir'), 'icons')) install_subdir('icons/hicolor', install_dir : get_option('datadir') / 'icons')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

BIN
data/screenshots/code.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

2
demos

@ -1 +1 @@
Subproject commit c92f1b3d5a0b1ba616396e28280c755679a84a18 Subproject commit cd8b209df99294c72a5846ead00797db0bafa862

1
gi-types Submodule

@ -0,0 +1 @@
Subproject commit 396fe147142e28a921f0745eff1a562c7a551843

View File

@ -1,13 +1,20 @@
project('Workbench', ['vala', 'c', 'rust'], project(
version: '45.4', 'Workbench',
meson_version: '>= 0.59.0', ['vala', 'c', 'rust'],
license: 'GPL-3.0-only' version: '48.0',
meson_version: '>= 1.0.0',
license: 'GPL-3.0-only',
default_options: [
'libdir=lib',
'warning_level=2',
'werror=false',
],
) )
gnome = import('gnome') gnome = import('gnome')
if get_option('profile') == 'development' if get_option('profile') == 'development'
app_id = 're.sonny.Workbench.Devel' app_id = 're.sonny.Workbench.Devel'
vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip() vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip()
if vcs_tag == '' if vcs_tag == ''
version_suffix = '-devel' version_suffix = '-devel'
@ -20,9 +27,9 @@ else
endif endif
prefix = get_option('prefix') prefix = get_option('prefix')
bindir = join_paths(prefix, 'bin') bindir = prefix / 'bin'
datadir = join_paths(prefix, get_option('datadir')) datadir = prefix / get_option('datadir')
pkgdatadir = join_paths(datadir, app_id) pkgdatadir = datadir / app_id
subdir('data') subdir('data')
subdir('src') subdir('src')
@ -30,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,
) )

1026
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
{ {
"private": true, "private": true,
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.22.11", "@babel/core": "^7.25.7",
"@babel/plugin-syntax-import-assertions": "^7.22.5", "@babel/eslint-parser": "^7.25.7",
"@babel/plugin-syntax-import-attributes": "^7.25.7",
"@rollup/plugin-commonjs": "^22.0.1", "@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-node-resolve": "^13.3.0",
"eslint": "^8.48.0", "eslint": "^8.48.0",
@ -12,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",
@ -26,10 +27,10 @@
"lint-staged": { "lint-staged": {
"*.{json,md,yaml,yml}": "prettier --write", "*.{json,md,yaml,yml}": "prettier --write",
"*.{js,cjs,mjs}": "eslint --fix", "*.{js,cjs,mjs}": "eslint --fix",
"*.css": "./build-aux/fun workbench-cli format", "*.css": "./build-aux/fun workbench-cli format css",
"*.py": "./build-aux/fun black", "*.py": "./build-aux/fun workbench-cli format python",
"*.rs": "./build-aux/fun rustfmt --edition 2021", "*.rs": "./build-aux/fun rustfmt --edition 2021",
"*.blp": "./build-aux/fun workbench-cli format", "*.blp": "./build-aux/fun workbench-cli format blueprint",
"*.vala": "./build-aux/fun workbench-cli format vala" "*.vala": "./build-aux/fun workbench-cli format vala"
} }
} }

View File

@ -17,11 +17,11 @@ template $Extension: ListBoxRow {
Label label_title {} Label label_title {}
[end] [end]
Image image_enabled { Image image_available {
icon-name: "test-pass-symbolic"; icon-name: "re.sonny.Workbench-test-pass-symbolic";
styles [ styles [
"success" "success",
] ]
} }
} }
@ -33,12 +33,13 @@ template $Extension: ListBoxRow {
margin-bottom: 14; margin-bottom: 14;
orientation: vertical; orientation: vertical;
Label label_hint { Label {
wrap: true; wrap: true;
xalign: 0; xalign: 0;
label: _("Run the following command");
styles [ styles [
"dim-label" "dim-label",
] ]
} }
@ -51,7 +52,7 @@ template $Extension: ListBoxRow {
xalign: 0; xalign: 0;
styles [ styles [
"command_snippet" "command_snippet",
] ]
} }
} }

View File

@ -9,9 +9,8 @@ export default GObject.registerClass(
Template, Template,
InternalChildren: [ InternalChildren: [
"label_title", "label_title",
"image_enabled", "image_available",
"installation_guide", "installation_guide",
"label_hint",
"label_command", "label_command",
], ],
Properties: { Properties: {
@ -22,20 +21,13 @@ export default GObject.registerClass(
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
"", "",
), ),
enabled: GObject.ParamSpec.boolean( available: GObject.ParamSpec.boolean(
"enabled", "available",
"", "",
"", "",
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
false, false,
), ),
hint: GObject.ParamSpec.string(
"hint",
"",
"",
GObject.ParamFlags.READWRITE,
"",
),
command: GObject.ParamSpec.string( command: GObject.ParamSpec.string(
"command", "command",
"", "",
@ -57,26 +49,19 @@ export default GObject.registerClass(
); );
this.bind_property( this.bind_property(
"enabled", "available",
this._image_enabled, this._image_available,
"visible", "visible",
GObject.BindingFlags.SYNC_CREATE, GObject.BindingFlags.SYNC_CREATE,
); );
this.bind_property( this.bind_property(
"enabled", "available",
this._installation_guide, this._installation_guide,
"visible", "visible",
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN, GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN,
); );
this.bind_property(
"hint",
this._label_hint,
"label",
GObject.BindingFlags.SYNC_CREATE,
);
this.bind_property( this.bind_property(
"command", "command",
this._label_command, this._label_command,

View File

@ -1,18 +1,14 @@
using Gtk 4.0; using Gtk 4.0;
using Adw 1; using Adw 1;
Adw.Window window { Adw.Dialog dialog {
hide-on-close: true; content-height: 750;
modal: false; content-width: 600;
default-height: 750; title: _("Extensions");
default-width: 600;
title: _("Workbench — Extensions");
Adw.ToolbarView { Adw.ToolbarView {
[top] [top]
Adw.HeaderBar { Adw.HeaderBar {}
show-title: false;
}
content: ScrolledWindow { content: ScrolledWindow {
hscrollbar-policy: never; hscrollbar-policy: never;
@ -38,42 +34,33 @@ Adw.Window window {
} }
} }
Label {
label: _("Extensions");
margin-bottom: 36;
styles [
"title-1"
]
}
ListBox { ListBox {
selection-mode: none; selection-mode: none;
styles [ styles [
"boxed-list" "boxed-list",
] ]
$Extension { $Extension {
title: _("JavaScript"); title: _("JavaScript");
enabled: true; available: true;
} }
$Extension { $Extension {
title: _("Python"); title: _("Python");
enabled: true; available: true;
} }
$Extension extension_rust { $Extension extension_rust {
title: _("Rust"); title: _("Rust");
hint: _("To enable Rust support, run the following command in your Console or Terminal");
command: "flatpak install flathub org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08";
} }
$Extension extension_vala { $Extension extension_vala {
title: _("Vala"); title: _("Vala");
hint: _("To enable Vala support, run the following command in your Console or Terminal"); }
command: "flatpak install flathub org.freedesktop.Sdk.Extension.vala//23.08";
$Extension extension_typescript {
title: _("TypeScript");
} }
} }
@ -85,7 +72,7 @@ Adw.Window window {
wrap: true; wrap: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
@ -96,7 +83,7 @@ Adw.Window window {
wrap: true; wrap: true;
styles [ styles [
"dim-label" "dim-label",
] ]
} }
} }

View File

@ -1,74 +1,89 @@
import Gio from "gi://Gio"; import Gio from "gi://Gio";
import GLib from "gi://GLib";
import { build } from "../../troll/src/main.js"; import { build } from "../../troll/src/main.js";
import Interface from "./Extensions.blp" with { type: "uri" }; import Interface from "./Extensions.blp" with { type: "uri" };
import illustration from "./extensions.svg"; import illustration from "./extensions.svg";
import { settings } from "../util.js";
import "./Extension.js"; import "./Extension.js";
import { settings } from "../util.js";
const extensions = (() => { import { getFlatpakInfo } from "../flatpak.js";
const keyfile = new GLib.KeyFile();
keyfile.load_from_file("/.flatpak-info", GLib.KeyFileFlags.NONE);
return keyfile
.get_string_list("Instance", "runtime-extensions")
.map((extension) => extension.split("=")[0]);
})();
export const action_extensions = new Gio.SimpleAction({ export const action_extensions = new Gio.SimpleAction({
name: "extensions", name: "extensions",
parameter_type: null, parameter_type: null,
}); });
export default function Extensions({ application }) { export function Extensions({ window }) {
const { const {
window, dialog,
picture_illustration, picture_illustration,
extension_rust, extension_rust,
extension_vala, extension_vala,
extension_typescript,
restart_hint, restart_hint,
all_set_hint, all_set_hint,
} = build(Interface); } = build(Interface);
picture_illustration.set_resource(illustration); picture_illustration.set_resource(illustration);
extension_rust.enabled = isRustEnabled(); extension_rust.available = isRustAvailable();
extension_vala.enabled = isValaEnabled(); extension_rust.command = `flatpak install flathub org.freedesktop.Sdk.Extension.rust-stable//${freedesktop_version} org.freedesktop.Sdk.Extension.${llvm}//${freedesktop_version}`;
for (const extension of [extension_rust, extension_vala]) { extension_vala.available = isValaAvailable();
if (!extension.enabled) { extension_vala.command = `flatpak install flathub org.freedesktop.Sdk.Extension.vala//${freedesktop_version}`;
extension_typescript.available = isTypeScriptAvailable();
extension_typescript.command = `flatpak install flathub org.freedesktop.Sdk.Extension.${node}//${freedesktop_version} org.freedesktop.Sdk.Extension.typescript//${freedesktop_version}`;
extension_typescript.visible = isTypeScriptEnabled();
for (const extension of [
extension_rust,
extension_vala,
extension_typescript,
]) {
if (!extension.available) {
all_set_hint.set_visible(false); all_set_hint.set_visible(false);
restart_hint.set_visible(true); restart_hint.set_visible(true);
} }
} }
action_extensions.connect("activate", () => { action_extensions.connect("activate", () => {
settings.set_boolean("open-extensions", true); dialog.present(window);
window.present();
}); });
window.connect("close-request", () => { window.add_action(action_extensions);
settings.set_boolean("open-extensions", false);
});
if (settings.get_boolean("open-extensions")) {
window.present();
}
application.add_action(action_extensions);
} }
export function isRustEnabled() { let rust_available = null;
return ( export function isRustAvailable() {
extensions.includes("org.freedesktop.Sdk.Extension.rust-stable") && rust_available ??=
extensions.includes("org.freedesktop.Sdk.Extension.llvm16") Gio.File.new_for_path("/usr/lib/sdk/rust-stable").query_exists(null) &&
); Gio.File.new_for_path(`/usr/lib/sdk/${llvm}`).query_exists(null);
return rust_available;
} }
export function isValaEnabled() { let vala_available = null;
return extensions.includes("org.freedesktop.Sdk.Extension.vala"); export function isValaAvailable() {
vala_available ??=
Gio.File.new_for_path("/usr/lib/sdk/vala").query_exists(null);
return vala_available;
}
let typescript_available = null;
export function isTypeScriptAvailable() {
typescript_available ??=
isTypeScriptEnabled() &&
Gio.File.new_for_path("/usr/lib/sdk/typescript").query_exists(null) &&
Gio.File.new_for_path(`/usr/lib/sdk/${node}`).query_exists(null);
return typescript_available;
}
const llvm = "llvm18";
const node = "node20";
const runtime = getFlatpakInfo().get_string("Application", "runtime");
const freedesktop_version = runtime.endsWith("master") ? "24.08" : "24.08";
export function isTypeScriptEnabled() {
return settings.get_boolean("typescript");
} }

View File

@ -1,24 +0,0 @@
using Gtk 4.0;
template $IconWidget: FlowBoxChild {
focusable: false;
halign: start;
Button button {
clicked => $onClicked();
width-request: 48;
height-request: 48;
Image image {
icon-name: "applications-science-symbolic";
// preview only
pixel-size: 32;
halign: center;
valign: center;
}
styles [
"flat"
]
}
}

View File

@ -1,47 +0,0 @@
import Gtk from "gi://Gtk";
import GObject from "gi://GObject";
import Template from "./IconWidget.blp" with { type: "uri" };
import { registerClass } from "../overrides.js";
class IconWidget extends Gtk.FlowBoxChild {
constructor(params = {}) {
super(params);
this.bind_property(
"icon_name",
this._image,
"icon-name",
GObject.BindingFlags.SYNC_CREATE,
);
this.bind_property(
"icon_name",
this,
"tooltip_text",
GObject.BindingFlags.SYNC_CREATE,
);
}
onClicked() {
this.emit("clicked");
}
}
export default registerClass(
{
GTypeName: "IconWidget",
Template,
InternalChildren: ["image"],
Properties: {
icon_name: GObject.ParamSpec.string(
"icon_name", // Name
"icon_name", // Nick
"", // Blurb
GObject.ParamFlags.READWRITE, // Flags
null, // Default value
),
},
Signals: {
clicked: {},
},
},
IconWidget,
);

View File

@ -1,81 +0,0 @@
using Gtk 4.0;
using Adw 1;
Adw.Window window {
width-request: 800;
height-request: 600;
hide-on-close: true;
title: _("Workbench — Icon Library");
Adw.ToastOverlay overlay {
Adw.ToolbarView {
[top]
Adw.HeaderBar {
[title]
Adw.Clamp {
maximum-size: 800;
SearchEntry search_entry {
hexpand: true;
placeholder-text: _("Search for icons by name, category or tag");
}
}
}
ScrolledWindow {
hexpand: true;
vexpand: true;
Adw.Clamp {
maximum-size: 800;
Box {
orientation: vertical;
Label {
styles [
"title-4"
]
label: "Icon Development Kit";
margin-bottom: 6;
margin-top: 12;
halign: start;
}
FlowBox flow_box_devkit {
visible: false;
valign: start;
min-children-per-line: 5;
max-children-per-line: 18;
activate-on-single-click: true;
selection-mode: none;
margin-bottom: 12;
}
Label {
styles [
"title-4"
]
label: "Platform icons";
margin-bottom: 6;
margin-top: 12;
halign: start;
}
FlowBox flow_box_platform {
visible: false;
valign: start;
min-children-per-line: 5;
max-children-per-line: 18;
activate-on-single-click: true;
selection-mode: none;
margin-bottom: 12;
}
}
}
}
}
}
}

View File

@ -1,131 +0,0 @@
import Gtk from "gi://Gtk?version=4.0";
import Gdk from "gi://Gdk";
import Adw from "gi://Adw";
import Gio from "gi://Gio";
import { build } from "../../troll/src/builder.js";
import IconWidget from "./IconWidget.js";
import resource from "./main.blp" with { type: "uri" };
const toasts = new Set();
export default function IconLibrary() {
const display = Gdk.Display.get_default();
const clipboard = display.get_clipboard();
const dev_kit_icons = getDevKitIcons();
const platform_icons = getPlatformIcons(dev_kit_icons);
const icons = Object.assign(
Object.create(null),
platform_icons,
dev_kit_icons,
);
const { window, overlay, search_entry, flow_box_devkit, flow_box_platform } =
build(resource);
function selectIcon(icon_name) {
clipboard.set(icon_name);
for (const toast of toasts) {
toast.dismiss();
}
const toast = new Adw.Toast({
title: `${icon_name}” copied to clipboard`,
priority: Adw.ToastPriority.HIGH,
});
toast.connect("dismissed", onToastDismissed);
toasts.add(toast);
overlay.add_toast(toast);
}
function filter_func({ icon_name }) {
return icons[icon_name]?.some((tag) => tag.includes(search_entry.text));
}
flow_box_devkit.set_filter_func(filter_func);
flow_box_platform.set_filter_func(filter_func);
search_entry.connect("search-changed", () => {
flow_box_devkit.invalidate_filter();
flow_box_platform.invalidate_filter();
});
function populateIconDevKit() {
for (const icon_name of Object.keys(dev_kit_icons).sort((a, b) =>
a.localeCompare(b),
)) {
const icon = new IconWidget({
icon_name,
});
icon.connect("clicked", () => selectIcon(icon_name));
flow_box_devkit.append(icon);
}
flow_box_devkit.visible = true;
}
function populatePlatformIcons() {
for (const icon_name of Object.keys(platform_icons).sort((a, b) =>
a.localeCompare(b),
)) {
const icon = new IconWidget({
icon_name,
});
icon.connect("clicked", () => selectIcon(icon_name));
flow_box_platform.append(icon);
}
flow_box_platform.visible = true;
}
populateIconDevKit();
populatePlatformIcons();
return window;
}
function onToastDismissed(toast) {
toasts.delete(toast);
}
function getDevKitIcons() {
const icons = Object.create(null);
const [bytes] = Gio.File.new_for_path(
"/app/share/icon-development-kit/icons.json",
).load_bytes(null);
const icons_dev_kit = JSON.parse(new TextDecoder().decode(bytes.get_data()));
for (const icon of icons_dev_kit) {
// https://gitlab.gnome.org/Teams/Design/icon-development-kit/-/issues/62
if (icon.context === "noexport-bits") continue;
icons[`${icon.filename}-symbolic`] = [
icon.filename,
icon.context,
...icon.tags,
];
}
return icons;
}
function getPlatformIcons(dev_kit_icons) {
const display = Gdk.Display.get_default();
const icons = Object.create(null);
const icon_theme = Gtk.IconTheme.get_for_display(display);
const icons_theme = icon_theme.get_icon_names();
for (const icon of icons_theme) {
if (
icon.startsWith("re.sonny.Workbench") ||
!icon.endsWith("-symbolic") ||
icon in dev_kit_icons
)
continue;
if (!(icon in icons)) icons[icon] = [icon.split("-symbolic")[0]];
}
return icons;
}

View File

@ -1,20 +1,20 @@
using Gtk 4.0; using Gtk 4.0;
using Adw 1; using Adw 1;
template $EntryRow: Adw.PreferencesRow { template $EntryRow: Adw.ActionRow {
activatable: true;
accessibility { accessibility {
labelled-by: title_label; labelled-by: title_label;
described-by: description_label; described-by: description_label;
} }
title: bind title_label.label; [prefix]
Box contents { Box contents {
orientation: horizontal; orientation: horizontal;
Box labels_box { Box labels_box {
margin-top: 6; margin-top: 6;
margin-start: 12;
margin-bottom: 6; margin-bottom: 6;
spacing: 3; spacing: 3;
orientation: vertical; orientation: vertical;
@ -28,7 +28,7 @@ template $EntryRow: Adw.PreferencesRow {
Label description_label { Label description_label {
styles [ styles [
"dim-label", "dim-label",
"caption" "caption",
] ]
xalign: 0; xalign: 0;
@ -43,13 +43,13 @@ template $EntryRow: Adw.PreferencesRow {
margin-top: 3; margin-top: 3;
} }
} }
}
Image { [suffix]
icon-name: "go-next-symbolic"; Image {
margin-end: 12; icon-name: "go-next-symbolic";
margin-start: 6; margin-start: 6;
hexpand: true; hexpand: true;
halign: end; halign: end;
}
} }
} }

View File

@ -6,7 +6,7 @@ import GObject from "gi://GObject";
import { getLanguage } from "../util.js"; import { getLanguage } from "../util.js";
import Template from "./EntryRow.blp" with { type: "uri" }; import Template from "./EntryRow.blp" with { type: "uri" };
class EntryRow extends Adw.PreferencesRow { class EntryRow extends Adw.ActionRow {
constructor({ demo, ...params } = {}) { constructor({ demo, ...params } = {}) {
super(params); super(params);
@ -22,7 +22,7 @@ class EntryRow extends Adw.PreferencesRow {
}); });
activate_action.connect("activate", () => { activate_action.connect("activate", () => {
this.emit("activated", null); this.emit("triggered", null);
}); });
action_group.add_action(activate_action); action_group.add_action(activate_action);
@ -47,7 +47,7 @@ class EntryRow extends Adw.PreferencesRow {
}); });
button.connect("clicked", () => { button.connect("clicked", () => {
this.emit("activated", language); this.emit("triggered", language);
}); });
return button; return button;
@ -68,7 +68,7 @@ export default GObject.registerClass(
), ),
}, },
Signals: { Signals: {
activated: { triggered: {
param_types: [GObject.TYPE_JSOBJECT], param_types: [GObject.TYPE_JSOBJECT],
}, },
}, },

View File

@ -1,75 +1,130 @@
using Gtk 4.0; using Gtk 4.0;
using Adw 1; using Adw 1;
Adw.PreferencesWindow window { Adw.Window window {
hide-on-close: true; hide-on-close: true;
modal: false; modal: false;
title: _("Workbench — Library"); title: _("Workbench — Library");
default-height: 700; default-height: 700;
default-width: 700; default-width: 700;
Adw.PreferencesPage { Adw.ToolbarView toolbar_view {
Adw.PreferencesGroup { [top]
Picture picture_illustration { Adw.HeaderBar header_bar {
can-shrink: false; title-widget: Adw.WindowTitle {
margin-bottom: 32; title: _("Workbench — Library");
} };
Label {
label: _("Learn, Test, Remix");
styles [
"title-1"
]
}
} }
Adw.PreferencesGroup library_uncategorized {} content: ScrolledWindow scrolled_window {
hscrollbar-policy: never;
Adw.PreferencesGroup library_tools { child: Adw.Clamp {
title: _("Tools"); maximum-size: 576;
} margin-end: 12;
margin-start: 12;
Adw.PreferencesGroup library_network { child: Box {
title: _("Network"); orientation: vertical;
} spacing: 12;
Adw.PreferencesGroup library_controls { Box {
title: _("Controls"); orientation: vertical;
}
Adw.PreferencesGroup library_layout { Box {
title: _("Layout"); halign: center;
} vexpand: false;
Adw.PreferencesGroup library_feedback { Picture picture_illustration {
title: _("Feedback"); can-shrink: false;
} margin-bottom: 32;
margin-top: 24;
}
}
Adw.PreferencesGroup library_navigation { Label {
title: _("Navigation"); label: _("Learn, Test, Remix");
}
Adw.PreferencesGroup library_user_interface { styles [
title: _("User Interface"); "title-1",
} ]
}
Adw.PreferencesGroup library_platform { Box {
title: _("Platform APIs"); spacing: 6;
}
Adw.PreferencesGroup { SearchEntry search_entry {
vexpand: true; search-delay: 100;
valign: end; placeholder-text: _("Search demos");
activates-default: true;
hexpand: true;
margin-top: 32;
}
Label { DropDown dropdown_language {
label: _('All examples are dedicated to the public domain\nand <b>can be used freely</b> under the terms of <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0 1.0</a>.'); valign: end;
use-markup: true;
styles [ model: Gtk.StringList {};
"caption" }
]
} DropDown dropdown_category {
} valign: end;
model: Gtk.StringList {};
}
}
}
ListBox listbox {
selection-mode: none;
styles [
"boxed-list",
]
}
Box {
halign: center;
margin-bottom: 24;
margin-top: 12;
orientation: vertical;
Box results_empty {
orientation: vertical;
visible: false;
margin-top: 46;
margin-bottom: 70;
spacing: 6;
Label {
label: _("No results");
styles [
"title-3",
]
}
Button button_reset {
label: _("Reset filters");
halign: center;
styles [
"pill",
]
}
}
Label {
label: _("All examples are dedicated to the public domain\nand <b>can be used freely</b> under the terms of <a href=\"https://creativecommons.org/publicdomain/zero/1.0/\">CC0 1.0</a>");
use-markup: true;
styles [
"caption",
]
}
}
};
};
};
} }
} }

View File

@ -14,12 +14,28 @@ import { createSessionFromDemo } from "../sessions.js";
import EntryRow from "./EntryRow.js"; import EntryRow from "./EntryRow.js";
import illustration from "./library.svg"; import illustration from "./library.svg";
import { gettext as _ } from "gettext";
import { build } from "../../troll/src/builder.js"; import { build } from "../../troll/src/builder.js";
import {
needsAdditionalPermissions,
showPermissionsDialog,
} from "../Permissions/Permissions.js";
import { isTypeScriptEnabled } from "../Extensions/Extensions.js";
export default function Library({ application }) { export default function Library({ application }) {
const objects = build(resource); const objects = build(resource);
const { window, picture_illustration } = objects; const {
window,
picture_illustration,
search_entry,
dropdown_category,
dropdown_language,
results_empty,
button_reset,
listbox,
scrolled_window,
} = objects;
window.application = application; window.application = application;
picture_illustration.set_resource(illustration); picture_illustration.set_resource(illustration);
@ -27,17 +43,60 @@ export default function Library({ application }) {
window.add_css_class("devel"); window.add_css_class("devel");
} }
let last_selected; let last_triggered;
window.connect("close-request", quitOnLastWindowClose); window.connect("close-request", quitOnLastWindowClose);
const demos = getDemos(); const categories = [
demos.forEach((demo) => { { id: "all", name: _("Any Category"), index: 0 },
const widget = new EntryRow({ demo: demo }); { id: "tools", name: _("Tools"), index: 1 },
if (demo.name === "Welcome") last_selected = widget; { id: "network", name: _("Network"), index: 2 },
{ id: "controls", name: _("Controls"), index: 3 },
{ id: "layout", name: _("Layout"), index: 4 },
{ id: "feedback", name: _("Feedback"), index: 5 },
{ id: "navigation", name: _("Navigation"), index: 6 },
{ id: "user_interface", name: _("User Interface"), index: 7 },
{ id: "platform", name: _("Platform APIs"), index: 8 },
];
const categories_by_id = Object.fromEntries(
categories.map((category) => [category.id, category]),
);
const categories_by_index = Object.fromEntries(
categories.map((category) => [category.index, category]),
);
const category_all = categories_by_id["all"];
widget.connect("activated", (_self, language) => { categories.forEach((category) => {
last_selected = widget; dropdown_category.model.append(category.name);
});
const languages = [
{ id: "all", name: _("Any Language"), index: 0 },
{ id: "javascript", name: _("JavaScript"), index: 1 },
{ id: "python", name: _("Python"), index: 2 },
{ id: "rust", name: _("Rust"), index: 3 },
{ id: "vala", name: _("Vala"), index: 4 },
];
if (isTypeScriptEnabled()) {
languages.push({ id: "typescript", name: _("TypeScript"), index: 5 });
}
const languages_by_id = Object.fromEntries(
languages.map((language) => [language.id, language]),
);
const languages_by_index = Object.fromEntries(
languages.map((language) => [language.index, language]),
);
languages.forEach((language) => {
dropdown_language.model.append(language.name);
});
const demos = getDemos();
const entries = demos.map((demo) => {
const entry_row = new EntryRow({ demo });
if (demo.name === "Welcome") last_triggered = entry_row;
entry_row.connect("triggered", (_self, language) => {
last_triggered = entry_row;
openDemo({ openDemo({
application, application,
@ -45,17 +104,66 @@ export default function Library({ application }) {
language, language,
}).catch(console.error); }).catch(console.error);
}); });
listbox.append(entry_row);
objects[`library_${demo.category}`].add(widget); const category = categories_by_id[demo.category];
const widget = entry_row;
const languages = demo.languages.map((lang) => languages_by_id[lang]);
return { ...demo, category, widget, languages };
}); });
const language_all = languages_by_id["all"];
function updateList() {
const current_category =
categories_by_index[dropdown_category.get_selected()];
const current_language =
languages_by_index[dropdown_language.get_selected()];
const search_term = search_entry.get_text().toLowerCase();
let results_found = false;
entries.forEach(({ name, description, category, languages, widget }) => {
const category_match =
current_category === category_all || category === current_category;
const language_match =
current_language === language_all ||
languages.includes(current_language);
const search_match =
search_term === "" ||
name.toLowerCase().includes(search_term) ||
description.toLowerCase().includes(search_term) ||
category.name.toLowerCase().includes(search_term);
const is_match = category_match && language_match && search_match;
widget.visible = is_match;
if (is_match) {
results_found = true;
}
});
results_empty.visible = !results_found;
}
search_entry.connect("search-changed", updateList);
dropdown_category.connect("notify::selected", updateList);
dropdown_language.connect("notify::selected", updateList);
function reset() {
scrolled_window.vadjustment = null;
search_entry.text = "";
dropdown_category.selected = category_all.index;
dropdown_language.selected = language_all.index;
}
button_reset.connect("clicked", reset);
window.connect("show", reset);
const action_library = new Gio.SimpleAction({ const action_library = new Gio.SimpleAction({
name: "library", name: "library",
parameter_type: null, parameter_type: null,
}); });
action_library.connect("activate", () => { action_library.connect("activate", () => {
window.present(); window.present();
last_selected?.grab_focus(); last_triggered?.grab_focus();
}); });
application.add_action(action_library); application.add_action(action_library);
application.set_accels_for_action("app.library", ["<Control><Shift>O"]); application.set_accels_for_action("app.library", ["<Control><Shift>O"]);
@ -80,15 +188,15 @@ export function getDemo(name) {
async function openDemo({ application, demo_name, language }) { async function openDemo({ application, demo_name, language }) {
const demo = getDemo(demo_name); const demo = getDemo(demo_name);
const session = createSessionFromDemo(demo); const session = await createSessionFromDemo(demo);
if (language) { if (language) {
session.settings.set_int("code-language", language.index); session.settings.set_int("code-language", language.index);
global_settings.set_int("recent-code-language", language.index); global_settings.set_int("recent-code-language", language.index);
// If the user explictely requested to open the demo // If the user explicitly requested to open the demo
// in a specific language then that's probably what they are interested in // in a specific language then that's probably what they are interested in
// therefor override the demo default and force show the code panel // therefore override the demo default and force show the code panel
session.settings.set_boolean("show-code", true); session.settings.set_boolean("show-code", true);
} }
@ -103,9 +211,17 @@ async function openDemo({ application, demo_name, language }) {
); );
} }
const { load, runCode } = Window({ application, session }); const { load, runCode, window } = Window({
application,
session,
});
await load(); await load();
if (needsAdditionalPermissions({ demo })) {
showPermissionsDialog({ window });
return;
}
const code_language = session.getCodeLanguage(); const code_language = session.getCodeLanguage();
const run = autorun && code_language.id === "javascript"; const run = autorun && code_language.id === "javascript";
if (run) { if (run) {

View File

@ -1,9 +1,17 @@
import Gio from "gi://Gio"; import Gio from "gi://Gio";
import GObject from "gi://GObject"; import GObject from "gi://GObject";
import { settings as global_settings, makeDropdownFlat } from "./util.js"; import { makeDropdownFlat, settings as global_settings } from "./util.js";
import { setupRustProject } from "./langs/rust/rust.js";
import { setupTypeScriptProject } from "./langs/typescript/typescript.js";
import { setupJavascriptProject } from "./langs/javascript/javascript.js";
export default function PanelCode({ builder, previewer, settings }) { export default function PanelCode({
builder,
previewer,
session: { settings, file },
langs,
}) {
const panel_code = builder.get_object("panel_code"); const panel_code = builder.get_object("panel_code");
const button_code = builder.get_object("button_code"); const button_code = builder.get_object("button_code");
const stack_code = builder.get_object("stack_code"); const stack_code = builder.get_object("stack_code");
@ -47,6 +55,22 @@ export default function PanelCode({ builder, previewer, settings }) {
panel.language = dropdown_code_lang.selected_item?.string; panel.language = dropdown_code_lang.selected_item?.string;
stack_code.visible_child_name = panel.language; stack_code.visible_child_name = panel.language;
previewer.useInternal().catch(console.error); previewer.useInternal().catch(console.error);
if (panel.language.toLowerCase() === "javascript") {
setupJavascriptProject(file, langs.javascript.document).catch(
console.error,
);
}
if (panel.language.toLowerCase() === "rust") {
setupRustProject(file).catch(console.error);
}
if (panel.language.toLowerCase() === "typescript") {
setupTypeScriptProject(file, langs.typescript.document).catch(
console.error,
);
}
} }
switchLanguage(); switchLanguage();

View File

@ -76,19 +76,18 @@ export default function PanelUI({
"button_ui_experimental_blueprint", "button_ui_experimental_blueprint",
); );
button_ui_experimental_blueprint.connect("clicked", () => { button_ui_experimental_blueprint.connect("clicked", () => {
const modal = builder.get_object("modal_blueprint_experimental"); const dialog = builder.get_object("dialog_blueprint_experimental");
modal.set_transient_for(application.get_active_window()); dialog.present(application.get_active_window());
modal.present();
}); });
const button_blueprint_documentation = builder.get_object( const button_blueprint_documentation = builder.get_object(
"button_blueprint_documentation", "button_blueprint_documentation",
); );
button_blueprint_documentation.connect("clicked", () => { button_blueprint_documentation.connect("clicked", () => {
Gtk.show_uri( new Gtk.UriLauncher({
null, uri: "https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/",
"https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/", })
null, .launch(application.get_active_window(), null)
); .catch(console.error);
}); });
let handler_id_xml = null; let handler_id_xml = null;

View File

@ -0,0 +1,155 @@
using Gtk 4.0;
using Adw 1;
Adw.Dialog dialog {
content-height: 750;
content-width: 600;
Adw.ToolbarView {
[top]
Adw.HeaderBar {}
content: ScrolledWindow {
hscrollbar-policy: never;
Adw.Clamp {
maximum-size: 520;
tightening-threshold: 400;
margin-start: 12;
margin-end: 12;
margin-bottom: 24;
Box {
orientation: vertical;
halign: fill;
spacing: 24;
// Gtk.Picture needs to be wrapped in a box to behave properly
Box {
halign: center;
Picture picture_illustration {
can-shrink: false;
margin-bottom: 24;
}
}
Label {
label: _("Permissions Needed");
styles [
"title-1",
]
}
Label {
label: _("Workbench needs additional permissions. Please run the following command in a terminal and restart Workbench.");
wrap: true;
justify: center;
}
Label label_command {
use-markup: true;
wrap: true;
wrap-mode: word_char;
selectable: true;
xalign: 0;
styles [
"command_snippet",
]
}
Box {
orientation: vertical;
Box {
margin-bottom: 6;
Label {
label: _("What it does");
halign: start;
hexpand: true;
styles [
"heading",
]
}
Button button_info {
icon-name: "re.sonny.Workbench-external-link-symbolic";
styles [
"flat",
]
}
}
ListBox {
selection-mode: none;
styles [
"boxed-list",
]
Adw.ActionRow {
[prefix]
Image {
icon-name: "re.sonny.Workbench-person-symbolic";
}
title: _("--user");
subtitle: _("Grant for your account only");
styles [
"property",
]
}
Adw.ActionRow {
[prefix]
Image {
icon-name: "re.sonny.Workbench-network-wireless-symbolic";
}
title: _("--share-network");
subtitle: _("Network access");
styles [
"property",
]
}
Adw.ActionRow {
[prefix]
Image {
icon-name: "re.sonny.Workbench-speakers-symbolic";
}
title: _("--socket=pulseaudio");
subtitle: _("Record and play audio");
styles [
"property",
]
}
Adw.ActionRow action_row_device {
[prefix]
Image {
icon-name: "re.sonny.Workbench-gamepad-symbolic";
}
// title: _("--device=input");
subtitle: _("Access to input device such as gamepads");
styles [
"property",
]
}
}
}
}
}
};
}
}

View File

@ -0,0 +1,72 @@
import Gio from "gi://Gio";
import Gtk from "gi://Gtk";
import { build } from "../../troll/src/main.js";
import Interface from "./Permissions.blp" with { type: "uri" };
import illustration from "./permissions.svg";
import {
getFlatpakId,
getFlatpakInfo,
isDeviceInputOverrideAvailable,
} from "../flatpak.js";
const device = isDeviceInputOverrideAvailable() ? "input" : "all";
const action_permissions = new Gio.SimpleAction({
name: "permissions",
parameter_type: null,
});
export function Permissions({ window }) {
const {
dialog,
picture_illustration,
label_command,
button_info,
action_row_device,
} = build(Interface);
picture_illustration.set_resource(illustration);
label_command.label = `flatpak override --user --share=network --socket=pulseaudio --device=${device} ${getFlatpakId()}`;
action_row_device.title = `--input=${device}`;
button_info.connect("clicked", () => {
new Gtk.UriLauncher({
uri: "https://docs.flatpak.org/en/latest/sandbox-permissions.html",
})
.launch(window, null)
.catch(console.error);
});
action_permissions.connect("activate", () => {
dialog.present(window);
});
window.add_action(action_permissions);
}
const missing_permissions = (() => {
const flatpak_info = getFlatpakInfo();
const shared = flatpak_info.get_string_list("Context", "shared");
const sockets = flatpak_info.get_string_list("Context", "sockets");
const devices = flatpak_info.get_string_list("Context", "devices");
return (
!shared.includes("network") ||
!sockets.includes("pulseaudio") ||
!devices.includes(device)
);
})();
export function needsAdditionalPermissions({ demo }) {
if (!demo["flatpak-finish-args"]) return false;
return missing_permissions;
}
export function showPermissionsDialog({ window }) {
window.activate_action("permissions", null);
}

View File

@ -0,0 +1,568 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="332"
height="200"
viewBox="0 0 332 200"
version="1.1"
id="svg5"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
sodipodi:docname="permissions.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="false"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="false"
inkscape:deskcolor="#ffffff"
inkscape:document-units="px"
showgrid="false"
inkscape:zoom="0.099784977"
inkscape:cx="-661.42221"
inkscape:cy="-65.140066"
inkscape:current-layer="layer1"
showguides="false"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="4"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="false" />
</sodipodi:namedview>
<defs
id="defs2">
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect65"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,21.13606,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,9.1490264,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<linearGradient
id="linearGradient63"
inkscape:collect="always">
<stop
style="stop-color:#fbe47c;stop-opacity:0.6635828;"
offset="0"
id="stop63" />
<stop
style="stop-color:#87e8b5;stop-opacity:0.7638889;"
offset="1"
id="stop64" />
</linearGradient>
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect62"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,1,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect60"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,2,0,1 @ F,0,1,1,0,2,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect58"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,6,0,1 @ F,0,1,1,0,6,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect56"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,1,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<linearGradient
id="linearGradient26"
inkscape:collect="always">
<stop
style="stop-color:#2177df;stop-opacity:1;"
offset="0"
id="stop26" />
<stop
style="stop-color:#1a5fb4;stop-opacity:1;"
offset="0.09090688"
id="stop28" />
<stop
style="stop-color:#1a5fb4;stop-opacity:1;"
offset="0.9090907"
id="stop29" />
<stop
style="stop-color:#15498a;stop-opacity:1;"
offset="1"
id="stop27" />
</linearGradient>
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect23"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,1,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<linearGradient
id="linearGradient5"
inkscape:collect="always">
<stop
style="stop-color:#5e5c64;stop-opacity:1;"
offset="0"
id="stop5" />
<stop
style="stop-color:#4d4c50;stop-opacity:1;"
offset="1"
id="stop6" />
</linearGradient>
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect5"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,2,0,1 @ F,0,1,1,0,2,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect3"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,6,0,1 @ F,0,1,1,0,6,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect2"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,8,0,1 @ F,0,0,1,0,8.2101528,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect211"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect157"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect102"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1 @ F,0,1,1,0,12.476317,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect39"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,3.414062,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1"
radius="0"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath31">
<path
style="opacity:1;fill:#865e3c;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:3.57621, 3.57621"
d="m 104.57142,32 c -2.53257,0 -4.571424,1.784002 -4.571424,4 V 82 H 227.99999 V 36 c 0,-2.215998 -2.03886,-4 -4.57143,-4 z"
id="path32" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath33">
<path
style="opacity:1;fill:#865e3c;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:3.57621, 3.57621"
d="m 99.999997,90 v 46 c 0,2.216 2.102573,4 4.714283,4 h 122.57143 c 2.61171,0 4.71428,-1.784 4.71428,-4 V 90 Z"
id="path34" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5"
id="linearGradient6"
x1="176.92285"
y1="156"
x2="176.92285"
y2="164"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4984166,0,0,1.4984166,-49.616298,-72.451818)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient26"
id="linearGradient27"
x1="100"
y1="120.00011"
x2="100"
y2="164"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.4984166,0,0,1.4984166,-49.616298,-72.451818)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient63"
id="linearGradient65"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-35.382733,-4.2152026)"
x1="248.07971"
y1="113.07767"
x2="85.016251"
y2="113.07767" />
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
id="circle65"
style="fill:url(#linearGradient65);stroke:none;stroke-width:1.46117;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 131.16602,27.330078 c -45.029881,-8.12e-4 -81.534017,36.503321 -81.533208,81.533202 2.7e-4,45.02912 36.504089,81.53206 81.533208,81.53125 8.38262,-0.006 16.67054,-1.30441 24.58233,-3.81292 11.09609,-3.51812 26.47255,-2.63586 37.20566,1.85535 9.07487,3.79734 18.86926,5.80785 28.84287,5.84038 41.61705,-7.5e-4 75.35384,-33.73841 75.35351,-75.35546 -7.4e-4,-41.616289 -33.73722,-75.352772 -75.35351,-75.353521 -8.35948,0.02724 -16.6344,1.44503 -24.49097,4.175374 -4.76994,1.657664 -11.30579,0.572701 -15.25124,-2.579772 -14.3779,-11.488134 -32.30568,-17.832988 -50.88865,-17.833883 z"
transform="matrix(-1.0569476,0,0,1.0569476,354.87042,-13.797304)" />
<path
style="fill:none;fill-opacity:1;stroke:#1a5fb4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 85.947825,152 H 64 a 4,4 135 0 0 -4,4 4,4 45 0 0 4,4 h 4 a 4,4 45 0 1 4,4 4,4 135 0 1 -4,4 H 56 a 4,4 135 0 0 -4,4 4,4 45 0 0 4,4 l 28,0 a 4,4 135 0 0 4,-4 4,4 135 0 1 4,-4 h 20"
id="path23"
sodipodi:nodetypes="cccccccccc"
transform="matrix(1.4984165,0,0,1.4984165,-49.616294,-72.451812)" />
<g
id="g21"
transform="matrix(1.4984165,0,0,1.4984165,-291.25069,-41.061959)"
style="fill:#5e5c64">
<path
id="path16"
style="color:#000000;fill:#5e5c64;stroke-linecap:square;-inkscape-stroke:none"
d="m 296.00007,60.838426 -15.15429,45.460934 a 1.0001,1.0001 0 0 0 -0.002,0.008 l -10.51757,31.55664 -0.72461,2.16992 -0.31641,0.94726 1.89844,0.63282 0.3164,-0.94922 0.61719,-1.85156 23.88281,-19.40625 23.88282,19.40625 0.18554,0.55468 0.5,-0.16601 a 1,1 0 0 0 0.86328,-0.28906 l 0.53321,-0.17774 -0.31446,-0.94726 -10.49414,-31.48047 v -0.004 a 1.0001,1.0001 0 0 0 -0.004,-0.008 l -0.006,-0.0195 a 1,1 0 0 0 -0.004,-0.008 z m 0,6.326172 6.58204,19.748047 h -13.16407 z m -5.23046,21.748047 h 10.46093 l -5.23047,4.40625 z m -2.25586,0.712891 5.93359,5 -10.56836,8.902344 z m 14.97461,0 4.63281,13.904294 -10.56836,-8.904294 z m -7.48829,6.308593 11.45704,9.650391 h -22.91407 z m -11.3789,11.650391 h 22.75781 l -11.37891,9.24609 z m -2.32422,0.6875 12.11719,9.84766 -21.11914,17.16015 z m 27.40625,0 9.00195,27.00781 -21.11914,-17.16015 z" />
</g>
<circle
style="fill:#deddda;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="circle82"
cx="152.28058"
cy="56.836697"
r="15.564472" />
<path
id="path1"
style="fill:#3d3846;stroke-width:2;stroke-dasharray:2, 2"
d="m 278,104 h 55.8457 l 8.80509,-38.153666 A 4.7730278,4.7730278 51.497589 0 0 338,60 l -44,0 a 7.5166441,7.5166441 141.40213 0 0 -7.32973,5.850797 z"
transform="matrix(1.4984165,0,0,1.4984165,-217.43895,5.4658483)" />
<path
id="path2"
style="fill:url(#linearGradient6);stroke-width:2.99683;stroke-dasharray:2.99683, 2.99683"
d="m 148.1747,161.30117 c 0,6.62041 5.3669,11.98733 11.98733,11.98733 h 107.57109 c 7.20105,0 13.44901,-4.9706 15.06784,-11.98733 z"
sodipodi:nodetypes="ccccc" />
<path
id="path3"
style="fill:#77767b;stroke-width:2.99683;stroke-dasharray:2.99683, 2.99683"
d="m 232.08602,161.30117 c 0,6.62041 5.3669,11.98733 11.98733,11.98733 h 23.65977 c 7.20105,0 13.44901,-4.9706 15.06784,-11.98733 z"
sodipodi:nodetypes="ccccc" />
<path
id="path4"
style="fill:#99c1f1;stroke-width:2;stroke-dasharray:2, 2"
d="m 282,104 h 47.8457 l 8.70812,-38.050404 A 1.5939923,1.5939923 51.445289 0 0 337,64 h -44 a 2.5,2.5 141.34019 0 0 -2.43902,1.95122 z"
sodipodi:nodetypes="ccccc"
transform="matrix(1.4984165,0,0,1.4984165,-217.43895,5.4658483)" />
<rect
style="fill:url(#linearGradient27);stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="rect7"
width="59.936661"
height="65.930313"
x="70.257019"
y="107.35817"
ry="6.3252244"
rx="6.3252244" />
<rect
style="fill:#62a0ea;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="rect6"
width="47.949329"
height="65.930313"
x="88.238022"
y="107.35818"
ry="6.3252249"
rx="6.3252244" />
<circle
style="fill:#1a5fb4;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="circle7"
cx="112.21269"
cy="155.30748"
r="11.987332" />
<circle
style="fill:#1a5fb4;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="circle8"
cx="112.21269"
cy="125.33916"
r="11.987332" />
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="path8"
cx="112.21269"
cy="125.33916"
r="4.4952497" />
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-dasharray:none"
id="circle9"
cx="112.21269"
cy="155.30748"
r="4.4952497" />
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path22"
cx="152.28058"
cy="54.836697"
r="15.564472" />
<circle
style="fill:#77767b;fill-opacity:1;stroke:none;stroke-width:2.99683;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="circle22"
cx="152.28058"
cy="54.836697"
r="3.1248076" />
<rect
style="fill:#f6f5f4;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="rect24"
width="14.984165"
height="2.9968331"
x="115.20953"
y="177.78374"
ry="1.4984165"
rx="1.4984165" />
<rect
style="fill:#1a5fb4;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="rect23"
width="13.485737"
height="5.9936943"
x="106.21901"
y="176.28529"
ry="2.9968472" />
<rect
style="fill:#c0bfbc;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="rect25"
width="1.4984146"
height="2.9968281"
x="122.70161"
y="177.78374" />
<rect
style="fill:#c0bfbc;fill-opacity:1;stroke:none;stroke-width:1.49841;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="rect26"
width="1.4984146"
height="2.9968281"
x="125.69843"
y="177.78374" />
<circle
style="fill:#bf61ca;fill-opacity:0.48627451;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="path71"
cx="150.07011"
cy="33.371632"
r="1.7915844" />
<circle
style="fill:#bf61ca;fill-opacity:0.48627451;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle71"
cx="150.07011"
cy="26.488079"
r="1.7915844" />
<circle
style="fill:#bf61ca;fill-opacity:0.48627451;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle72"
cx="150.07011"
cy="19.604527"
r="1.7915844" />
<circle
style="fill:#bf61ca;fill-opacity:0.48627451;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle77"
cx="150.07011"
cy="12.720974"
r="1.7915844" />
<circle
style="fill:#c061cb;fill-opacity:0.484565;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle78"
cx="154.56282"
cy="30.071247"
r="1.7915844" />
<circle
style="fill:#c061cb;fill-opacity:0.484565;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle79"
cx="154.56282"
cy="23.187695"
r="1.7915844" />
<circle
style="fill:#c061cb;fill-opacity:0.484565;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle80"
cx="154.56282"
cy="16.304142"
r="1.7915844" />
<circle
style="fill:#c061cb;fill-opacity:0.484565;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:0.443622"
id="circle81"
cx="154.56282"
cy="9.4205904"
r="1.7915844" />
<g
fill="#222222"
id="g2"
transform="matrix(1.7236266,0,-0.3679857,1.7236266,234.34039,117.54652)"
style="fill:#62a0ea;stroke-width:0.580172">
<path
d="M 9.492188,0.140625 C 8.640625,-0.0234375 7.769531,-0.0429688 6.917969,0.0742188 5.21875,0.304688 3.589844,1.082031 2.316406,2.367188 -0.230469,4.933594 -0.734375,8.90625 1.085938,12.03125 c 1.824218,3.121094 5.53125,4.636719 9.019531,3.683594 3.488281,-0.949219 5.90625,-4.132813 5.890625,-7.75 0,-0.550782 -0.453125,-1 -1.003906,-0.996094 -0.550782,0.00391 -0.996094,0.453125 -0.996094,1.003906 0.01563,2.722656 -1.792969,5.097656 -4.417969,5.816406 C 6.953125,14.503906 4.1875,13.371094 2.816406,11.023438 1.445312,8.671875 1.820312,5.707031 3.738281,3.773438 5.652344,1.84375 8.613281,1.4375 10.976562,2.789062 11.453125,3.0625 12.066406,2.898438 12.339844,2.417969 12.613281,1.9375 12.449219,1.328125 11.96875,1.050781 11.183594,0.605469 10.347656,0.300781 9.492188,0.140625 Z m 0,0"
id="path1-6"
style="fill:#62a0ea;stroke-width:0.580172" />
<path
d="M 15.753906,3.65625 C 15.929688,3.457031 16.015625,3.195312 16,2.933594 15.980469,2.667969 15.859375,2.421875 15.660156,2.246094 15.460938,2.070312 15.199219,1.980469 14.933594,2 14.667969,2.015625 14.421875,2.140625 14.246094,2.339844 L 7.949219,9.535156 5.707031,7.289062 C 5.316406,6.898438 4.683594,6.898438 4.292969,7.289062 4.105469,7.476562 4,7.734375 4,8 4,8.265625 4.105469,8.519531 4.292969,8.707031 l 3,3 C 7.488281,11.902344 7.757812,12.007812 8.035156,12 8.3125,11.988281 8.570312,11.867188 8.753906,11.65625 Z m 0,0"
id="path2-7"
style="fill:#62a0ea;stroke-width:0.580172" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -30,10 +30,7 @@ export default function External({ output, builder, onWindowChange }) {
updateColorScheme(); updateColorScheme();
stack.set_visible_child_name("close_window"); stack.set_visible_child_name("close_window");
try { try {
await dbus_proxy.OpenWindowAsync( await dbus_proxy.OpenWindowAsync(output.get_width(), output.get_height());
output.get_allocated_width(),
output.get_allocated_height(),
);
} catch (err) { } catch (err) {
console.debug(err); console.debug(err);
} }

View File

@ -132,7 +132,7 @@ export default function Internal({
const prop_name = prop.get_name(); const prop_name = prop.get_name();
// AdwWindow and AdwApplicationWindow have child and titlebar properties but do not support setting them // AdwWindow and AdwApplicationWindow have child and titlebar properties but do not support setting them
// "Using gtk_window_get_titlebar() and gtk_window_set_titlebar() is not supported and will result in a crash." // "Using gtk_window_get_titlebar() and gtk_window_set_titlebar() is not supported and will result in a crash."
// https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.4/class.Window.html // https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.6/class.Window.html
// https://github.com/workbenchdev/Workbench/issues/130 // https://github.com/workbenchdev/Workbench/issues/130
if ( if (
(object_preview instanceof Adw.Window || (object_preview instanceof Adw.Window ||
@ -219,7 +219,7 @@ export default function Internal({
} }
css_provider = new Gtk.CssProvider(); css_provider = new Gtk.CssProvider();
css_provider.load_from_data(style, -1); css_provider.load_from_string(style);
Gtk.StyleContext.add_provider_for_display( Gtk.StyleContext.add_provider_for_display(
output.get_display(), output.get_display(),
css_provider, css_provider,
@ -257,7 +257,7 @@ function scopeStylesheet(style, id) {
for (const node of ast.nodes) { for (const node of ast.nodes) {
if (node.selector === "window") { if (node.selector === "window") {
node.selector = `#${id}`; node.selector = `#${id}`;
} else if (node.selector) { } else if (!node.selector.startsWith(":")) {
node.selector = `#${id} ${node.selector}`; node.selector = `#${id} ${node.selector}`;
} }
} }
@ -272,8 +272,8 @@ function scopeStylesheet(style, id) {
function screenshot({ widget, path }) { function screenshot({ widget, path }) {
const paintable = new Gtk.WidgetPaintable({ widget }); const paintable = new Gtk.WidgetPaintable({ widget });
const width = widget.get_allocated_width(); const width = widget.get_width();
const height = widget.get_allocated_height(); const height = widget.get_height();
const snapshot = Gtk.Snapshot.new(); const snapshot = Gtk.Snapshot.new();
paintable.snapshot(snapshot, width, height); paintable.snapshot(snapshot, width, height);

View File

@ -147,9 +147,7 @@ export default function Previewer({
panel_code.language === "JavaScript" && panel_code.language === "JavaScript" &&
flags & Gtk.BuilderClosureFlags.SWAPPED flags & Gtk.BuilderClosureFlags.SWAPPED
) { ) {
console.warning( console.warn('Signal flag "swapped" is unsupported in JavaScript.');
'Signal flag "swapped" is unsupported in JavaScript.',
);
} }
return this[function_name] || this.noop; return this[function_name] || this.noop;
} }

View File

@ -1,8 +1,9 @@
executable('workbench-previewer-module', executable('workbench-previewer-module',
'previewer.vala', 'previewer.vala',
dependencies: [ dependency('gio-2.0'), dependency('gmodule-2.0'), dependency('libadwaita-1'), dependency('shumate-1.0'), dependency('webkitgtk-6.0') ], dependencies: [ dependency('gtksourceview-5'), dependency('gmodule-2.0'), dependency('libadwaita-1'), dependency('shumate-1.0'), dependency('webkitgtk-6.0'), libworkbench_vapi ],
# vala_args: [ '--gresourcesdir=' + meson.current_build_dir() ], # vala_args: [ '--gresourcesdir=' + meson.current_build_dir() ],
install: true, install: true,
link_with: libworkbench,
) )
executable('workbench-crasher', executable('workbench-crasher',

View File

@ -6,19 +6,20 @@ namespace Workbench {
this.notify["ColorScheme"].connect (() => { this.notify["ColorScheme"].connect (() => {
this.style_manager.color_scheme = this.ColorScheme; this.style_manager.color_scheme = this.ColorScheme;
}); });
// See application.js
var icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default());
string[] resource_path = {"/org/gtk/libgtk/icons/", "/org/gnome/Adwaita/icons/", "/re/sonny/Workbench/icons/"};
icon_theme.resource_path = resource_path;
string [] search_path = {"/usr/share/icons", "/app/share/icons"};
icon_theme.search_path = search_path;
} }
private void ensure_window () { private void ensure_window () {
if (this.window != null) { if (this.window != null) {
return; return;
} }
var window = new Gtk.Window () { var window = new Workbench.PreviewWindow ();
// Ensure the header bar has the same height as the one on Workbench main window
titlebar = new Gtk.HeaderBar (),
title = "Preview",
default_width = 600,
default_height = 800
};
this.set_window (window); this.set_window (window);
} }
@ -37,8 +38,8 @@ namespace Workbench {
public bool screenshot (string path) { public bool screenshot (string path) {
Gtk.Widget widget = this.target; Gtk.Widget widget = this.target;
var paintable = new Gtk.WidgetPaintable (widget); var paintable = new Gtk.WidgetPaintable (widget);
int width = widget.get_allocated_width (); int width = widget.get_width ();
int height = widget.get_allocated_height (); int height = widget.get_height ();
var snapshot = new Gtk.Snapshot (); var snapshot = new Gtk.Snapshot ();
paintable.snapshot (snapshot, width, height); paintable.snapshot (snapshot, width, height);
Gsk.RenderNode? node = snapshot.to_node (); Gsk.RenderNode? node = snapshot.to_node ();
@ -83,7 +84,7 @@ namespace Workbench {
// Not a Root/Window // Not a Root/Window
if (!(target is Gtk.Root)) { if (!(target is Gtk.Root)) {
this.ensure_window (); this.ensure_window ();
this.window.child = target; ((Workbench.PreviewWindow) this.window).set_content (target);
return; return;
} }
@ -124,7 +125,7 @@ namespace Workbench {
var end = section.get_end_location (); var end = section.get_end_location ();
this.css_parser_error (error.message, (int) start.lines, (int) start.line_chars, (int) end.lines, (int) end.line_chars); this.css_parser_error (error.message, (int) start.lines, (int) start.line_chars, (int) end.lines, (int) end.line_chars);
}); });
this.css.load_from_data (content.data); this.css.load_from_string (content);
Gtk.StyleContext.add_provider_for_display ( Gtk.StyleContext.add_provider_for_display (
Gdk.Display.get_default (), Gdk.Display.get_default (),
this.css, this.css,
@ -142,6 +143,8 @@ namespace Workbench {
return; return;
} }
this.reload_icons (uri);
void* function; void* function;
this.module.symbol ("set_base_uri", out function); this.module.symbol ("set_base_uri", out function);
@ -169,6 +172,17 @@ namespace Workbench {
main_function (); main_function ();
} }
public async void reload_icons (string uri) {
if (this.resource_icons != null) {
this.resource_icons._unregister ();
this.resource_icons = null;
}
try {
this.resource_icons = Resource.load (File.new_for_uri(uri).get_child("icons.gresource").get_path());
this.resource_icons._register ();
} catch {}
}
public void close_window () { public void close_window () {
if (this.window == null) { if (this.window == null) {
return; return;
@ -211,6 +225,7 @@ namespace Workbench {
private Module module; private Module module;
private Gtk.Builder? builder = null; private Gtk.Builder? builder = null;
private Adw.StyleManager style_manager = Adw.StyleManager.get_default (); private Adw.StyleManager style_manager = Adw.StyleManager.get_default ();
private GLib.Resource? resource_icons = null;
} }
void main (string[] args) { void main (string[] args) {
@ -219,6 +234,11 @@ namespace Workbench {
Process.exit (1); Process.exit (1);
} }
var app_id = GLib.Environment.get_variable("FLATPAK_ID");
var resource = Resource.load (@"/app/share/$app_id/re.sonny.Workbench.libworkbench.gresource");
GLib.resources_register (resource);
var loop = new MainLoop (); var loop = new MainLoop ();
Adw.init (); Adw.init ();

View File

@ -28,6 +28,8 @@ export function isPreviewable(class_name) {
const klass = getObjectClass(class_name); const klass = getObjectClass(class_name);
if (!klass) return false; if (!klass) return false;
if (GObject.type_is_a(klass, Adw.Dialog)) return false;
// GLib-GObject-ERROR: cannot create instance of abstract (non-instantiatable) type 'GtkWidget' // GLib-GObject-ERROR: cannot create instance of abstract (non-instantiatable) type 'GtkWidget'
if (GObject.type_test_flags(klass, GObject.TypeFlags.ABSTRACT)) return false; if (GObject.type_test_flags(klass, GObject.TypeFlags.ABSTRACT)) return false;
@ -56,7 +58,7 @@ function getKlass(el) {
return getObjectClass(class_name); return getObjectClass(class_name);
} }
function assertObjectBuildable(el_object, root) { function assertObjectBuildable(el_object, is_root) {
const klass = getKlass(el_object); const klass = getKlass(el_object);
if (klass) { if (klass) {
// GLib-GObject-ERROR: cannot create instance of abstract (non-instantiatable) type 'GtkWidget' // GLib-GObject-ERROR: cannot create instance of abstract (non-instantiatable) type 'GtkWidget'
@ -76,9 +78,16 @@ function assertObjectBuildable(el_object, root) {
} }
// Gtk:ERROR:../gtk/gtkwidget.c:2448:gtk_widget_root: assertion failed: (priv->root == NULL) // Gtk:ERROR:../gtk/gtkwidget.c:2448:gtk_widget_root: assertion failed: (priv->root == NULL)
if (!root && GObject.type_is_a(klass, Gtk.Root)) { if (!is_root && GObject.type_is_a(klass, Gtk.Root)) {
throw new Error( throw new Error(
`${klass.$gtype.name} is a GtkRoot. GtkRoot objects can only appear at the top-level.`, `${klass.$gtype.name} is a GtkRoot. GtkRoot objects can only be used at the top-level.`,
);
}
// Adwaita-Trying to add AdwDialog 0x558667ff74d0 to GtkBox 0x558666bd17c0. Use adw_dialog_present() to show dialogs.
if (!is_root && GObject.type_is_a(klass, Adw.Dialog)) {
throw new Error(
`${klass.$gtype.name} is a AdwDialog. AdwDialog objects can only be used at the top-level.`,
); );
} }
@ -101,14 +110,14 @@ function assertObjectBuildable(el_object, root) {
`${klass.$gtype.name} does not support the child property.`, `${klass.$gtype.name} does not support the child property.`,
); );
} }
}
// Gtk-ERROR **: 23:19:54.204: GtkStackPage '<unnamed>' [0x55b094802eb0] is missing a child widget // Gtk-ERROR **: 23:19:54.204: GtkStackPage '<unnamed>' [0x55b094802eb0] is missing a child widget
if (GObject.type_is_a(klass, Gtk.StackPage)) { if (GObject.type_is_a(klass, Gtk.StackPage)) {
const child = getChildProperty(el_object); const child = getChildProperty(el_object);
// log(child); // log(child);
if (!child) { if (!child) {
throw new Error(`${klass.$gtype.name} is missing a child widget.`); throw new Error(`${klass.$gtype.name} is missing a child widget.`);
}
} }
} }
@ -164,7 +173,7 @@ function getNamespaces() {
function getSearchPathNamespaces(search_path) { function getSearchPathNamespaces(search_path) {
const enumerator = Gio.File.new_for_path(search_path).enumerate_children( const enumerator = Gio.File.new_for_path(search_path).enumerate_children(
"standard::name", `${Gio.FILE_ATTRIBUTE_STANDARD_NAME},${Gio.FILE_ATTRIBUTE_STANDARD_IS_HIDDEN}`,
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
null, null,
); );
@ -172,6 +181,7 @@ function getSearchPathNamespaces(search_path) {
const namespaces = []; const namespaces = [];
for (const file_info of enumerator) { for (const file_info of enumerator) {
if (file_info.get_is_hidden()) continue;
const name = file_info.get_name(); const name = file_info.get_name();
if (!name.endsWith(".typelib")) continue; if (!name.endsWith(".typelib")) continue;
const [namespace] = name.split("-"); const [namespace] = name.split("-");

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

@ -8,7 +8,7 @@ import {
getGjsVersion, getGjsVersion,
getGLibVersion, getGLibVersion,
} from "../troll/src/util.js"; } from "../troll/src/util.js";
import { getFlatpakInfo } from "./util.js"; import { getFlatpakInfo } from "./flatpak.js";
export default function About({ application }) { export default function About({ application }) {
const flatpak_info = getFlatpakInfo(); const flatpak_info = getFlatpakInfo();
@ -26,16 +26,15 @@ ${getValaVersion()}
${getBlueprintVersion()} ${getBlueprintVersion()}
`.trim(); `.trim();
const dialog = new Adw.AboutWindow({ const dialog = new Adw.AboutDialog({
transient_for: application.get_active_window(),
application_name: "Workbench", application_name: "Workbench",
developer_name: "Sonny Piers", developer_name: "Sonny Piers",
copyright: "© 2022 Sonny Piers", copyright: "© 2022 Sonny Piers",
license_type: Gtk.License.GPL_3_0_ONLY, license_type: Gtk.License.GPL_3_0_ONLY,
version: pkg.version, version: pkg.version,
website: "https://apps.gnome.org/Workbench", website: "https://workbench.sonny.re",
application_icon: pkg.name, application_icon: pkg.name,
issue_url: "https://github.com/workbenchdev/Workbench/issues", issue_url: "https://workbench.sonny.re/feedback",
debug_info, debug_info,
developers: [ developers: [
"Sonny Piers https://sonny.re", "Sonny Piers https://sonny.re",
@ -82,6 +81,11 @@ ${getBlueprintVersion()}
"Urtsi Santsi <urtsi.santsi@proton.me>", "Urtsi Santsi <urtsi.santsi@proton.me>",
"Roland Lötscher https://github.com/rolandlo", "Roland Lötscher https://github.com/rolandlo",
"Gregor Niehl https://fosstodon.org/@gregorni", "Gregor Niehl https://fosstodon.org/@gregorni",
"Jamie Gravendeel https://jamie.garden",
"Bharat Tyagi https://github.com/BharatAtbrat",
"Jan Fooken https://git.janvhs.com",
"Vladimir Vaskov https://github.com/Rirusha",
"Nokse https://github.com/Nokse22",
// Add yourself as // Add yourself as
// "John Doe", // "John Doe",
// or // or
@ -89,7 +93,7 @@ ${getBlueprintVersion()}
// or // or
// "John Doe https://john.com", // "John Doe https://john.com",
]); ]);
dialog.present(); dialog.present(application.active_window);
return { dialog }; return { dialog };
} }
@ -100,5 +104,5 @@ function getValaVersion() {
} }
function getBlueprintVersion() { function getBlueprintVersion() {
return "Blueprint 80aaee37"; return "Blueprint 0.16.0";
} }

View File

@ -1,14 +1,13 @@
import Gtk from "gi://Gtk"; import Gtk from "gi://Gtk";
import Gio from "gi://Gio"; import Gio from "gi://Gio";
import GLib from "gi://GLib"; import GLib from "gi://GLib";
import Gdk from "gi://Gdk";
import Xdp from "gi://Xdp"; import Xdp from "gi://Xdp";
import XdpGtk from "gi://XdpGtk4"; import XdpGtk from "gi://XdpGtk4";
import About from "./about.js"; import About from "./about.js";
import Window from "./window.js";
import { portal, settings } from "./util.js"; import { portal, settings } from "./util.js";
import { createSession } from "./sessions.js";
import IconLibrary from "./IconLibrary/main.js";
export default function Actions({ application }) { export default function Actions({ application }) {
const quit = new Gio.SimpleAction({ const quit = new Gio.SimpleAction({
@ -30,38 +29,16 @@ export default function Actions({ application }) {
}); });
application.add_action(showAboutDialog); application.add_action(showAboutDialog);
const action_icon_library = new Gio.SimpleAction({
name: "icon_library",
});
let window_icon_browser;
action_icon_library.connect("activate", (_self, _target) => {
window_icon_browser ??= IconLibrary();
window_icon_browser.present();
});
application.add_action(action_icon_library);
const action_open_uri = new Gio.SimpleAction({ const action_open_uri = new Gio.SimpleAction({
name: "open_uri", name: "open_uri",
parameter_type: new GLib.VariantType("s"), parameter_type: new GLib.VariantType("s"),
}); });
action_open_uri.connect("activate", (_self, target) => { action_open_uri.connect("activate", (_self, target) => {
// This is not using the portal but we silence the GVFS warnings new Gtk.UriLauncher({
// in `log_handler.js` uri: target.unpack(),
Gtk.show_uri( })
application.get_active_window(), .launch(application.get_active_window(), null)
target.unpack(), .catch(console.error);
Gdk.CURRENT_TIME,
);
// an other option is to use libportal:
// const parent = XdpGtk.parent_new_gtk(application.get_active_window());
// portal
// .open_uri(
// parent,
// target.unpack(),
// Xdp.OpenUriFlags.NONE,
// null, // cancellable
// )
// .catch(console.error);
}); });
application.add_action(action_open_uri); application.add_action(action_open_uri);
@ -90,6 +67,15 @@ export default function Actions({ application }) {
// application.add_action(settings.create_action("safe-mode")); // application.add_action(settings.create_action("safe-mode"));
// application.add_action(settings.create_action("auto-preview")); // application.add_action(settings.create_action("auto-preview"));
const action_new_project = new Gio.SimpleAction({
name: "new",
});
action_new_project.connect("activate", (_self, _target) => {
newProject({ application }).catch(console.error);
});
application.add_action(action_new_project);
application.set_accels_for_action("app.new", ["<Control>N"]);
const action_open_file = new Gio.SimpleAction({ const action_open_file = new Gio.SimpleAction({
name: "open", name: "open",
parameter_type: new GLib.VariantType("s"), parameter_type: new GLib.VariantType("s"),
@ -122,6 +108,12 @@ async function showScreenshot({ application, uri }) {
); );
} }
async function newProject({ application }) {
const session = createSession();
const { load } = Window({ application, session });
await load();
}
async function open({ application, hint }) { async function open({ application, hint }) {
const file_dialog = new Gtk.FileDialog(); const file_dialog = new Gtk.FileDialog();

View File

@ -1,12 +1,13 @@
import Adw from "gi://Adw"; import Adw from "gi://Adw";
import Gio from "gi://Gio"; import Gio from "gi://Gio";
import Gtk from "gi://Gtk";
import Gdk from "gi://Gdk";
import Window from "./window.js"; import Window from "./window.js";
import Actions from "./actions.js"; import Actions from "./actions.js";
import { settings, data_dir, ensureDir } from "./util.js"; import { settings, data_dir, ensureDir } from "./util.js";
import { overrides } from "./overrides.js"; import { overrides } from "./overrides.js";
import Library, { getDemo } from "./Library/Library.js"; import Library, { getDemo } from "./Library/Library.js";
import Extensions from "./Extensions/Extensions.js";
import { import {
Session, Session,
addToRecentProjects, addToRecentProjects,
@ -15,6 +16,35 @@ import {
} from "./sessions.js"; } from "./sessions.js";
import ShortcutsWindow from "./shortcutsWindow.js"; import ShortcutsWindow from "./shortcutsWindow.js";
import "./icons/re.sonny.Workbench-beaker.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-code-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-placeholder-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-preview-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-ui-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-screenshot-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-multitasking-windows-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-down-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-eraser4-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-larger-brush-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-terminal-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-test-pass-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-up-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-library-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-gamepad-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-network-wireless-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-person-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-speakers-symbolic.svg" with { type: "icon" };
import "./icons/re.sonny.Workbench-external-link-symbolic.svg" with { type: "icon" };
const icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default());
icon_theme.resource_path = [
"/org/gtk/libgtk/icons/",
"/org/gnome/Adwaita/icons/",
"/re/sonny/Workbench/icons/",
];
// Remove hosts and useless search paths
icon_theme.search_path = ["/usr/share/icons", "/app/share/icons"];
ensureDir(data_dir); ensureDir(data_dir);
const application = new Adw.Application({ const application = new Adw.Application({
@ -39,23 +69,39 @@ application.connect("open", (_self, files, hint) => {
load().catch(console.error); load().catch(console.error);
}); });
application.connect("startup", () => { let proc_biome;
Library({
application,
});
Extensions({ application.connect("startup", () => {
// biome lsp-proxy starts a background server
// it does not get stopped and leaves a process hanging
// so manage it manually instead
// See https://github.com/workbenchdev/Workbench/issues/828
const subprocess_launcher = Gio.SubprocessLauncher.new(
Gio.SubprocessFlags.STDERR_SILENCE,
);
proc_biome = subprocess_launcher.spawnv([
"biome",
"__run_server",
"--config-path",
pkg.pkgdatadir,
]);
Library({
application, application,
}); });
ShortcutsWindow({ application }); ShortcutsWindow({ application });
restoreSessions(); restoreSessions().catch(console.error);
});
application.connect("shutdown", () => {
proc_biome?.force_exit();
}); });
application.connect("activate", () => { application.connect("activate", () => {
if (application.is_remote) { if (application.is_remote) {
bootstrap(); bootstrap().catch(console.error);
} }
}); });
@ -75,14 +121,11 @@ function setColorScheme() {
setColorScheme(); setColorScheme();
settings.connect("changed::color-scheme", setColorScheme); settings.connect("changed::color-scheme", setColorScheme);
// We are not using async otherwise the app segfaults async function restoreSessions() {
// does not like opening a window in a promise const sessions = await getSessions();
// TODO: make a reproducer and file a GJS bug
function restoreSessions() {
const sessions = getSessions();
if (sessions.length < 1) { if (sessions.length < 1) {
bootstrap(); bootstrap().catch(console.error);
} else { } else {
sessions.forEach((session) => { sessions.forEach((session) => {
const { load } = Window({ const { load } = Window({
@ -94,7 +137,7 @@ function restoreSessions() {
} }
} }
function bootstrap() { async function bootstrap() {
const first_run = settings.get_boolean("first-run"); const first_run = settings.get_boolean("first-run");
if (!first_run) { if (!first_run) {
application.activate_action("library", null); application.activate_action("library", null);
@ -102,7 +145,7 @@ function bootstrap() {
} }
const demo = getDemo("Welcome"); const demo = getDemo("Welcome");
const session = createSessionFromDemo(demo); const session = await createSessionFromDemo(demo);
const { load, window } = Window({ const { load, window } = Window({
application, application,
session, session,

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(

View File

@ -8,5 +8,5 @@ It exposes the formatter and linter used in Workbench for the different language
```sh ```sh
make cli make cli
./build-aux/fun workbench-cli ci demos/demos/* ./build-aux/fun workbench-cli ci demos/src/*
``` ```

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,22 +5,42 @@ 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 Shumate from "gi://Shumate";
import WebKit from "gi://WebKit";
import { createLSPClient, languages, getLanguage } from "../common.js"; import { createLSPClient, languages, PYTHON_LSP_CONFIG } from "../common.js";
import lint, { waitForDiagnostics } from "./lint.js"; import lint from "./lint.js";
import format, { formatting } from "./format.js"; import format from "./format.js";
Gtk.init(); import blueprint from "./blueprint.js";
import css from "./css.js";
import javascript from "./javascript.js";
import typescript from "./typescript.js";
import vala from "./vala.js";
import python from "./python.js";
import rust from "./rust.js";
import { Interrupt } from "./util.js";
GObject.type_ensure(Shumate.SimpleMap);
GObject.type_ensure(WebKit.WebView);
export async function main([action, ...args]) { export async function main([action, ...args]) {
const current_dir = Gio.File.new_for_path(GLib.get_current_dir()); const current_dir = Gio.File.new_for_path(GLib.get_current_dir());
if (action === "ci") { if (action === "ci") {
const filenames = args; const filenames = args;
const success = await ci({ filenames, current_dir }); 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;
@ -31,12 +51,10 @@ export async function main([action, ...args]) {
} }
if (lang.id === "vala") { if (lang.id === "vala") {
const api_file = ( const file_api = Gio.File.new_for_path(pkg.pkgdatadir).get_child(
GLib.getenv("FLATPAK_ID") "workbench.vala",
? Gio.File.new_for_path(pkg.pkgdatadir) );
: current_dir.resolve_relative_path("src/langs/vala") file_api.copy(
).get_child("workbench.vala");
api_file.copy(
current_dir.get_child("workbench.vala"), current_dir.get_child("workbench.vala"),
Gio.FileCopyFlags.OVERWRITE, Gio.FileCopyFlags.OVERWRITE,
null, null,
@ -51,34 +69,49 @@ export async function main([action, ...args]) {
lspc._start_process(); lspc._start_process();
await lspc._initialize(); await lspc._initialize();
let success = false; if (lang.id === "python") {
await lspc._request("workspace/didChangeConfiguration", {
if (action === "lint") { settings: PYTHON_LSP_CONFIG,
success = await lint({ filenames, lang, lspc, ci: false }); });
} else if (action === "check") {
success = await lint({ filenames, lang, lspc, ci: true });
} else if (action === "format") {
success = await format({ filenames, lang, lspc });
} else {
printerr(`Unknown action "${action}"}`);
} }
return success ? 0 : 1; try {
if (action === "lint") {
await lint({ filenames, lang, lspc, ci: false });
return 0;
} else if (action === "check") {
await lint({ filenames, lang, lspc, ci: true });
return 0;
} else if (action === "format") {
await format({ filenames, lang, lspc });
return 0;
} else {
printerr(`Unknown action "${action}"}`);
return 1;
}
} catch (err) {
if (err instanceof Interrupt) {
return 1;
} else {
throw err;
}
}
} }
import { parse } from "../langs/xml/xml.js";
import Shumate from "gi://Shumate";
import { LSPError, diagnostic_severities } from "../lsp/LSP.js";
// Why?
new Shumate.Map();
const application = new Adw.Application(); const application = new Adw.Application();
const window = new Adw.ApplicationWindow(); const window = new Adw.ApplicationWindow();
function createLSPClients({ root_uri }) { function createLSPClients({ root_uri }) {
return Object.fromEntries( return Object.fromEntries(
["javascript", "blueprint", "css", "vala"].map((id) => { [
"javascript",
"blueprint",
"css",
"vala",
"rust",
"python",
"typescript",
].map((id) => {
const lang = languages.find((language) => language.id === id); const lang = languages.find((language) => language.id === id);
const lspc = createLSPClient({ const lspc = createLSPClient({
lang, lang,
@ -90,31 +123,20 @@ function createLSPClients({ root_uri }) {
); );
} }
async function checkFile({ lspc, file, lang, uri }) { async function ci({ filenames }) {
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, current_dir }) {
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);
print(`\n📂${demo_dir.get_path()}`);
const [compatible, required_runtime_version] = isDemoCompatible(demo_dir);
if (!compatible) {
print(
` ⚠️ skipped - requires runtime version ${required_runtime_version}`,
);
continue;
}
const lsp_clients = createLSPClients({ root_uri: demo_dir.get_uri() }); const lsp_clients = createLSPClients({ root_uri: demo_dir.get_uri() });
await Promise.all( await Promise.all(
Object.entries(lsp_clients).map(([, lspc]) => { Object.entries(lsp_clients).map(([, lspc]) => {
@ -122,282 +144,64 @@ async function ci({ filenames, current_dir }) {
}), }),
); );
print(`\n📂${demo_dir.get_path()}`);
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,
},
});
let diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.blueprint,
});
diagnostics = diagnostics.filter((diagnostic) => {
return !diagnostic.message.startsWith(
// https://github.com/workbenchdev/demos/issues/42
"Adw.ViewSwitcherTitle is deprecated",
);
});
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()}`); const file_typescript = demo_dir.get_child("main.ts");
print(" ✅ runs"); if (file_typescript.query_exists(null)) {
await typescript({
await lsp_clients.javascript._notify("textDocument/didClose", { file: file_typescript,
textDocument: { lspc: lsp_clients.typescript,
uri, blueprint_object_ids,
}, demo_dir,
application,
builder,
template,
window,
}); });
} }
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 file_python = demo_dir.get_child("main.py");
const languageId = "vala"; if (file_python.query_exists(null)) {
let version = 0; await python({ file: file_python, lspc: lsp_clients.python });
}
const api_file = ( const file_rust = demo_dir.get_child("code.rs");
GLib.getenv("FLATPAK_ID") if (file_rust.query_exists(null)) {
? Gio.File.new_for_path(`/app/share/${GLib.getenv("FLATPAK_ID")}`) await rust({ file: file_rust, lspc: lsp_clients.rust });
: current_dir.resolve_relative_path("src/langs/vala")
).get_child("workbench.vala");
api_file.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,
},
});
const diagnostics = await waitForDiagnostics({
uri,
lspc: lsp_clients.vala,
});
if (
![
// FIXME: https://github.com/workbenchdev/demos/issues/43
"List View Widgets",
// FIXME: deprecated features, no replacement?
"Text Fields",
].includes(demo_dir.get_basename()) &&
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,
},
});
} }
await Promise.all( await Promise.all(
@ -406,43 +210,38 @@ async function ci({ filenames, current_dir }) {
}), }),
); );
} }
return true;
} }
function getXMLObjectIds(tree, object_ids) { const key_file = new GLib.KeyFile();
for (const object of tree.getChildren("object")) { key_file.load_from_file("/.flatpak-info", GLib.KeyFileFlags.NONE);
if (object.attrs.id) object_ids.push(object.attrs.id); // runtime/org.gnome.Sdk/x86_64/master
// <child> or <property name="child"> const [, , , runtime_version] = key_file
for (const child of object.getChildElements()) { .get_string("Application", "runtime")
getXMLObjectIds(child, object_ids); .split("/");
}
function isDemoCompatible(file) {
let str;
try {
str = new TextDecoder().decode(
file.get_child("main.json").load_contents(null)[1],
);
} catch (err) {
console.warn(err);
return true;
} }
}
function getCodeObjectIds(text) { const demo = JSON.parse(str);
const object_ids = []; demo.name = file.get_basename();
for (const match of text.matchAll(/get_object\("(.+)"\)/g)) {
object_ids.push(match[1]); const demo_runtime_version = demo["runtime-version"];
if (demo_runtime_version === "master") {
return [runtime_version === "master", demo_runtime_version];
} else if (runtime_version === "master") {
return [true, demo_runtime_version];
} else if (!demo_runtime_version) {
return [true, demo_runtime_version];
} }
return object_ids;
}
function serializeDiagnostics({ diagnostics }) { return [+runtime_version >= +demo_runtime_version, demo_runtime_version];
return (
diagnostics
.map(({ severity, range, message }) => {
return (
" ❌ " +
diagnostic_severities[severity] +
" " +
range.start.line +
":" +
range.start.character +
" " +
message.split("\n")[0]
);
})
.join("\n") + "\n"
);
} }

View File

@ -3,7 +3,7 @@ bin_conf.set('GJS', find_program('gjs').full_path())
bin_conf.set('version', meson.project_version() + version_suffix) bin_conf.set('version', meson.project_version() + version_suffix)
bin_conf.set('app_id', app_id) bin_conf.set('app_id', app_id)
bin_conf.set('prefix', prefix) bin_conf.set('prefix', prefix)
bin_conf.set('libdir', join_paths(get_option('prefix'), get_option('libdir'))) bin_conf.set('libdir', get_option('prefix') / get_option('libdir'))
bin_conf.set('datadir', datadir) bin_conf.set('datadir', datadir)
bin_conf.set('pkgdatadir', pkgdatadir) bin_conf.set('pkgdatadir', pkgdatadir)
bin_conf.set('sourcedir', meson.project_source_root()) bin_conf.set('sourcedir', meson.project_source_root())

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(),
},
});
}

Some files were not shown because too many files have changed in this diff Show More