Skip to content

Commit a9b7599

Browse files
authored
Merge pull request #1 from imoize/refactor/use-ui-file
Use ui template and blueprint
2 parents 996d967 + 171feca commit a9b7599

27 files changed

+761
-614
lines changed

.github/copilot-instructions.md

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Instruction for GNOME Shell and Nautilus Extensions Development
2+
3+
# Personality
4+
You are an expert GNOME Shell extension developer with deep knowledge of, JavaScript & TypeScript, GTK and libadwaita, Adwaita (Adw), python, also GNOME Shell architecture and GObject introspection and GNOME Nautilus. You provide focused, practical code completions that follow modern GNOME 47 and later extension development practices.
5+
When it's related to gnome "shell extension" and JavaScript or TypeScript or related, you must use GNOME Shell Extension Part Instruction.
6+
When it's related to gnome "nautilus extension" and Python or related, you must use GNOME Nautilus Extension Part Instruction.
7+
8+
# Technology Used
9+
- JavaScript
10+
- TypeScript
11+
- GJS (GNOME JavaScript)
12+
- GTK
13+
- Adwaita (Adw)
14+
- libadwaita
15+
- python
16+
- blueprint-compiler
17+
18+
# GNOME Shell Extension Part
19+
20+
## Import Best Practices
21+
- Always use ES module imports with the new resource URI format (e.g., 'gi://GObject', 'resource:///org/gnome/shell/ui/main.js')
22+
- Always place imports at the top level of the file, never inside functions or blocks
23+
- Group imports by source (GNOME Shell core, GTK/GLib libraries, extension modules)
24+
- For GTK 4, use 'gi://Gtk?version=4.0' format
25+
- For Adw, use 'gi://Adw?version=1' format
26+
- Never use the older imports.gi or imports.misc style imports
27+
- Avoid legacy styles:
28+
- Do **not** use `imports.gi.*` or `imports.misc.*`
29+
- Always place imports at the top level of the file, never inside functions or conditionals
30+
31+
## Extension Structure Best Practices
32+
- All extensions must use class-based structure extending the Extension class
33+
- All preference pages must use class-based structure extending ExtensionPreferences
34+
- Use export default for the main extension and preferences classes
35+
- Use this.getSettings() inside ExtensionPreferences instead of ExtensionUtils.getSettings()
36+
- Use this.metadata and this.path instead of Me.metadata and Me.path
37+
38+
## Code Style Guidelines
39+
- Use ES modules syntax (import/export) at the top level only
40+
- Follow GNOME Shell 48 coding conventions and idioms
41+
- Prefer async/await over callbacks where appropriate
42+
- Use proper GObject class registration patterns
43+
- Follow signals connection/disconnection best practices
44+
- Handle proper cleanup in disable() methods
45+
46+
## Completion Behavior
47+
- Always suggest imports at the file's top level only
48+
- Flag improper import placement within functions or conditional blocks
49+
- Prioritize completing whole logical blocks over single lines
50+
- Suggest standardized import patterns for commonly used GNOME Shell modules
51+
- Complete function signatures with proper parameter types and defaults
52+
- Add descriptive JSDoc comments for public API methods
53+
- Include type annotations for TypeScript-enabled environments
54+
55+
## Context Awareness
56+
- Check for GObject inheritance patterns and suggest appropriate parent class methods
57+
- Recognize GNOME Shell UI component patterns and suggest related components
58+
- Detect signal connection patterns and suggest proper disconnection in cleanup
59+
- Identify resource allocation and suggest proper cleanup patterns
60+
- Recognize API version differences between GNOME 45, 46, 47, and 48
61+
62+
## Autocompletion Triggers
63+
- When typing 'import' suggest common GNOME Shell module imports with proper resource URI format
64+
- When typing 'class' suggest appropriate class extension patterns
65+
- When typing extension lifecycle methods (enable/disable) suggest standard patterns
66+
- When connecting signals, suggest corresponding disconnection code
67+
- When creating UI elements, suggest standard style classes and properties
68+
69+
## Function Documentation
70+
- Always provide documentation for public API methods
71+
- Include parameter types and descriptions
72+
- Document signal emissions
73+
- Note any resource allocation that requires cleanup
74+
- Indicate API compatibility concerns
75+
76+
## Extension Structure
77+
- Suggest appropriate file organization for extensions
78+
- Propose modular breakdown of complex extensions
79+
- Recommend proper metadata.json structures
80+
- Suggest appropriate GSettings schema organization
81+
- Recommend proper prefs.js organization following the class-based pattern
82+
83+
## Error Handling
84+
- Suggest try/catch blocks for file operations and external API calls
85+
- Recommend proper error logging patterns using console.log
86+
- Suggest defensive coding patterns for GNOME Shell API calls
87+
- Recommend graceful fallbacks for version-specific features
88+
89+
## Performance Guidelines
90+
- Flag potential performance issues in UI update loops
91+
- Suggest debouncing for high-frequency events
92+
- Recommend proper use of GLib timers with cancellation
93+
- Identify potential memory leaks in signal connections
94+
- Suggest batching UI updates where appropriate
95+
96+
## Development Workflow
97+
- Suggest logging statements that aid debugging
98+
- Recommend Looking Glass usage for interactive debugging
99+
- Suggest extension testing patterns with nested sessions in Wayland
100+
- Recommend proper extension packaging techniques
101+
- Provide reload commands for extension testing
102+
103+
## Extension Compatibility
104+
- Flag API usage that might be version-specific
105+
- Suggest compatibility checks for different GNOME versions
106+
- Recommend graceful fallbacks for version-specific features
107+
- Suggest proper shell-version specifications in metadata.json
108+
109+
# GNOME Nautilus Extension Part
110+
111+
## Import Best Practices
112+
- Use standard Python imports and PEP8-style grouping
113+
- Always use `from gi.repository import` for GTK/Gio/Nautilus modules
114+
- Do not use `gi.require_version` unless absolutely necessary (e.g., ambiguous GTK versions)
115+
- Avoid `import *` and deprecated modules
116+
- Prefer `Optional`, `list[str]`, and `dict[str, Any]` type annotations over `List`, `Dict` from typing
117+
118+
## Structure Best Practices
119+
- All program models should be class-based
120+
- Use separate modules (e.g., `models.py`, `manager.py`) for maintainability
121+
- Use property decorators for calculated fields (e.g., `@property def is_installed`)
122+
- Avoid global state outside of single registry or configuration loaders
123+
- Structure code to align with GNOME directory layouts for schemas and resources
124+
125+
## Type Hints and Annotations
126+
- Strongly prefer full Python type annotations (PEP 484/526 style)
127+
- Annotate method return types and parameters, including constructors
128+
- Use `tuple[str, ...]` for fixed-structure command arguments
129+
- Avoid untyped `list`, `dict`, `any`, use `list[str]`, `dict[str, Any]`, etc.
130+
131+
## Code Style Guidelines
132+
- Follow PEP8 with 4-space indentation
133+
- Use snake_case for methods and variables, PascalCase for classes
134+
- Place all imports at top level
135+
- Use docstrings with triple quotes for all public classes and methods
136+
- Prefer f-strings over old-style `%` formatting
137+
138+
## Completion Behavior
139+
- Suggest complete method stubs with full type signatures and docstrings
140+
- Insert missing docstrings or type annotations for existing methods
141+
- Add property decorators where field access implies computation
142+
- Suggest helper functions or static methods for repeated logic
143+
144+
## Docstring Style
145+
- All public methods must have Google-style or reStructuredText docstrings
146+
- Document parameter types and meanings
147+
- Indicate return type and description
148+
- For exceptions, include `Raises:` section
149+
- Document GNOME-specific logic (e.g., `.desktop` lookup or Gio.Settings parsing)
150+
151+
## Extension Integration
152+
- Suggest proper GSettings schema lookup patterns with `Gio.SettingsSchemaSource`
153+
- When working with Nautilus.MenuItem, recommend id-prefix-safe naming
154+
- Always disconnect signals, spawn cleanup when relevant
155+
- Suggest `GLib.spawn_async` with `GLib.spawn_close_pid` for subprocess launching
156+
157+
## Error Handling
158+
- Wrap file or settings parsing in try/except
159+
- Raise descriptive RuntimeErrors for misconfigurations
160+
- Use specific exception classes like `JSONDecodeError`, `KeyError`, `FileNotFoundError`
161+
162+
## Performance Guidelines
163+
- Use `@lru_cache` for disk-bound or schema-heavy lookups
164+
- Avoid repeated IO access in loops
165+
- Reuse settings objects when possible
166+
167+
## Dev/Debug Recommendations
168+
- Suggest `print` or `logging` for debugging only if logging is structured
169+
- Avoid `print` in production extension logic
170+
- Recommend dconf/gsettings CLI for settings validation
171+
172+
## Autocompletion Triggers
173+
- When typing `class`, suggest base classes like `Nautilus.MenuProvider`, `object`
174+
- When typing `@property`, suggest common property patterns
175+
- When typing `def __init__`, suggest full signature with typing
176+
- When typing `import`, recommend `gi.repository` modules and `os`, `json`, `typing`, `GLib`
177+
178+
## Compatibility Awareness
179+
- Flag code that assumes GTK3/GTK4 availability without checks
180+
- Suggest graceful fallback when a command or desktop file is missing
181+
- Recommend version checks when relying on specific Nautilus behaviors
182+
183+
## Best Practices Summary
184+
- Modular, type-safe, documented Python code
185+
- Full integration with GNOME GSettings schema
186+
- Nautilus.MenuItem creation follows naming conventions and behavior expectations
187+
- Asynchronous or subprocess code uses `GLib.spawn_async` + `spawn_close_pid`
188+
- Extension-specific data stays under `.local/share/gnome-shell/extensions/<uuid>/`
189+
190+
## Example Definitions (for autocomplete suggestions)
191+
- `ProgramRegistry`: Suggest extending `dict[int, Program]` with helper methods
192+
- `Native` and `Flatpak`: Suggest property definitions and lazy loading patterns
193+
- `Program`: Suggest `supports_files`, `installed_packages` as computed properties
194+
- `ProgramConfigLoader`: Suggest GSettings access and `load_from_gsettings()` stubs

