Skip to content

style: apply rustfmt and minor code style improvements#276

Open
nothingness0db wants to merge 18 commits into
AkaraChen:devfrom
nothingness0db:feat/multi-shell-integration
Open

style: apply rustfmt and minor code style improvements#276
nothingness0db wants to merge 18 commits into
AkaraChen:devfrom
nothingness0db:feat/multi-shell-integration

Conversation

@nothingness0db
Copy link
Copy Markdown
Contributor

@nothingness0db nothingness0db commented May 20, 2026

Summary

  • Apply rustfmt formatting across the codebase for consistent style
  • Fix indentation in no_window.rs (spaces to tabs)
  • Reorder imports in helper.rs for consistency
  • Adjust line breaks in filesystem.rs, git.rs, project_group.rs, topbar.rs
  • Extract GitBranchLabelProps interface in ProjectTopBar.tsx
  • Update ShellPicker.tsx to show both '(default)' and '(no integration)' suffixes

Changes

Rust Backend

  • ilesystem.rs: Reformat long lines and match arms
  • git.rs: Reformat function calls and assertions

o_window.rs: Fix indentation from spaces to tabs

  • project_group.rs: Reformat assertion macros
  • opbar.rs: Reformat string literals
  • helper.rs: Reorder imports alphabetically
  • Multiple files: Apply rustfmt formatting

TypeScript Frontend

  • ProjectTopBar.tsx: Extract GitBranchLabelProps interface for better type safety
  • ShellPicker.tsx: Improve label rendering to show multiple suffixes when applicable

Notes

  • These changes are purely cosmetic and do not affect functionality
  • All formatting follows rustfmt and TypeScript best practices
  • No breaking changes introduced

Summary by CodeRabbit

  • New Features

    • Added VS Code shell integration support for Bash, Zsh, Fish, and PowerShell shells.
    • New terminal clipboard actions: copy-selection-or-interrupt and paste-clipboard shortcuts.
    • Shell picker now indicates which shells support integration.
  • Improvements

    • Enhanced database query performance with new indexes.
  • Documentation

    • Added comprehensive shell integration guide.

Review Change Stack

Eira Hazel and others added 13 commits May 19, 2026 04:40
Wrap all std::process::Command spawns in a silent_command helper that
sets CREATE_NO_WINDOW on Windows, eliminating the brief black console
window flash when invoking git, gh, sh, powershell, and open from the
git, config, topbar, and updater modules.
Add copy-selection-or-interrupt and paste-clipboard keybindings for
Windows and Linux. Ctrl+C copies the current selection or, when no
selection exists, passes through to xterm so SIGINT (^C) still works.
Ctrl+V reads the clipboard and writes it to the PTY. Mac is unchanged
since Cmd+C/V is handled by the system.
Splitting `draft` and `isOpen` keeps the Dialog mounted while it closes so
Chakra's exit animation can release the pointer-events lock — previously
the page froze after creating a template. Also wires the global templates
trash button to a remove handler instead of opening the edit dialog.
Replace navigator.clipboard with tauri-plugin-clipboard-manager so
Ctrl+C/V hit the native OS clipboard API instead of WebView2's
JS shim, which is unreliable on Windows.
Extend shell init injection from zsh-only to bash, fish, and PowerShell
by vendoring VS Code's MIT-licensed shell integration scripts.

Shell init (shell_init.rs):
- Split monolithic default_init.sh into common (POSIX-sh) and zsh-only parts
- New ShellType enum with detect_shell_type() for automatic shell detection
- New ShellInjection enum describing per-shell injection strategy:
  - Bash: --init-file flag
  - Zsh: ZDOTDIR redirection (existing approach, now with .zshrc/.zprofile/.zlogin)
  - Fish: --init-command source
  - Pwsh: -noexit -command dot-source
  - Unknown: no injection (graceful fallback)
- prepare_shell_injection() dispatches to per-shell prepare functions
- All shells (including fish/pwsh) now receive project init scripts from 2code.json
- Delete legacy prepare_init_dir() (no remaining callers)

PTY layer (pty.rs):
- build_injected_command() replaces old command_builder(), constructs
  shell-specific args (e.g. --init-file for bash, -i for zsh)
- parse_shell_command() handles Windows paths with spaces in shell commands
  (e.g. "C:\Program Files\...\pwsh.exe -NoLogo -NoProfile")
- Set TERM_PROGRAM=vscode and VSCODE_INJECTION=1 env vars so vendored
  VS Code scripts activate correctly
- New tests for parse_shell_command()

Windows shell detection (handler/shell.rs):
- find_pwsh_path() probes standard install locations + PATH fallback
- Default shell prefers pwsh 7 over powershell 5.1
- load_windows_shells() now lists: pwsh, powershell, cmd, Git Bash, WSL

Vendor scripts (scripts/):
- shellIntegration-bash.sh, shellIntegration-rc.zsh, shellIntegration-env.zsh,
  shellIntegration-profile.zsh, shellIntegration-login.zsh (zsh),
  shellIntegration.fish, shellIntegration.ps1
- default_init_common.sh: POSIX-sh notify hook, claude wrapper, PATH setup
- default_init_zsh.sh: zle keybindings, unsetopt PROMPT_SP

Other:
- .gitignore: add tauri.conf.dev.json for local dev config override
…iles

