Implement the actual encoding selector. There are currently only two encodings in the selector used as placeholders, but more will be added in the future. As of now, the encoding picker is not actually triggered.

This commit is contained in:
R Aadarsh 2025-08-23 20:03:26 +05:30
parent fae2f8ff1c
commit 5723987b59
10 changed files with 453 additions and 191 deletions

68
Cargo.lock generated
View file

@ -5194,6 +5194,70 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "encoding"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
dependencies = [
"encoding-index-japanese",
"encoding-index-korean",
"encoding-index-simpchinese",
"encoding-index-singlebyte",
"encoding-index-tradchinese",
]
[[package]]
name = "encoding-index-japanese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-korean"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-simpchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-singlebyte"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding-index-tradchinese"
version = "1.20141219.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
dependencies = [
"encoding_index_tests",
]
[[package]]
name = "encoding_index_tests"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
[[package]]
name = "encoding_rs"
version = "0.8.35"
@ -5207,9 +5271,9 @@ dependencies = [
name = "encodings"
version = "0.1.0"
dependencies = [
"editor",
"fuzzy",
"gpui",
"language",
"picker",
"ui",
"util",
@ -6055,6 +6119,7 @@ dependencies = [
"async-trait",
"cocoa 0.26.0",
"collections",
"encoding",
"fsevent",
"futures 0.3.31",
"git",
@ -9035,6 +9100,7 @@ dependencies = [
"ctor",
"diffy",
"ec4rs",
"encoding",
"fs",
"futures 0.3.31",
"fuzzy",

View file

@ -238,7 +238,6 @@ activity_indicator = { path = "crates/activity_indicator" }
agent_ui = { path = "crates/agent_ui" }
agent_settings = { path = "crates/agent_settings" }
agent_servers = { path = "crates/agent_servers" }
ai = { path = "crates/ai" }
ai_onboarding = { path = "crates/ai_onboarding" }
anthropic = { path = "crates/anthropic" }
askpass = { path = "crates/askpass" }
@ -250,7 +249,6 @@ assistant_tool = { path = "crates/assistant_tool" }
assistant_tools = { path = "crates/assistant_tools" }
audio = { path = "crates/audio" }
auto_update = { path = "crates/auto_update" }
auto_update_helper = { path = "crates/auto_update_helper" }
auto_update_ui = { path = "crates/auto_update_ui" }
aws_http_client = { path = "crates/aws_http_client" }
bedrock = { path = "crates/bedrock" }
@ -264,7 +262,6 @@ clock = { path = "crates/clock" }
cloud_api_client = { path = "crates/cloud_api_client" }
cloud_api_types = { path = "crates/cloud_api_types" }
cloud_llm_client = { path = "crates/cloud_llm_client" }
collab = { path = "crates/collab" }
collab_ui = { path = "crates/collab_ui" }
collections = { path = "crates/collections" }
command_palette = { path = "crates/command_palette" }
@ -348,8 +345,6 @@ outline_panel = { path = "crates/outline_panel" }
panel = { path = "crates/panel" }
paths = { path = "crates/paths" }
picker = { path = "crates/picker" }
plugin = { path = "crates/plugin" }
plugin_macros = { path = "crates/plugin_macros" }
prettier = { path = "crates/prettier" }
settings_profile_selector = { path = "crates/settings_profile_selector" }
project = { path = "crates/project" }
@ -370,7 +365,6 @@ rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" }
rules_library = { path = "crates/rules_library" }
search = { path = "crates/search" }
semantic_index = { path = "crates/semantic_index" }
semantic_version = { path = "crates/semantic_version" }
session = { path = "crates/session" }
settings = { path = "crates/settings" }
@ -381,7 +375,6 @@ snippets_ui = { path = "crates/snippets_ui" }
sqlez = { path = "crates/sqlez" }
sqlez_macros = { path = "crates/sqlez_macros" }
story = { path = "crates/story" }
storybook = { path = "crates/storybook" }
streaming_diff = { path = "crates/streaming_diff" }
sum_tree = { path = "crates/sum_tree" }
supermaven = { path = "crates/supermaven" }
@ -397,7 +390,6 @@ terminal_view = { path = "crates/terminal_view" }
text = { path = "crates/text" }
theme = { path = "crates/theme" }
theme_extension = { path = "crates/theme_extension" }
theme_importer = { path = "crates/theme_importer" }
theme_selector = { path = "crates/theme_selector" }
time_format = { path = "crates/time_format" }
title_bar = { path = "crates/title_bar" }
@ -469,7 +461,6 @@ ciborium = "0.2"
circular-buffer = "1.0"
clap = { version = "4.4", features = ["derive"] }
cocoa = "0.26"
cocoa-foundation = "0.2.0"
convert_case = "0.8.0"
core-foundation = "0.10.0"
core-foundation-sys = "0.8.6"
@ -545,7 +536,6 @@ pet = { git = "https://github.com/microsoft/python-environment-tools.git", rev =
pet-conda = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-core = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-fs = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-pixi = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-poetry = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-reporter = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
portable-pty = "0.9.0"
@ -668,7 +658,6 @@ wasmtime = { version = "29", default-features = false, features = [
wasmtime-wasi = "29"
which = "6.0.0"
windows-core = "0.61"
wit-component = "0.221"
workspace-hack = "0.1.0"
yawc = "0.2.5"
zstd = "0.11"
@ -742,11 +731,7 @@ codegen-units = 16
[profile.dev.package]
taffy = { opt-level = 3 }
cranelift-codegen = { opt-level = 3 }
cranelift-codegen-meta = { opt-level = 3 }
cranelift-codegen-shared = { opt-level = 3 }
resvg = { opt-level = 3 }
rustybuzz = { opt-level = 3 }
ttf-parser = { opt-level = 3 }
wasmtime-cranelift = { opt-level = 3 }
wasmtime = { opt-level = 3 }
# Build single-source-file crates with cg=1 as it helps make `cargo build` of a whole workspace a bit faster
@ -756,7 +741,6 @@ breadcrumbs = { codegen-units = 1 }
collections = { codegen-units = 1 }
command_palette = { codegen-units = 1 }
command_palette_hooks = { codegen-units = 1 }
extension_cli = { codegen-units = 1 }
feature_flags = { codegen-units = 1 }
file_icons = { codegen-units = 1 }
fsevent = { codegen-units = 1 }

View file

@ -9,9 +9,9 @@ ui.workspace = true
workspace.workspace = true
gpui.workspace = true
picker.workspace = true
language.workspace = true
util.workspace = true
fuzzy.workspace = true
editor.workspace = true
[lints]
workspace = true

View file

@ -1,194 +1,42 @@
use std::sync::Weak;
use std::sync::atomic::AtomicBool;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{AppContext, ClickEvent, DismissEvent, Entity, EventEmitter, Focusable, WeakEntity};
use language::Buffer;
use picker::{Picker, PickerDelegate};
use ui::{
Button, ButtonCommon, Context, Label, LabelSize, ListItem, Render, Styled, Tooltip, Window,
div, rems, v_flex,
};
use editor::Editor;
use gpui::{ClickEvent, Entity, WeakEntity};
use ui::{Button, ButtonCommon, Context, LabelSize, Render, Tooltip, Window, div};
use ui::{Clickable, ParentElement};
use util::ResultExt;
use workspace::{ItemHandle, ModalView, StatusItemView, Workspace};
use workspace::{ItemHandle, StatusItemView, Workspace};
use crate::selectors::save_or_reopen::{EncodingSaveOrReopenSelector, get_current_encoding};
pub enum Encoding {
Utf8(WeakEntity<Workspace>),
Utf8,
Iso8859_1,
}
impl Encoding {
pub fn as_str(&self) -> &str {
match &self {
Encoding::Utf8(_) => "UTF-8",
Encoding::Utf8 => "UTF-8",
Encoding::Iso8859_1 => "ISO 8859-1",
}
}
}
impl EncodingSaveOrReopenSelector {
pub fn new(window: &mut Window, cx: &mut Context<EncodingSaveOrReopenSelector>) -> Self {
let delegate = EncodingSaveOrReopenDelegate::new(cx.entity().downgrade());
let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx));
Self { picker }
}
pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
workspace.toggle_modal(window, cx, |window, cx| {
EncodingSaveOrReopenSelector::new(window, cx)
});
}
pub struct EncodingIndicator {
pub encoding: Encoding,
pub workspace: WeakEntity<Workspace>,
}
pub struct EncodingSaveOrReopenSelector {
picker: Entity<Picker<EncodingSaveOrReopenDelegate>>,
}
pub mod selectors;
impl Focusable for EncodingSaveOrReopenSelector {
fn focus_handle(&self, cx: &ui::App) -> gpui::FocusHandle {
self.picker.focus_handle(cx)
}
}
impl Render for EncodingSaveOrReopenSelector {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl ui::IntoElement {
v_flex().w(rems(34.0)).child(self.picker.clone())
}
}
impl ModalView for EncodingSaveOrReopenSelector {}
impl EventEmitter<DismissEvent> for EncodingSaveOrReopenSelector {}
pub struct EncodingSaveOrReopenDelegate {
encoding_selector: WeakEntity<EncodingSaveOrReopenSelector>,
current_selection: usize,
matches: Vec<StringMatch>,
pub actions: Vec<StringMatchCandidate>,
}
impl EncodingSaveOrReopenDelegate {
pub fn new(selector: WeakEntity<EncodingSaveOrReopenSelector>) -> Self {
Self {
encoding_selector: selector,
current_selection: 0,
matches: Vec::new(),
actions: vec![
StringMatchCandidate::new(0, "Save with encoding"),
StringMatchCandidate::new(1, "Reopen with encoding"),
],
}
}
pub fn get_actions(&self) -> (&str, &str) {
(&self.actions[0].string, &self.actions[1].string)
}
}
impl PickerDelegate for EncodingSaveOrReopenDelegate {
type ListItem = ListItem;
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.current_selection
}
fn set_selected_index(
&mut self,
ix: usize,
_window: &mut Window,
_cx: &mut Context<Picker<Self>>,
) {
self.current_selection = ix;
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut ui::App) -> std::sync::Arc<str> {
"Select an action...".into()
}
fn update_matches(
&mut self,
query: String,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> gpui::Task<()> {
let executor = cx.background_executor().clone();
let actions = self.actions.clone();
cx.spawn_in(window, async move |this, cx| {
let matches = if query.is_empty() {
actions
.into_iter()
.enumerate()
.map(|(index, value)| StringMatch {
candidate_id: index,
score: 0.0,
positions: vec![],
string: value.string,
})
.collect::<Vec<StringMatch>>()
} else {
fuzzy::match_strings(
&actions,
&query,
false,
false,
2,
&AtomicBool::new(false),
executor,
)
.await
};
this.update(cx, |picker, cx| {
let delegate = &mut picker.delegate;
delegate.current_selection = matches.len().saturating_sub(1);
delegate.matches = matches;
cx.notify();
})
.log_err();
})
}
fn confirm(&mut self, secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {}
fn dismissed(&mut self, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
self.encoding_selector
.update(cx, |_, cx| cx.emit(DismissEvent))
.log_err();
}
fn render_match(
&self,
ix: usize,
selected: bool,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
Some(ListItem::new(ix).child(Label::new(&self.matches[ix].string)))
}
}
fn get_current_encoding() -> &'static str {
"UTF-8"
}
impl Render for Encoding {
impl Render for EncodingIndicator {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl ui::IntoElement {
let encoding_indicator = div();
let status_element = div();
encoding_indicator.child(
status_element.child(
Button::new("encoding", get_current_encoding())
.label_size(LabelSize::Small)
.tooltip(Tooltip::text("Select Encoding"))
.on_click(cx.listener(|encoding, _: &ClickEvent, window, cx| {
if let Some(workspace) = match encoding {
Encoding::Utf8(workspace) => workspace.upgrade(),
} {
.on_click(cx.listener(|indicator, _: &ClickEvent, window, cx| {
if let Some(workspace) = indicator.workspace.upgrade() {
workspace.update(cx, |workspace, cx| {
EncodingSaveOrReopenSelector::toggle(workspace, window, cx)
})
@ -199,7 +47,11 @@ impl Render for Encoding {
}
}
impl StatusItemView for Encoding {
impl EncodingIndicator {
pub fn get_current_encoding(&self, cx: &mut Context<Self>, editor: WeakEntity<Editor>) {}
}
impl StatusItemView for EncodingIndicator {
fn set_active_pane_item(
&mut self,
_active_pane_item: Option<&dyn ItemHandle>,

View file

@ -0,0 +1,331 @@
pub mod save_or_reopen {
use gpui::Styled;
use gpui::{AppContext, ParentElement};
use picker::Picker;
use picker::PickerDelegate;
use std::sync::atomic::AtomicBool;
use util::ResultExt;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{DismissEvent, Entity, EventEmitter, Focusable, WeakEntity};
use ui::{Context, Label, ListItem, Render, Window, rems, v_flex};
use workspace::{ModalView, Workspace};
pub struct EncodingSaveOrReopenSelector {
picker: Entity<Picker<EncodingSaveOrReopenDelegate>>,
}
impl EncodingSaveOrReopenSelector {
pub fn new(window: &mut Window, cx: &mut Context<EncodingSaveOrReopenSelector>) -> Self {
let delegate = EncodingSaveOrReopenDelegate::new(cx.entity().downgrade());
let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx));
Self { picker }
}
pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
workspace.toggle_modal(window, cx, |window, cx| {
EncodingSaveOrReopenSelector::new(window, cx)
});
}
}
impl Focusable for EncodingSaveOrReopenSelector {
fn focus_handle(&self, cx: &ui::App) -> gpui::FocusHandle {
self.picker.focus_handle(cx)
}
}
impl Render for EncodingSaveOrReopenSelector {
fn render(
&mut self,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> impl ui::IntoElement {
v_flex().w(rems(34.0)).child(self.picker.clone())
}
}
impl ModalView for EncodingSaveOrReopenSelector {}
impl EventEmitter<DismissEvent> for EncodingSaveOrReopenSelector {}
pub struct EncodingSaveOrReopenDelegate {
encoding_selector: WeakEntity<EncodingSaveOrReopenSelector>,
current_selection: usize,
matches: Vec<StringMatch>,
pub actions: Vec<StringMatchCandidate>,
}
impl EncodingSaveOrReopenDelegate {
pub fn new(selector: WeakEntity<EncodingSaveOrReopenSelector>) -> Self {
Self {
encoding_selector: selector,
current_selection: 0,
matches: Vec::new(),
actions: vec![
StringMatchCandidate::new(0, "Save with encoding"),
StringMatchCandidate::new(1, "Reopen with encoding"),
],
}
}
pub fn get_actions(&self) -> (&str, &str) {
(&self.actions[0].string, &self.actions[1].string)
}
}
impl PickerDelegate for EncodingSaveOrReopenDelegate {
type ListItem = ListItem;
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.current_selection
}
fn set_selected_index(
&mut self,
ix: usize,
_window: &mut Window,
_cx: &mut Context<Picker<Self>>,
) {
self.current_selection = ix;
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut ui::App) -> std::sync::Arc<str> {
"Select an action...".into()
}
fn update_matches(
&mut self,
query: String,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> gpui::Task<()> {
let executor = cx.background_executor().clone();
let actions = self.actions.clone();
cx.spawn_in(window, async move |this, cx| {
let matches = if query.is_empty() {
actions
.into_iter()
.enumerate()
.map(|(index, value)| StringMatch {
candidate_id: index,
score: 0.0,
positions: vec![],
string: value.string,
})
.collect::<Vec<StringMatch>>()
} else {
fuzzy::match_strings(
&actions,
&query,
false,
false,
2,
&AtomicBool::new(false),
executor,
)
.await
};
this.update(cx, |picker, cx| {
let delegate = &mut picker.delegate;
delegate.current_selection = matches.len().saturating_sub(1);
delegate.matches = matches;
cx.notify();
})
.log_err();
})
}
fn confirm(
&mut self,
secondary: bool,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) {
}
fn dismissed(&mut self, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
self.encoding_selector
.update(cx, |_, cx| cx.emit(DismissEvent))
.log_err();
}
fn render_match(
&self,
ix: usize,
selected: bool,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
Some(ListItem::new(ix).child(Label::new(&self.matches[ix].string)))
}
}
pub fn get_current_encoding() -> &'static str {
"UTF-8"
}
}
pub mod encoding {
use std::sync::atomic::AtomicBool;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
AppContext, BackgroundExecutor, DismissEvent, Entity, EventEmitter, Focusable, WeakEntity,
};
use picker::{Picker, PickerDelegate};
use ui::{Context, Label, ListItem, ParentElement, Render, Styled, Window, rems, v_flex};
use util::{ResultExt, TryFutureExt};
use workspace::{ModalView, Workspace};
pub struct EncodingSelector {
pub picker: Entity<Picker<EncodingSelectorDelegate>>,
}
pub struct EncodingSelectorDelegate {
current_selection: usize,
encodings: Vec<StringMatchCandidate>,
matches: Vec<StringMatch>,
selector: WeakEntity<EncodingSelector>,
}
impl EncodingSelectorDelegate {
pub fn new(selector: WeakEntity<EncodingSelector>) -> EncodingSelectorDelegate {
EncodingSelectorDelegate {
current_selection: 0,
encodings: vec![
StringMatchCandidate::new(0, "UTF-8"),
StringMatchCandidate::new(1, "ISO 8859-1"),
],
matches: Vec::new(),
selector,
}
}
}
impl PickerDelegate for EncodingSelectorDelegate {
type ListItem = ListItem;
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.current_selection
}
fn set_selected_index(
&mut self,
ix: usize,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) {
self.current_selection = ix;
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut ui::App) -> std::sync::Arc<str> {
"Select an encoding...".into()
}
fn update_matches(
&mut self,
query: String,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> gpui::Task<()> {
let executor = cx.background_executor().clone();
let encodings = self.encodings.clone();
let current_selection = self.current_selection;
cx.spawn_in(window, async move |picker, cx| {
let matches: Vec<StringMatch>;
if query.is_empty() {
matches = encodings
.into_iter()
.enumerate()
.map(|(index, value)| StringMatch {
candidate_id: index,
score: 0.0,
positions: Vec::new(),
string: value.string,
})
.collect();
} else {
matches = fuzzy::match_strings(
&encodings,
&query,
false,
false,
0,
&AtomicBool::new(false),
executor,
)
.await
}
})
}
fn confirm(
&mut self,
secondary: bool,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) {
}
fn dismissed(&mut self, window: &mut Window, cx: &mut Context<Picker<Self>>) {
self.selector
.update(cx, |_, cx| cx.emit(DismissEvent))
.log_err();
}
fn render_match(
&self,
ix: usize,
selected: bool,
window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
Some(ListItem::new(ix).child(Label::new(&self.matches[ix].string)))
}
}
impl EncodingSelector {
pub fn new(window: &mut Window, cx: &mut Context<EncodingSelector>) -> EncodingSelector {
let delegate = EncodingSelectorDelegate::new(cx.entity().downgrade());
let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx));
EncodingSelector { picker: picker }
}
pub fn toggle(workspace: &mut Workspace, window: &mut Window, cx: &mut Context<Workspace>) {
workspace.toggle_modal(window, cx, |window, cx| EncodingSelector::new(window, cx));
}
}
impl EventEmitter<DismissEvent> for EncodingSelector {}
impl Focusable for EncodingSelector {
fn focus_handle(&self, cx: &ui::App) -> gpui::FocusHandle {
cx.focus_handle()
}
}
impl ModalView for EncodingSelector {}
impl Render for EncodingSelector {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl ui::IntoElement {
v_flex().w(rems(34.0)).child(self.picker.clone())
}
}
}

View file

@ -34,6 +34,8 @@ text.workspace = true
time.workspace = true
util.workspace = true
workspace-hack.workspace = true
encoding = "0.2.33"
[target.'cfg(target_os = "macos")'.dependencies]
fsevent.workspace = true

View file

@ -0,0 +1,21 @@
use encoding::Encoding;
pub enum CharacterEncoding {
Utf8,
Iso8859_1,
Cp865,
}
pub fn to_utf8<'a>(input: Vec<u8>, encoding: &'a impl encoding::Encoding) -> String {
match encoding.decode(&input, encoding::DecoderTrap::Strict) {
Ok(v) => return v,
Err(_) => panic!(),
}
}
pub fn to<'a>(input: String, target: &'a impl encoding::Encoding) -> Vec<u8> {
match target.encode(&input, encoding::EncoderTrap::Strict) {
Ok(v) => v,
Err(_) => panic!(),
}
}

View file

@ -70,6 +70,7 @@ util.workspace = true
watch.workspace = true
workspace-hack.workspace = true
diffy = "0.4.2"
encoding = "0.2.33"
[dev-dependencies]
collections = { workspace = true, features = ["test-support"] }

View file

@ -127,6 +127,7 @@ pub struct Buffer {
has_unsaved_edits: Cell<(clock::Global, bool)>,
change_bits: Vec<rc::Weak<Cell<bool>>>,
_subscriptions: Vec<gpui::Subscription>,
encoding: &'static dyn encoding::Encoding,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -958,6 +959,7 @@ impl Buffer {
has_conflict: false,
change_bits: Default::default(),
_subscriptions: Vec::new(),
encoding: encoding::all::UTF_8,
}
}

View file

@ -397,7 +397,10 @@ pub fn initialize_workspace(
}
});
let encoding_indicator = cx.new(|_cx| encodings::Encoding::Utf8(workspace.weak_handle()));
let encoding_indicator = cx.new(|_cx| encodings::EncodingIndicator {
encoding: encodings::Encoding::Utf8,
workspace: workspace_handle.downgrade(),
});
let cursor_position =
cx.new(|_| go_to_line::cursor_position::CursorPosition::new(workspace));