Add a status indicator to indicate the current file's encoding. When clicked a modal view opens that lets user choose to either reopen or save a file with a particular encoding. The actual implementations are incomplete
This commit is contained in:
parent
b1b60bb7fe
commit
fae2f8ff1c
7 changed files with 249 additions and 1 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -5203,6 +5203,19 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encodings"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"fuzzy",
|
||||
"gpui",
|
||||
"language",
|
||||
"picker",
|
||||
"ui",
|
||||
"util",
|
||||
"workspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "endi"
|
||||
version = "1.1.0"
|
||||
|
@ -20437,6 +20450,7 @@ dependencies = [
|
|||
"diagnostics",
|
||||
"edit_prediction_button",
|
||||
"editor",
|
||||
"encodings",
|
||||
"env_logger 0.11.8",
|
||||
"extension",
|
||||
"extension_host",
|
||||
|
|
|
@ -55,6 +55,7 @@ members = [
|
|||
"crates/diagnostics",
|
||||
"crates/docs_preprocessor",
|
||||
"crates/editor",
|
||||
"crates/encodings",
|
||||
"crates/eval",
|
||||
"crates/explorer_command_injector",
|
||||
"crates/extension",
|
||||
|
@ -214,7 +215,7 @@ members = [
|
|||
#
|
||||
|
||||
"tooling/workspace-hack",
|
||||
"tooling/xtask",
|
||||
"tooling/xtask", "crates/encodings",
|
||||
]
|
||||
default-members = ["crates/zed"]
|
||||
|
||||
|
@ -309,6 +310,7 @@ icons = { path = "crates/icons" }
|
|||
image_viewer = { path = "crates/image_viewer" }
|
||||
edit_prediction = { path = "crates/edit_prediction" }
|
||||
edit_prediction_button = { path = "crates/edit_prediction_button" }
|
||||
encodings = {path = "crates/encodings"}
|
||||
inspector_ui = { path = "crates/inspector_ui" }
|
||||
install_cli = { path = "crates/install_cli" }
|
||||
jj = { path = "crates/jj" }
|
||||
|
|
17
crates/encodings/Cargo.toml
Normal file
17
crates/encodings/Cargo.toml
Normal file
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "encodings"
|
||||
version = "0.1.0"
|
||||
publish.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ui.workspace = true
|
||||
workspace.workspace = true
|
||||
gpui.workspace = true
|
||||
picker.workspace = true
|
||||
language.workspace = true
|
||||
util.workspace = true
|
||||
fuzzy.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
210
crates/encodings/src/lib.rs
Normal file
210
crates/encodings/src/lib.rs
Normal file
|
@ -0,0 +1,210 @@
|
|||
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 ui::{Clickable, ParentElement};
|
||||
use util::ResultExt;
|
||||
use workspace::{ItemHandle, ModalView, StatusItemView, Workspace};
|
||||
|
||||
pub enum Encoding {
|
||||
Utf8(WeakEntity<Workspace>),
|
||||
}
|
||||
|
||||
impl Encoding {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match &self {
|
||||
Encoding::Utf8(_) => "UTF-8",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 EncodingSaveOrReopenSelector {
|
||||
picker: Entity<Picker<EncodingSaveOrReopenDelegate>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl ui::IntoElement {
|
||||
let encoding_indicator = div();
|
||||
|
||||
encoding_indicator.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(),
|
||||
} {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
EncodingSaveOrReopenSelector::toggle(workspace, window, cx)
|
||||
})
|
||||
} else {
|
||||
}
|
||||
})),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl StatusItemView for Encoding {
|
||||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
_active_pane_item: Option<&dyn ItemHandle>,
|
||||
_window: &mut Window,
|
||||
_cx: &mut Context<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
|
@ -118,6 +118,7 @@ use crate::persistence::{
|
|||
model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},
|
||||
};
|
||||
|
||||
|
||||
pub const SERIALIZATION_THROTTLE_TIME: Duration = Duration::from_millis(200);
|
||||
|
||||
static ZED_WINDOW_SIZE: LazyLock<Option<Size<Pixels>>> = LazyLock::new(|| {
|
||||
|
|
|
@ -55,6 +55,7 @@ debugger_tools.workspace = true
|
|||
debugger_ui.workspace = true
|
||||
diagnostics.workspace = true
|
||||
editor.workspace = true
|
||||
encodings.workspace = true
|
||||
env_logger.workspace = true
|
||||
extension.workspace = true
|
||||
extension_host.workspace = true
|
||||
|
|
|
@ -397,6 +397,8 @@ pub fn initialize_workspace(
|
|||
}
|
||||
});
|
||||
|
||||
let encoding_indicator = cx.new(|_cx| encodings::Encoding::Utf8(workspace.weak_handle()));
|
||||
|
||||
let cursor_position =
|
||||
cx.new(|_| go_to_line::cursor_position::CursorPosition::new(workspace));
|
||||
workspace.status_bar().update(cx, |status_bar, cx| {
|
||||
|
@ -409,6 +411,7 @@ pub fn initialize_workspace(
|
|||
status_bar.add_right_item(active_toolchain_language, window, cx);
|
||||
status_bar.add_right_item(vim_mode_indicator, window, cx);
|
||||
status_bar.add_right_item(cursor_position, window, cx);
|
||||
status_bar.add_right_item(encoding_indicator, window, cx);
|
||||
status_bar.add_right_item(image_info, window, cx);
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue