mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-13 08:09:25 +00:00
Git blobs were always decoded as UTF-8, so files in GBK or other legacy encodings showed every line as changed in the gutter, diff, blame and commit views, and staging/committing could re-encode them wrongly. Blob text is now decoded and encoded with the file's encoding: the open document's encoding, else detection on the working file with the project default as fallback, else detection on the blob. Covers line hunks, file-at-revision, blame, stage patch/hunks, commit, conflict versions, diff text, and the agent worktree's file_at, partial commit and patch helpers. Text that cannot be represented in the target encoding is reported as an error instead of being written lossily. Fixes #243 未在 Windows 实机验证。
47 lines
1.6 KiB
Rust
47 lines
1.6 KiB
Rust
//! File content uses the document's encoding; Git metadata remains UTF-8.
|
|
use encoding_rs::{Encoding, UTF_8, UTF_16BE, UTF_16LE};
|
|
use ide_core::{IdeError, IdeResult};
|
|
use std::borrow::Cow;
|
|
|
|
pub(crate) fn has_bom(bytes: &[u8], encoding: &'static Encoding) -> bool {
|
|
Encoding::for_bom(bytes).is_some_and(|(enc, _)| enc == encoding)
|
|
}
|
|
|
|
pub(crate) fn decode<'a>(bytes: &'a [u8], encoding: &'static Encoding) -> Cow<'a, str> {
|
|
let body = match Encoding::for_bom(bytes) {
|
|
Some((enc, len)) if enc == encoding => &bytes[len..],
|
|
_ => bytes,
|
|
};
|
|
encoding.decode_without_bom_handling(body).0
|
|
}
|
|
|
|
pub(crate) fn is_binary(bytes: &[u8], encoding: &'static Encoding) -> bool {
|
|
encoding != UTF_16LE && encoding != UTF_16BE && bytes.contains(&0)
|
|
}
|
|
|
|
pub(crate) fn encode(text: &str, encoding: &'static Encoding, bom: bool) -> IdeResult<Vec<u8>> {
|
|
let mut out = Vec::new();
|
|
if encoding == UTF_16LE || encoding == UTF_16BE {
|
|
let le = encoding == UTF_16LE;
|
|
if bom {
|
|
out.extend_from_slice(if le { &[0xff, 0xfe] } else { &[0xfe, 0xff] });
|
|
}
|
|
for unit in text.encode_utf16() {
|
|
out.extend_from_slice(&if le { unit.to_le_bytes() } else { unit.to_be_bytes() });
|
|
}
|
|
} else {
|
|
let (bytes, _, errors) = encoding.encode(text);
|
|
if errors {
|
|
return Err(IdeError::invalid(format!(
|
|
"text contains characters not representable in {}",
|
|
encoding.name()
|
|
)));
|
|
}
|
|
if bom && encoding == UTF_8 {
|
|
out.extend_from_slice(&[0xef, 0xbb, 0xbf]);
|
|
}
|
|
out.extend_from_slice(&bytes);
|
|
}
|
|
Ok(out)
|
|
}
|