1use crate::{EncodingSelector, Toggle};
2
3use editor::Editor;
4use encoding_rs::{Encoding, UTF_8};
5use gpui::{
6 Context, Entity, IntoElement, ParentElement, Render, Styled, Subscription, WeakEntity, Window,
7 div,
8};
9use project::Project;
10use ui::{Button, ButtonCommon, Clickable, LabelSize, Tooltip};
11use workspace::{
12 StatusBarSettings, StatusItemView, Workspace,
13 item::{ItemHandle, Settings},
14};
15
16pub struct ActiveBufferEncoding {
17 active_encoding: Option<&'static Encoding>,
18 workspace: WeakEntity<Workspace>,
19 project: Entity<Project>,
20 _observe_active_editor: Option<Subscription>,
21 has_bom: bool,
22 is_dirty: bool,
23 is_shared: bool,
24 is_via_remote_server: bool,
25}
26
27impl ActiveBufferEncoding {
28 pub fn new(workspace: &Workspace) -> Self {
29 Self {
30 active_encoding: None,
31 workspace: workspace.weak_handle(),
32 project: workspace.project().clone(),
33 _observe_active_editor: None,
34 has_bom: false,
35 is_dirty: false,
36 is_shared: false,
37 is_via_remote_server: false,
38 }
39 }
40
41 fn update_encoding(&mut self, editor: Entity<Editor>, _: &mut Window, cx: &mut Context<Self>) {
42 self.active_encoding = None;
43 self.has_bom = false;
44 self.is_dirty = false;
45
46 let project = self.project.read(cx);
47 self.is_shared = project.is_shared();
48 self.is_via_remote_server = project.is_via_remote_server();
49
50 if let Some((_, buffer, _)) = editor.read(cx).active_excerpt(cx) {
51 let buffer = buffer.read(cx);
52 self.active_encoding = Some(buffer.encoding());
53 self.has_bom = buffer.has_bom();
54 self.is_dirty = buffer.is_dirty();
55 }
56
57 cx.notify();
58 }
59}
60
61impl Render for ActiveBufferEncoding {
62 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
63 let Some(active_encoding) = self.active_encoding else {
64 return div().hidden();
65 };
66
67 let display_option = StatusBarSettings::get_global(cx).active_encoding_button;
68 let is_utf8 = active_encoding == UTF_8;
69 if !display_option.should_show(is_utf8, self.has_bom) {
70 return div().hidden();
71 }
72
73 let mut text = active_encoding.name().to_string();
74 if self.has_bom {
75 text.push_str(" (BOM)");
76 }
77
78 let (disabled, tooltip_text) = if self.is_dirty {
79 (true, "Save file to change encoding")
80 } else if self.is_shared {
81 (true, "Cannot change encoding during collaboration")
82 } else if self.is_via_remote_server {
83 (true, "Cannot change encoding of remote server file")
84 } else {
85 (false, "Reopen with Encoding")
86 };
87
88 div().child(
89 Button::new("change-encoding", text)
90 .label_size(LabelSize::Small)
91 .on_click(cx.listener(move |this, _, window, cx| {
92 if disabled {
93 return;
94 }
95 if let Some(workspace) = this.workspace.upgrade() {
96 workspace.update(cx, |workspace, cx| {
97 EncodingSelector::toggle(workspace, window, cx)
98 });
99 }
100 }))
101 .tooltip(move |_window, cx| {
102 if disabled {
103 Tooltip::text(tooltip_text)(_window, cx)
104 } else {
105 Tooltip::for_action(tooltip_text, &Toggle, cx)
106 }
107 }),
108 )
109 }
110}
111
112impl StatusItemView for ActiveBufferEncoding {
113 fn set_active_pane_item(
114 &mut self,
115 active_pane_item: Option<&dyn ItemHandle>,
116 window: &mut Window,
117 cx: &mut Context<Self>,
118 ) {
119 if let Some(editor) = active_pane_item.and_then(|item| item.downcast::<Editor>()) {
120 self._observe_active_editor =
121 Some(cx.observe_in(&editor, window, Self::update_encoding));
122 self.update_encoding(editor, window, cx);
123 } else {
124 self.active_encoding = None;
125 self.has_bom = false;
126 self.is_dirty = false;
127 self.is_shared = false;
128 self.is_via_remote_server = false;
129 self._observe_active_editor = None;
130 }
131
132 cx.notify();
133 }
134}