Skip to content

Add auto save setting for the Warp text editor#13435

Merged
szgupta merged 10 commits into
masterfrom
suraj/editor-auto-save
Jul 17, 2026
Merged

Add auto save setting for the Warp text editor#13435
szgupta merged 10 commits into
masterfrom
suraj/editor-auto-save

Conversation

@szgupta

@szgupta szgupta commented Jul 7, 2026

Copy link
Copy Markdown
Member

Demo: https://www.loom.com/share/e61d6e666caa41deb9171c1cbbcc07c3

Description

Adds an opt-in Auto save setting for the Warp text editor. When enabled, the editor saves changes automatically so you don't have to press Cmd-S.

Behavior mirrors VS Code:

  • While typing — debounced ~1s after you stop typing (VS Code's files.autoSave: afterDelay). Saves without running the LSP formatter, so formatting never disrupts you mid-edit.
  • On focus loss — when the editor loses focus to another view in the app (onFocusChange) or its window is navigated away from / the app is deactivated (onWindowChange). These honor the existing Format on save setting, exactly like a manual Cmd-S.

Scope & guards:

  • Applies to normal file editing and the code review panel's editable diffs (both are LocalCodeEditorView with diff_type = None).
  • Never auto-saves the agent "edit-file" accept/reject diffs (a separate InlineDiffView type; plus a diff_type.is_some() guard).
  • Skips untitled files (no path), disconnected remotes, and buffers with no unsaved changes.
  • Defaults to off; cloud-synced like other editor settings.

Unobtrusive behavior when auto-save is on:

  • The "File saved." toast is suppressed for auto-saves (still shown for manual Cmd-S), via an auto_saved flag on LocalCodeEditorEvent::FileSaved.
  • The unsaved-changes dot is hidden at every surface (editor tab bar, single-tab pane header, workspace tab strip, and code review diff headers), so it no longer flickers as you type.
  • Closing never blocks on an "unsaved changes" dialog for files that can be auto-saved. Instead the pending edits are flushed silently and the close proceeds. This covers the file/editor tab, the code pane, the workspace tab(s), the window, app quit, and the code review pane. The close/quit dialog still appears for things auto-save can't handle — running processes, shared sessions, or unsaved buffers with no backing file (e.g. untitled files) — so those are never silently discarded.

The setting lives at Settings → Code → Code Editor and Review → Auto save (code.editor.auto_save).

How

  • New auto_save bool in CodeSettings (app/src/settings/code.rs), mirroring format_on_save.
  • Toggle widget + ToggleAutoSave action in app/src/settings_view/code_page.rs.
  • Auto-save logic in app/src/code/local_code_editor.rs: a debounced channel (afterDelay, no formatting), View::on_blur (focus loss), and a WindowManager subscription (window navigation). Both focus paths respect format-on-save.
  • Indicator/toast suppression in app/src/code/view.rs, app/src/tab.rs, and app/src/code_review/code_review_view.rs.
  • Close/quit handling centralized in UnsavedStateSummary::save_unsaved_code_and_should_warn (app/src/quit_warning/mod.rs), backed by CodeView::auto_save_all_unsaved_tabs and CodeReviewView::auto_save_all_unsaved_files. Wired into the window/app close (app/src/lib.rs), pane close (app/src/pane_group/mod.rs), tab close (app/src/workspace/view.rs), the editor tab close (app/src/code/view.rs), and the code review close (app/src/code_review/code_review_view.rs).

Linked Issue

None.

  • The linked issue is labeled ready-to-spec or ready-to-implement.
  • Where appropriate, screenshots or a short video of the implementation are included below (especially for user-visible or UI changes).

Testing

  • I have manually tested my changes locally with ./script/run

Validated with cargo fmt and cargo clippy -p warp --lib -- -D warnings (both pass) after merging latest master. No automated tests were added: auto-save is driven by debounce timers plus focus/window/close lifecycle events that are awkward to unit test, and the underlying save path (save_local / perform_save) is unchanged and already exercised. Manual verification is recommended before merge.

Screenshots / Videos

N/A — settings toggle plus editor behavior. Happy to add a screen recording.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-IMPROVEMENT: Added an opt-in "Auto save" setting for the Warp text editor (Settings > Code > Code Editor and Review) that saves changes as you type and when the editor loses focus, and flushes edits automatically when closing instead of prompting.


Warp conversation

Co-Authored-By: Oz oz-agent@warp.dev

szgupta and others added 2 commits July 7, 2026 11:36
Adds an opt-in "Auto save" setting (Settings > Code > Code Editor and Review) that automatically saves changes in the Warp text editor.

Triggers mirror VS Code:
- afterDelay: debounced ~1s while typing; saves without running the LSP formatter.
- onFocusChange / onWindowChange: when the editor loses focus or its window is navigated away from; honors the existing "Format on save" setting.

Applies to the Warp text editor, including diff/review views. Untitled files, disconnected remotes, and unchanged buffers are skipped. Defaults to off.

Co-Authored-By: Oz <oz-agent@warp.dev>
@cla-bot cla-bot Bot added the cla-signed label Jul 7, 2026
szgupta and others added 5 commits July 7, 2026 11:56
- Only exclude pending accept/reject diffs (diff_type Some) from auto-save; code-review panel edits and normal editing remain eligible. Agent "edit-file" diffs use a separate view type (InlineDiffView) and were never auto-saved.
- Suppress the "File saved." toast for auto-saves (shown only for manual cmd-s saves) via an auto_saved flag on LocalCodeEditorEvent::FileSaved.
- Hide the unsaved-changes dot in code tabs when auto-save is enabled so it no longer flickers on/off as the user types.

Co-Authored-By: Oz <oz-agent@warp.dev>
The pane-level (code pane header) indicator was already gated; this also gates the workspace tab-strip indicator, so no unsaved dot flickers at either level while auto-save persists edits.

Co-Authored-By: Oz <oz-agent@warp.dev>
When auto-save is enabled and a file with a backing path is closed before the debounce fires, flush the pending edits and close instead of blocking on the "unsaved changes" dialog. The flush is marked as an auto-save so it stays silent (no toast). Untitled files still prompt, since auto-save can't persist them without a Save As.

Co-Authored-By: Oz <oz-agent@warp.dev>
The code review diff headers render their own per-file unsaved indicator via render_unsaved_circle_with_tooltip; gate it on the auto_save setting like the editor tab and workspace tab indicators, so it no longer flickers while editing.

Co-Authored-By: Oz <oz-agent@warp.dev>
…ode review)

