Skip to content

feat(cd): support ~ expansion to home directory#15

Merged
Pawank06 merged 5 commits intomainfrom
feature/cd-home-dir
Jan 9, 2026
Merged

feat(cd): support ~ expansion to home directory#15
Pawank06 merged 5 commits intomainfrom
feature/cd-home-dir

Conversation

@Pawank06
Copy link
Owner

@Pawank06 Pawank06 commented Jan 9, 2026

summary

  • add support for ~ expansion in the cd builtin
  • resolve home directory from the user environment

notes

  • improves usability of directory navigation
  • aligns cd behavior with standard unix shells

@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

Warning

Rate limit exceeded

@Pawank06 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 1 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e834970 and 24adfa4.

📒 Files selected for processing (1)
  • src/main.rs
📝 Walkthrough

Walkthrough

Adds tilde (~/~/...) expansion to the cd handling using HOME, performs pre-checks for path existence and directory status for non-tilde targets, and refines error messages for PATH/HOME read failures, non-existent targets, non-directories, and chdir failures.

Changes

Cohort / File(s) Summary
CD Command Enhancement
src/main.rs
Implements ~ and ~/... expansion via HOME; on HOME read failure prints a specific error. For non-tilde paths, adds exists and is_dir() checks before set_current_dir(). Updates error text to reference expanded/full paths and distinguishes failure reasons (missing, not a directory, chdir error).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Shell
    participant Env as Environment (HOME)
    participant FS as Filesystem

    User->>Shell: run `cd <target>`
    Shell->>Shell: detect if target == "~" or startsWith("~/")
    alt tilde path
        Shell->>Env: read HOME
        Env-->>Shell: HOME value / error
        opt HOME success
            Shell->>FS: attempt chdir(expanded_path)
            FS-->>Shell: success / failure
        end
    else non-tilde path
        Shell->>FS: check exists(target)
        FS-->>Shell: exists / missing
        opt exists
            Shell->>FS: check is_dir(target)
            FS-->>Shell: is_dir / not_dir
            opt is_dir
                Shell->>FS: attempt chdir(target)
                FS-->>Shell: success / failure
            end
        end
    end
    Shell->>User: print success or specific error message
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I sniffed the HOME and stretched my tail,

A tilde trail beneath the pale moonlight,
I checked each step before I leapt,
No wrong turns in the midnight sweep,
I hopped in safe and snug tonight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cd): support ~ expansion to home directory' accurately reflects the main change: adding tilde expansion support to the cd builtin command.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@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: 1

🤖 Fix all issues with AI agents
In @src/main.rs:
- Around line 88-96: The current tilde handling only checks for path == "~" and
should instead detect paths starting with "~" and replace the leading "~" with
the HOME env value before calling env::set_current_dir; update the logic around
the variable path to if path.starts_with('~') { let home = env::var("HOME")?;
let expanded = format!("{}{}", home, &path[1..]);
env::set_current_dir(&expanded) ... } (use env::var("HOME") and
env::set_current_dir accordingly), and fix the error message text from "Couldn't
able to read env variable HOME: {}" to a grammatically correct message such as
"Could not read HOME environment variable: {}" while preserving existing error
handling for env::set_current_dir failures.
🧹 Nitpick comments (2)
src/main.rs (2)

92-92: Inconsistent error message format.

Line 92 (and line 104) are missing a colon between the path and error message, unlike lines 99 and 101 which follow the standard Unix format "cd: <path>: <error>".

♻️ Proposed fix for consistent formatting
-                                eprintln!("cd: {} {}", &val, e)
+                                eprintln!("cd: {}: {}", &val, e)

Also apply the same fix to line 104:

-                            eprintln!("cd: {} {}", path.display(), e);
+                            eprintln!("cd: {}: {}", full_path, e);

98-107: Good validation logic with pre-checks.

The pre-validation of path existence and directory status before attempting to change directory is good practice and provides clear user-facing error messages.


Optional: Use full_path for consistency in error message.

Line 104 uses path.display() while lines 99 and 101 use full_path. For consistency, consider using full_path on line 104 as well.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e2a9ea3 and 63e0822.

📒 Files selected for processing (1)
  • src/main.rs

