Thanks for contributing!
| Crate | Purpose |
|---|---|
fresh-editor |
Editor library + fresh binary (terminal UI, LSP, plugins, …) |
fresh-gui |
Standalone windowed backend (winit + wgpu). Defines the GuiApplication trait; no dependency on fresh-editor. |
fresh-core |
Shared core types and plugin API |
fresh-languages |
Tree-sitter language grammars |
fresh-plugin-runtime |
QuickJS-based plugin runtime |
fresh-plugin-api-macros |
Proc-macros for the plugin API |
fresh-parser-js |
JavaScript/TypeScript parser |
The gui feature on fresh-editor pulls in fresh-gui as an optional dependency.
When it is disabled (the default), no windowing or GPU crates are compiled.
- Commit messages must describe the motivation / goal of each commit, not just what changed
- Separate bug fixes from new functionality into distinct commits
- Individual commits should pass
cargo check --all-targetsandcargo fmt - If your change touches GUI code, also verify:
cargo check --all-targets --features gui
-
Reproduce Before Fixing: When fixing bugs, add tests (e2e if it's a user-facing bug) — first reproduce the issue in a test that fails or times out, then add the fix that makes the test pass.
-
E2E Tests for New Flows: Any new user flow or feature must include an end-to-end (e2e) test. E2E tests send keyboard/mouse events and examine the final rendered output, do not examine internal state.
-
No timeouts or time-sensitive tests: Use "semantic waiting" (waiting for specific state changes/events) instead of fixed timers to ensure test stability. Wait indefinitely, don't put timeouts inside tests (cargo nextest will timeout externally).
-
Test isolation: Tests should run in parallel. Use the internal clipboard mode in tests to isolate them from the host system and prevent flakiness in CI. Same for other external resources (temp files, etc. should all be isolated between tests, under a per-test temporary workdir).
Tip: For manual reproduction/validation you can use tmux + send-keys + render-pane to script ad-hoc tests on the UI, for example when trying to reproduce an issue. This can help understand how to write an e2e test.
-
Cross-Platform Consistency: Avoid hard-coding newline or CRLF related logic, consider the buffer mode.
-
Avoid full-buffer scans: The editor is designed to handle huge files via lazy, viewport-localized operations. Prefer algorithms that operate on visible/relevant ranges rather than scanning the entire buffer.
-
LSP: Ensure LSP interactions follow the correct lifecycle (e.g.,
didOpenmust always precede other requests to avoid server-side errors). Use the appropriate existing helpers for this pattern. -
Use the
FileSystemtrait for all filesystem access: Never usestd::fsdirectly in editor code. TheFileSystemtrait (model/filesystem.rs) abstracts over local and remote (SSH) filesystems. Use it for reading files, listing directories, checking metadata, etc. This ensures features work transparently on remote hosts. -
Use
ProcessSpawnerfor spawning external commands: Never usestd::process::Commanddirectly. TheProcessSpawnertrait (services/remote/spawner.rs) routes process execution through eitherLocalProcessSpawnerorRemoteProcessSpawner, so plugins and core features (likegit ls-filesin the file finder) work on remote hosts. -
Regenerate plugin types and schemas: After modifying the plugin API or config types:
- TypeScript definitions (
plugins/lib/fresh.d.ts): Auto-generated from Rust types with#[derive(TS)]. Run:cargo test -p fresh-plugin-runtime write_fresh_dts_file -- --ignored - JSON schemas (
plugins/config-schema.json,plugins/schemas/theme.schema.json): Auto-generated from Rust types with#[derive(JsonSchema)]. Run:./scripts/gen_schema.sh - Package schema (
plugins/schemas/package.schema.json): Auto-generated from Rust types with#[derive(JsonSchema)]. Run:./scripts/gen_schema.sh
- TypeScript definitions (
-
Type check plugins: Run
crates/fresh-editor/plugins/check-types.sh(requirestsc)