When auto-save is enabled, close/quit paths no longer prompt about unsaved FILE changes: they flush-save all saveable editors silently first. The warning still shows for things auto-save can't handle (running processes, shared sessions, or unsaved buffers with no backing file such as untitled files).

Centralized via UnsavedStateSummary::save_unsaved_code_and_should_warn, backed by CodeView::auto_save_all_unsaved_tabs and CodeReviewView::auto_save_all_unsaved_files (both mark saves as auto-saves so no toast fires).

Co-Authored-By: Oz <oz-agent@warp.dev>
@szgupta
szgupta marked this pull request as ready for review July 8, 2026 04:35
@szgupta
szgupta requested a review from kevinyang372 July 8, 2026 04:35
@oz-for-oss

oz-for-oss Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@szgupta

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@oz-for-oss oz-for-oss Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR adds an opt-in code.editor.auto_save setting, wires it into the code settings UI, implements debounce/focus/window-triggered saves, suppresses save indicators/toasts for auto-saves, and changes close/quit flows to flush code editors silently when auto-save is enabled.

Concerns

  • Disconnected remote file buffers are treated as auto-saveable during close/quit flushing because the new code only checks for a file_id; failed saves can allow the close to proceed without warning and discard unsaved remote edits.
  • The focus-loss auto-save marker can remain set when save_local returns an immediate error, causing the next successful manual save to be misclassified as an auto-save.
  • For this user-facing change, please include screenshots or a screen recording demonstrating the settings toggle and editor behavior working end to end.

Verdict

Found: 1 critical, 1 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/code/view.rs Outdated
let has_backing_file = self
.tab_at(index)
.is_some_and(|tab| tab.editor_view.as_ref(ctx).file_id().is_some());
if has_backing_file {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [CRITICAL] This only checks for a file_id, so disconnected remote buffers are treated as auto-saveable; save_local then fails immediately but unsaveable_changes_remain stays false, allowing close/quit to proceed without warning and discard unsaved remote edits. Check !editor.is_remote_disconnected(ctx) or return true when the save fails before suppressing the warning.

Comment thread app/src/code/local_code_editor.rs Outdated
Comment on lines +1241 to +1243
// Mark this as an auto-save so the "File saved." toast is suppressed.
self.auto_save_in_flight = true;
let _ = self.save_local(ctx);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] If save_local returns early for NoFileId or RemoteDisconnected, auto_save_in_flight remains set and the next manual save is emitted as auto_saved, suppressing the success toast. Clear the marker when the save does not start.

Suggested change
// Mark this as an auto-save so the "File saved." toast is suppressed.
self.auto_save_in_flight = true;
let _ = self.save_local(ctx);
// Mark this as an auto-save so the "File saved." toast is suppressed.
self.auto_save_in_flight = true;
if self.save_local(ctx).is_err() {
self.auto_save_in_flight = false;
}

- auto_save_all_unsaved_tabs: treat disconnected remote buffers (which have a file_id but cannot actually save) as unsaveable, so close/quit still warns instead of silently discarding their edits.

- auto_save_on_focus_change: clear the auto_save_in_flight marker when save_local returns early (untitled/disconnected remote) so a later manual save still shows its 'File saved.' toast.

- Add wasm stubs for CodeView::auto_save_all_unsaved_tabs and LocalCodeEditorView::mark_next_save_as_auto_save, which are called from non-wasm-gated code (quit_warning, code_review_view) and were breaking the wasm build.

Co-Authored-By: Oz <oz-agent@warp.dev>
// pending accept/reject diff (e.g. an agent "edit-file"
// proposal), which must never auto-save. Editable
// code-review diffs use `diff_type = None` and stay eligible.
if me.diff_type.is_none() && *CodeSettings::as_ref(ctx).auto_save {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very much a nit -- we should queue a debounced auto-save after user manually saves as well?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Warp Agent] Queuing a debounced auto-save right after a manual save would end up a no-op: auto_save_after_delay early-returns when has_unsaved_changes is false, and any edit made after the manual save re-queues the debounce via the ContentChanged handler anyway. So the current wiring already covers this — leaving as-is.

/// Set while an auto-save (debounced or focus-change) is in flight so the
/// resulting `FileSaved` event can be marked as an auto-save and suppress
/// the success toast.
auto_save_in_flight: bool,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a general save state? Something like

enum SaveState {
      Saving { is_auto_save: bool },
      None
}

This way we could also do things like early return on save attempts when the editor is already saving

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Warp Agent] Considered this — the subtlety is that auto_save_in_flight really means "label the next save as an auto-save", not "a save is in flight": the close flows set it via mark_next_save_as_auto_save() before separately invoking the save, so SaveState::Saving { is_auto_save } would conflate labeling with in-flight tracking. The early-return-on-saving idea is also a behavior change: saves complete asynchronously via GlobalBufferModel events, so a manual cmd-s during an in-flight auto-save would get dropped, and a stuck Saving state would silently swallow future saves (re-saving today is idempotent/harmless). Deferring the refactor to a follow-up rather than bundling it here — happy to pick it up if you feel strongly.

Comment thread app/src/code/view.rs
/// as an auto-save so it stays silent (no "File saved." toast). Returns
/// `true` if any unsaved tab could NOT be auto-saved (e.g. an untitled
/// buffer with no path), so callers can still warn before discarding those.
pub fn auto_save_all_unsaved_tabs(&mut self, ctx: &mut ViewContext<Self>) -> bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeView wraps LocalCodeEditorView right? In that case, do we need an ad-hoc autosave logic for the parent view (I assume the child editors will handle auto-save themselves)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Warp Agent] The child editors auto-save only on the typing debounce (1s) and focus change; auto_save_all_unsaved_tabs is the close/quit-time flush (called from UnsavedStateSummary::save_unsaved_code_and_should_warn). At close, a pending debounce hasn't fired yet and no blur may occur before teardown, so edits from the last second would be lost without it. The parent also needs to aggregate across all tabs to decide whether anything remains that auto-save can't persist (untitled buffers, disconnected remotes) and still warrant the warning dialog. The actual save is still delegated to the child editor — this is just tab orchestration.

}
}

/// Flush-saves every unsaved file in the review, marking each save as an

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto -- I assume the child editor views will handle auto-save here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Warp Agent] Same rationale as CodeView: this is the close-time flush (called from CodeReviewView::close). The child editors can't know the review pane is closing, and the parent owns the unsaved-file aggregation and the close-vs-prompt decision.

@szgupta
szgupta requested a review from kevinyang372 July 17, 2026 05:53
Auto-save previously hid the unsaved-changes indicator (editor tab dot,
workspace tab indicator, and code review per-file dot) unconditionally,
even for untitled buffers and disconnected remotes that auto-save cannot
persist. Add LocalCodeEditorView::can_auto_save and make all three
indicator sites auto-save-aware so unsaveable changes stay visible.

Co-Authored-By: Oz <oz-agent@warp.dev>
@szgupta

szgupta commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

[Warp Agent] Pushed 348b260 fixing a bug in the unsaved-indicator suppression: with auto-save enabled, the unsaved-changes indicator (editor tab dot, workspace tab indicator, and code review per-file dot) was hidden unconditionally — including for untitled buffers and disconnected remotes that auto-save can't actually persist.

The fix adds LocalCodeEditorView::can_auto_save() (backing file_id present + remote host still connected, reused by the close-time flush in auto_save_all_unsaved_tabs) and makes all three indicator sites auto-save-aware: the dot is now hidden only for changes auto-save can persist, so unsaveable changes stay visible.

Co-Authored-By: Oz <oz-agent@warp.dev>
@szgupta
szgupta merged commit 29ed596 into master Jul 17, 2026
26 checks passed
@szgupta
szgupta deleted the suraj/editor-auto-save branch July 17, 2026 20:47
iamwavecut pushed a commit to iamwavecut/warp that referenced this pull request Jul 18, 2026
Demo: https://www.loom.com/share/e61d6e666caa41deb9171c1cbbcc07c3

Adds an opt-in **Auto save** setting for the Warp text editor. When
enabled, the editor saves changes automatically so you don't have to
press Cmd-S.

Behavior mirrors VS Code:
- **While typing** — debounced ~1s after you stop typing (VS Code's
`files.autoSave: afterDelay`). Saves **without** running the LSP
formatter, so formatting never disrupts you mid-edit.
- **On focus loss** — when the editor loses focus to another view in the
app (`onFocusChange`) or its window is navigated away from / the app is
deactivated (`onWindowChange`). These **honor** the existing **Format on
save** setting, exactly like a manual Cmd-S.

Scope & guards:
- Applies to normal file editing **and the code review panel's editable
diffs** (both are `LocalCodeEditorView` with `diff_type = None`).
- **Never** auto-saves the agent "edit-file" accept/reject diffs (a
separate `InlineDiffView` type; plus a `diff_type.is_some()` guard).
- Skips untitled files (no path), disconnected remotes, and buffers with
no unsaved changes.
- Defaults to **off**; cloud-synced like other editor settings.

Unobtrusive behavior when auto-save is on:
- The **"File saved." toast is suppressed** for auto-saves (still shown
for manual Cmd-S), via an `auto_saved` flag on
`LocalCodeEditorEvent::FileSaved`.
- The **unsaved-changes dot is hidden** at every surface (editor tab
bar, single-tab pane header, workspace tab strip, and code review diff
headers), so it no longer flickers as you type.
- **Closing never blocks on an "unsaved changes" dialog for files that
can be auto-saved.** Instead the pending edits are flushed silently and
the close proceeds. This covers the file/editor tab, the code pane, the
workspace tab(s), the window, app quit, and the code review pane. The
close/quit dialog still appears for things auto-save can't handle —
running processes, shared sessions, or unsaved buffers with **no backing
file** (e.g. untitled files) — so those are never silently discarded.

The setting lives at **Settings → Code → Code Editor and Review → Auto
save** (`code.editor.auto_save`).

- New `auto_save` bool in `CodeSettings` (`app/src/settings/code.rs`),
mirroring `format_on_save`.
- Toggle widget + `ToggleAutoSave` action in
`app/src/settings_view/code_page.rs`.
- Auto-save logic in `app/src/code/local_code_editor.rs`: a debounced
channel (afterDelay, no formatting), `View::on_blur` (focus loss), and a
`WindowManager` subscription (window navigation). Both focus paths
respect format-on-save.
- Indicator/toast suppression in `app/src/code/view.rs`,
`app/src/tab.rs`, and `app/src/code_review/code_review_view.rs`.
- Close/quit handling centralized in
`UnsavedStateSummary::save_unsaved_code_and_should_warn`
(`app/src/quit_warning/mod.rs`), backed by
`CodeView::auto_save_all_unsaved_tabs` and
`CodeReviewView::auto_save_all_unsaved_files`. Wired into the window/app
close (`app/src/lib.rs`), pane close (`app/src/pane_group/mod.rs`), tab
close (`app/src/workspace/view.rs`), the editor tab close
(`app/src/code/view.rs`), and the code review close
(`app/src/code_review/code_review_view.rs`).

_None._
- [ ] The linked issue is labeled `ready-to-spec` or
`ready-to-implement`.
- [ ] Where appropriate, screenshots or a short video of the
implementation are included below (especially for user-visible or UI
changes).

- [ ] I have manually tested my changes locally with `./script/run`

Validated with `cargo fmt` and `cargo clippy -p warp --lib -- -D
warnings` (both pass) after merging latest `master`. No automated tests
were added: auto-save is driven by debounce timers plus
focus/window/close lifecycle events that are awkward to unit test, and
the underlying save path (`save_local` / `perform_save`) is unchanged
and already exercised. Manual verification is recommended before merge.

_N/A — settings toggle plus editor behavior. Happy to add a screen
recording._

- [x] Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-IMPROVEMENT: Added an opt-in "Auto save" setting for the Warp
text editor (Settings > Code > Code Editor and Review) that saves
changes as you type and when the editor loses focus, and flushes edits
automatically when closing instead of prompting.

---
[Warp
conversation](https://staging.warp.dev/conversation/d9f632e9-8c0c-4f27-8c0c-a7fa791ad0f8)

Co-Authored-By: Oz <oz-agent@warp.dev>

---------

Co-authored-by: Oz <oz-agent@warp.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants