mirror of
https://github.com/openai/codex.git
synced 2026-11-13 22:47:20 +00:00
Render turn diffs for foreign environment paths (#34654)
## Why Turn diffs need to render paths from remote environments whose path convention may differ from the Codex host. ## What changed - Preserve `PathUri` values through applied patch deltas, display-root discovery, and turn-diff tracking. - Add host-independent relative-path rendering and normalize Windows drive-letter case in `PathUri`. - Render paths relative to each environment's repository root while keeping Git diff headers slash-separated. ## Testing - Cover POSIX, Windows, UNC, encoded-separator, and opaque URI relative paths. - Verify an applied patch in a remote Windows working directory emits a portable unified diff. GitOrigin-RevId: 526f70ae36a40627de5496d375310d12295b69bb
This commit is contained in:
1 parent
9fce9e13fd
commit
1823c13771
11 files changed
+303
-95
No files matched your search
@@ -38,8 +38,9 @@ const BAD_PATH_URI_PREFIX: &str = "file:///%00/bad/path/";
|
||||
/// created by [`Self::from_abs_path`] are opaque to these lexical operations.
|
||||
///
|
||||
/// `file:` paths retain their URI spelling so they can be parsed independently
|
||||
/// of the current host. A local POSIX `file:` URI can also retain
|
||||
/// percent-encoded non-UTF-8 bytes for lossless native round trips.
|
||||
/// of the current host, except that Windows drive letters are canonicalized to
|
||||
/// uppercase. A local POSIX `file:` URI can also retain percent-encoded non-UTF-8
|
||||
/// bytes for lossless native round trips.
|
||||
///
|
||||
/// Like [VS Code resources], path operations use `/` URI separators on every
|
||||
/// host. Lexical path operations preserve a URL authority without interpreting
|
||||
@@ -281,6 +282,43 @@ impl PathUri {
|
||||
path_segments.starts_with(&base_segments)
|
||||
}
|
||||
|
||||
/// Returns the decoded relative path from `base` to this URI.
|
||||
///
|
||||
/// The result uses the separators of the inferred path convention,
|
||||
/// independently of the current host. Both URIs must use the same inferred
|
||||
/// path convention and authority, and this URI must be lexically equal to
|
||||
/// or below `base`. Percent-encoded native path separators fail closed.
|
||||
/// Opaque fallback URIs created by [`Self::from_abs_path`] are only relative
|
||||
/// to themselves.
|
||||
pub fn relative_path_from(&self, base: &Self) -> Option<String> {
|
||||
if self == base {
|
||||
return Some(String::new());
|
||||
}
|
||||
if decode_bad_path_uri(&self.0).is_some()
|
||||
|| decode_bad_path_uri(&base.0).is_some()
|
||||
|| self.0.host_str() != base.0.host_str()
|
||||
|| self.infer_path_convention() != base.infer_path_convention()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let convention = self.infer_path_convention()?;
|
||||
let path_segments = containment_path_segments(&self.0, convention)?;
|
||||
let base_segments = containment_path_segments(&base.0, convention)?;
|
||||
let relative_segments = path_segments.strip_prefix(base_segments.as_slice())?;
|
||||
let separator = match convention {
|
||||
PathConvention::Posix => "/",
|
||||
PathConvention::Windows => "\\",
|
||||
};
|
||||
Some(
|
||||
relative_segments
|
||||
.iter()
|
||||
.map(|segment| decode_uri_path(segment))
|
||||
.collect::<Vec<_>>()
|
||||
.join(separator),
|
||||
)
|
||||
}
|
||||
|
||||
/// Lexically resolves native absolute or relative path text against this URI.
|
||||
///
|
||||
/// Path text is interpreted using the POSIX or Windows convention inferred
|
||||
@@ -453,6 +491,7 @@ impl TryFrom<Url> for PathUri {
|
||||
}
|
||||
validate_file_url(&url)?;
|
||||
let url = without_localhost_authority(url);
|
||||
let url = with_normalized_windows_drive_letter(url);
|
||||
Ok(Self(url))
|
||||
}
|
||||
}
|
||||
@@ -524,6 +563,32 @@ fn without_localhost_authority(mut url: Url) -> Url {
|
||||
url
|
||||
}
|
||||
|
||||
fn with_normalized_windows_drive_letter(mut url: Url) -> Url {
|
||||
if url.host_str().is_some() {
|
||||
return url;
|
||||
}
|
||||
|
||||
let path = url.path();
|
||||
let Some(drive_start) = path.bytes().position(|byte| byte != b'/') else {
|
||||
return url;
|
||||
};
|
||||
let Some(drive) = path[drive_start..].split('/').next() else {
|
||||
return url;
|
||||
};
|
||||
if !is_windows_drive_uri_segment(drive) || drive.as_bytes()[0].is_ascii_uppercase() {
|
||||
return url;
|
||||
}
|
||||
|
||||
let drive_letter = char::from(drive.as_bytes()[0]).to_ascii_uppercase();
|
||||
let normalized_path = format!(
|
||||
"{}{drive_letter}{}",
|
||||
&path[..drive_start],
|
||||
&path[drive_start + 1..]
|
||||
);
|
||||
url.set_path(&normalized_path);
|
||||
url
|
||||
}
|
||||
|
||||
/// Percent-decodes a URI path when it is valid UTF-8.
|
||||
///
|
||||
/// `file:` URLs may contain encoded non-UTF-8 bytes. In that case the encoded
|
||||
|
||||
Reference in new issue
Block a user