.github/workflows/release.yml

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,27 @@ jobs:
3030
- name: Build
3131
run: npm run build
3232

33-
- name: Compile schemas
34-
run: glib-compile-schemas schemas
35-
36-
- name: Copy Files to dist
37-
run: |
38-
cp metadata.json dist/
39-
cp -r nautilus-extension/* dist/
40-
cp -r schemas dist/
41-
42-
- name: Archive Package
43-
uses: somaz94/compress-decompress@v1
44-
with:
45-
command: compress
46-
source: ./dist
47-
format: zip
48-
includeRoot: false
49-
destfilename: '${{ env.EXTENSION_NAME }}'
50-
dest: ./artifacts
51-
5233
- name: Upload Artifact
5334
uses: actions/upload-artifact@v4
5435
with:
5536
path: dist
5637
name: ${{ env.EXTENSION_NAME }}
5738
compression-level: 9
5839

40+
- name: Update CHANGELOG
41+
id: changelog
42+
uses: requarks/changelog-action@v1
43+
with:
44+
token: ${{ secrets.GITHUB_TOKEN }}
45+
tag: ${{ github.ref_name }}
46+
writeToFile: true
47+
useGitmojis: false
48+
5949
- name: Release
6050
uses: softprops/action-gh-release@v2
6151
if: startsWith(github.ref, 'refs/tags/')
6252
with:
63-
files: ./artifacts/${{ env.EXTENSION_NAME }}.zip
53+
files: ${{ env.EXTENSION_NAME }}.zip
6454
token: ${{ secrets.GITHUB_TOKEN }}
6555
tag_name: ${{ github.ref_name }}
66-
body: Initial Release
56+
body: ${{ steps.changelog.outputs.changes }}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
__pycache__
22
node_modules
3+
dist
34
schemas/gschemas.compiled
4-
flickernaut.zip
5+
flickernaut*.zip

Makefile

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,62 @@
1-
NAME=flickernaut
2-
DOMAIN=imoize.github.io
1+
NAME = flickernaut
2+
UUID = $(NAME)@imoize.github.io
33

4-
.PHONY: all pack install clean
4+
BLP_FILES := $(shell find resources/ui -name '*.blp')
5+
UI_FILES := $(patsubst resources/ui/%.blp,src/ui/%.ui,$(BLP_FILES))
56

6-
all: dist/extension.js
7+
UI_SRC := $(shell find src/ui -name '*.ui')
8+
UI_DST := $(patsubst src/ui/%,dist/ui/%,$(UI_SRC))
9+
10+
.PHONY: all build build-ui pack install test test-shell remove clean
11+
12+
all: pack
713

814
node_modules: package.json
915
npm install
1016

11-
dist/extension.js dist/prefs.js: node_modules
17+
build: node_modules
1218
tsc
19+
@$(MAKE) build-ui
20+
21+
build-ui: $(UI_FILES)
1322

14-
schemas/gschemas.compiled: schemas/org.gnome.shell.extensions.$(NAME).gschema.xml
23+
$(UI_FILES): src/ui/%.ui: resources/ui/%.blp
24+
@mkdir -p $(dir $@)
25+
@echo "Compiling Blueprint: $< → $@"
26+
@blueprint-compiler compile $< --output $@
27+
28+
schemas/gschemas.compiled: schemas/org.gnome.shell.extensions.${NAME}.gschema.xml
1529
glib-compile-schemas schemas
1630

17-
dist: dist/extension.js dist/prefs.js schemas/gschemas.compiled
18-
@cp -r schemas dist/
31+
copy-ui: $(UI_DST)
32+
33+
$(UI_DST): dist/ui/%: src/ui/%
34+
@mkdir -p $(dir $@)
35+
@cp $< $@
36+
37+
pack: build schemas/gschemas.compiled copy-ui
1938
@cp metadata.json dist/
20-
@cp -r nautilus-extension/Flickernaut dist/
21-
@cp nautilus-extension/nautilus-flickernaut.py dist/
39+
@cp -r schemas dist/
40+
@cp -r nautilus-extension/* dist/
41+
@(cd dist && zip ../$(UUID).shell-extension.zip -9r .)
42+
43+
install: pack
44+
gnome-extensions install -f $(UUID).shell-extension.zip
2245

23-
$(NAME).zip: dist
24-
@(cd dist && zip ../$(NAME).zip -9r .)
46+
test: pack
47+
@rm -rf $(HOME)/.local/share/gnome-shell/extensions/$(UUID)
48+
@cp -r dist $(HOME)/.local/share/gnome-shell/extensions/$(UUID)
49+
gnome-extensions prefs $(UUID)
2550

26-
pack: $(NAME).zip
51+
test-shell:
52+
@env GNOME_SHELL_SLOWDOWN_FACTOR=2 \
53+
MUTTER_DEBUG_DUMMY_MODE_SPECS=1500x1000 \
54+
MUTTER_DEBUG_DUMMY_MONITOR_SCALES=1 \
55+
dbus-run-session -- gnome-shell --nested --wayland
2756

28-
install: $(NAME).zip
29-
@touch ~/.local/share/gnome-shell/extensions/$(NAME)@$(DOMAIN)
30-
@rm -rf ~/.local/share/gnome-shell/extensions/$(NAME)@$(DOMAIN)
31-
@mv dist ~/.local/share/gnome-shell/extensions/$(NAME)@$(DOMAIN)
57+
remove:
58+
@rm -rf $(HOME)/.local/share/gnome-shell/extensions/$(UUID)
3259

3360
clean:
34-
@rm -rf dist $(NAME).zip
35-
@rm -rf schemas/gschemas.compiled
36-
@rm -rf ~/.local/share/gnome-shell/extensions/$(NAME)@$(DOMAIN)
61+
@rm -rf dist $(UUID).shell-extension.zip
62+
@rm -rf schemas/gschemas.compiled

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GNOME Shell Extension - Flickernaut
22

3-
A GNOME extension that adds quick-launch to Nautilus context menu entries for your installed dev tools, IDEs, and custom apps.
3+
A GNOME extension that adds custom entry to Nautilus context menu for your installed dev tools, IDEs, and custom apps.
44

55
<p align="center">
66
<img src="assets/preview1.png" alt="Flickernaut Preview" width="50%" />

eslint.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export default antfu({
1414
css: true,
1515
},
1616
ignores: [
17-
'build/**/*',
17+
'dist/**/*',
1818
'node_modules/**',
1919
],
2020
plugins: {

metadata.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
22
"name": "Flickernaut",
3-
"description": "An extension that adds quick-launch to Nautilus context menu entries",
3+
"description": "A GNOME extension that adds custom entry to Nautilus context menu",
44
"uuid": "[email protected]",
55
"url": "https://github.com/imoize/flickernaut",
66
"settings-schema": "org.gnome.shell.extensions.flickernaut",
7-
"session-modes": ["user", "unlock-dialog"],
7+
"session-modes": ["user"],
88
"shell-version": [
99
"48"
10-
]
10+
],
11+
"version": 2
1112
}

0 commit comments

Comments
 (0)