Initial public release of Warp.

Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
David Stern
2026-04-28 08:43:33 -05:00
commit 0dbd3d567a
4982 changed files with 1431549 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
# Product Spec: Support ~ expansion in /open-file slash command
**Issue:** [warpdotdev/warp-external#408](https://github.com/warpdotdev/warp-external/issues/408)
**Figma:** none provided
## Summary
The `/open-file` slash command should expand `~` to the user's home directory, matching the behavior of the Cmd-O open file dialog. Currently, typing `/open-file ~/foo.txt` incorrectly prepends the working directory, producing a path like `/current/dir/~/foo.txt` instead of `/home/user/foo.txt`.
## Problem
When a user types `/open-file ~/some/file.txt` and presses Enter, the `~` is treated as a literal directory name. The slash command handler joins the raw argument with the current working directory, resulting in a broken path like `/Users/me/project/~/some/file.txt`. This always fails with "File not found" because no literal `~` directory exists.
The Cmd-O (open file palette) already handles `~` correctly by calling `shellexpand::tilde()` before resolving the path. Users who discover `~` works in Cmd-O reasonably expect it to work in `/open-file` as well.
## Goals
- `~` at the start of a path in `/open-file` expands to the user's home directory.
- Behavior is consistent with the Cmd-O open file palette.
- Existing relative and absolute path handling is unaffected.
## Non-goals
- Supporting `$HOME` or other environment variable expansion in `/open-file` (follow-up if needed).
- Supporting `~otheruser` syntax (non-standard and not supported in Cmd-O either).
- Changing how autosuggestions/completions populate paths (that is a separate concern).
## User experience
### Current behavior (broken)
1. User types `/open-file ~/Documents/notes.txt` and presses Enter.
2. The handler joins `~` literally with the working directory, producing e.g. `/Users/me/project/~/Documents/notes.txt`.
3. A "File not found" error toast appears.
### Expected behavior (after fix)
1. User types `/open-file ~/Documents/notes.txt` and presses Enter.
2. `~` is expanded to the user's home directory (e.g. `/Users/me`).
3. The resulting absolute path `/Users/me/Documents/notes.txt` is used directly (not joined with the working directory).
4. If the file exists, it opens in Warp's code editor.
5. If the file does not exist, the "File not found" toast shows the expanded path (e.g. `File not found: /Users/me/Documents/notes.txt`), not the literal `~` form.
### Edge cases
- **`~` alone:** `/open-file ~` should show the "only works for files, not directories" error (since `~` expands to the home directory, which is a directory).
- **`~/` prefix:** `/open-file ~/foo.txt` expands correctly.
- **No tilde:** `/open-file foo.txt` continues to resolve relative to the current working directory (unchanged).
- **Absolute paths:** `/open-file /etc/hosts` continues to work (unchanged — `PathBuf::join` with an absolute path already replaces the base).
- **Escaped tilde from autosuggestion:** If the path comes from shell autosuggestion with escape characters (e.g. `\~`), the unescape step happens first, then tilde expansion applies to the unescaped result.
- **Line/column suffix:** `/open-file ~/foo.txt:10:5` should expand `~` and preserve the line/column argument.
## Success criteria
1. `/open-file ~/path/to/file.txt` opens the file at `$HOME/path/to/file.txt`.
2. `/open-file ~/path/to/file.txt:10` opens the file at line 10.
3. `/open-file relative/path.txt` still resolves relative to the working directory.
4. `/open-file /absolute/path.txt` still works as an absolute path.
5. The "File not found" error toast displays the expanded path, not the literal `~`.
6. `/open-file ~` shows the "only works for files, not directories" error.
7. Behavior matches the Cmd-O file palette for `~` paths.
## Validation
- **Unit test:** Add a test that verifies `/open-file ~/somefile` expands `~` to the home directory and resolves to the correct absolute path.
- **Manual test:** Type `/open-file ~/.bashrc` (or any file known to exist in the home directory) and confirm it opens correctly.
- **Regression test:** Confirm `/open-file relative.txt` and `/open-file /absolute/path.txt` continue to work.
## Open questions
None.
+73
View File
@@ -0,0 +1,73 @@
# Tech Spec: Support ~ expansion in /open-file slash command
**Issue:** [warpdotdev/warp-external#408](https://github.com/warpdotdev/warp-external/issues/408)
## Problem
The `/open-file` slash command handler does not expand `~` before resolving the file path. The argument is unescaped and then joined directly with the current working directory, so `~/foo.txt` becomes `/cwd/~/foo.txt`. The Cmd-O open file palette already handles this correctly by calling `shellexpand::tilde()`.
## Relevant code
- `app/src/terminal/input/slash_commands/mod.rs (445-450)` — The `/open-file` (`commands::EDIT`) handler that parses the path argument and resolves it. This is the code that needs to change.
- `app/src/search/command_palette/files/data_source.rs:196` — The Cmd-O palette's tilde expansion: `shellexpand::tilde(&query_file_content).into_owned()`. This is the pattern to follow.
- `crates/warp_util/src/path.rs (149-181)` — `CleanPathResult::with_line_and_column_number()`, which strips line/column suffixes from the path string. Called before path resolution.
- `app/src/terminal/input_test.rs (2553-2596)` — Existing test `test_open_slash_command_clears_buffer_on_success` that exercises the `/open-file` handler with a real file.
## Current state
The handler in `slash_commands/mod.rs` does this sequence:
1. Parses line/column suffix with `CleanPathResult::with_line_and_column_number(args.trim())`
2. Unescapes shell characters with `session.shell_family().unescape(&parsed_path.path)`
3. Joins with cwd: `current_dir.join(&*unescaped_path)`
Step 3 always prepends the working directory. When the path starts with `~`, this produces an invalid path. There is no tilde expansion step.
## Proposed changes
### Single change in `app/src/terminal/input/slash_commands/mod.rs`
After the unescape step (line 449) and before the `current_dir.join()` call (line 450), add a tilde expansion step using `shellexpand::tilde()`:
```rust
let parsed_path = CleanPathResult::with_line_and_column_number(args.trim());
let unescaped_path = session.shell_family().unescape(&parsed_path.path);
let expanded_path = shellexpand::tilde(&unescaped_path);
let file_path = current_dir.join(&*expanded_path);
```
This works correctly for all cases because of how `PathBuf::join` behaves:
- **Tilde path** (`~/foo.txt`): `shellexpand::tilde` converts to `/home/user/foo.txt` (absolute), and `join` with an absolute path replaces the base entirely.
- **Relative path** (`foo.txt`): `shellexpand::tilde` is a no-op, and `join` prepends `current_dir` as before.
- **Absolute path** (`/etc/hosts`): `shellexpand::tilde` is a no-op, and `join` replaces the base (existing behavior).
No other files need to change.
## End-to-end flow
1. User types `/open-file ~/Documents/notes.txt` and presses Enter.
2. `execute_slash_command` is called with argument `~/Documents/notes.txt`.
3. `CleanPathResult::with_line_and_column_number` strips any `:line:col` suffix → path = `~/Documents/notes.txt`.
4. `shell_family().unescape()` removes shell escape characters → path = `~/Documents/notes.txt` (no change unless escaped).
5. **New:** `shellexpand::tilde()` expands `~` → path = `/home/user/Documents/notes.txt`.
6. `current_dir.join()` sees an absolute path and uses it directly.
7. `std::fs::metadata` confirms the file exists and it opens in the editor.
## Risks and mitigations
**Risk:** `shellexpand::tilde` could fail if `$HOME` is not set.
**Mitigation:** `shellexpand::tilde` returns the input unchanged when the home directory cannot be determined, so it degrades gracefully to the current (broken) behavior. This matches how other call sites in the codebase use it.
**Risk:** Interaction with shell-escaped `~` from autosuggestions.
**Mitigation:** The unescape step runs before tilde expansion. If autosuggestion produces `\~`, it unescapes to `~`, then tilde expansion works correctly. If somehow `~` was already escaped to mean a literal `~` directory name, that's an extreme edge case not worth special-casing.
## Testing and validation
1. **New unit test:** Add a `#[cfg(feature = "local_fs")]` test similar to `test_open_slash_command_clears_buffer_on_success` that creates a temp file at a known location, simulates `/open-file ~/relative-to-home` using the temp file's home-relative path, and verifies the buffer clears (indicating success).
2. **Manual test:** Run Warp, type `/open-file ~/.bashrc`, confirm it opens.
3. **Regression:** Existing tests (`test_open_slash_command_clears_buffer_on_success`, `test_open_slash_command_requires_path`, etc.) continue to pass.
## Follow-ups
- Consider supporting `$HOME` and other environment variable expansion (via `shellexpand::full` or `shellexpand::env`) if users request it.
- Investigate whether the completions/autosuggestions engine should also offer `~`-prefixed path completions.