Compare commits
94 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
730729b2f1 | ||
|
b5d2e7806f | ||
|
a48d234c56 | ||
|
34fbe9f018 | ||
|
dc0c931917 | ||
|
af32c09966 | ||
|
584b9e440e | ||
|
2a65be9e33 | ||
|
630dbb486f | ||
|
8ec88e697b | ||
|
987a9d4587 | ||
|
42c5e6c1d7 | ||
|
39f6eb9b51 | ||
|
156186b1c9 | ||
|
e97114eee2 | ||
|
0719075808 | ||
|
aa93296968 | ||
|
5506bf85f9 | ||
|
1b75996fab | ||
|
2057f39390 | ||
|
d9badbe19c | ||
|
6c173507a5 | ||
|
541572809a | ||
|
eafa99f771 | ||
|
48897f71d2 | ||
|
812895129f | ||
|
e5c077bd78 | ||
|
d79bc8c84a | ||
|
efb14d9961 | ||
|
2e4e318e17 | ||
|
26e63a11a5 | ||
|
dfb44ab923 | ||
|
7aa97b6cc7 | ||
|
d02b1d1eef | ||
|
020cfec21b | ||
|
154f5eaa82 | ||
|
2c1dad91de | ||
|
b66871f6bd | ||
|
6a1dd637ce | ||
|
3a8e52ceb0 | ||
|
bf5e999a00 | ||
|
2c0a46abf2 | ||
|
669d808c89 | ||
|
fa3f77ef51 | ||
|
05d6c3cf1a | ||
|
2d9b184bd5 | ||
|
60cfdb38fb | ||
|
f4eb0e604b | ||
|
2b13cf3ce2 | ||
|
afea0a5339 | ||
|
be55d5a675 | ||
|
bdf7bed717 | ||
|
78dbbfbc75 | ||
|
dd9a3e87a3 | ||
|
d4066fc32a | ||
|
5a29338cce | ||
|
ea18e429c9 | ||
|
b16fc2ddec | ||
|
d8f06f1b46 | ||
|
84f1bfa1cc | ||
|
17a8e4a6af | ||
|
e9748dd79f | ||
|
a4e1163e13 | ||
|
3a9c3338e0 | ||
|
b26fd1d381 | ||
|
d2c8150675 | ||
|
17e5377587 | ||
|
df4b1d4461 | ||
|
89a9f1b348 | ||
|
26d48f4fe1 | ||
|
0b0a0a283c | ||
|
b2dc1df6f3 | ||
|
563a316695 | ||
|
c65bdb49e2 | ||
|
3ae1c8c611 | ||
|
be124d22d8 | ||
|
d8584653ce | ||
|
16f4f12810 | ||
|
fae77d8ea1 | ||
|
d8c7992512 | ||
|
2b7a0aa6da | ||
|
1ebbe1e391 | ||
|
f511bc15ec | ||
|
16cda14d9a | ||
|
6ee084e1a0 | ||
|
4126d00920 | ||
|
ac5ec74787 | ||
|
185dfe415a | ||
|
4c2944e89c | ||
|
9f6af155b8 | ||
|
5d442dbe33 | ||
|
011d9d837f | ||
|
75ce9e32a6 | ||
|
13dccf5b30 |
@ -4,11 +4,10 @@ env:
|
||||
parser: "@babel/eslint-parser"
|
||||
parserOptions:
|
||||
sourceType: module
|
||||
ecmaVersion: 2023
|
||||
requireConfigFile: false
|
||||
babelOptions:
|
||||
plugins:
|
||||
- "@babel/plugin-syntax-import-assertions"
|
||||
- "@babel/plugin-syntax-import-attributes"
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- plugin:import/errors
|
||||
|
4
.gitconfig
Normal file
@ -0,0 +1,4 @@
|
||||
[re.sonny.Commit]
|
||||
title-length-hint=72
|
||||
body-length-wrap=50
|
||||
auto-capitalize-title=true
|
8
.github/workflows/CI.yaml
vendored
@ -5,10 +5,11 @@ name: CI
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
CI:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
@ -16,13 +17,12 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: "npm"
|
||||
|
||||
- name: Install host dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install flatpak flatpak-builder mutter
|
||||
sudo apt-get install flatpak mutter flatpak-builder
|
||||
|
||||
# Restore caches
|
||||
- name: Restore Flatpak dependencies
|
||||
|
32
.github/workflows/deploy.yaml
vendored
Normal 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 }}
|
1
.gitignore
vendored
@ -15,6 +15,7 @@ install
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.gresource
|
||||
.frun
|
||||
|
||||
# IDEs / editors
|
||||
.idea
|
||||
|
7
.gitmodules
vendored
@ -4,3 +4,10 @@
|
||||
[submodule "demos"]
|
||||
path = demos
|
||||
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
|
||||
|
17
.vscode/settings.json
vendored
@ -5,8 +5,8 @@
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
"**/.git/subtree-cache/**": true,
|
||||
"**/node_modules/*/**": true,
|
||||
"**/.hg/store/**": true,
|
||||
"**/node_modules/*/**": true,
|
||||
"**/.flatpak": true,
|
||||
"**/src/lib": true,
|
||||
".flatpak": true,
|
||||
@ -14,6 +14,12 @@
|
||||
"_build/**": true
|
||||
},
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"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": [
|
||||
@ -23,13 +29,10 @@
|
||||
"build",
|
||||
"builddir"
|
||||
],
|
||||
"[yaml]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"vala.languageServerPath": "${workspaceFolder}/.flatpak/vala-language-server.sh",
|
||||
"[meson]": {
|
||||
"editor.defaultFormatter": "mesonbuild.mesonbuild"
|
||||
},
|
||||
"mesonbuild.configureOnOpen": false,
|
||||
"mesonbuild.buildFolder": "_build",
|
||||
"mesonbuild.mesonPath": "${workspaceFolder}/.flatpak/meson.sh"
|
||||
|
@ -32,7 +32,7 @@ We provide a couple of tools to make the development process pleasant.
|
||||
# sudo dnf install flatpak flatpak-builder nodejs make gcc gcc-c++
|
||||
|
||||
cd Workbench
|
||||
make setup
|
||||
make
|
||||
```
|
||||
|
||||
Before submitting a PR, we recommend running tests locally with
|
||||
|
41
Makefile
@ -1,17 +1,28 @@
|
||||
SHELL:=/bin/bash -O globstar
|
||||
.PHONY: setup build lint unit test ci sandbox flatpak
|
||||
.DEFAULT_GOAL := test
|
||||
.DEFAULT_GOAL := setup
|
||||
|
||||
setup:
|
||||
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//48 org.flatpak.Builder org.freedesktop.Sdk.Extension.rust-stable//24.08 org.freedesktop.Sdk.Extension.vala//24.08 org.freedesktop.Sdk.Extension.llvm18//24.08 org.freedesktop.Sdk.Extension.node20//24.08 org.freedesktop.Sdk.Extension.typescript//24.08
|
||||
# flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo
|
||||
flatpak install --or-update --user --noninteractive flathub org.gnome.Sdk//46 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
|
||||
npm install
|
||||
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
|
||||
|
||||
|
||||
build: devel
|
||||
|
||||
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
|
||||
@ -32,11 +43,12 @@ lint:
|
||||
# CSS
|
||||
./build-aux/fun workbench-cli check css src/**/*.css
|
||||
# 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 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.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:
|
||||
./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
|
||||
# flatpak run org.freedesktop.appstream.cli validate --override=release-time-missing=info --no-net data/app.metainfo.xml
|
||||
@ -50,24 +62,27 @@ unit:
|
||||
|
||||
test: unit lint
|
||||
./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
|
||||
# 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
|
||||
# make sure to test without the sdk extensions installed
|
||||
sandbox: setup
|
||||
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 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//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:
|
||||
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
|
||||
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
|
||||
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
|
||||
clean:
|
||||
|
18
README.md
@ -6,7 +6,7 @@ Learn and prototype with GNOME technologies
|
||||
|
||||

|
||||
|
||||
<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.
|
||||
|
||||
@ -14,12 +14,12 @@ Among other things, Workbench comes with
|
||||
|
||||
- Live GTK/CSS preview
|
||||
- Library of 100+ examples
|
||||
<!-- - JavaScript, TypeScript, Rust, Python and Vala support -->
|
||||
- JavaScript, Rust, Python and Vala support
|
||||
- Declarative user interface syntax
|
||||
- Autosave, sessions and projects
|
||||
- Code linter and formatter
|
||||
- Code diagnostics, completion and formatter
|
||||
- Terminal output
|
||||
- 1000+ icons
|
||||
|
||||
ℹ️ 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] |
|
||||
| ---------- | --------- | ------ | ---------------- |
|
||||
| JavaScript | ✅ | ✅ | 95 |
|
||||
| Python | ✅ | ✅ | 89 |
|
||||
| Vala | ✅ | ✅ | 59 |
|
||||
| Rust | ✅ | ✅ | 45 |
|
||||
| JavaScript | ✅ | ✅ | 103 |
|
||||
| Python | ✅ | ✅ | 98 |
|
||||
| Vala | ✅ | ✅ | 92 |
|
||||
| Rust | ✅ | ✅ | 52 |
|
||||
| Blueprint | ✅ | ✅ | |
|
||||
| CSS | ✅ | ✅ | |
|
||||
|
||||
[1] As of 2024-01-14 <!--counted with `~/go/bin/scc demos/src`-->
|
||||
[1] As of 2024-06-16 <!--counted with `~/go/bin/scc demos/src`-->
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
<details>
|
||||
<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)
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
<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>
|
||||
|
||||
<homepage rdf:resource="https://apps.gnome.org/Workbench" />
|
||||
<bug-database rdf:resource="https://github.com/workbenchdev/Workbench/issues" />
|
||||
<homepage rdf:resource="https://workbench.sonny.re" />
|
||||
<bug-database rdf:resource="https://workbench.sonny.re/feedback" />
|
||||
<programming-language>JavaScript</programming-language>
|
||||
<programming-language>Vala</programming-language>
|
||||
<programming-language>C</programming-language>
|
||||
|
1
blueprint-compiler
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 04ef0944db56ab01307a29aaa7303df6067cb3c0
|
@ -4,16 +4,6 @@ This directory contains the Flatpak Manifest and other build utilities.
|
||||
|
||||
## Workbench Flatpak Manifests
|
||||
|
||||
### gst-plugin-gtk4
|
||||
|
||||
```sh
|
||||
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 Modules
|
||||
|
||||
The `modules/python-*.json` files contain Flatpak modules to install Python dependencies.
|
||||
|
4
build-aux/exceptions.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"re.sonny.Workbench": ["external-gitmodule-url-found"],
|
||||
"re.sonny.Workbench.Devel": ["external-gitmodule-url-found"]
|
||||
}
|
@ -1,77 +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/src");
|
||||
const demos = [];
|
||||
|
||||
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();
|
||||
|
||||
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
@ -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();
|
@ -12,13 +12,17 @@
|
||||
"modules": [
|
||||
{
|
||||
"name": "jsonrpc-glib",
|
||||
"config-opts": ["--buildtype=release", "-Denable_tests=false"],
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib",
|
||||
"--buildtype=release",
|
||||
"-Denable_tests=false"
|
||||
],
|
||||
"buildsystem": "meson",
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.gnome.org/sources/jsonrpc-glib/3.44/jsonrpc-glib-3.44.0.tar.xz",
|
||||
"sha256": "69406a0250d0cc5175408cae7eca80c0c6bfaefc4ae1830b354c0433bcd5ce06"
|
||||
"url": "https://download.gnome.org/sources/jsonrpc-glib/3.44/jsonrpc-glib-3.44.1.tar.xz",
|
||||
"sha256": "1361d17e9c805646afe5102e59baf8ca450238600fcabd01586c654b78bb30df"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -7,15 +7,15 @@
|
||||
"type": "file",
|
||||
"dest-filename": "biome",
|
||||
"only-arches": ["aarch64"],
|
||||
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.6.0/biome-linux-arm64",
|
||||
"sha256": "e25968d3cc7df0e8e36ecf99d87296c0dca394d18ada7e75cbe22cec149e4549"
|
||||
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.9.4/biome-linux-arm64",
|
||||
"sha256": "f0f0f3e7cdec78420a600b05bfc364aa9b804811bd3bbae04e7bf090828ae970"
|
||||
},
|
||||
{
|
||||
"type": "file",
|
||||
"dest-filename": "biome",
|
||||
"only-arches": ["x86_64"],
|
||||
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.6.0/biome-linux-x64",
|
||||
"sha256": "207ae06f84e4d4f0958837fa8e8c97a347af2217a4c55f5c6b53fba521095696"
|
||||
"url": "https://github.com/biomejs/biome/releases/download/cli%2Fv1.9.4/biome-linux-x64",
|
||||
"sha256": "ce247fb644999ef52e5111dd6fd6e471019669fc9c4a44b5699721e39b7032c3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -3,9 +3,8 @@
|
||||
"buildsystem": "meson",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://gitlab.gnome.org/jwestman/blueprint-compiler.git",
|
||||
"commit": "d47955c5a20b2f7cf85ff25a00b02160883aa0b1"
|
||||
"type": "dir",
|
||||
"path": "../../blueprint-compiler"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
12
build-aux/modules/gom.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "gst-plugin-gtk4",
|
||||
"buildsystem": "simple",
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://crates.io/api/v1/crates/gst-plugin-gtk4/0.12.1/download",
|
||||
"dest-filename": "gst-plugin-gtk4-0.12.1.tar.gz",
|
||||
"sha256": "162762eb8df14f696707ff54382b3c02f58706255ab3a37a61d59bc1d0c0115a"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
@ -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": "c5fecee437afd64fa0aac5755af9259aaa24b667"
|
||||
}
|
||||
],
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
"name": "libportal",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib",
|
||||
"-Dtests=false",
|
||||
"-Dbackend-gtk3=disabled",
|
||||
"-Dbackend-gtk4=enabled",
|
||||
@ -11,8 +12,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/flatpak/libportal/releases/download/0.7.1/libportal-0.7.1.tar.xz",
|
||||
"sha256": "297b90b263fad22190a26b8c7e8ea938fe6b18fb936265e588927179920d3805"
|
||||
"url": "https://github.com/flatpak/libportal/releases/download/0.9.1/libportal-0.9.1.tar.xz",
|
||||
"sha256": "de801ee349ed3c255a9af3c01b1a401fab5b3fc1c35eb2fd7dfb35d4b8194d7f"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "libshumate",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": ["-Dgtk_doc=false"],
|
||||
"config-opts": ["--libdir=/app/lib", "-Ddemos=false", "-Dgtk_doc=false"],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.gnome.org/sources/libshumate/1.2/libshumate-1.2.0.tar.xz",
|
||||
"sha256": "4f8413a707cd00f84cee39ca49f58c48fc436f008ea80d6532ac37dafd0ba96b"
|
||||
"url": "https://download.gnome.org/sources/libshumate/1.4/libshumate-1.4.rc.tar.xz",
|
||||
"sha256": "a57b97dbbda55bcb07c6f0197ff006128518c2b2c88fbee8bea5168acbc9baee"
|
||||
}
|
||||
],
|
||||
"modules": [
|
||||
@ -29,8 +29,8 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.5.0/protobuf-c-1.5.0.tar.gz",
|
||||
"sha256": "7b404c63361ed35b3667aec75cc37b54298d56dd2bcf369de3373212cc06fd98"
|
||||
"url": "https://github.com/protobuf-c/protobuf-c/releases/download/v1.4.0/protobuf-c-1.4.0.tar.gz",
|
||||
"sha256": "26d98ee9bf18a6eba0d3f855ddec31dbe857667d269bc0b6017335572f85bbcb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "libspelling",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": ["-Ddocs=false"],
|
||||
"config-opts": ["--libdir=/app/lib", "-Ddocs=false"],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.gnome.org/sources/libspelling/0.2/libspelling-0.2.1.tar.xz",
|
||||
"sha256": "7a787b467bd493f6baffb44138dbc4bef78aaab60efb76a7db88b243bf0f6343"
|
||||
"url": "https://download.gnome.org/sources/libspelling/0.4/libspelling-0.4.6.tar.xz",
|
||||
"sha256": "3248a9b5336ea2f727d2db912d2f0083accc0505ce707679b3d9b8266c0101f5"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
"name": "vte",
|
||||
"buildsystem": "meson",
|
||||
"config-opts": [
|
||||
"--libdir=/app/lib",
|
||||
"-Ddocs=false",
|
||||
"-Dgtk3=false",
|
||||
"-Dgtk4=true",
|
||||
@ -11,8 +12,21 @@
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://download.gnome.org/sources/vte/0.76/vte-0.76.0.tar.xz",
|
||||
"sha256": "bbce30b8f504370b12d6439c07a82993e97d7e9afe2dd367817cd58ff029ffda"
|
||||
"url": "https://download.gnome.org/sources/vte/0.79/vte-0.79.91.tar.xz",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json",
|
||||
"id": "re.sonny.Workbench.Devel",
|
||||
"runtime": "org.gnome.Sdk",
|
||||
"runtime-version": "46",
|
||||
"runtime-version": "48",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"sdk-extensions": [
|
||||
"org.freedesktop.Sdk.Extension.vala",
|
||||
"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": {
|
||||
"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"
|
||||
},
|
||||
"command": "workbench",
|
||||
@ -18,9 +21,7 @@
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=wayland",
|
||||
"--device=dri",
|
||||
"--share=network",
|
||||
"--socket=pulseaudio"
|
||||
"--device=dri"
|
||||
],
|
||||
"cleanup": [
|
||||
"#/include",
|
||||
@ -37,13 +38,12 @@
|
||||
"modules": [
|
||||
"modules/blueprint-compiler.json",
|
||||
"modules/biome.json",
|
||||
"modules/gst-plugin-gtk4.json",
|
||||
"modules/vte.json",
|
||||
"modules/libshumate.json",
|
||||
"modules/libportal.json",
|
||||
"modules/libspelling.json",
|
||||
"modules/gom.json",
|
||||
"modules/GTKCssLanguageServer.json",
|
||||
"modules/icon-development-kit.json",
|
||||
"modules/python-python-lsp-server.json",
|
||||
"modules/python-ruff.json",
|
||||
"modules/python-python-lsp-ruff.json",
|
||||
|
@ -1,15 +1,18 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/flatpak/flatpak-builder/main/data/flatpak-manifest.schema.json",
|
||||
"id": "re.sonny.Workbench",
|
||||
"runtime": "org.gnome.Sdk",
|
||||
"runtime-version": "46",
|
||||
"runtime-version": "48",
|
||||
"sdk": "org.gnome.Sdk",
|
||||
"sdk-extensions": [
|
||||
"org.freedesktop.Sdk.Extension.vala",
|
||||
"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": {
|
||||
"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"
|
||||
},
|
||||
"command": "workbench",
|
||||
@ -18,9 +21,7 @@
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=wayland",
|
||||
"--device=dri",
|
||||
"--share=network",
|
||||
"--socket=pulseaudio"
|
||||
"--device=dri"
|
||||
],
|
||||
"cleanup": [
|
||||
"#/include",
|
||||
@ -37,13 +38,12 @@
|
||||
"modules": [
|
||||
"modules/blueprint-compiler.json",
|
||||
"modules/biome.json",
|
||||
"modules/gst-plugin-gtk4.json",
|
||||
"modules/vte.json",
|
||||
"modules/libshumate.json",
|
||||
"modules/libportal.json",
|
||||
"modules/libspelling.json",
|
||||
"modules/gom.json",
|
||||
"modules/GTKCssLanguageServer.json",
|
||||
"modules/icon-development-kit.json",
|
||||
"modules/python-python-lsp-server.json",
|
||||
"modules/python-ruff.json",
|
||||
"modules/python-python-lsp-ruff.json",
|
||||
|
308
build-aux/wip/minimist.js
Normal 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
@ -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
@ -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
|
@ -8,6 +8,6 @@ Type=Application
|
||||
Categories=WebDevelopment;Development;IDE;GNOME;GTK;
|
||||
Icon=@app_id@
|
||||
# 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
|
||||
StartupNotify=true
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<schemalist gettext-domain="@app_id@">
|
||||
<schemalist>
|
||||
<enum id="re.sonny.Workbench.UserInterfaceLanguage">
|
||||
<value nick="blueprint" value="0"/>
|
||||
<value nick="xml" value="1"/>
|
||||
@ -18,6 +18,9 @@
|
||||
<key name="first-run" type="b">
|
||||
<default>true</default>
|
||||
</key>
|
||||
<key name="typescript" type="b">
|
||||
<default>true</default>
|
||||
</key>
|
||||
</schema>
|
||||
<schema id="@app_id@.Session" path="/re/sonny/Workbench/">
|
||||
<key name="show-code" type="b">
|
||||
@ -56,5 +59,17 @@
|
||||
<key name="edited" type="b">
|
||||
<default>false</default>
|
||||
</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>
|
||||
</schemalist>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<id>@app_id@</id>
|
||||
<launchable type="desktop-id">@app_id@.desktop</launchable>
|
||||
<name translatable="no">Workbench</name>
|
||||
<developer id="sonny.re">
|
||||
<developer id="re.sonny">
|
||||
<name translatable="no">Sonny Piers</name>
|
||||
</developer>
|
||||
<update_contact>sonnyp@gnome.org</update_contact>
|
||||
@ -19,35 +19,157 @@
|
||||
<li>JavaScript, Rust, Python and Vala support</li>
|
||||
<li>Declarative user interface syntax</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>1000+ icons</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url type="homepage">https://apps.gnome.org/Workbench</url>
|
||||
<url type="bugtracker">https://github.com/workbenchdev/Workbench/issues</url>
|
||||
<url type="donation">https://ko-fi.com/sonnyp</url>
|
||||
<url type="vcs-browser">https://github.com/workbenchdev/Workbench</url>
|
||||
<url type="homepage">https://workbench.sonny.re</url>
|
||||
<url type="bugtracker">https://workbench.sonny.re/feedback</url>
|
||||
<url type="donation">https://workbench.sonny.re/donate</url>
|
||||
<url type="vcs-browser">https://workbench.sonny.re/source</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot.png</image>
|
||||
<caption>Workbench welcome screen</caption>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/welcome.png</image>
|
||||
<caption>Welcome screen</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-code.png</image>
|
||||
<caption>Workbench CSS Gradients demo</caption>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/code.png</image>
|
||||
<caption>Drawing Area demo</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-library.png</image>
|
||||
<caption>Workbench Library window</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshot-extensions.png</image>
|
||||
<caption>Workbench Extensions Window</caption>
|
||||
<image>https://raw.githubusercontent.com/workbenchdev/Workbench/main/data/screenshots/library.png</image>
|
||||
<caption>Library window</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1" />
|
||||
<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>
|
||||
@ -66,7 +188,7 @@
|
||||
<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</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>
|
||||
@ -113,7 +235,6 @@
|
||||
<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>Add "Copy" and "Select All" to Console</li>
|
||||
<!-- <li>Add find text support</li> -->
|
||||
<li>Add Vala formatter support</li>
|
||||
<li>Add WebP image format support</li>
|
||||
<li>Use Biome instead of prettier as JavaScript formatter</li>
|
||||
@ -571,11 +692,9 @@
|
||||
<kudo>ModernToolkit</kudo>
|
||||
</kudos>
|
||||
<branding>
|
||||
<color type="primary">#33d17a</color>
|
||||
<color type="primary" scheme_preference="light">#57e389</color>
|
||||
<color type="primary" scheme_preference="dark">#26a269</color>
|
||||
</branding>
|
||||
<custom>
|
||||
<value key="GnomeSoftware::key-colors">[(51, 209, 122)]</value>
|
||||
</custom>
|
||||
<requires>
|
||||
<display_length compare="ge">1024</display_length>
|
||||
</requires>
|
||||
|
@ -2,7 +2,7 @@ desktop_file = configure_file(
|
||||
input: 'app.desktop',
|
||||
output: '@0@.desktop'.format(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: true)
|
||||
@ -14,26 +14,28 @@ configure_file(
|
||||
input: 'app.service',
|
||||
output: '@0@.service'.format(app_id),
|
||||
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(
|
||||
input: 'app.metainfo.xml',
|
||||
output: '@0@.metainfo.xml'.format(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: true)
|
||||
test('Validate metainfo file', appstream_cli,
|
||||
args: ['validate', '--override=release-time-missing=info', '--no-net', '--explain', appstream_file]
|
||||
appstreamcli = find_program('appstreamcli', required: false)
|
||||
test(
|
||||
'Validate appstream file',
|
||||
appstreamcli,
|
||||
args: ['validate', '--no-net', '--explain', appstream_file],
|
||||
)
|
||||
|
||||
configure_file(
|
||||
input: 'app.gschema.xml',
|
||||
output: '@0@.gschema.xml'.format(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: true)
|
||||
@ -41,4 +43,4 @@ test('Validate schema file', compile_schemas,
|
||||
args: ['--strict', '--dry-run', meson.current_source_dir()]
|
||||
)
|
||||
|
||||
install_subdir('icons/hicolor', install_dir : join_paths(get_option('datadir'), 'icons'))
|
||||
install_subdir('icons/hicolor', install_dir : get_option('datadir') / 'icons')
|
||||
|
Before Width: | Height: | Size: 560 KiB |
Before Width: | Height: | Size: 230 KiB |
Before Width: | Height: | Size: 165 KiB |
Before Width: | Height: | Size: 503 KiB |
BIN
data/screenshots/code-dark.png
Normal file
After Width: | Height: | Size: 125 KiB |
BIN
data/screenshots/code.png
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
data/screenshots/library-dark.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
data/screenshots/library.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
data/screenshots/welcome-dark.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
data/screenshots/welcome.png
Normal file
After Width: | Height: | Size: 118 KiB |
2
demos
@ -1 +1 @@
|
||||
Subproject commit 20cfcef70038c2aba1df485c3dd7d14d58537139
|
||||
Subproject commit cd8b209df99294c72a5846ead00797db0bafa862
|
1
gi-types
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 396fe147142e28a921f0745eff1a562c7a551843
|
23
meson.build
@ -1,7 +1,14 @@
|
||||
project('Workbench', ['vala', 'c', 'rust'],
|
||||
version: '46',
|
||||
meson_version: '>= 0.59.0',
|
||||
license: 'GPL-3.0-only'
|
||||
project(
|
||||
'Workbench',
|
||||
['vala', 'c', 'rust'],
|
||||
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')
|
||||
@ -20,9 +27,9 @@ else
|
||||
endif
|
||||
|
||||
prefix = get_option('prefix')
|
||||
bindir = join_paths(prefix, 'bin')
|
||||
datadir = join_paths(prefix, get_option('datadir'))
|
||||
pkgdatadir = join_paths(datadir, app_id)
|
||||
bindir = prefix / 'bin'
|
||||
datadir = prefix / get_option('datadir')
|
||||
pkgdatadir = datadir / app_id
|
||||
|
||||
subdir('data')
|
||||
subdir('src')
|
||||
@ -30,5 +37,5 @@ subdir('src')
|
||||
gnome.post_install(
|
||||
glib_compile_schemas: true,
|
||||
gtk_update_icon_cache: true,
|
||||
update_desktop_database: true
|
||||
update_desktop_database: true,
|
||||
)
|
1026
package-lock.json
generated
@ -1,8 +1,9 @@
|
||||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.22.11",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.22.5",
|
||||
"@babel/core": "^7.25.7",
|
||||
"@babel/eslint-parser": "^7.25.7",
|
||||
"@babel/plugin-syntax-import-attributes": "^7.25.7",
|
||||
"@rollup/plugin-commonjs": "^22.0.1",
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
"eslint": "^8.48.0",
|
||||
@ -12,7 +13,7 @@
|
||||
"events": "^3.3.0",
|
||||
"husky": "^8.0.3",
|
||||
"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",
|
||||
"prettier": "3.0.3",
|
||||
"rollup": "^2.76.0",
|
||||
|
@ -17,11 +17,11 @@ template $Extension: ListBoxRow {
|
||||
Label label_title {}
|
||||
|
||||
[end]
|
||||
Image image_enabled {
|
||||
icon-name: "test-pass-symbolic";
|
||||
Image image_available {
|
||||
icon-name: "re.sonny.Workbench-test-pass-symbolic";
|
||||
|
||||
styles [
|
||||
"success"
|
||||
"success",
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -33,19 +33,13 @@ template $Extension: ListBoxRow {
|
||||
margin-bottom: 14;
|
||||
orientation: vertical;
|
||||
|
||||
Button button {
|
||||
label: _("Install");
|
||||
visible: false;
|
||||
halign: start;
|
||||
margin-bottom: 12;
|
||||
}
|
||||
|
||||
Label label_hint {
|
||||
Label {
|
||||
wrap: true;
|
||||
xalign: 0;
|
||||
label: _("Run the following command");
|
||||
|
||||
styles [
|
||||
"dim-label"
|
||||
"dim-label",
|
||||
]
|
||||
}
|
||||
|
||||
@ -58,7 +52,7 @@ template $Extension: ListBoxRow {
|
||||
xalign: 0;
|
||||
|
||||
styles [
|
||||
"command_snippet"
|
||||
"command_snippet",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,9 @@ export default GObject.registerClass(
|
||||
Template,
|
||||
InternalChildren: [
|
||||
"label_title",
|
||||
"image_enabled",
|
||||
"image_available",
|
||||
"installation_guide",
|
||||
"label_hint",
|
||||
"label_command",
|
||||
"button",
|
||||
],
|
||||
Properties: {
|
||||
title: GObject.ParamSpec.string(
|
||||
@ -23,27 +21,13 @@ export default GObject.registerClass(
|
||||
GObject.ParamFlags.READWRITE,
|
||||
"",
|
||||
),
|
||||
enabled: GObject.ParamSpec.boolean(
|
||||
"enabled",
|
||||
available: GObject.ParamSpec.boolean(
|
||||
"available",
|
||||
"",
|
||||
"",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
false,
|
||||
),
|
||||
uri: GObject.ParamSpec.string(
|
||||
"uri",
|
||||
"",
|
||||
"",
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT,
|
||||
"",
|
||||
),
|
||||
hint: GObject.ParamSpec.string(
|
||||
"hint",
|
||||
"",
|
||||
"",
|
||||
GObject.ParamFlags.READWRITE,
|
||||
"",
|
||||
),
|
||||
command: GObject.ParamSpec.string(
|
||||
"command",
|
||||
"",
|
||||
@ -57,15 +41,6 @@ export default GObject.registerClass(
|
||||
constructor(properties = {}) {
|
||||
super(properties);
|
||||
|
||||
if (properties.uri) {
|
||||
this._button.visible = true;
|
||||
this._button.connect("clicked", () => {
|
||||
new Gtk.UriLauncher({ uri: properties.uri })
|
||||
.launch(this.get_root(), null)
|
||||
.catch(console.error);
|
||||
});
|
||||
}
|
||||
|
||||
this.bind_property(
|
||||
"title",
|
||||
this._label_title,
|
||||
@ -74,26 +49,19 @@ export default GObject.registerClass(
|
||||
);
|
||||
|
||||
this.bind_property(
|
||||
"enabled",
|
||||
this._image_enabled,
|
||||
"available",
|
||||
this._image_available,
|
||||
"visible",
|
||||
GObject.BindingFlags.SYNC_CREATE,
|
||||
);
|
||||
|
||||
this.bind_property(
|
||||
"enabled",
|
||||
"available",
|
||||
this._installation_guide,
|
||||
"visible",
|
||||
GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.INVERT_BOOLEAN,
|
||||
);
|
||||
|
||||
this.bind_property(
|
||||
"hint",
|
||||
this._label_hint,
|
||||
"label",
|
||||
GObject.BindingFlags.SYNC_CREATE,
|
||||
);
|
||||
|
||||
this.bind_property(
|
||||
"command",
|
||||
this._label_command,
|
||||
|
@ -38,30 +38,29 @@ Adw.Dialog dialog {
|
||||
selection-mode: none;
|
||||
|
||||
styles [
|
||||
"boxed-list"
|
||||
"boxed-list",
|
||||
]
|
||||
|
||||
$Extension {
|
||||
title: _("JavaScript");
|
||||
enabled: true;
|
||||
available: true;
|
||||
}
|
||||
|
||||
$Extension {
|
||||
title: _("Python");
|
||||
enabled: true;
|
||||
available: true;
|
||||
}
|
||||
|
||||
$Extension extension_rust {
|
||||
title: _("Rust");
|
||||
hint: _("Run the following command");
|
||||
command: "flatpak install flathub org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08";
|
||||
}
|
||||
|
||||
$Extension extension_vala {
|
||||
title: _("Vala");
|
||||
hint: _("or run the following command");
|
||||
command: "flatpak install flathub org.freedesktop.Sdk.Extension.vala//23.08";
|
||||
uri: "appstream://org.freedesktop.Sdk.Extension.vala";
|
||||
}
|
||||
|
||||
$Extension extension_typescript {
|
||||
title: _("TypeScript");
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +72,7 @@ Adw.Dialog dialog {
|
||||
wrap: true;
|
||||
|
||||
styles [
|
||||
"dim-label"
|
||||
"dim-label",
|
||||
]
|
||||
}
|
||||
|
||||
@ -84,7 +83,7 @@ Adw.Dialog dialog {
|
||||
wrap: true;
|
||||
|
||||
styles [
|
||||
"dim-label"
|
||||
"dim-label",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import Interface from "./Extensions.blp" with { type: "uri" };
|
||||
import illustration from "./extensions.svg";
|
||||
|
||||
import "./Extension.js";
|
||||
import { settings } from "../util.js";
|
||||
import { getFlatpakInfo } from "../flatpak.js";
|
||||
|
||||
export const action_extensions = new Gio.SimpleAction({
|
||||
name: "extensions",
|
||||
@ -18,17 +20,29 @@ export function Extensions({ window }) {
|
||||
picture_illustration,
|
||||
extension_rust,
|
||||
extension_vala,
|
||||
extension_typescript,
|
||||
restart_hint,
|
||||
all_set_hint,
|
||||
} = build(Interface);
|
||||
|
||||
picture_illustration.set_resource(illustration);
|
||||
|
||||
extension_rust.enabled = isRustEnabled();
|
||||
extension_vala.enabled = isValaEnabled();
|
||||
extension_rust.available = isRustAvailable();
|
||||
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]) {
|
||||
if (!extension.enabled) {
|
||||
extension_vala.available = isValaAvailable();
|
||||
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);
|
||||
restart_hint.set_visible(true);
|
||||
}
|
||||
@ -41,17 +55,35 @@ export function Extensions({ window }) {
|
||||
window.add_action(action_extensions);
|
||||
}
|
||||
|
||||
let rust_enabled;
|
||||
export function isRustEnabled() {
|
||||
rust_enabled ??=
|
||||
let rust_available = null;
|
||||
export function isRustAvailable() {
|
||||
rust_available ??=
|
||||
Gio.File.new_for_path("/usr/lib/sdk/rust-stable").query_exists(null) &&
|
||||
Gio.File.new_for_path("/usr/lib/sdk/llvm16").query_exists(null);
|
||||
return rust_enabled;
|
||||
Gio.File.new_for_path(`/usr/lib/sdk/${llvm}`).query_exists(null);
|
||||
return rust_available;
|
||||
}
|
||||
|
||||
let vala_enabled;
|
||||
export function isValaEnabled() {
|
||||
vala_enabled ??=
|
||||
let vala_available = null;
|
||||
export function isValaAvailable() {
|
||||
vala_available ??=
|
||||
Gio.File.new_for_path("/usr/lib/sdk/vala").query_exists(null);
|
||||
return vala_enabled;
|
||||
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");
|
||||
}
|
||||
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
@ -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,
|
||||
);
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
import Gtk from "gi://Gtk";
|
||||
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;
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $EntryRow: Adw.PreferencesRow {
|
||||
template $EntryRow: Adw.ActionRow {
|
||||
activatable: true;
|
||||
|
||||
accessibility {
|
||||
labelled-by: title_label;
|
||||
described-by: description_label;
|
||||
}
|
||||
|
||||
title: bind title_label.label;
|
||||
|
||||
[prefix]
|
||||
Box contents {
|
||||
orientation: horizontal;
|
||||
|
||||
Box labels_box {
|
||||
margin-top: 6;
|
||||
margin-start: 12;
|
||||
margin-bottom: 6;
|
||||
spacing: 3;
|
||||
orientation: vertical;
|
||||
@ -28,7 +28,7 @@ template $EntryRow: Adw.PreferencesRow {
|
||||
Label description_label {
|
||||
styles [
|
||||
"dim-label",
|
||||
"caption"
|
||||
"caption",
|
||||
]
|
||||
|
||||
xalign: 0;
|
||||
@ -43,13 +43,13 @@ template $EntryRow: Adw.PreferencesRow {
|
||||
margin-top: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[suffix]
|
||||
Image {
|
||||
icon-name: "go-next-symbolic";
|
||||
margin-end: 12;
|
||||
margin-start: 6;
|
||||
hexpand: true;
|
||||
halign: end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import GObject from "gi://GObject";
|
||||
import { getLanguage } from "../util.js";
|
||||
import Template from "./EntryRow.blp" with { type: "uri" };
|
||||
|
||||
class EntryRow extends Adw.PreferencesRow {
|
||||
class EntryRow extends Adw.ActionRow {
|
||||
constructor({ demo, ...params } = {}) {
|
||||
super(params);
|
||||
|
||||
@ -22,7 +22,7 @@ class EntryRow extends Adw.PreferencesRow {
|
||||
});
|
||||
|
||||
activate_action.connect("activate", () => {
|
||||
this.emit("activated", null);
|
||||
this.emit("triggered", null);
|
||||
});
|
||||
action_group.add_action(activate_action);
|
||||
|
||||
@ -47,7 +47,7 @@ class EntryRow extends Adw.PreferencesRow {
|
||||
});
|
||||
|
||||
button.connect("clicked", () => {
|
||||
this.emit("activated", language);
|
||||
this.emit("triggered", language);
|
||||
});
|
||||
|
||||
return button;
|
||||
@ -68,7 +68,7 @@ export default GObject.registerClass(
|
||||
),
|
||||
},
|
||||
Signals: {
|
||||
activated: {
|
||||
triggered: {
|
||||
param_types: [GObject.TYPE_JSOBJECT],
|
||||
},
|
||||
},
|
||||
|
@ -1,75 +1,130 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
Adw.PreferencesWindow window {
|
||||
Adw.Window window {
|
||||
hide-on-close: true;
|
||||
modal: false;
|
||||
title: _("Workbench — Library");
|
||||
default-height: 700;
|
||||
default-width: 700;
|
||||
|
||||
Adw.PreferencesPage {
|
||||
Adw.PreferencesGroup {
|
||||
Adw.ToolbarView toolbar_view {
|
||||
[top]
|
||||
Adw.HeaderBar header_bar {
|
||||
title-widget: Adw.WindowTitle {
|
||||
title: _("Workbench — Library");
|
||||
};
|
||||
}
|
||||
|
||||
content: ScrolledWindow scrolled_window {
|
||||
hscrollbar-policy: never;
|
||||
|
||||
child: Adw.Clamp {
|
||||
maximum-size: 576;
|
||||
margin-end: 12;
|
||||
margin-start: 12;
|
||||
|
||||
child: Box {
|
||||
orientation: vertical;
|
||||
spacing: 12;
|
||||
|
||||
Box {
|
||||
orientation: vertical;
|
||||
|
||||
Box {
|
||||
halign: center;
|
||||
vexpand: false;
|
||||
|
||||
Picture picture_illustration {
|
||||
can-shrink: false;
|
||||
margin-bottom: 32;
|
||||
margin-top: 24;
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
label: _("Learn, Test, Remix");
|
||||
|
||||
styles [
|
||||
"title-1"
|
||||
"title-1",
|
||||
]
|
||||
}
|
||||
|
||||
Box {
|
||||
spacing: 6;
|
||||
|
||||
SearchEntry search_entry {
|
||||
search-delay: 100;
|
||||
placeholder-text: _("Search demos");
|
||||
activates-default: true;
|
||||
hexpand: true;
|
||||
margin-top: 32;
|
||||
}
|
||||
|
||||
DropDown dropdown_language {
|
||||
valign: end;
|
||||
|
||||
model: Gtk.StringList {};
|
||||
}
|
||||
|
||||
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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_uncategorized {}
|
||||
|
||||
Adw.PreferencesGroup library_tools {
|
||||
title: _("Tools");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_network {
|
||||
title: _("Network");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_controls {
|
||||
title: _("Controls");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_layout {
|
||||
title: _("Layout");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_feedback {
|
||||
title: _("Feedback");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_navigation {
|
||||
title: _("Navigation");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_user_interface {
|
||||
title: _("User Interface");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup library_platform {
|
||||
title: _("Platform APIs");
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup {
|
||||
vexpand: true;
|
||||
valign: end;
|
||||
|
||||
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>');
|
||||
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"
|
||||
"caption",
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,28 @@ import { createSessionFromDemo } from "../sessions.js";
|
||||
import EntryRow from "./EntryRow.js";
|
||||
|
||||
import illustration from "./library.svg";
|
||||
import { gettext as _ } from "gettext";
|
||||
|
||||
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 }) {
|
||||
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;
|
||||
picture_illustration.set_resource(illustration);
|
||||
|
||||
@ -27,17 +43,60 @@ export default function Library({ application }) {
|
||||
window.add_css_class("devel");
|
||||
}
|
||||
|
||||
let last_selected;
|
||||
let last_triggered;
|
||||
|
||||
window.connect("close-request", quitOnLastWindowClose);
|
||||
|
||||
const demos = getDemos();
|
||||
demos.forEach((demo) => {
|
||||
const widget = new EntryRow({ demo: demo });
|
||||
if (demo.name === "Welcome") last_selected = widget;
|
||||
const categories = [
|
||||
{ id: "all", name: _("Any Category"), index: 0 },
|
||||
{ id: "tools", name: _("Tools"), index: 1 },
|
||||
{ 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) => {
|
||||
last_selected = widget;
|
||||
categories.forEach((category) => {
|
||||
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({
|
||||
application,
|
||||
@ -45,17 +104,66 @@ export default function Library({ application }) {
|
||||
language,
|
||||
}).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({
|
||||
name: "library",
|
||||
parameter_type: null,
|
||||
});
|
||||
action_library.connect("activate", () => {
|
||||
window.present();
|
||||
last_selected?.grab_focus();
|
||||
last_triggered?.grab_focus();
|
||||
});
|
||||
application.add_action(action_library);
|
||||
application.set_accels_for_action("app.library", ["<Control><Shift>O"]);
|
||||
@ -86,9 +194,9 @@ async function openDemo({ application, demo_name, language }) {
|
||||
session.settings.set_int("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
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
if (needsAdditionalPermissions({ demo })) {
|
||||
showPermissionsDialog({ window });
|
||||
return;
|
||||
}
|
||||
|
||||
const code_language = session.getCodeLanguage();
|
||||
const run = autorun && code_language.id === "javascript";
|
||||
if (run) {
|
||||
|
@ -1,13 +1,16 @@
|
||||
import Gio from "gi://Gio";
|
||||
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,
|
||||
session: { settings, file },
|
||||
langs,
|
||||
}) {
|
||||
const panel_code = builder.get_object("panel_code");
|
||||
const button_code = builder.get_object("button_code");
|
||||
@ -53,9 +56,21 @@ export default function PanelCode({
|
||||
stack_code.visible_child_name = panel.language;
|
||||
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();
|
||||
|
||||
|
@ -76,19 +76,18 @@ export default function PanelUI({
|
||||
"button_ui_experimental_blueprint",
|
||||
);
|
||||
button_ui_experimental_blueprint.connect("clicked", () => {
|
||||
const modal = builder.get_object("modal_blueprint_experimental");
|
||||
modal.set_transient_for(application.get_active_window());
|
||||
modal.present();
|
||||
const dialog = builder.get_object("dialog_blueprint_experimental");
|
||||
dialog.present(application.get_active_window());
|
||||
});
|
||||
const button_blueprint_documentation = builder.get_object(
|
||||
"button_blueprint_documentation",
|
||||
);
|
||||
button_blueprint_documentation.connect("clicked", () => {
|
||||
Gtk.show_uri(
|
||||
null,
|
||||
"https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/",
|
||||
null,
|
||||
);
|
||||
new Gtk.UriLauncher({
|
||||
uri: "https://jwestman.pages.gitlab.gnome.org/blueprint-compiler/",
|
||||
})
|
||||
.launch(application.get_active_window(), null)
|
||||
.catch(console.error);
|
||||
});
|
||||
|
||||
let handler_id_xml = null;
|
||||
|
155
src/Permissions/Permissions.blp
Normal 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",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
72
src/Permissions/Permissions.js
Normal 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);
|
||||
}
|
568
src/Permissions/permissions.svg
Normal 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 |
@ -30,10 +30,7 @@ export default function External({ output, builder, onWindowChange }) {
|
||||
updateColorScheme();
|
||||
stack.set_visible_child_name("close_window");
|
||||
try {
|
||||
await dbus_proxy.OpenWindowAsync(
|
||||
output.get_allocated_width(),
|
||||
output.get_allocated_height(),
|
||||
);
|
||||
await dbus_proxy.OpenWindowAsync(output.get_width(), output.get_height());
|
||||
} catch (err) {
|
||||
console.debug(err);
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ export default function Internal({
|
||||
const prop_name = prop.get_name();
|
||||
// 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."
|
||||
// https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.5/class.Window.html
|
||||
// https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1.6/class.Window.html
|
||||
// https://github.com/workbenchdev/Workbench/issues/130
|
||||
if (
|
||||
(object_preview instanceof Adw.Window ||
|
||||
@ -257,7 +257,7 @@ function scopeStylesheet(style, id) {
|
||||
for (const node of ast.nodes) {
|
||||
if (node.selector === "window") {
|
||||
node.selector = `#${id}`;
|
||||
} else if (node.selector) {
|
||||
} else if (!node.selector.startsWith(":")) {
|
||||
node.selector = `#${id} ${node.selector}`;
|
||||
}
|
||||
}
|
||||
@ -272,8 +272,8 @@ function scopeStylesheet(style, id) {
|
||||
|
||||
function screenshot({ widget, path }) {
|
||||
const paintable = new Gtk.WidgetPaintable({ widget });
|
||||
const width = widget.get_allocated_width();
|
||||
const height = widget.get_allocated_height();
|
||||
const width = widget.get_width();
|
||||
const height = widget.get_height();
|
||||
|
||||
const snapshot = Gtk.Snapshot.new();
|
||||
paintable.snapshot(snapshot, width, height);
|
||||
|
@ -6,6 +6,13 @@ namespace Workbench {
|
||||
this.notify["ColorScheme"].connect (() => {
|
||||
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 () {
|
||||
@ -31,8 +38,8 @@ namespace Workbench {
|
||||
public bool screenshot (string path) {
|
||||
Gtk.Widget widget = this.target;
|
||||
var paintable = new Gtk.WidgetPaintable (widget);
|
||||
int width = widget.get_allocated_width ();
|
||||
int height = widget.get_allocated_height ();
|
||||
int width = widget.get_width ();
|
||||
int height = widget.get_height ();
|
||||
var snapshot = new Gtk.Snapshot ();
|
||||
paintable.snapshot (snapshot, width, height);
|
||||
Gsk.RenderNode? node = snapshot.to_node ();
|
||||
@ -136,6 +143,8 @@ namespace Workbench {
|
||||
return;
|
||||
}
|
||||
|
||||
this.reload_icons (uri);
|
||||
|
||||
void* function;
|
||||
|
||||
this.module.symbol ("set_base_uri", out function);
|
||||
@ -163,6 +172,17 @@ namespace Workbench {
|
||||
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 () {
|
||||
if (this.window == null) {
|
||||
return;
|
||||
@ -205,6 +225,7 @@ namespace Workbench {
|
||||
private Module module;
|
||||
private Gtk.Builder? builder = null;
|
||||
private Adw.StyleManager style_manager = Adw.StyleManager.get_default ();
|
||||
private GLib.Resource? resource_icons = null;
|
||||
}
|
||||
|
||||
void main (string[] args) {
|
||||
@ -214,7 +235,8 @@ namespace Workbench {
|
||||
}
|
||||
|
||||
var app_id = GLib.Environment.get_variable("FLATPAK_ID");
|
||||
Resource.load (@"/app/share/$app_id/re.sonny.Workbench.libworkbench.gresource")._register ();
|
||||
var resource = Resource.load (@"/app/share/$app_id/re.sonny.Workbench.libworkbench.gresource");
|
||||
GLib.resources_register (resource);
|
||||
|
||||
|
||||
var loop = new MainLoop ();
|
||||
|
@ -110,7 +110,6 @@ function assertObjectBuildable(el_object, is_root) {
|
||||
`${klass.$gtype.name} does not support the child property.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Gtk-ERROR **: 23:19:54.204: GtkStackPage '<unnamed>' [0x55b094802eb0] is missing a child widget
|
||||
if (GObject.type_is_a(klass, Gtk.StackPage)) {
|
||||
@ -120,6 +119,7 @@ function assertObjectBuildable(el_object, is_root) {
|
||||
throw new Error(`${klass.$gtype.name} is missing a child widget.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const child_property = getChildProperty(el_object);
|
||||
if (child_property) {
|
||||
|
@ -12,8 +12,7 @@ class WorkbenchHoverProvider extends GObject.Object {
|
||||
}
|
||||
|
||||
findDiagnostics(context) {
|
||||
const iter = new Gtk.TextIter();
|
||||
context.get_iter(iter);
|
||||
const [, iter] = context.get_iter();
|
||||
|
||||
const line = iter.get_line();
|
||||
// Looks like line_offset starts at 0
|
||||
|
11
src/about.js
@ -8,7 +8,7 @@ import {
|
||||
getGjsVersion,
|
||||
getGLibVersion,
|
||||
} from "../troll/src/util.js";
|
||||
import { getFlatpakInfo } from "./util.js";
|
||||
import { getFlatpakInfo } from "./flatpak.js";
|
||||
|
||||
export default function About({ application }) {
|
||||
const flatpak_info = getFlatpakInfo();
|
||||
@ -32,9 +32,9 @@ ${getBlueprintVersion()}
|
||||
copyright: "© 2022 Sonny Piers",
|
||||
license_type: Gtk.License.GPL_3_0_ONLY,
|
||||
version: pkg.version,
|
||||
website: "https://apps.gnome.org/Workbench",
|
||||
website: "https://workbench.sonny.re",
|
||||
application_icon: pkg.name,
|
||||
issue_url: "https://github.com/workbenchdev/Workbench/issues",
|
||||
issue_url: "https://workbench.sonny.re/feedback",
|
||||
debug_info,
|
||||
developers: [
|
||||
"Sonny Piers https://sonny.re",
|
||||
@ -81,10 +81,11 @@ ${getBlueprintVersion()}
|
||||
"Urtsi Santsi <urtsi.santsi@proton.me>",
|
||||
"Roland Lötscher https://github.com/rolandlo",
|
||||
"Gregor Niehl https://fosstodon.org/@gregorni",
|
||||
"Bart Gravendeel https://monster.codeberg.page",
|
||||
"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
|
||||
// "John Doe",
|
||||
// or
|
||||
@ -103,5 +104,5 @@ function getValaVersion() {
|
||||
}
|
||||
|
||||
function getBlueprintVersion() {
|
||||
return "Blueprint d47955c5";
|
||||
return "Blueprint 0.16.0";
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
import Gtk from "gi://Gtk";
|
||||
import Gio from "gi://Gio";
|
||||
import GLib from "gi://GLib";
|
||||
import Gdk from "gi://Gdk";
|
||||
import Xdp from "gi://Xdp";
|
||||
import XdpGtk from "gi://XdpGtk4";
|
||||
|
||||
import About from "./about.js";
|
||||
import Window from "./window.js";
|
||||
import { portal, settings } from "./util.js";
|
||||
|
||||
import IconLibrary from "./IconLibrary/main.js";
|
||||
import { createSession } from "./sessions.js";
|
||||
|
||||
export default function Actions({ application }) {
|
||||
const quit = new Gio.SimpleAction({
|
||||
@ -30,38 +29,16 @@ export default function Actions({ application }) {
|
||||
});
|
||||
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({
|
||||
name: "open_uri",
|
||||
parameter_type: new GLib.VariantType("s"),
|
||||
});
|
||||
action_open_uri.connect("activate", (_self, target) => {
|
||||
// This is not using the portal but we silence the GVFS warnings
|
||||
// in `log_handler.js`
|
||||
Gtk.show_uri(
|
||||
application.get_active_window(),
|
||||
target.unpack(),
|
||||
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);
|
||||
new Gtk.UriLauncher({
|
||||
uri: target.unpack(),
|
||||
})
|
||||
.launch(application.get_active_window(), null)
|
||||
.catch(console.error);
|
||||
});
|
||||
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("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({
|
||||
name: "open",
|
||||
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 }) {
|
||||
const file_dialog = new Gtk.FileDialog();
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import Adw from "gi://Adw";
|
||||
import Gio from "gi://Gio";
|
||||
import Gtk from "gi://Gtk";
|
||||
import Gdk from "gi://Gdk";
|
||||
|
||||
import Window from "./window.js";
|
||||
import Actions from "./actions.js";
|
||||
@ -14,6 +16,35 @@ import {
|
||||
} from "./sessions.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);
|
||||
|
||||
const application = new Adw.Application({
|
||||
|
@ -1,7 +1,6 @@
|
||||
#!@GJS@ -m
|
||||
|
||||
import { exit, programArgs } from "system";
|
||||
import GLib from "gi://GLib";
|
||||
import { setConsoleLogDomain } from "console";
|
||||
import Xdp from "gi://Xdp";
|
||||
|
||||
@ -14,7 +13,6 @@ imports.package.init({
|
||||
datadir: "@datadir@",
|
||||
});
|
||||
setConsoleLogDomain(pkg.name);
|
||||
GLib.set_application_name("Workbench");
|
||||
|
||||
if (!Xdp.Portal.running_under_flatpak()) {
|
||||
console.error(
|
||||
|
97
src/cli/blueprint.js
Normal 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
@ -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
@ -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(),
|
||||
},
|
||||
});
|
||||
}
|
@ -4,6 +4,7 @@ import Gio from "gi://Gio";
|
||||
|
||||
import { formatting } from "./format.js";
|
||||
import { diagnostic_severities } from "../lsp/LSP.js";
|
||||
import { waitForDiagnostics } from "./util.js";
|
||||
|
||||
export default async function lint({ filenames, lang, lspc, ci }) {
|
||||
let success = true;
|
||||
@ -47,19 +48,6 @@ export default async function lint({ filenames, lang, lspc, ci }) {
|
||||
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 }) {
|
||||
return (
|
||||
`\n${file.get_path()}\n` +
|
||||
|
539
src/cli/main.js
@ -5,23 +5,23 @@ import "../init.js";
|
||||
|
||||
import GLib from "gi://GLib";
|
||||
import Gio from "gi://Gio";
|
||||
import Gtk from "gi://Gtk";
|
||||
import Adw from "gi://Adw";
|
||||
import GObject from "gi://GObject";
|
||||
import Shumate from "gi://Shumate";
|
||||
import WebKit from "gi://WebKit";
|
||||
|
||||
import { parse } from "../langs/xml/xml.js";
|
||||
import { LSPError, diagnostic_severities } from "../lsp/LSP.js";
|
||||
import { createLSPClient, languages, PYTHON_LSP_CONFIG } from "../common.js";
|
||||
import lint from "./lint.js";
|
||||
import format from "./format.js";
|
||||
|
||||
import {
|
||||
createLSPClient,
|
||||
languages,
|
||||
getLanguage,
|
||||
PYTHON_LSP_CONFIG,
|
||||
} from "../common.js";
|
||||
import lint, { waitForDiagnostics } from "./lint.js";
|
||||
import format, { formatting } from "./format.js";
|
||||
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);
|
||||
@ -31,8 +31,16 @@ export async function main([action, ...args]) {
|
||||
|
||||
if (action === "ci") {
|
||||
const filenames = args;
|
||||
const success = await ci({ filenames, current_dir });
|
||||
return success ? 0 : 1;
|
||||
try {
|
||||
await ci({ filenames });
|
||||
return 0;
|
||||
} catch (err) {
|
||||
if (err instanceof Interrupt) {
|
||||
return 1;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const [language_id, ...filenames] = args;
|
||||
@ -43,12 +51,10 @@ export async function main([action, ...args]) {
|
||||
}
|
||||
|
||||
if (lang.id === "vala") {
|
||||
const api_file = (
|
||||
GLib.getenv("FLATPAK_ID")
|
||||
? Gio.File.new_for_path(pkg.pkgdatadir)
|
||||
: current_dir.resolve_relative_path("src/langs/vala")
|
||||
).get_child("workbench.vala");
|
||||
api_file.copy(
|
||||
const file_api = Gio.File.new_for_path(pkg.pkgdatadir).get_child(
|
||||
"workbench.vala",
|
||||
);
|
||||
file_api.copy(
|
||||
current_dir.get_child("workbench.vala"),
|
||||
Gio.FileCopyFlags.OVERWRITE,
|
||||
null,
|
||||
@ -69,19 +75,27 @@ export async function main([action, ...args]) {
|
||||
});
|
||||
}
|
||||
|
||||
let success = false;
|
||||
|
||||
try {
|
||||
if (action === "lint") {
|
||||
success = await lint({ filenames, lang, lspc, ci: false });
|
||||
await lint({ filenames, lang, lspc, ci: false });
|
||||
return 0;
|
||||
} else if (action === "check") {
|
||||
success = await lint({ filenames, lang, lspc, ci: true });
|
||||
await lint({ filenames, lang, lspc, ci: true });
|
||||
return 0;
|
||||
} else if (action === "format") {
|
||||
success = await format({ filenames, lang, lspc });
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
|
||||
const application = new Adw.Application();
|
||||
@ -89,7 +103,15 @@ const window = new Adw.ApplicationWindow();
|
||||
|
||||
function createLSPClients({ root_uri }) {
|
||||
return Object.fromEntries(
|
||||
["javascript", "blueprint", "css", "vala", "rust", "python"].map((id) => {
|
||||
[
|
||||
"javascript",
|
||||
"blueprint",
|
||||
"css",
|
||||
"vala",
|
||||
"rust",
|
||||
"python",
|
||||
"typescript",
|
||||
].map((id) => {
|
||||
const lang = languages.find((language) => language.id === id);
|
||||
const lspc = createLSPClient({
|
||||
lang,
|
||||
@ -101,31 +123,20 @@ function createLSPClients({ root_uri }) {
|
||||
);
|
||||
}
|
||||
|
||||
async function checkFile({ lspc, file, lang, uri }) {
|
||||
const [contents] = await file.load_contents_async(null);
|
||||
const text = new TextDecoder().decode(contents);
|
||||
const buffer = new Gtk.TextBuffer({ text });
|
||||
|
||||
const buffer_tmp = new Gtk.TextBuffer({ text: buffer.text });
|
||||
await formatting({ buffer: buffer_tmp, uri, lang, lspc });
|
||||
|
||||
if (buffer_tmp.text === buffer.text) {
|
||||
print(` ✅ checks`);
|
||||
return true;
|
||||
} else {
|
||||
printerr(
|
||||
` ❌ formatting differs - open and run ${file
|
||||
.get_parent()
|
||||
.get_basename()} with Workbench to fix`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function ci({ filenames, current_dir }) {
|
||||
async function ci({ filenames }) {
|
||||
for (const filename of filenames) {
|
||||
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() });
|
||||
await Promise.all(
|
||||
Object.entries(lsp_clients).map(([, lspc]) => {
|
||||
@ -133,377 +144,64 @@ async function ci({ filenames, current_dir }) {
|
||||
}),
|
||||
);
|
||||
|
||||
print(`\n📂${demo_dir.get_path()}`);
|
||||
|
||||
let template = null;
|
||||
const builder = new Gtk.Builder();
|
||||
const blueprint_object_ids = [];
|
||||
let xml = null;
|
||||
let builder = null;
|
||||
let blueprint_object_ids = null;
|
||||
|
||||
const file_blueprint = demo_dir.get_child("main.blp");
|
||||
if (file_blueprint.query_exists(null)) {
|
||||
print(` ${file_blueprint.get_path()}`);
|
||||
const uri = file_blueprint.get_uri();
|
||||
const languageId = "blueprint";
|
||||
let version = 0;
|
||||
|
||||
const [contents] = await file_blueprint.load_contents_async(null);
|
||||
const text = new TextDecoder().decode(contents);
|
||||
|
||||
await lsp_clients.blueprint._notify("textDocument/didOpen", {
|
||||
textDocument: {
|
||||
uri,
|
||||
languageId,
|
||||
version: version++,
|
||||
text,
|
||||
},
|
||||
});
|
||||
|
||||
const diagnostics = await waitForDiagnostics({
|
||||
uri,
|
||||
lspc: lsp_clients.blueprint,
|
||||
});
|
||||
if (diagnostics.length > 0) {
|
||||
printerr(serializeDiagnostics({ diagnostics }));
|
||||
return false;
|
||||
}
|
||||
|
||||
print(` ✅ lints`);
|
||||
|
||||
({ xml } = await lsp_clients.blueprint._request(
|
||||
"textDocument/x-blueprint-compile",
|
||||
{
|
||||
textDocument: {
|
||||
uri,
|
||||
},
|
||||
},
|
||||
));
|
||||
|
||||
print(` ✅ compiles`);
|
||||
|
||||
try {
|
||||
await lsp_clients.blueprint._request("x-blueprint/decompile", {
|
||||
text: xml,
|
||||
});
|
||||
print(" ✅ decompiles");
|
||||
} catch (err) {
|
||||
if (!(err instanceof LSPError)) throw err;
|
||||
if (
|
||||
![
|
||||
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/128
|
||||
"unsupported XML tag: <condition>",
|
||||
// https://gitlab.gnome.org/jwestman/blueprint-compiler/-/issues/139
|
||||
"unsupported XML tag: <items>",
|
||||
].includes(err.message)
|
||||
) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
const checks = await checkFile({
|
||||
lspc: lsp_clients.blueprint,
|
||||
({ template, builder, blueprint_object_ids } = await blueprint({
|
||||
file: file_blueprint,
|
||||
lang: getLanguage("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);
|
||||
}
|
||||
lspc: lsp_clients.blueprint,
|
||||
}));
|
||||
}
|
||||
|
||||
const file_css = demo_dir.get_child("main.css");
|
||||
if (file_css.query_exists(null)) {
|
||||
print(` ${file_css.get_path()}`);
|
||||
|
||||
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,
|
||||
},
|
||||
});
|
||||
await css({ file: file_css, lspc: lsp_clients.css });
|
||||
}
|
||||
|
||||
const file_javascript = demo_dir.get_child("main.js");
|
||||
if (file_javascript.query_exists(null)) {
|
||||
print(` ${file_javascript.get_path()}`);
|
||||
|
||||
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,
|
||||
await javascript({
|
||||
file: file_javascript,
|
||||
lang: getLanguage("javascript"),
|
||||
uri,
|
||||
});
|
||||
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,
|
||||
lspc: lsp_clients.javascript,
|
||||
blueprint_object_ids,
|
||||
demo_dir,
|
||||
application,
|
||||
builder,
|
||||
template,
|
||||
resolve(path) {
|
||||
return demo_dir.resolve_relative_path(path).get_uri();
|
||||
},
|
||||
preview() {},
|
||||
};
|
||||
window,
|
||||
});
|
||||
}
|
||||
|
||||
await import(`file://${file_javascript.get_path()}`);
|
||||
print(" ✅ runs");
|
||||
|
||||
await lsp_clients.javascript._notify("textDocument/didClose", {
|
||||
textDocument: {
|
||||
uri,
|
||||
},
|
||||
const file_typescript = demo_dir.get_child("main.ts");
|
||||
if (file_typescript.query_exists(null)) {
|
||||
await typescript({
|
||||
file: file_typescript,
|
||||
lspc: lsp_clients.typescript,
|
||||
blueprint_object_ids,
|
||||
demo_dir,
|
||||
application,
|
||||
builder,
|
||||
template,
|
||||
window,
|
||||
});
|
||||
}
|
||||
|
||||
const file_vala = demo_dir.get_child("main.vala");
|
||||
if (file_vala.query_exists(null)) {
|
||||
print(` ${file_vala.get_path()}`);
|
||||
|
||||
const uri = file_vala.get_uri();
|
||||
const languageId = "vala";
|
||||
let version = 0;
|
||||
|
||||
const api_file = (
|
||||
GLib.getenv("FLATPAK_ID")
|
||||
? Gio.File.new_for_path(`/app/share/${GLib.getenv("FLATPAK_ID")}`)
|
||||
: 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,
|
||||
},
|
||||
});
|
||||
|
||||
let diagnostics = await waitForDiagnostics({
|
||||
uri,
|
||||
lspc: lsp_clients.vala,
|
||||
});
|
||||
// FIXME: deprecated features, no replacement?
|
||||
if (demo_dir.get_basename() === "Text Fields") {
|
||||
const ignore_for_text_fields = [
|
||||
"`Gtk.EntryCompletion' has been deprecated since 4.10",
|
||||
"`Gtk.Entry.completion' has been deprecated since 4.10",
|
||||
"`Gtk.ListStore' has been deprecated since 4.10",
|
||||
"`Gtk.TreeIter' has been deprecated since 4.10",
|
||||
];
|
||||
diagnostics = diagnostics.filter((diagnostic) => {
|
||||
return !ignore_for_text_fields.includes(diagnostic.message);
|
||||
});
|
||||
}
|
||||
|
||||
if (diagnostics.length > 0) {
|
||||
printerr(serializeDiagnostics({ diagnostics }));
|
||||
return false;
|
||||
}
|
||||
print(` ✅ lints`);
|
||||
|
||||
const checks = await checkFile({
|
||||
lspc: lsp_clients.vala,
|
||||
file: file_vala,
|
||||
lang: getLanguage("vala"),
|
||||
uri,
|
||||
});
|
||||
if (!checks) return false;
|
||||
|
||||
await lsp_clients.vala._notify("textDocument/didClose", {
|
||||
textDocument: {
|
||||
uri,
|
||||
},
|
||||
});
|
||||
await vala({ file: file_vala, lspc: lsp_clients.vala, demo_dir });
|
||||
}
|
||||
|
||||
const file_python = demo_dir.get_child("main.py");
|
||||
if (file_python.query_exists(null)) {
|
||||
print(` ${file_python.get_path()}`);
|
||||
|
||||
const uri = file_python.get_uri();
|
||||
const languageId = "python";
|
||||
let version = 0;
|
||||
|
||||
const [contents] = await file_python.load_contents_async(null);
|
||||
const text = new TextDecoder().decode(contents);
|
||||
|
||||
await lsp_clients.python._request("workspace/didChangeConfiguration", {
|
||||
settings: PYTHON_LSP_CONFIG,
|
||||
});
|
||||
|
||||
await lsp_clients.python._notify("textDocument/didOpen", {
|
||||
textDocument: {
|
||||
uri,
|
||||
languageId,
|
||||
version: version++,
|
||||
text,
|
||||
},
|
||||
});
|
||||
|
||||
const diagnostics = await waitForDiagnostics({
|
||||
uri,
|
||||
lspc: lsp_clients.python,
|
||||
});
|
||||
if (diagnostics.length > 0) {
|
||||
printerr(serializeDiagnostics({ diagnostics }));
|
||||
return false;
|
||||
}
|
||||
print(` ✅ lints`);
|
||||
|
||||
const checks = await checkFile({
|
||||
lspc: lsp_clients.python,
|
||||
file: file_python,
|
||||
lang: getLanguage("python"),
|
||||
uri,
|
||||
});
|
||||
if (!checks) return false;
|
||||
|
||||
await lsp_clients.python._notify("textDocument/didClose", {
|
||||
textDocument: {
|
||||
uri,
|
||||
},
|
||||
});
|
||||
await python({ file: file_python, lspc: lsp_clients.python });
|
||||
}
|
||||
|
||||
const file_rust = demo_dir.get_child("code.rs");
|
||||
if (file_rust.query_exists(null)) {
|
||||
print(` ${file_rust.get_path()}`);
|
||||
|
||||
const uri = file_rust.get_uri();
|
||||
const languageId = "rust";
|
||||
let version = 0;
|
||||
|
||||
const [contents] = await file_rust.load_contents_async(null);
|
||||
const text = new TextDecoder().decode(contents);
|
||||
|
||||
await lsp_clients.rust._notify("textDocument/didOpen", {
|
||||
textDocument: {
|
||||
uri,
|
||||
languageId,
|
||||
version: version++,
|
||||
text,
|
||||
},
|
||||
});
|
||||
|
||||
// FIXME: rust analyzer doesn't publish diagnostics if there are none
|
||||
// probably we should switch to pulling diagnostics but unknown if supported
|
||||
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_pullDiagnostics
|
||||
|
||||
// const diagnostics = await waitForDiagnostics({
|
||||
// uri,
|
||||
// lspc: lsp_clients.rust,
|
||||
// });
|
||||
// if (diagnostics.length > 0) {
|
||||
// printerr(serializeDiagnostics({ diagnostics }));
|
||||
// return false;
|
||||
// }
|
||||
// print(` ✅ lints`);
|
||||
|
||||
const checks = await checkFile({
|
||||
lspc: lsp_clients.rust,
|
||||
file: file_rust,
|
||||
lang: getLanguage("rust"),
|
||||
uri,
|
||||
});
|
||||
if (!checks) return false;
|
||||
|
||||
await lsp_clients.rust._notify("textDocument/didClose", {
|
||||
textDocument: {
|
||||
uri,
|
||||
},
|
||||
});
|
||||
await rust({ file: file_rust, lspc: lsp_clients.rust });
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
@ -512,43 +210,38 @@ async function ci({ filenames, current_dir }) {
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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(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 getXMLObjectIds(tree, object_ids) {
|
||||
for (const object of tree.getChildren("object")) {
|
||||
if (object.attrs.id) object_ids.push(object.attrs.id);
|
||||
// <child> or <property name="child">
|
||||
for (const child of object.getChildElements()) {
|
||||
getXMLObjectIds(child, object_ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCodeObjectIds(text) {
|
||||
const object_ids = [];
|
||||
for (const match of text.matchAll(/get_object\("(.+)"\)/g)) {
|
||||
object_ids.push(match[1]);
|
||||
}
|
||||
return object_ids;
|
||||
}
|
||||
const demo = JSON.parse(str);
|
||||
demo.name = file.get_basename();
|
||||
|
||||
function serializeDiagnostics({ diagnostics }) {
|
||||
return (
|
||||
diagnostics
|
||||
.map(({ severity, range, message }) => {
|
||||
return (
|
||||
" ❌ " +
|
||||
diagnostic_severities[severity] +
|
||||
" " +
|
||||
range.start.line +
|
||||
":" +
|
||||
range.start.character +
|
||||
" " +
|
||||
message.split("\n")[0]
|
||||
);
|
||||
})
|
||||
.join("\n") + "\n"
|
||||
);
|
||||
const 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 [+runtime_version >= +demo_runtime_version, demo_runtime_version];
|
||||
}
|
||||
|
@ -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('app_id', app_id)
|
||||
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('pkgdatadir', pkgdatadir)
|
||||
bin_conf.set('sourcedir', meson.project_source_root())
|
||||
|
30
src/cli/python.js
Normal 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
@ -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
@ -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
@ -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
@ -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(),
|
||||
},
|
||||
});
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import GLib from "gi://GLib";
|
||||
|
||||
import LSPClient from "./lsp/LSPClient.js";
|
||||
|
||||
const formatting_options = {
|
||||
@ -19,6 +17,10 @@ export const languages = [
|
||||
types: [],
|
||||
document: null,
|
||||
default_file: "main.blp",
|
||||
// language_server: [
|
||||
// "/home/sonny/Projects/GNOME/blueprint-compiler/blueprint-compiler.py",
|
||||
// "lsp",
|
||||
// ],
|
||||
language_server: ["blueprint-compiler", "lsp"],
|
||||
formatting_options: {
|
||||
...formatting_options,
|
||||
@ -43,13 +45,12 @@ export const languages = [
|
||||
document: null,
|
||||
default_file: "main.js",
|
||||
index: 0,
|
||||
// language_server: ["typescript-language-server", "--stdio"],
|
||||
language_server: [
|
||||
"biome",
|
||||
"lsp-proxy",
|
||||
// src/meson.build installs biome.json there
|
||||
GLib.getenv("FLATPAK_ID")
|
||||
? `--config-path=${pkg.pkgdatadir}`
|
||||
: `--config-path=src/langs/javascript`,
|
||||
`--config-path=${pkg.pkgdatadir}`,
|
||||
],
|
||||
formatting_options: {
|
||||
...formatting_options,
|
||||
@ -115,6 +116,21 @@ export const languages = [
|
||||
tabSize: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "typescript",
|
||||
name: "TypeScript",
|
||||
panel: "code",
|
||||
extensions: [".ts", ".mts"],
|
||||
types: [],
|
||||
document: null,
|
||||
default_file: "main.ts",
|
||||
index: 4,
|
||||
language_server: ["typescript-language-server", "--stdio"],
|
||||
formatting_options: {
|
||||
...formatting_options,
|
||||
tabSize: 2,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export function getLanguage(id) {
|
||||
@ -131,19 +147,30 @@ export function createLSPClient({ lang, root_uri, quiet = true }) {
|
||||
languageId: language_id,
|
||||
quiet,
|
||||
});
|
||||
|
||||
if (quiet === false) {
|
||||
lspc.connect("exit", () => {
|
||||
console.debug(`${language_id} language server exit`);
|
||||
console.log(`${language_id} language server exit`);
|
||||
});
|
||||
lspc.connect("output", (_self, message) => {
|
||||
console.debug(
|
||||
`${language_id} language server OUT:\n${JSON.stringify(message)}`,
|
||||
console.log(
|
||||
`${language_id} language server OUT:\n${JSON.stringify(
|
||||
message,
|
||||
null,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
lspc.connect("input", (_self, message) => {
|
||||
console.debug(
|
||||
`${language_id} language server IN:\n${JSON.stringify(message)}`,
|
||||
console.log(
|
||||
`${language_id} language server IN:\n${JSON.stringify(
|
||||
message,
|
||||
null,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return lspc;
|
||||
}
|
||||
|
36
src/flatpak.js
Normal file
@ -0,0 +1,36 @@
|
||||
import GLib from "gi://GLib";
|
||||
|
||||
let flatpak_info;
|
||||
export function getFlatpakInfo() {
|
||||
if (flatpak_info) return flatpak_info;
|
||||
flatpak_info = new GLib.KeyFile();
|
||||
try {
|
||||
flatpak_info.load_from_file("/.flatpak-info", GLib.KeyFileFlags.NONE);
|
||||
} catch (err) {
|
||||
if (!err.matches(GLib.FileError, GLib.FileError.NOENT)) {
|
||||
console.error(err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return flatpak_info;
|
||||
}
|
||||
|
||||
export function getFlatpakId() {
|
||||
return getFlatpakInfo().get_string("Application", "name");
|
||||
}
|
||||
|
||||
// https://repology.org/project/flatpak/versions
|
||||
export function isDeviceInputOverrideAvailable(flatpak_version) {
|
||||
flatpak_version ??= getFlatpakInfo().get_string(
|
||||
"Instance",
|
||||
"flatpak-version",
|
||||
);
|
||||
|
||||
// https://github.com/flatpak/flatpak/releases/tag/1.15.6
|
||||
return (
|
||||
flatpak_version.localeCompare("1.15.6", undefined, {
|
||||
numeric: true,
|
||||
sensitivity: "base",
|
||||
}) > -1
|
||||
);
|
||||
}
|
2
src/icons/re.sonny.Workbench-down-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 2.292969 6.707031 l 5 5 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 5 -5 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 s -1.023437 -0.390625 -1.414062 0 l -4.292969 4.292969 l -4.292969 -4.292969 c -0.390625 -0.390625 -1.023437 -0.390625 -1.414062 0 s -0.390625 1.023437 0 1.414062 z m 0 0" fill="#222222" fill-rule="evenodd"/></svg>
|
After Width: | Height: | Size: 484 B |
2
src/icons/re.sonny.Workbench-eraser4-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 13.949219 8.359375 s 0 0.019531 0.003906 0.011719 l -5.003906 4.914062 l 0.699219 -0.285156 h -4.621094 l 0.707031 0.292969 l -3.683594 -3.683594 v -0.019531 l 6.554688 -6.554688 h 0.019531 l -0.292969 -0.707031 c 0 0.265625 0.105469 0.519531 0.292969 0.707031 z m -3.617188 -6.03125 c 0 -0.265625 -0.105469 -0.519531 -0.292969 -0.707031 c -0.789062 -0.789063 -2.058593 -0.789063 -2.847656 0 l -6.554687 6.554687 c -0.789063 0.789063 -0.789063 2.058594 0 2.847657 l 3.683593 3.683593 c 0.1875 0.1875 0.441407 0.292969 0.707032 0.292969 h 4.621094 c 0.261718 0 0.511718 -0.101562 0.699218 -0.285156 l 5.015625 -4.921875 c 0.789063 -0.789063 0.789063 -2.058594 0 -2.847657 l -5.324219 -5.324218 z m 0 0"/><path d="m 4.277344 7.007812 l 6.015625 5.992188 c 0.195312 0.195312 0.511719 0.195312 0.707031 0 s 0.195312 -0.511719 0 -0.707031 l -6.015625 -5.996094 c -0.195313 -0.195313 -0.511719 -0.195313 -0.707031 0.003906 c -0.195313 0.195313 -0.195313 0.511719 0 0.707031 z m 0 0"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
2
src/icons/re.sonny.Workbench-external-link-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 3 2 c -1.660156 0 -3 1.339844 -3 3 v 8 c 0 1.660156 1.339844 3 3 3 h 8 c 1.660156 0 3 -1.339844 3 -3 v -4 c 0 -0.550781 -0.449219 -1 -1 -1 s -1 0.449219 -1 1 v 4 c 0 0.554688 -0.445312 1 -1 1 h -8 c -0.554688 0 -1 -0.445312 -1 -1 v -8 c 0 -0.554688 0.445312 -1 1 -1 h 4 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 7 -2 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 2.585938 l -5.292969 5.289062 c -0.390625 0.394532 -0.390625 1.027344 0 1.417969 s 1.023437 0.390625 1.414062 0 l 5.292969 -5.292969 v 2.585938 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -5 c 0 -0.085938 -0.011719 -0.171875 -0.035156 -0.257812 c -0.023438 -0.085938 -0.054688 -0.167969 -0.101563 -0.242188 c -0.042969 -0.074219 -0.09375 -0.144531 -0.15625 -0.207031 c -0.015625 -0.011719 -0.03125 -0.023438 -0.046875 -0.035157 c -0.054687 -0.050781 -0.117187 -0.09375 -0.183594 -0.128906 c -0.035156 -0.019531 -0.074218 -0.035156 -0.113281 -0.0468748 c -0.050781 -0.0234374 -0.101562 -0.0390624 -0.15625 -0.0507812 c -0.039062 -0.0117188 -0.082031 -0.015625 -0.121093 -0.0195312 c -0.03125 -0.00781255 -0.058594 -0.00781255 -0.085938 -0.0117188 z m 0 0" fill="#222222"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
2
src/icons/re.sonny.Workbench-gamepad-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 4 2 c -1.597656 0 -2.644531 0.664062 -3 2 l -0.738281 8.324219 c -0.261719 1.59375 1.738281 2.175781 2.738281 1.175781 l 2.75 -4.5 h 4.5 l 2.75 4.5 c 1 1 3 0.527344 2.738281 -1.175781 l -0.738281 -8.324219 c -0.214844 -1.203125 -1.402344 -2.03125 -2.972656 -2.027344 z m 0.25 2 h 0.5 c 0.136719 0 0.25 0.113281 0.25 0.25 v 0.75 h 0.75 c 0.136719 0 0.25 0.113281 0.25 0.25 v 0.5 c 0 0.136719 -0.113281 0.25 -0.25 0.25 h -0.75 v 0.75 c 0 0.136719 -0.113281 0.25 -0.25 0.25 h -0.5 c -0.136719 0 -0.25 -0.113281 -0.25 -0.25 v -0.75 h -0.75 c -0.136719 0 -0.25 -0.113281 -0.25 -0.25 v -0.5 c 0 -0.136719 0.113281 -0.25 0.25 -0.25 h 0.75 v -0.75 c 0 -0.136719 0.113281 -0.25 0.25 -0.25 z m 5.765625 -0.113281 c 0.59375 0 1.078125 0.484375 1.078125 1.082031 s -0.484375 1.082031 -1.078125 1.082031 c -0.597656 0 -1.082031 -0.484375 -1.082031 -1.082031 s 0.484375 -1.082031 1.082031 -1.082031 z m 2.96875 2.019531 c 0.597656 0 1.082031 0.484375 1.082031 1.078125 c 0 0.597656 -0.484375 1.082031 -1.082031 1.082031 c -0.59375 0 -1.078125 -0.484375 -1.078125 -1.082031 c 0 -0.59375 0.484375 -1.078125 1.078125 -1.078125 z m 0 0" fill="#222222"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
2
src/icons/re.sonny.Workbench-larger-brush-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 7.996094 0 c -1.109375 0 -2 0.890625 -2 2 v 3.003906 c 0 0.632813 -0.480469 0.996094 -1 0.996094 h -1 c -1.109375 0 -2 0.890625 -2 2 v 1 h 12 v -1 c 0 -1.109375 -0.894532 -2 -2 -2 h -0.976563 c -0.53125 0 -1.023437 -0.359375 -1.023437 -1 v -3 c 0 -1.109375 -0.894532 -2 -2 -2 z m 0 1.40625 c 0.324218 0 0.59375 0.265625 0.59375 0.59375 s -0.269532 0.59375 -0.59375 0.59375 c -0.328125 0 -0.59375 -0.265625 -0.59375 -0.59375 s 0.265625 -0.59375 0.59375 -0.59375 z m 0 0"/><path d="m 2 10 h 12 l -0.800781 5.003906 c -0.199219 0.820313 -0.699219 0.996094 -1.246094 0.996094 h -1.953125 v -3 l -1.125 3 h -1.847656 l -0.027344 -3 l -1.035156 3 h -0.964844 v -1.5 l -1 1.5 h -3 l 0.210938 -1.046875 z m 0 0"/></g></svg>
|
After Width: | Height: | Size: 871 B |
2
src/icons/re.sonny.Workbench-library-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 1.5 2 h 2 c 0.277344 0 0.5 0.222656 0.5 0.5 v 12 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -2 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -12 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 5.5 4 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 10 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -10 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 8.5 3 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 11 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -11 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 10.707031 1.460938 l 0.964844 -0.261719 c 0.265625 -0.070313 0.539063 0.089843 0.613281 0.355469 l 3.363282 12.558593 c 0.070312 0.265625 -0.085938 0.539063 -0.351563 0.609375 l -0.96875 0.261719 c -0.265625 0.070313 -0.539063 -0.089844 -0.613281 -0.355469 l -3.363282 -12.554687 c -0.070312 -0.269531 0.085938 -0.542969 0.355469 -0.613281 z m 0 0"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><g fill="#222222"><path d="m 2.035156 7.007812 c -0.53125 0 -1.03125 0.421876 -1.03125 1 v 7.011719 h 8.011719 v -3.984375 h -2 v 1.984375 h -4.011719 v -2.996093 h 2.015625 v -3.015626 z m 0 0"/><path d="m 8.019531 1.007812 c -0.53125 0 -1.03125 0.421876 -1.03125 1 v 7.011719 h 8.011719 v -7.042969 c 0 -0.578124 -0.519531 -0.96875 -1.019531 -0.96875 z m 0.96875 3.015626 h 4.011719 v 2.996093 h -4.011719 z m 0 0"/></g></svg>
|
After Width: | Height: | Size: 555 B |
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m 8 1.992188 c -2.617188 0 -5.238281 0.933593 -7.195312 2.808593 l -0.496094 0.480469 c -0.3984378 0.378906 -0.410156 1.011719 -0.03125 1.410156 c 0.382812 0.398438 1.015625 0.410156 1.414062 0.03125 l 0.5 -0.476562 c 3.085938 -2.957032 8.53125 -2.957032 11.617188 0 l 0.5 0.476562 c 0.398437 0.378906 1.03125 0.367188 1.414062 -0.03125 c 0.378906 -0.398437 0.367188 -1.03125 -0.03125 -1.410156 l -0.496094 -0.484375 c -1.957031 -1.871094 -4.578124 -2.804687 -7.195312 -2.804687 z m -0.03125 4.007812 c -1.570312 0.011719 -3.128906 0.628906 -4.207031 1.8125 l -0.5 0.550781 c -0.179688 0.195313 -0.277344 0.453125 -0.261719 0.71875 c 0.011719 0.265625 0.128906 0.515625 0.328125 0.695313 c 0.195313 0.179687 0.453125 0.273437 0.71875 0.257812 c 0.265625 -0.011718 0.515625 -0.128906 0.695313 -0.328125 l 0.496093 -0.546875 c 1.277344 -1.402344 4.160157 -1.496094 5.523438 0.003906 l 0.5 0.542969 c 0.175781 0.199219 0.425781 0.316407 0.691406 0.328125 c 0.265625 0.015625 0.523437 -0.078125 0.722656 -0.257812 c 0.195313 -0.179688 0.3125 -0.429688 0.324219 -0.695313 c 0.011719 -0.261719 -0.082031 -0.523437 -0.261719 -0.71875 l -0.5 -0.546875 c -1.121093 -1.234375 -2.703125 -1.828125 -4.269531 -1.816406 z m 0.03125 4 c -0.511719 0 -1.023438 0.195312 -1.414062 0.585938 c -0.78125 0.78125 -0.78125 2.046874 0 2.828124 s 2.046874 0.78125 2.828124 0 s 0.78125 -2.046874 0 -2.828124 c -0.390624 -0.390626 -0.902343 -0.585938 -1.414062 -0.585938 z m 0 0" fill="#2e3436"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
2
src/icons/re.sonny.Workbench-person-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 8 1 c -1.65625 0 -3 1.34375 -3 3 s 1.34375 3 3 3 s 3 -1.34375 3 -3 s -1.34375 -3 -3 -3 z m -1.5 7 c -2.492188 0 -4.5 2.007812 -4.5 4.5 v 1.5 c 0 1 1 1 1 1 h 10 s 1 0 1 -1 v -1.5 c 0 -2.492188 -2.007812 -4.5 -4.5 -4.5 z m 0 0" fill="#222222"/></svg>
|
After Width: | Height: | Size: 386 B |
2
src/icons/re.sonny.Workbench-speakers-symbolic.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 12.039062 0.00390625 c -0.257812 -0.01171875 -0.523437 0.07421875 -0.726562 0.28124975 l -3.3125 3.292969 v 1.421875 h 1.390625 l 3.304687 -3.296875 c 0.40625 -0.40625 0.363282 -1.042969 0.03125 -1.394531 c -0.175781 -0.183594 -0.429687 -0.292969 -0.6875 -0.30468775 z m -5.039062 1.00390575 c -0.296875 -0.003906 -0.578125 0.125 -0.765625 0.351563 l -3.234375 3.640625 h -1 c -1.09375 0 -2 0.84375 -2 2 v 2 c 0 1.089844 0.910156 2 2 2 h 1 l 3.234375 3.640625 c 0.207031 0.253906 0.488281 0.363281 0.765625 0.359375 z m 1 5.992188 v 2 h 6 c 0.75 0 1 -0.5 1 -1 s -0.25 -1 -1 -1 z m 0 4 v 1.421875 l 3.324219 3.292969 c 0.402343 0.410156 1.0625 0.347656 1.414062 -0.023438 c 0.332031 -0.351562 0.371094 -0.988281 -0.03125 -1.390625 l -3.316406 -3.300781 z m 0 0" fill="#222222"/></svg>
|
After Width: | Height: | Size: 921 B |