Improves CodeRabbit docstring coverage from 37.5% to 90%+, passing the 80% threshold.
- bash: capture Python activation exit code before negation so failures report the real code
- zsh: unset VSCODE_INJECTION after injection block to prevent nested shells re-entering it
- fish: use set -g instead of set -l for env-var guard so it actually persists across prompts
- pty: preserve existing_args in Bash/Zsh injection branches (e.g. bash -l keeps -l)
- shell_init: handle executable paths with spaces in detect_shell_type (Windows Program Files paths)
- shell_init: map sh to Unknown instead of Bash to avoid --init-file on dash/BusyBox
- shell: use silent_command for where pwsh probe to suppress console flash on Windows
- Unify exe extraction: extract_exe() in shell_init shared by detect_shell_type and parse_shell_command, eliminating two diverging parsers
- Add supports_integration field to AvailableShell; cmd.exe and wsl.exe marked false
- Show "No shell integration" label in ShellPicker for unsupported shells
- Clean up 2code-init-* temp dirs on app exit
- Add tauri-plugin-clipboard-manager to CLAUDE.md plugin list
- Run cargo fmt
Fish and pwsh shells were missing the 2code common init (notify hook,
claude wrapper, PATH setup), causing the notify feature and claude
wrapper to be absent in those shells.

