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:
Matouš Dzivjak 2021-12-25 16:10:46 +01:00 committed by GitHub
parent ec878e4011
commit 4b0b1a5657
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 19 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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;

View File

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

View File

@ -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"] }

View File

@ -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));