mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 01:16:18 +04:00
feat(ui): file encoding in statusline (#1355)
* feat(ui): file encoding in statusline Display file encoding in statusline if the encoding isn't UTF-8. * Re-export encoding_rs from core From there it can be imported by other mods that rely on it.
This commit is contained in:
parent
ec878e4011
commit
4b0b1a5657
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -370,6 +370,7 @@ version = "0.5.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"encoding_rs",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
"helix-syntax",
|
"helix-syntax",
|
||||||
"log",
|
"log",
|
||||||
@ -471,7 +472,6 @@ dependencies = [
|
|||||||
"chardetng",
|
"chardetng",
|
||||||
"clipboard-win",
|
"clipboard-win",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"encoding_rs",
|
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"helix-core",
|
"helix-core",
|
||||||
"helix-lsp",
|
"helix-lsp",
|
||||||
|
@ -35,6 +35,7 @@ toml = "0.5"
|
|||||||
similar = "2.1"
|
similar = "2.1"
|
||||||
|
|
||||||
etcetera = "0.3"
|
etcetera = "0.3"
|
||||||
|
encoding_rs = "0.8"
|
||||||
|
|
||||||
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
|
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
pub use encoding_rs as encoding;
|
||||||
|
|
||||||
pub mod auto_pairs;
|
pub mod auto_pairs;
|
||||||
pub mod chars;
|
pub mod chars;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
use helix_core::{
|
use helix_core::{
|
||||||
coords_at_pos,
|
coords_at_pos, encoding,
|
||||||
graphemes::{ensure_grapheme_boundary_next, next_grapheme_boundary, prev_grapheme_boundary},
|
graphemes::{ensure_grapheme_boundary_next, next_grapheme_boundary, prev_grapheme_boundary},
|
||||||
movement::Direction,
|
movement::Direction,
|
||||||
syntax::{self, HighlightEvent},
|
syntax::{self, HighlightEvent},
|
||||||
@ -621,6 +621,13 @@ pub fn render_statusline(
|
|||||||
base_style,
|
base_style,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let enc = doc.encoding();
|
||||||
|
if enc != encoding::UTF_8 {
|
||||||
|
right_side_text
|
||||||
|
.0
|
||||||
|
.push(Span::styled(format!(" {} ", enc.name()), base_style));
|
||||||
|
}
|
||||||
|
|
||||||
// Render to the statusline.
|
// Render to the statusline.
|
||||||
surface.set_spans(
|
surface.set_spans(
|
||||||
viewport.x
|
viewport.x
|
||||||
|
@ -29,7 +29,6 @@ futures-util = { version = "0.3", features = ["std", "async-await"], default-fea
|
|||||||
|
|
||||||
slotmap = "1"
|
slotmap = "1"
|
||||||
|
|
||||||
encoding_rs = "0.8"
|
|
||||||
chardetng = "0.1"
|
chardetng = "0.1"
|
||||||
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use helix_core::{
|
use helix_core::{
|
||||||
|
encoding,
|
||||||
history::History,
|
history::History,
|
||||||
indent::{auto_detect_indent_style, IndentStyle},
|
indent::{auto_detect_indent_style, IndentStyle},
|
||||||
line_ending::auto_detect_line_ending,
|
line_ending::auto_detect_line_ending,
|
||||||
@ -74,7 +75,7 @@ pub struct Document {
|
|||||||
pub(crate) selections: HashMap<ViewId, Selection>,
|
pub(crate) selections: HashMap<ViewId, Selection>,
|
||||||
|
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
encoding: &'static encoding_rs::Encoding,
|
encoding: &'static encoding::Encoding,
|
||||||
|
|
||||||
/// Current editing mode.
|
/// Current editing mode.
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
@ -143,8 +144,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
/// be used to override encoding auto-detection.
|
/// be used to override encoding auto-detection.
|
||||||
pub fn from_reader<R: std::io::Read + ?Sized>(
|
pub fn from_reader<R: std::io::Read + ?Sized>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
encoding: Option<&'static encoding_rs::Encoding>,
|
encoding: Option<&'static encoding::Encoding>,
|
||||||
) -> Result<(Rope, &'static encoding_rs::Encoding), Error> {
|
) -> Result<(Rope, &'static encoding::Encoding), Error> {
|
||||||
// These two buffers are 8192 bytes in size each and are used as
|
// These two buffers are 8192 bytes in size each and are used as
|
||||||
// intermediaries during the decoding process. Text read into `buf`
|
// intermediaries during the decoding process. Text read into `buf`
|
||||||
// from `reader` is decoded into `buf_out` as UTF-8. Once either
|
// from `reader` is decoded into `buf_out` as UTF-8. Once either
|
||||||
@ -212,11 +213,11 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
|
|||||||
total_read += read;
|
total_read += read;
|
||||||
total_written += written;
|
total_written += written;
|
||||||
match result {
|
match result {
|
||||||
encoding_rs::CoderResult::InputEmpty => {
|
encoding::CoderResult::InputEmpty => {
|
||||||
debug_assert_eq!(slice.len(), total_read);
|
debug_assert_eq!(slice.len(), total_read);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
encoding_rs::CoderResult::OutputFull => {
|
encoding::CoderResult::OutputFull => {
|
||||||
debug_assert!(slice.len() > total_read);
|
debug_assert!(slice.len() > total_read);
|
||||||
builder.append(&buf_str[..total_written]);
|
builder.append(&buf_str[..total_written]);
|
||||||
total_written = 0;
|
total_written = 0;
|
||||||
@ -251,7 +252,7 @@ pub fn from_reader<R: std::io::Read + ?Sized>(
|
|||||||
/// replacement characters may appear in the encoded text.
|
/// replacement characters may appear in the encoded text.
|
||||||
pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
|
pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
|
||||||
writer: &'a mut W,
|
writer: &'a mut W,
|
||||||
encoding: &'static encoding_rs::Encoding,
|
encoding: &'static encoding::Encoding,
|
||||||
rope: &'a Rope,
|
rope: &'a Rope,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Text inside a `Rope` is stored as non-contiguous blocks of data called
|
// Text inside a `Rope` is stored as non-contiguous blocks of data called
|
||||||
@ -286,12 +287,12 @@ pub async fn to_writer<'a, W: tokio::io::AsyncWriteExt + Unpin + ?Sized>(
|
|||||||
total_read += read;
|
total_read += read;
|
||||||
total_written += written;
|
total_written += written;
|
||||||
match result {
|
match result {
|
||||||
encoding_rs::CoderResult::InputEmpty => {
|
encoding::CoderResult::InputEmpty => {
|
||||||
debug_assert_eq!(chunk.len(), total_read);
|
debug_assert_eq!(chunk.len(), total_read);
|
||||||
debug_assert!(buf.len() >= total_written);
|
debug_assert!(buf.len() >= total_written);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
encoding_rs::CoderResult::OutputFull => {
|
encoding::CoderResult::OutputFull => {
|
||||||
debug_assert!(chunk.len() > total_read);
|
debug_assert!(chunk.len() > total_read);
|
||||||
writer.write_all(&buf[..total_written]).await?;
|
writer.write_all(&buf[..total_written]).await?;
|
||||||
total_written = 0;
|
total_written = 0;
|
||||||
@ -322,8 +323,8 @@ fn take_with<T, F>(mut_ref: &mut T, f: F)
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
impl Document {
|
impl Document {
|
||||||
pub fn from(text: Rope, encoding: Option<&'static encoding_rs::Encoding>) -> Self {
|
pub fn from(text: Rope, encoding: Option<&'static encoding::Encoding>) -> Self {
|
||||||
let encoding = encoding.unwrap_or(encoding_rs::UTF_8);
|
let encoding = encoding.unwrap_or(encoding::UTF_8);
|
||||||
let changes = ChangeSet::new(&text);
|
let changes = ChangeSet::new(&text);
|
||||||
let old_state = None;
|
let old_state = None;
|
||||||
|
|
||||||
@ -356,7 +357,7 @@ pub fn from(text: Rope, encoding: Option<&'static encoding_rs::Encoding>) -> Sel
|
|||||||
/// overwritten with the `encoding` parameter.
|
/// overwritten with the `encoding` parameter.
|
||||||
pub fn open(
|
pub fn open(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
encoding: Option<&'static encoding_rs::Encoding>,
|
encoding: Option<&'static encoding::Encoding>,
|
||||||
theme: Option<&Theme>,
|
theme: Option<&Theme>,
|
||||||
config_loader: Option<&syntax::Loader>,
|
config_loader: Option<&syntax::Loader>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
@ -366,7 +367,7 @@ pub fn open(
|
|||||||
std::fs::File::open(path).context(format!("unable to open {:?}", path))?;
|
std::fs::File::open(path).context(format!("unable to open {:?}", path))?;
|
||||||
from_reader(&mut file, encoding)?
|
from_reader(&mut file, encoding)?
|
||||||
} else {
|
} else {
|
||||||
let encoding = encoding.unwrap_or(encoding_rs::UTF_8);
|
let encoding = encoding.unwrap_or(encoding::UTF_8);
|
||||||
(Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding)
|
(Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -548,7 +549,7 @@ pub fn reload(&mut self, view_id: ViewId) -> Result<(), Error> {
|
|||||||
|
|
||||||
/// Sets the [`Document`]'s encoding with the encoding correspondent to `label`.
|
/// Sets the [`Document`]'s encoding with the encoding correspondent to `label`.
|
||||||
pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
|
pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
|
||||||
match encoding_rs::Encoding::for_label(label.as_bytes()) {
|
match encoding::Encoding::for_label(label.as_bytes()) {
|
||||||
Some(encoding) => self.encoding = encoding,
|
Some(encoding) => self.encoding = encoding,
|
||||||
None => return Err(anyhow::anyhow!("unknown encoding")),
|
None => return Err(anyhow::anyhow!("unknown encoding")),
|
||||||
}
|
}
|
||||||
@ -556,7 +557,7 @@ pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`Document`]'s current encoding.
|
/// Returns the [`Document`]'s current encoding.
|
||||||
pub fn encoding(&self) -> &'static encoding_rs::Encoding {
|
pub fn encoding(&self) -> &'static encoding::Encoding {
|
||||||
self.encoding
|
self.encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,7 +1124,7 @@ fn test_line_ending() {
|
|||||||
|
|
||||||
macro_rules! test_decode {
|
macro_rules! test_decode {
|
||||||
($label:expr, $label_override:expr) => {
|
($label:expr, $label_override:expr) => {
|
||||||
let encoding = encoding_rs::Encoding::for_label($label_override.as_bytes()).unwrap();
|
let encoding = encoding::Encoding::for_label($label_override.as_bytes()).unwrap();
|
||||||
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/encoding");
|
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/encoding");
|
||||||
let path = base_path.join(format!("{}_in.txt", $label));
|
let path = base_path.join(format!("{}_in.txt", $label));
|
||||||
let ref_path = base_path.join(format!("{}_in_ref.txt", $label));
|
let ref_path = base_path.join(format!("{}_in_ref.txt", $label));
|
||||||
@ -1142,7 +1143,7 @@ macro_rules! test_decode {
|
|||||||
|
|
||||||
macro_rules! test_encode {
|
macro_rules! test_encode {
|
||||||
($label:expr, $label_override:expr) => {
|
($label:expr, $label_override:expr) => {
|
||||||
let encoding = encoding_rs::Encoding::for_label($label_override.as_bytes()).unwrap();
|
let encoding = encoding::Encoding::for_label($label_override.as_bytes()).unwrap();
|
||||||
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/encoding");
|
let base_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/encoding");
|
||||||
let path = base_path.join(format!("{}_out.txt", $label));
|
let path = base_path.join(format!("{}_out.txt", $label));
|
||||||
let ref_path = base_path.join(format!("{}_out_ref.txt", $label));
|
let ref_path = base_path.join(format!("{}_out_ref.txt", $label));
|
||||||
|
Loading…
Reference in New Issue
Block a user