src/main.rs Outdated
Comment on lines 88 to 96
if path == "~" {
match env::var("HOME") {
Ok(val) => {
if let Err(e) = env::set_current_dir(&val) {
eprintln!("cd: {} {}", &val, e)
}
}
Err(e) => eprintln!("Couldn't able to read env variable HOME: {}", e),
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incomplete tilde expansion: only handles bare ~, not ~/path.

Standard Unix shells expand ~ at the beginning of any path (e.g., ~/Documents, ~/.config), but this implementation only handles the exact string "~". This deviates from the PR objective to "align cd behavior with standard Unix shells."

Consider expanding any path that starts with ~:

🔧 Proposed fix to support full tilde expansion
-                if path == "~" {
+                let path_str = full_path.as_str();
+                if path_str == "~" || path_str.starts_with("~/") {
                     match env::var("HOME") {
                         Ok(val) => {
-                            if let Err(e) = env::set_current_dir(&val) {
+                            let expanded = if path_str == "~" {
+                                val.clone()
+                            } else {
+                                path_str.replacen("~", &val, 1)
+                            };
+                            if let Err(e) = env::set_current_dir(&expanded) {
-                                eprintln!("cd: {} {}", &val, e)
+                                eprintln!("cd: {}: {}", &expanded, e)
                             }
                         }
                         Err(e) => eprintln!("Couldn't able to read env variable HOME: {}", e),
                     }

Fix grammatical error in error message.

Line 95: "Couldn't able to read" is grammatically incorrect.

📝 Proposed fix
-                        Err(e) => eprintln!("Couldn't able to read env variable HOME: {}", e),
+                        Err(e) => eprintln!("cd: Unable to read HOME environment variable: {}", e),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if path == "~" {
match env::var("HOME") {
Ok(val) => {
if let Err(e) = env::set_current_dir(&val) {
eprintln!("cd: {} {}", &val, e)
}
}
Err(e) => eprintln!("Couldn't able to read env variable HOME: {}", e),
}
if path == "~" {
match env::var("HOME") {
Ok(val) => {
if let Err(e) = env::set_current_dir(&val) {
eprintln!("cd: {} {}", &val, e)
}
}
Err(e) => eprintln!("cd: Unable to read HOME environment variable: {}", e),
}
🤖 Prompt for AI Agents
In @src/main.rs around lines 88 - 96, The current tilde handling only checks for
path == "~" and should instead detect paths starting with "~" and replace the
leading "~" with the HOME env value before calling env::set_current_dir; update
the logic around the variable path to if path.starts_with('~') { let home =
env::var("HOME")?; let expanded = format!("{}{}", home, &path[1..]);
env::set_current_dir(&expanded) ... } (use env::var("HOME") and
env::set_current_dir accordingly), and fix the error message text from "Couldn't
able to read env variable HOME: {}" to a grammatically correct message such as
"Could not read HOME environment variable: {}" while preserving existing error
handling for env::set_current_dir failures.

Copy link

@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: 0

Caution

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

⚠️ Outside diff range comments (1)
src/main.rs (1)

33-43: type should include cd as a builtin.
Currently cd is implemented as a builtin (Line 79+) but type won’t report it as one.

Proposed fix
-                let builtin = ["exit", "echo", "type", "pwd"];
+                let builtin = ["exit", "echo", "type", "pwd", "cd"];
🧹 Nitpick comments (1)
src/main.rs (1)

87-112: Prefer PathBuf + strip_prefix (and var_os) over replacen for ~ expansion.
Today this works for "~" / "~/", but string replacement is easy to regress, and env::var("HOME") fails for non‑UTF8 HOME even though set_current_dir can handle it.

Proposed refactor (safer expansion + consistent error formatting)
 use std::env;
 use std::fs;
 use std::io::{self, Write};
 use std::os::unix::fs::PermissionsExt;
 use std::os::unix::process::CommandExt;
 use std::path::Path;
+use std::path::PathBuf;
 use std::process::Command;

@@
                 let args = &parts[1..];
                 let full_path = args.join(" ");
                 let path = Path::new(&full_path);
                 let path_str = full_path.as_str();
                 if path_str == "~" || path_str.starts_with("~/") {
-                    match env::var("HOME") {
-                        Ok(val) => {
-                            let expanded = if path_str == "~" {
-                                val.clone()
-                            } else {
-                                path_str.replacen("~", &val, 1)
-                            };
-
-                            if let Err(e) = env::set_current_dir(&expanded) {
-                                eprintln!("cd: {} {}", &expanded, e)
-                            }
-                        }
-                        Err(e) => eprintln!("cd: Unable to read HOME environment variable: {}", e),
-                    }
+                    match env::var_os("HOME") {
+                        Some(home) if !home.is_empty() => {
+                            let expanded: PathBuf = if path_str == "~" {
+                                home.into()
+                            } else {
+                                let suffix = path_str.strip_prefix("~/").unwrap();
+                                PathBuf::from(home).join(suffix)
+                            };
+
+                            if let Err(e) = env::set_current_dir(&expanded) {
+                                eprintln!("cd: {}: {}", expanded.display(), e);
+                            }
+                        }
+                        _ => eprintln!("cd: HOME is not set"),
+                    };
                 } else {
                     if !path.exists() {
-                        println!("cd: {}: No such file or directory", full_path);
+                        eprintln!("cd: {}: No such file or directory", full_path);
                     } else if !path.is_dir() {
-                        println!("cd: {}: Not a directory", full_path);
+                        eprintln!("cd: {}: Not a directory", full_path);
                     } else {
                         if let Err(e) = env::set_current_dir(&full_path) {
-                            eprintln!("cd: {} {}", path.display(), e);
+                            eprintln!("cd: {}: {}", path.display(), e);
                         }
                     }
                 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1778b0 and e834970.

📒 Files selected for processing (1)
  • src/main.rs
🔇 Additional comments (1)
src/main.rs (1)

44-72: Good: PATH read failure is now sent to stderr with clearer wording.
Line 71: switching to eprintln! is the right direction for error output.

@Pawank06 Pawank06 merged commit db60c54 into main Jan 9, 2026
2 checks passed
@Pawank06 Pawank06 deleted the feature/cd-home-dir branch January 9, 2026 16:11
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.

1 participant