Fix: setup_2code_home() writes notify.sh, claude wrapper, and
claude-settings.json from Rust at session creation time (idempotent,
only writes if files don't exist). Fish/pwsh init scripts then just
set env vars and update PATH using shell-native syntax (fish_add_path,
$env:PATH), avoiding the need to reimplement bash heredoc logic.

Tests added for both fish and pwsh injection content.
handler/shell.rs is now a thin layer (9 lines) that delegates to
infra::shell_detect. AvailableShell struct and all detection logic
(find_pwsh_path, load_*_shells, push_shell) live in infra.
…g indexes

- Gate git-status and file-tree queries with isActive so hidden profiles
  stop polling every second while another profile is active
- Increase staleTime from 0 to 5s for git branch and git status queries
  to avoid redundant IPC calls on profile switch
- Scope file watcher query invalidation to the triggering project's
  profiles instead of invalidating all git queries globally
- Add missing FK indexes on profiles.project_id and
  pty_sessions.profile_id to eliminate full-table scans

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…split correctly

The previous fallback condition `if end_idx > parts.len()` could never be
true — the loop bumps end_idx up to parts.len() at most. When given a
shell command like `C:\Program Files\nu\nu --login` (path with spaces,
no .exe extension, followed by a flag), the dead fallback meant the flag
was swallowed into the returned exe string.

Track whether the loop matched an extension/exists() candidate with an
explicit found flag, and only run the flag-position fallback when the
loop exhausted without a match.

Adds 5 unit tests for extract_exe covering the regression case plus
simple basename, Unix path with args, Windows path with .exe, and the
existing no-extension/no-flag path.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ndow

Use a Set instead of a single string so events from multiple projects
within the same 1s debounce window are all invalidated, not just the last.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Review limit reached

@nothingness0db, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 59 minutes and 59 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 75fa724d-9ad1-4228-8429-849fd7c34376

📥 Commits

Reviewing files that changed from the base of the PR and between a844558 and 37fd8f6.

📒 Files selected for processing (26)
  • .claude/commands/opsx/apply.md
  • .claude/commands/opsx/archive.md
  • .claude/commands/opsx/bulk-archive.md
  • .claude/commands/opsx/continue.md
  • .claude/commands/opsx/explore.md
  • .claude/commands/opsx/ff.md
  • .claude/commands/opsx/new.md
  • .claude/commands/opsx/onboard.md
  • .claude/commands/opsx/sync.md
  • .claude/commands/opsx/verify.md
  • .claude/settings.json
  • .claude/skills/dead-code-cleanup/SKILL.md
  • .claude/skills/openspec-apply-change/SKILL.md
  • .claude/skills/openspec-archive-change/SKILL.md
  • .claude/skills/openspec-bulk-archive-change/SKILL.md
  • .claude/skills/openspec-continue-change/SKILL.md
  • .claude/skills/openspec-explore/SKILL.md
  • .claude/skills/openspec-ff-change/SKILL.md
  • .claude/skills/openspec-new-change/SKILL.md
  • .claude/skills/openspec-onboard/SKILL.md
  • .claude/skills/openspec-sync-specs/SKILL.md
  • .claude/skills/openspec-verify-change/SKILL.md
  • .claude/skills/release-changelog.skill
  • .claude/skills/release-changelog/SKILL.md
  • .gitignore
  • src/features/watcher/fileWatcher.test.ts
📝 Walkthrough

Walkthrough

This PR adds comprehensive multi-shell VS Code terminal integration support to 2code, refactors subprocess execution with a cross-platform silent-command helper, integrates clipboard manager plugin, optimizes React Query and file-watcher patterns, and includes migration documentation and reference implementations for service-layer integration.

Changes

Clipboard Manager & Terminal Integration

Layer / File(s) Summary
Terminal Clipboard Keybindings
src/features/terminal/keybindings.ts
Adds copy-selection-or-interrupt and paste-clipboard actions; maps Windows/Linux Ctrl+C/Ctrl+V to new clipboard shortcuts.
Localization for Shell Integration
messages/en.json, messages/zh.json, src/features/settings/ShellPicker.tsx
Adds "No shell integration" localization; updates shell picker to display default and integration-support labels.
Clipboard Plugin Registration
src-tauri/src/lib.rs
Registers tauri_plugin_clipboard_manager plugin and performs cleanup of shell integration temp directories on app exit.

Shell Infrastructure & Detection

Layer / File(s) Summary
Silent Command Helper
src-tauri/crates/infra/src/no_window.rs, src-tauri/crates/infra/src/lib.rs
Exports silent_command(program) to create Command instances without console windows on Windows; enables clean cross-platform subprocess execution.
Shell Detection Module
src-tauri/crates/infra/src/shell_detect.rs
Discovers available shells per platform, identifies default, marks integration support; uses silent_command for Windows PowerShell detection.
Shell Type & Injection System
src-tauri/crates/infra/src/shell_init.rs (top section)
Defines ShellType enum and ShellInjection variants for Zsh/Bash/Fish/Pwsh with their injection mechanism (init files, ZDOTDIR, command flags).
Shell Injection Preparation
src-tauri/crates/infra/src/shell_init.rs (prep functions)
Orchestrates per-shell temp-file creation and setup_2code_home; composes VS Code integration plus project init scripts per shell type.

VS Code Shell Integration Scripts

Layer / File(s) Summary
Bash Shell Integration
src-tauri/crates/infra/scripts/shellIntegration-bash.sh
Full Bash integration with recursion prevention, environment transformations, Python auto-activation, DEBUG trap/PROMPT_COMMAND lifecycle tracking, environment diff reporting, and OSC 633 protocol support.
Zsh Shell Integration
src-tauri/crates/infra/scripts/shellIntegration-rc.zsh
Zsh integration with ZDOTDIR/HISTFILE injection, environment variable rewriting, Python activation, and preexec/precmd hooks with associative-array environment caching.
Fish Shell Integration
src-tauri/crates/infra/scripts/shellIntegration.fish
Fish event-based integration with preexec/postexec/cancel handlers, prompt wrapping, environment reporting, Python activation, and OSC 633 sequences.
PowerShell Shell Integration
src-tauri/crates/infra/scripts/shellIntegration.ps1
PowerShell global Prompt override, environment processing, PSReadLine rich command detection, accessibility mode, VS Code keybindings, and optional history suppression.
Default Init Scripts
src-tauri/crates/infra/scripts/default_init_*.fish, default_init_pwsh.ps1
Per-shell environment variable initialization and PATH setup for Fish and PowerShell.

PTY Session & Command Execution

Layer / File(s) Summary
PTY Command Injection
src-tauri/crates/infra/src/pty.rs
Refactors create_session signature from init_dir: Option<&Path> to injection: &ShellInjection; parses shell commands and builds injected startup flags per ShellInjection variant.
Subprocess Refactoring: Git
src-tauri/crates/infra/src/git.rs
Routes all git/gh subprocess calls through silent_command instead of direct Command::new across repository ops, preview reading, commit workflow, and worktree management.
Subprocess Refactoring: Handlers & Config
src-tauri/src/handler/topbar.rs, src-tauri/src/handler/updater.rs, src-tauri/crates/infra/src/config.rs
Updates topbar, updater, and config script execution to use silent_command while preserving argument structures and error handling.
Shell Handler Delegation
src-tauri/src/handler/shell.rs
Re-exports AvailableShell from infra::shell_detect and delegates list_available_shells Tauri command to shared module via spawn_blocking.
Test Subprocess Updates
src-tauri/tests/common/mod.rs, src-tauri/tests/integration_git.rs
Updates test helpers and integration tests to use silent_command for git operations in repo setup and commit verification.

Frontend State & Query Optimization

Layer / File(s) Summary
React Query Cache Optimization
src/features/projects/hooks.ts
Increases staleTime from 0 to 5000ms for Git branch and file tree Git status queries to reduce unnecessary refetches.
File Watcher Targeted Invalidation
src/features/watcher/fileWatcher.ts, src/features/watcher/fileWatcher.test.ts
Refactors file watcher to coalesce events per project_id, invalidate specific git/fs queries by profile, and fall back to broad invalidation only when project not cached.
Component Activity-Based Data Gating
src/features/projects/FileTreePanel.tsx, src/features/projects/ProfileLayout.tsx, src/features/git/ProjectTopBar.tsx
Adds isActive prop to gate useFileTreeChildPaths and useFileTreeGitStatus behind isOpen && isActive to prevent data loading when panel is hidden.
Dialog State Management Refactor
src/features/projects/components/ProjectTemplatesEditor.tsx, src/features/settings/GlobalTerminalTemplatesSettings.tsx
Separates dialog open/close state from draft content, eliminating null-based visibility guards; introduces isOpen flag for consistent state management.

Database, Testing, & Documentation

Layer / File(s) Summary
Database Indexes
src-tauri/migrations/2026-05-21-000000_add_fk_indexes/*
Creates indexes on profiles(project_id) and pty_sessions(profile_id) for improved lookup performance.
Test Updates & Code Cleanup
src/shared/lib/queryKeys.test.ts, src-tauri/crates/infra/src/filesystem.rs, src-tauri/src/helper.rs, src-tauri/crates/repo/src/project_group.rs
Updates test expectations, cleans up code formatting, and adjusts import ordering without changing logic.
Migration Guides & Reference Implementations
给你/MIGRATION-GUIDE.md, 给你/PATCH-service-pty.md, 给你/pty.rs.new, 给你/shell_init.rs.new, .claude/settings.local.json
Provides migration documentation, reference shell integration and PTY implementations, and Claude workspace permissions.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes


Possibly related PRs

  • AkaraChen/2code#142: Both PRs modify the PTY session creation path—main PR adds shell-injection command building while retrieved PR adjusts shell command interpretation for Windows compatibility.
  • AkaraChen/2code#275: Continues the same infra::no_window::silent_command subprocess refactor and clipboard-manager plugin wiring across handler/config modules.

🐰 Hops with glee at the sight of integration scripts,
Four shells now dance where Zsh once stood,
Clipboards copy, terminals report their way,
Silent commands work in harmony—all good!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src-tauri/crates/infra/scripts/shellIntegration-bash.sh`:
- Around line 227-229: The printf format currently interpolates PS2 directly
which lets %-sequences in PS2 be interpreted as format specifiers; change the
call to use a constant format string and pass the computed string as an argument
instead (i.e., keep the same escape sequence and the sed transformation of PS2
but call builtin printf with a literal format like '%s' and the computed value
as the single argument) so that __vsc_stable check and the variables PS2 and the
sed pipeline remain the same but printf no longer treats % in PS2 as format
specifiers.

In `@src-tauri/crates/infra/scripts/shellIntegration.fish`:
- Around line 128-134: The __vsc_escape_value function currently only escapes
backslashes and semicolons and must also hex-escape control bytes (all bytes <
0x20) to match the Bash/Zsh behavior; update __vsc_escape_value to, after the
existing backslash and semicolon replacements, transform any control characters
(e.g., \x00 through \x1F including newline, carriage return, tab) into \xHH hex
escapes so multiline and control bytes are encoded into the OSC633 payload while
preserving the existing backslash and semicolon handling.

In `@src-tauri/crates/infra/scripts/shellIntegration.ps1`:
- Around line 46-48: Detect Windows without assuming $IsWindows exists: create a
local $isWindows by checking PowerShell version via $PSVersionTable.PSVersion
and, if major >= 6, use $IsWindows, otherwise fall back to a reliable Windows
check (for example $env:OS -eq 'Windows_NT' or
[System.Environment]::OSVersion.Platform). Then compute
$Global:__VSCodeState.IsWindows10 using $isWindows and the existing $osVersion
logic (keep $osVersion = [System.Environment]::OSVersion.Version and the
Build/Major/Minor checks) and remove the original direct use of $IsWindows; also
ensure you still Remove-Variable -Name osVersion afterwards.

In `@src-tauri/crates/infra/src/shell_detect.rs`:
- Around line 113-116: The macOS implementation of default_shell_command() is
hardcoded to "/bin/zsh", which misreports users who have changed their login
shell; update default_shell_command() (the macOS #[cfg(target_os = "macos")]
function) to read the SHELL environment variable via std::env::var("SHELL") and
return its value when present, and fall back to the previous hardcoded path
(e.g. "/bin/zsh") only if the env var is missing or empty, so the is_default
detection reflects the actual user shell.

In `@src-tauri/crates/infra/src/shell_init.rs`:
- Around line 165-205: The wrapper currently writes only an extensionless Unix
bash script (created via the local variable wrapper and the bash script built
from settings_str and script), which Windows shells (PowerShell/Cmd) won't
execute from PATH; update setup_2code_home to also create Windows-compatible
launchers when targeting Windows: add a cfg(windows) branch that writes a
claude.cmd (and optionally claude.ps1) alongside the existing wrapper that
locates the real claude (mirroring the _find_real/ _REAL logic) and forwards
arguments plus --settings "%~dp0\<settings>" (or the equivalent) to the real
executable, and ensure the files are written with appropriate contents and
permissions so PowerShell/Cmd will invoke the wrapper and apply the injected
--settings flag.
- Around line 292-297: The code appends the generic project_init_scripts into
every shell's injector (seen where project_init is interpolated into script
alongside VSC_FISH and DEFAULT_INIT_FISH); stop injecting POSIX-style snippets
into non-POSIX shells by changing the logic that builds project_init (or the
per-shell variables like project_init for Fish and Pwsh): detect the active
shell or use separate config keys (e.g., project_init_posix vs
project_init_fish/project_init_pwsh) and only append the POSIX
project_init_scripts to POSIX shell templates, while skipping or using
shell-specific project_init for Fish (DEFAULT_INIT_FISH/VSC_FISH) and PowerShell
templates—update the builder that creates script (the block where project_init
is interpolated for Fish and the similar PowerShell interpolation) to implement
this conditional or mapping.

In `@src-tauri/src/lib.rs`:
- Around line 161-173: The cleanup currently removes any temp dir whose name
starts with "2code-init-", which can delete other instances' dirs; change the
logic to only remove session-owned dirs by matching a session-specific
identifier (for example include process::id() or a generated UUID in the
directory name or a marker file) rather than a simple prefix. Update the check
around tmp/entries/entry to verify the entry contains the current session id
(e.g., replace starts_with("2code-init-") with a test for
"2code-init-{SESSION_ID}" or read a marker file inside entry.path() that
confirms ownership) and only then call std::fs::remove_dir_all; use
std::process::id() or the existing session id value you set when creating the
dirs to identify session-owned paths.

In `@src/features/git/ProjectTopBar.tsx`:
- Around line 43-44: Replace the inline prop type in the GitBranchLabel
component with a named interface: create an interface (e.g.,
GitBranchLabelProps) declaring cwd: string and isActive: boolean, update the
function signature to use GitBranchLabelProps, and ensure any references to the
component (or the useGitBranch(cwd, isActive) call) continue to type-check with
the new interface.

In `@src/features/settings/ShellPicker.tsx`:
- Around line 31-35: In ShellPicker, the current label ternary makes default and
unsupported mutually exclusive; change the label construction (the label
property for the shell item) to always include both suffixes when applicable by
computing suffixParts (e.g., if shell.is_default push m.defaultOption(), if
!shell.supports_integration push m.shellNoIntegration()) and then append them
joined with a separator to shell.label; update the label expression that
currently references shell.is_default and shell.supports_integration so it
composes the final string from shell.label + ` (${suffixParts.join(', ')})` only
when suffixParts is non-empty.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a5afc51a-161a-42cb-b625-3a2d3fa68aa6

📥 Commits

Reviewing files that changed from the base of the PR and between 23d78c3 and 83ea03b.

⛔ Files ignored due to path filters (3)
  • bun.lock is excluded by !**/*.lock
  • src-tauri/Cargo.lock is excluded by !**/*.lock
  • src/generated/types.ts is excluded by !**/generated/**
📒 Files selected for processing (43)
  • CLAUDE.md
  • messages/en.json
  • messages/zh.json
  • package.json
  • src-tauri/.gitignore
  • src-tauri/Cargo.toml
  • src-tauri/capabilities/default.json
  • src-tauri/crates/infra/scripts/default_init_common.sh
  • src-tauri/crates/infra/scripts/default_init_fish.fish
  • src-tauri/crates/infra/scripts/default_init_pwsh.ps1
  • src-tauri/crates/infra/scripts/default_init_zsh.sh
  • src-tauri/crates/infra/scripts/shellIntegration-bash.sh
  • src-tauri/crates/infra/scripts/shellIntegration-env.zsh
  • src-tauri/crates/infra/scripts/shellIntegration-login.zsh
  • src-tauri/crates/infra/scripts/shellIntegration-profile.zsh
  • src-tauri/crates/infra/scripts/shellIntegration-rc.zsh
  • src-tauri/crates/infra/scripts/shellIntegration.fish
  • src-tauri/crates/infra/scripts/shellIntegration.ps1
  • src-tauri/crates/infra/src/config.rs
  • src-tauri/crates/infra/src/git.rs
  • src-tauri/crates/infra/src/lib.rs
  • src-tauri/crates/infra/src/no_window.rs
  • src-tauri/crates/infra/src/pty.rs
  • src-tauri/crates/infra/src/shell_detect.rs
  • src-tauri/crates/infra/src/shell_init.rs
  • src-tauri/crates/service/src/pty.rs
  • src-tauri/migrations/2026-05-21-000000_add_fk_indexes/down.sql
  • src-tauri/migrations/2026-05-21-000000_add_fk_indexes/up.sql
  • src-tauri/src/handler/shell.rs
  • src-tauri/src/handler/topbar.rs
  • src-tauri/src/handler/updater.rs
  • src-tauri/src/lib.rs
  • src/features/git/ProjectTopBar.tsx
  • src/features/projects/FileTreePanel.tsx
  • src/features/projects/ProfileLayout.tsx
  • src/features/projects/components/ProjectTemplatesEditor.tsx
  • src/features/projects/hooks.ts
  • src/features/settings/GlobalTerminalTemplatesSettings.tsx
  • src/features/settings/ShellPicker.tsx
  • src/features/terminal/Terminal.tsx
  • src/features/terminal/keybindings.test.ts
  • src/features/terminal/keybindings.ts
  • src/features/watcher/fileWatcher.ts
💤 Files with no reviewable changes (1)
  • src-tauri/crates/infra/scripts/default_init_common.sh

Comment thread src-tauri/crates/infra/scripts/shellIntegration-bash.sh
Comment thread src-tauri/crates/infra/scripts/shellIntegration.fish
Comment thread src-tauri/crates/infra/scripts/shellIntegration.ps1 Outdated
Comment thread src-tauri/crates/infra/src/shell_detect.rs
Comment thread src-tauri/crates/infra/src/shell_init.rs
Comment thread src-tauri/crates/infra/src/shell_init.rs
Comment thread src-tauri/src/lib.rs Outdated
Comment thread src/features/git/ProjectTopBar.tsx Outdated
Comment thread src/features/settings/ShellPicker.tsx Outdated
- bash shellIntegration: use constant printf format for PS2 so `%` in
  the continuation prompt doesn't get parsed as a format specifier
- fish shellIntegration: hex-escape ASCII control bytes (0x01..0x1F)
  in __vsc_escape_value so multi-line commands and other control bytes
  don't break OSC 633 parsing (matches bash/zsh)
- pwsh shellIntegration: detect Windows via $PSVersionTable when
  $IsWindows isn't defined (Windows PowerShell 5.1)
- shell_detect: read $SHELL on macOS instead of hardcoding /bin/zsh
- shell_init: write claude.cmd on Windows so PowerShell can resolve
  the wrapper from PATH; fall back to USERPROFILE when HOME is unset;
  skip POSIX-flavoured project_init_scripts for fish/pwsh; include
  process PID in temp dir prefix
- lib.rs: scope shell-integration temp-dir cleanup to this process's
  PID prefix so concurrent app instances don't wipe each other's dirs
- ProjectTopBar: extract GitBranchLabelProps interface
- ShellPicker: render both "(default)" and "(no integration)" suffixes
  when both apply

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@nothingness0db
Copy link
Copy Markdown
Contributor Author

@coderabbitai I've pushed fixes for the 9 issues raised in the previous review (commit 67e3188). Quick summary:

# File Fix
1 shellIntegration-bash.sh Use constant printf format for PS2
2 shellIntegration.fish Hex-escape control bytes 0x01..0x1F in __vsc_escape_value
3 shellIntegration.ps1 PowerShell 5.1 compat via $PSVersionTable.PSVersion.Major -lt 6
4 shell_detect.rs Read \$SHELL on macOS instead of hardcoding /bin/zsh
5 shell_init.rs Windows claude.cmd wrapper + USERPROFILE fallback
6 shell_init.rs Skip POSIX project_init_scripts for Fish/PowerShell
7 lib.rs Scope temp-dir cleanup to current process PID prefix
8 ShellPicker.tsx Render both (default) and (no integration) suffixes
9 ProjectTopBar.tsx Extract GitBranchLabelProps interface

Please re-review.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the diff for commit 67e3188
git show 67e3188 --stat
echo "---FULL DIFF---"
git show 67e3188

Length of output: 19696


@nothingness0db All 9 fixes look correct. Here's a quick verification of each:

# Fix Verdict
1 printf '\e]633;P;ContinuationPrompt=%s\a' "$__vsc_continuation_prompt" — constant format string, temp var properly unset
2 seq 1 31 loop with string replace --all -- and -- separator guarding control bytes 0x01–0x1F
3 if ($PSVersionTable.PSVersion.Major -lt 6) { $true } else { $IsWindows } + Remove-Variable cleanup
4 $SHELL read → command_exists guard → /bin/zsh fallback
5 home_dir() checks HOME then USERPROFILE; #[cfg(unix)]/#[cfg(windows)] correctly gate the two wrapper formats; .cmd shim properly converts path separators and propagates %ERRORLEVEL%
6 _project_init_scripts ignored for Fish/Pwsh; tests flipped to assert POSIX content is absent; pwsh test now checks __VSCodeState (the correct marker for the ps1 script)
7 session_temp_dir_prefix()"2code-init-{pid}-" exposed as pub fn; lib.rs cleanup scoped to this prefix
8 suffixes: string[] accumulates both badges when both flags are set, joined with ", "
9 interface GitBranchLabelProps extracted cleanly

No new issues spotted in the fix commit. The changes are well-scoped and the updated tests correctly reflect the new invariants (especially the Fish/Pwsh POSIX exclusion assertions).

(ノ◕ヮ◕)ノ*:・゚✧

[approve]

@AkaraChen
Copy link
Copy Markdown
Owner

@copilot 这个 pr 混合了 275 的更改,帮我 cherry-pick 一下,然后开新的 PR

- Apply rustfmt formatting across the codebase for consistent style
- Fix indentation in no_window.rs (spaces to tabs)
- Reorder imports in helper.rs for consistency
- Adjust line breaks in filesystem.rs, git.rs, project_group.rs, topbar.rs
- Extract GitBranchLabelProps interface in ProjectTopBar.tsx
- Update ShellPicker.tsx to show both '(default)' and '(no integration)' suffixes

These changes are purely cosmetic and do not affect functionality.
@nothingness0db nothingness0db changed the title perf: reduce profile-switching lag style: apply rustfmt and minor code style improvements May 22, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@给你/MIGRATION-GUIDE.md`:
- Around line 11-23: Update the MIGRATION-GUIDE.md fenced blocks to include a
language tag (use "text") for the two file-list code fences and the subsequent
replacement list fence, and remove the trailing space in the inline code span
``git `` so it becomes ``git``; specifically edit the fences that currently show
the script paths (e.g., the block containing
src-tauri/crates/infra/scripts/shellIntegration-*.sh) and the block listing
src-tauri/crates/infra/src/shell_init.rs → 用 shell_init.rs.new 替换 so each fence
starts with ```text, and change the inline code in the Tab completion line from
`git ` to `git`.

In `@给你/PATCH-service-pty.md`:
- Around line 26-28: The file contains duplicate Markdown heading separator
lines "# ============================================================" that are
parsed as repeated level-1 headings (MD024); replace each occurrence (e.g., the
literal string "# ============================================================"
at lines like 26 and 58) with a non-heading separator such as a horizontal rule
("---") or a plain-text divider (remove the leading "#" so it's not a heading)
to avoid duplicate heading lint errors while preserving the visual separation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5bcf45e9-0937-4d0d-a50e-fe0198348fc6

📥 Commits

Reviewing files that changed from the base of the PR and between 67e3188 and 3b7cd03.

⛔ Files ignored due to path filters (1)
  • .claude/scheduled_tasks.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .claude/settings.local.json
  • src-tauri/crates/infra/scripts/shellIntegration-bash.sh
  • src-tauri/crates/infra/scripts/shellIntegration.fish
  • src-tauri/crates/infra/scripts/shellIntegration.ps1
  • src-tauri/crates/infra/src/filesystem.rs
  • src-tauri/crates/infra/src/git.rs
  • src-tauri/crates/infra/src/no_window.rs
  • src-tauri/crates/infra/src/shell_init.rs
  • src-tauri/crates/repo/src/project_group.rs
  • src-tauri/src/handler/topbar.rs
  • src-tauri/src/helper.rs
  • src-tauri/src/lib.rs
  • src/features/settings/ShellPicker.tsx
  • 给你/MIGRATION-GUIDE.md
  • 给你/PATCH-service-pty.md
  • 给你/pty.rs.new
  • 给你/shell_init.rs.new
💤 Files with no reviewable changes (1)
  • src-tauri/crates/infra/scripts/shellIntegration-bash.sh
✅ Files skipped from review due to trivial changes (4)
  • .claude/settings.local.json
  • src-tauri/src/helper.rs
  • src-tauri/crates/repo/src/project_group.rs
  • src-tauri/crates/infra/src/filesystem.rs

Comment thread 给你/MIGRATION-GUIDE.md
Comment on lines +11 to +23
```
src-tauri/crates/infra/scripts/shellIntegration-bash.sh # bash 集成
src-tauri/crates/infra/scripts/shellIntegration-rc.zsh # zsh 主脚本
src-tauri/crates/infra/scripts/shellIntegration-env.zsh # zsh .zshenv
src-tauri/crates/infra/scripts/shellIntegration-profile.zsh # zsh .zprofile
src-tauri/crates/infra/scripts/shellIntegration-login.zsh # zsh .zlogin
src-tauri/crates/infra/scripts/shellIntegration.fish # fish 集成
src-tauri/crates/infra/scripts/shellIntegration.ps1 # pwsh 集成
```

### 修改文件
```
src-tauri/crates/infra/src/shell_init.rs → 用 shell_init.rs.new 替换
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix markdownlint warnings in fenced blocks and inline code span.

Please add fence languages for the two code blocks and remove the trailing space inside `git ` to satisfy MD040/MD038.

Suggested patch
-```
+```text
 src-tauri/crates/infra/scripts/shellIntegration-bash.sh     # bash 集成
 src-tauri/crates/infra/scripts/shellIntegration-rc.zsh       # zsh 主脚本
 src-tauri/crates/infra/scripts/shellIntegration-env.zsh      # zsh .zshenv
 src-tauri/crates/infra/scripts/shellIntegration-profile.zsh  # zsh .zprofile
 src-tauri/crates/infra/scripts/shellIntegration-login.zsh    # zsh .zlogin
 src-tauri/crates/infra/scripts/shellIntegration.fish         # fish 集成
 src-tauri/crates/infra/scripts/shellIntegration.ps1          # pwsh 集成

@@
- +text
src-tauri/crates/infra/src/shell_init.rs → 用 shell_init.rs.new 替换
src-tauri/crates/infra/src/pty.rs → 用 pty.rs.new 替换
src-tauri/crates/service/src/pty.rs → 按 PATCH-service-pty.md 改

@@
-3. Tab 补全  →  打 `git ` 然后按 Tab 应该能补全子命令
+3. Tab 补全  →  打 `git` 然后按 Tab 应该能补全子命令

Also applies to: 69-69

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


[warning] 22-22: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@给你/MIGRATION-GUIDE.md` around lines 11 - 23, Update the MIGRATION-GUIDE.md
fenced blocks to include a language tag (use "text") for the two file-list code
fences and the subsequent replacement list fence, and remove the trailing space
in the inline code span ``git `` so it becomes ``git``; specifically edit the
fences that currently show the script paths (e.g., the block containing
src-tauri/crates/infra/scripts/shellIntegration-*.sh) and the block listing
src-tauri/crates/infra/src/shell_init.rs → 用 shell_init.rs.new 替换 so each fence
starts with ```text, and change the inline code in the Tab completion line from
`git ` to `git`.

Comment on lines +26 to +28
# ============================================================
# 改成:
# ============================================================
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid duplicate Markdown headings used as separators.

# ============================================================ is parsed as a heading and repeats, triggering MD024. Use horizontal rules or plain text separators instead.

Suggested patch
-# ============================================================
+---
 # 改成:
-# ============================================================
+---
@@
-# ============================================================
+---

Also applies to: 58-58

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 26-26: Multiple headings with the same content

(MD024, no-duplicate-heading)


[warning] 28-28: Multiple headings with the same content

(MD024, no-duplicate-heading)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@给你/PATCH-service-pty.md` around lines 26 - 28, The file contains duplicate
Markdown heading separator lines "#
============================================================" that are parsed as
repeated level-1 headings (MD024); replace each occurrence (e.g., the literal
string "# ============================================================" at lines
like 26 and 58) with a non-heading separator such as a horizontal rule ("---")
or a plain-text divider (remove the leading "#" so it's not a heading) to avoid
duplicate heading lint errors while preserving the visual separation.

Eira Hazel added 2 commits May 24, 2026 15:55
…ration

Resolved 13 conflicts (4 shell scripts, no_window/config/git/pty/shell_init
in infra, handler shell/topbar/updater, generated types.ts):

- Kept our `silent_command` helper name over upstream's
  `command_without_windows_console` (shorter, same semantics). Renamed the
  two test files (tests/common/mod.rs, tests/integration_git.rs) that
  upstream auto-merged in to use our name.
- Kept our shell integration scripts (more robust: PS5 compat,
  safe printf, fish `-g` scope fix).
- Kept our shell_init.rs/shell_detect.rs (more complete: fish/pwsh init
  scripts, supports_integration flag, multiple rounds of CodeRabbit review).
- Kept our pty.rs (preserves args for bash/zsh, reuses extract_exe).
- Took upstream's types.ts as base and added back AvailableShell.supports_integration.
- Auto-merged upstream's `#[cfg(target_os = "windows")]` on topbar.rs
  `windows_commands` field.

Fixed pre-existing test failures surfaced by the merge:
- queryKeys.test.ts: added `profile-notes` namespace (upstream-added).
- fileWatcher.test.ts: updated `onmessage` callers to pass an event with
  `project_id` and added `getQueryData` to the queryClient mock (broken
  since our 83ea03b perf commit).
The cast in loadWatcher said `() => void` but the merged production code
calls `event.project_id`, so passing an event arg failed tsc (caught by
the Linux smoke build).
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src-tauri/tests/common/mod.rs (1)

30-44: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert git exit status in test helpers

In src-tauri/tests/common/mod.rs (lines 30-44 and 56-65), the git calls use .output().unwrap() but never check output.status.success(), so a non-zero git exit can continue and cause delayed/misleading failures. Assert command success (and include stderr) or centralize this in a helper. Also consider applying the same check to the other silent_command("git")...output().unwrap() usages in src-tauri/tests/integration_git.rs.

Proposed fix
+fn run_git_checked(dir: &std::path::Path, args: &[&str]) {
+	let output = silent_command("git")
+		.args(args)
+		.current_dir(dir)
+		.output()
+		.expect("spawn git");
+	assert!(
+		output.status.success(),
+		"git {:?} failed: {}",
+		args,
+		String::from_utf8_lossy(&output.stderr)
+	);
+}
+
 pub fn create_temp_git_repo() -> PathBuf {
 	let dir = std::env::temp_dir()
 		.join(format!("2code-integ-{}", uuid::Uuid::new_v4()));
 	std::fs::create_dir_all(&dir).unwrap();
-	silent_command("git")
-		.args(["init"])
-		.current_dir(&dir)
-		.output()
-		.unwrap();
-	silent_command("git")
-		.args(["config", "user.email", "test@test.com"])
-		.current_dir(&dir)
-		.output()
-		.unwrap();
-	silent_command("git")
-		.args(["config", "user.name", "Test User"])
-		.current_dir(&dir)
-		.output()
-		.unwrap();
+	run_git_checked(&dir, &["init"]);
+	run_git_checked(&dir, &["config", "user.email", "test@test.com"]);
+	run_git_checked(&dir, &["config", "user.name", "Test User"]);
 	dir
 }
@@
-	silent_command("git")
-		.args(["add", filename])
-		.current_dir(dir)
-		.output()
-		.unwrap();
-	silent_command("git")
-		.args(["commit", "-m", msg])
-		.current_dir(dir)
-		.output()
-		.unwrap();
+	run_git_checked(dir, &["add", filename]);
+	run_git_checked(dir, &["commit", "-m", msg]);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tests/common/mod.rs` around lines 30 - 44, The git command
invocations using silent_command(...).output().unwrap() do not check the process
exit status; modify those calls (the silent_command("git") sequences) to assert
that output.status.success() and include output.stderr (as UTF-8) in the failure
message, or factor this into a small helper like assert_command_success(output,
&cmd_args) that panics with stderr when status is non-success; apply the same
check/helper to the other silent_command("git") usages (including those
referenced in integration_git.rs) so every git invocation fails fast with stderr
shown.
src-tauri/tests/integration_git.rs (1)

38-42: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Check git exit status for direct subprocess calls in tests.

Lines 38, 275, 280, 388, 395, and 436 run git commands with .output().unwrap() but never check status.success(). A non-zero exit code is silently ignored, potentially masking git failures or leaving tests in unexpected states.

Proposed fix pattern
-	let head = silent_command("git")
+	let head = silent_command("git")
 		.args(["rev-parse", "HEAD"])
 		.current_dir(&dir)
 		.output()
 		.unwrap();
+	assert!(
+		head.status.success(),
+		"git rev-parse failed: {}",
+		String::from_utf8_lossy(&head.stderr)
+	);

Apply the same status assertion pattern (or a shared helper) to all git invocations in this file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/tests/integration_git.rs` around lines 38 - 42, Multiple test git
invocations use silent_command(...).args(...).current_dir(...).output().unwrap()
and ignore the subprocess exit code; capture the Output result (calling it e.g.
out) and assert the command succeeded by checking out.status.success() (or use
out.status and assert with a descriptive message including out.stderr/stdout)
for each occurrence of silent_command(...) in this file (including the
add/commit/push variants), so failures don't get silently ignored.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src-tauri/tests/common/mod.rs`:
- Around line 30-44: The git command invocations using
silent_command(...).output().unwrap() do not check the process exit status;
modify those calls (the silent_command("git") sequences) to assert that
output.status.success() and include output.stderr (as UTF-8) in the failure
message, or factor this into a small helper like assert_command_success(output,
&cmd_args) that panics with stderr when status is non-success; apply the same
check/helper to the other silent_command("git") usages (including those
referenced in integration_git.rs) so every git invocation fails fast with stderr
shown.

In `@src-tauri/tests/integration_git.rs`:
- Around line 38-42: Multiple test git invocations use
silent_command(...).args(...).current_dir(...).output().unwrap() and ignore the
subprocess exit code; capture the Output result (calling it e.g. out) and assert
the command succeeded by checking out.status.success() (or use out.status and
assert with a descriptive message including out.stderr/stdout) for each
occurrence of silent_command(...) in this file (including the add/commit/push
variants), so failures don't get silently ignored.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8f91f8b2-4f27-487e-98f5-8144c439a9ca

📥 Commits

Reviewing files that changed from the base of the PR and between 3b7cd03 and a844558.

⛔ Files ignored due to path filters (1)
  • src/generated/types.ts is excluded by !**/generated/**
📒 Files selected for processing (10)
  • messages/en.json
  • messages/zh.json
  • src-tauri/src/handler/topbar.rs
  • src-tauri/src/lib.rs
  • src-tauri/tests/common/mod.rs
  • src-tauri/tests/integration_git.rs
  • src/features/projects/FileTreePanel.tsx
  • src/features/terminal/Terminal.tsx
  • src/features/watcher/fileWatcher.test.ts
  • src/shared/lib/queryKeys.test.ts
✅ Files skipped from review due to trivial changes (3)
  • src/shared/lib/queryKeys.test.ts
  • messages/zh.json
  • src/features/terminal/Terminal.tsx

@nothingness0db
Copy link
Copy Markdown
Contributor Author

已 merge 最新 dev(commit a844558),CI 全绿。

合并过程的一个决策点想 surface 一下:上游新增的 command_without_windows_console helper 和我们之前的 silent_command 是同一个功能(Windows 下 hide console,其他平台 noop)。merge 时我保留了 silent_command(名字短一些),把上游 auto-merge 进来的两个测试文件(tests/common/mod.rstests/integration_git.rs)也改成了这个名字。如果你更想跟上游统一用 command_without_windows_console,告诉我一下,是个全文件 rename,几分钟的事。

@netlify
Copy link
Copy Markdown

netlify Bot commented May 30, 2026

Deploy Preview for grand-selkie-225f87 failed. Why did it fail? →

Name Link
🔨 Latest commit 37fd8f6
🔍 Latest deploy log https://app.netlify.com/projects/grand-selkie-225f87/deploys/6a1a4b686a7112000719cce7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants