Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions crates/fresh-editor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4600,6 +4600,9 @@ impl Config {
"launch.json".to_string(),
"extensions.json".to_string(),
"argv.json".to_string(),
// Bun's text lockfile is JSONC (trailing commas), not
// strict JSON (#2921).
"bun.lock".to_string(),
],
grammar: "jsonc".to_string(),
comment_prefix: Some("//".to_string()),
Expand Down Expand Up @@ -9432,6 +9435,25 @@ mod tests {
}
}

/// Well-known JSONC filenames must route to the `jsonc` language so
/// they get JSON highlighting instead of falling through to plain
/// text. Regression test for #2921: `bun.lock` is JSONC (trailing
/// commas) but no default language claimed it.
#[test]
fn test_default_languages_map_jsonc_filenames() {
use crate::services::lsp::manager::detect_language;
use std::path::Path;

let languages = Config::default_languages();
for filename in ["bun.lock", "tsconfig.json", "devcontainer.json"] {
assert_eq!(
detect_language(Path::new(filename), &languages),
Some("jsonc".to_string()),
"expected `{filename}` to be detected as jsonc"
);
}
}

#[test]
#[cfg(feature = "runtime")]
fn test_gdscript_lsp_disabled_by_default() {
Expand Down
21 changes: 19 additions & 2 deletions crates/fresh-editor/src/init_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,15 @@ const editor = getEditor();

/// `tsconfig.json` for the user's init.ts. Matches the plugin-dev
/// workspace (no DOM, no ambient types) so LSP behaviour is consistent
/// with plugins.
/// with plugins. `moduleResolution` must be `bundler` (matching
/// `plugins/tsconfig.json` and `check-types.sh`): TypeScript 7 removed
/// the old `node` (node10) resolution mode, so a tsserver reading this
/// file would fail with TS5108 (#2872).
const INIT_TSCONFIG: &str = r#"{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
Expand Down Expand Up @@ -682,6 +685,20 @@ mod tests {
assert_eq!(p, PathBuf::from("/tmp/fresh/init.ts"));
}

/// TypeScript 7 removed `moduleResolution: node` (node10); a tsserver
/// reading a generated tsconfig that still uses it fails with TS5108.
/// The generated config must use `bundler`, matching
/// `plugins/tsconfig.json` and `check-types.sh` (#2872).
#[test]
fn generated_tsconfig_does_not_use_removed_module_resolution() {
let parsed: serde_json::Value = serde_json::from_str(INIT_TSCONFIG)
.expect("generated tsconfig.json must be valid JSON");
assert_eq!(
parsed["compilerOptions"]["moduleResolution"], "bundler",
"moduleResolution must be `bundler`; `node` (node10) was removed in TypeScript 7"
);
}

#[test]
fn crash_fuse_trips_after_threshold_consecutive_failures() {
let tmp = TempDir::new().unwrap();
Expand Down
25 changes: 24 additions & 1 deletion crates/fresh-editor/src/services/plugins/plugin_dev_workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ pub struct PluginDevWorkspace {
/// - No DOM lib (plugins run in QuickJS, not a browser)
/// - `types: []` prevents picking up @types/node or other ambient types
/// - `skipLibCheck: true` avoids checking fresh.d.ts itself
/// - `moduleResolution: bundler` (matching `plugins/tsconfig.json` and
/// `check-types.sh`): TypeScript 7 removed the old `node` (node10)
/// resolution mode, so a tsserver reading this file would fail with
/// TS5108 (#2872)
const TSCONFIG_CONTENT: &str = r#"{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"moduleResolution": "bundler",
"strict": true,
"noEmit": true,
"skipLibCheck": true,
Expand Down Expand Up @@ -114,3 +118,22 @@ impl Drop for PluginDevWorkspace {
self.cleanup();
}
}

#[cfg(test)]
mod tests {
use super::*;

/// TypeScript 7 removed `moduleResolution: node` (node10); a tsserver
/// reading a generated tsconfig that still uses it fails with TS5108.
/// The generated config must use `bundler`, matching
/// `plugins/tsconfig.json` and `check-types.sh` (#2872).
#[test]
fn generated_tsconfig_does_not_use_removed_module_resolution() {
let parsed: serde_json::Value = serde_json::from_str(TSCONFIG_CONTENT)
.expect("generated tsconfig.json must be valid JSON");
assert_eq!(
parsed["compilerOptions"]["moduleResolution"], "bundler",
"moduleResolution must be `bundler`; `node` (node10) was removed in TypeScript 7"
);
}
}
2 changes: 1 addition & 1 deletion docs/blog/editing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Place your cursor on a word, press **Ctrl+W** to select it, then **Ctrl+D** to s

## Search & Replace

**Ctrl+H** opens find-and-replace with live highlighting as you type. Supports regex with capture groups (`$1`, `$2`), find-in-selection, and a confirm-each toggle.
**Ctrl+R** opens find-and-replace with live highlighting as you type. Supports regex with capture groups (`$1`, `$2`), find-in-selection, and a confirm-each toggle. (Ctrl+H is deliberately not used: terminals transmit it as Backspace, so Fresh binds it to delete-word-backward instead.)

<div class="showcase-demo">
<img src="./search-replace/showcase.gif" alt="Search and replace demo" />
Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/keyboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ The macOS keymap is designed around these constraints:

**Ctrl+Shift combinations don't work.** Some macOS terminals cannot reliably send Ctrl+Shift sequences. For example, Ctrl+Shift+Z produces a caron character (ˇ) instead of being recognized as a key chord. The macOS keymap uses Ctrl+Alt as an alternative modifier.

**Some Ctrl keys are ASCII control characters.** In terminal protocols, Ctrl+J is Line Feed (newline), Ctrl+M is Carriage Return (Enter), and Ctrl+I is Tab. Binding actions to these keys causes erratic behavior. The macOS keymap avoids these collisions.
**Some Ctrl keys are ASCII control characters.** In terminal protocols, Ctrl+J is Line Feed (newline), Ctrl+M is Carriage Return (Enter), Ctrl+I is Tab, and Ctrl+H is Backspace. Binding actions to these keys causes erratic behavior. The macOS keymap avoids these collisions. This is also why find-and-replace is on **Ctrl+R** rather than Ctrl+H: most terminals transmit Ctrl+H as Backspace, so Fresh treats it as Ctrl+Backspace (delete previous word) in every keymap.

**International keyboards use Alt for essential characters.** On German, French, and other ISO layouts, Alt (Option) combined with letters produces characters like @, [, ], {, and }. The macOS keymap avoids Alt+letter combinations that would block character input.

**Unix readline conventions are preserved.** Terminal users expect Ctrl+Y to "yank" (paste from the kill ring), Ctrl+K to kill to end of line, and Ctrl+U to kill to start of line. The macOS keymap respects these conventions rather than overriding them with GUI editor shortcuts.

Use the **Command Palette** (Ctrl+P) or **Show Keybindings** (Ctrl+H) to discover the actual key bindings, or view the keymap file directly at `keymaps/macos.json`.
Use the **Command Palette** (Ctrl+P) or run **Show Keyboard Shortcuts** from it to discover the actual key bindings, or view the keymap file directly at `keymaps/macos.json`.

#### Recommended Terminal Emulators

Expand Down
2 changes: 1 addition & 1 deletion docs/features/lsp.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Some LSP servers expect a different `languageId` than Fresh's internal language

### Rust LSP Mode Switching

Use "Switch Rust Analyzer Mode" from the command palette to toggle between Full and Reduced Memory modes for rust-analyzer.
Use "Rust LSP: Configure Mode" from the command palette to toggle between Full and Reduced Memory modes for rust-analyzer.

## Configuring Language Detection via Settings UI

Expand Down
Loading