fix(natives): resolved bash for extensionless shell rc files
blockRangeAt inferred no language for files like `zshrc`/`.zshrc`/`.bashrc` because `Path::extension` returns `None` for bare and dotfile names alike, so the edit tool's `replace block` / `insert after block` ops were permanently unresolvable on them — an agent retrying the block op would loop on the same "could not resolve a syntactic block" error. from_extension now maps known shell rc/profile basenames (zshrc, zshenv, zprofile, zlogin, zlogout, zsh_aliases, bashrc, bash_profile, bash_login, bash_logout, bash_aliases, profile, kshrc, mkshrc, shrc; with or without a leading dot) to the bash grammar, alongside the existing Makefile/Dockerfile basename handling. Adds a block-resolution regression test over a zsh `if [[ … ]]; then … fi` block in `zshrc`/`.zshrc`/`.bashrc`.
This commit is contained in:
@@ -298,6 +298,19 @@ mod tests {
|
||||
assert_eq!(resolve(TS_EXAMPLE, "x.unknownext", 2), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_zsh_if_block_in_extensionless_rc_file() {
|
||||
// Regression: an extensionless shell rc file (`zshrc`/`.zshrc`) must
|
||||
// infer the bash grammar so `replace block` / `insert after block`
|
||||
// works. Previously `Path::extension` returned `None`, leaving block
|
||||
// ops permanently unresolvable on these files.
|
||||
let code = "ZSH_COMPDUMP=x\nif [[ -f \"$ZSH_COMPDUMP\" ]]; then\n compinit -C\nelse\n compinit\nfi\n";
|
||||
let span = Some(BlockRange { start_line: 2, end_line: 6 });
|
||||
assert_eq!(resolve(code, "modules/zsh/zshrc", 2), span);
|
||||
assert_eq!(resolve(code, ".zshrc", 2), span);
|
||||
assert_eq!(resolve(code, "/home/u/.bashrc", 2), span);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolves_top_level_python_def() {
|
||||
let code = "x = 1\ndef greet():\n return 1\n";
|
||||
|
||||
@@ -627,6 +627,31 @@ fn from_extension(path: &Path) -> Option<SupportLang> {
|
||||
return Some(SupportLang::Dockerfile);
|
||||
}
|
||||
|
||||
// Extensionless shell rc/profile files. `Path::extension` returns `None`
|
||||
// for both bare (`zshrc`) and dotfile (`.zshrc`) forms, so they would
|
||||
// otherwise resolve to no language and disable block-aware ops on them.
|
||||
let stem = name.strip_prefix('.').unwrap_or(name);
|
||||
if matches!(
|
||||
stem,
|
||||
"zshrc"
|
||||
| "zshenv"
|
||||
| "zprofile"
|
||||
| "zlogin"
|
||||
| "zlogout"
|
||||
| "zsh_aliases"
|
||||
| "bashrc"
|
||||
| "bash_profile"
|
||||
| "bash_login"
|
||||
| "bash_logout"
|
||||
| "bash_aliases"
|
||||
| "profile"
|
||||
| "kshrc"
|
||||
| "mkshrc"
|
||||
| "shrc"
|
||||
) {
|
||||
return Some(SupportLang::Bash);
|
||||
}
|
||||
|
||||
let ext = path.extension()?.to_str()?;
|
||||
SupportLang::all_langs()
|
||||
.iter()
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `blockRangeAt` (and thus the edit tool's `replace block` / `insert after block` ops) failing on extensionless shell rc/profile files. `Path::extension` returns `None` for both bare (`zshrc`) and dotfile (`.zshrc`, `.bashrc`) forms, so language inference fell through to "unrecognized" and block resolution was permanently unresolvable on those files — an agent retrying the block op would loop on the same error. Known shell rc/profile basenames (`zshrc`/`zshenv`/`zprofile`/`zlogin`/`zlogout`/`bashrc`/`bash_profile`/`bash_login`/`bash_logout`/`bash_aliases`/`profile`/`kshrc`/`mkshrc`/`shrc`, with or without a leading dot) now resolve to the bash grammar.
|
||||
|
||||
## [15.11.0] - 2026-06-10
|
||||
### Breaking Changes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user