1//! A crate for handling file encodings in the text editor.
2use editor::{Editor, EditorSettings};
3use encoding_rs::Encoding;
4use gpui::{ClickEvent, Entity, Subscription, WeakEntity};
5use settings::Settings;
6use ui::{Button, ButtonCommon, Context, LabelSize, Render, Tooltip, Window, div};
7use ui::{Clickable, ParentElement};
8use workspace::{ItemHandle, StatusItemView, Workspace};
9
10use crate::selectors::save_or_reopen::EncodingSaveOrReopenSelector;
11
12/// A status bar item that shows the current file encoding and allows changing it.
13pub struct EncodingIndicator {
14 pub encoding: Option<&'static Encoding>,
15 pub workspace: WeakEntity<Workspace>,
16 observe: Option<Subscription>, // Subscription to observe changes in the active editor
17 show: bool, // Whether to show the indicator or not, based on whether an editor is active
18}
19
20pub mod selectors;
21
22impl Render for EncodingIndicator {
23 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl ui::IntoElement {
24 let status_element = div();
25
26 if (!EditorSettings::get_global(cx).status_bar.encoding_indicator) || !self.show {
27 return status_element;
28 }
29
30 status_element.child(
31 Button::new(
32 "encoding",
33 encoding_name(self.encoding.unwrap_or(encoding_rs::UTF_8)),
34 )
35 .label_size(LabelSize::Small)
36 .tooltip(Tooltip::text("Select Encoding"))
37 .on_click(cx.listener(|indicator, _: &ClickEvent, window, cx| {
38 if let Some(workspace) = indicator.workspace.upgrade() {
39 workspace.update(cx, |workspace, cx| {
40 EncodingSaveOrReopenSelector::toggle(workspace, window, cx)
41 })
42 } else {
43 }
44 })),
45 )
46 }
47}
48
49impl EncodingIndicator {
50 pub fn new(
51 encoding: Option<&'static Encoding>,
52 workspace: WeakEntity<Workspace>,
53 observe: Option<Subscription>,
54 ) -> EncodingIndicator {
55 EncodingIndicator {
56 encoding,
57 workspace,
58 observe,
59 show: true,
60 }
61 }
62
63 pub fn update(
64 &mut self,
65 editor: Entity<Editor>,
66 _: &mut Window,
67 cx: &mut Context<EncodingIndicator>,
68 ) {
69 let editor = editor.read(cx);
70 if let Some((_, buffer, _)) = editor.active_excerpt(cx) {
71 let encoding = buffer.read(cx).encoding;
72 self.encoding = Some(encoding);
73 }
74
75 cx.notify();
76 }
77}
78
79impl StatusItemView for EncodingIndicator {
80 fn set_active_pane_item(
81 &mut self,
82 active_pane_item: Option<&dyn ItemHandle>,
83 window: &mut Window,
84 cx: &mut Context<Self>,
85 ) {
86 match active_pane_item.and_then(|item| item.downcast::<Editor>()) {
87 Some(editor) => {
88 self.observe = Some(cx.observe_in(&editor, window, Self::update));
89 self.update(editor, window, cx);
90 self.show = true;
91 }
92 None => {
93 self.encoding = None;
94 self.observe = None;
95 self.show = false;
96 }
97 }
98 }
99}
100
101/// Get a human-readable name for the given encoding.
102pub fn encoding_name(encoding: &'static Encoding) -> String {
103 let name = encoding.name();
104
105 match name {
106 "UTF-8" => "UTF-8",
107 "UTF-16LE" => "UTF-16 LE",
108 "UTF-16BE" => "UTF-16 BE",
109 "windows-1252" => "Windows-1252",
110 "windows-1251" => "Windows-1251",
111 "windows-1250" => "Windows-1250",
112 "ISO-8859-2" => "ISO 8859-2",
113 "ISO-8859-3" => "ISO 8859-3",
114 "ISO-8859-4" => "ISO 8859-4",
115 "ISO-8859-5" => "ISO 8859-5",
116 "ISO-8859-6" => "ISO 8859-6",
117 "ISO-8859-7" => "ISO 8859-7",
118 "ISO-8859-8" => "ISO 8859-8",
119 "ISO-8859-13" => "ISO 8859-13",
120 "ISO-8859-15" => "ISO 8859-15",
121 "KOI8-R" => "KOI8-R",
122 "KOI8-U" => "KOI8-U",
123 "macintosh" => "MacRoman",
124 "x-mac-cyrillic" => "Mac Cyrillic",
125 "windows-874" => "Windows-874",
126 "windows-1253" => "Windows-1253",
127 "windows-1254" => "Windows-1254",
128 "windows-1255" => "Windows-1255",
129 "windows-1256" => "Windows-1256",
130 "windows-1257" => "Windows-1257",
131 "windows-1258" => "Windows-1258",
132 "EUC-KR" => "Windows-949",
133 "EUC-JP" => "EUC-JP",
134 "ISO-2022-JP" => "ISO 2022-JP",
135 "GBK" => "GBK",
136 "gb18030" => "GB18030",
137 "Big5" => "Big5",
138 _ => name,
139 }
140 .to_string()
141}
142
143/// Get an encoding from its index in the predefined list.
144/// If the index is out of range, UTF-8 is returned as a default.
145pub fn encoding_from_index(index: usize) -> &'static Encoding {
146 match index {
147 0 => encoding_rs::UTF_8,
148 1 => encoding_rs::UTF_16LE,
149 2 => encoding_rs::UTF_16BE,
150 3 => encoding_rs::WINDOWS_1252,
151 4 => encoding_rs::WINDOWS_1251,
152 5 => encoding_rs::WINDOWS_1250,
153 6 => encoding_rs::ISO_8859_2,
154 7 => encoding_rs::ISO_8859_3,
155 8 => encoding_rs::ISO_8859_4,
156 9 => encoding_rs::ISO_8859_5,
157 10 => encoding_rs::ISO_8859_6,
158 11 => encoding_rs::ISO_8859_7,
159 12 => encoding_rs::ISO_8859_8,
160 13 => encoding_rs::ISO_8859_13,
161 14 => encoding_rs::ISO_8859_15,
162 15 => encoding_rs::KOI8_R,
163 16 => encoding_rs::KOI8_U,
164 17 => encoding_rs::MACINTOSH,
165 18 => encoding_rs::X_MAC_CYRILLIC,
166 19 => encoding_rs::WINDOWS_874,
167 20 => encoding_rs::WINDOWS_1253,
168 21 => encoding_rs::WINDOWS_1254,
169 22 => encoding_rs::WINDOWS_1255,
170 23 => encoding_rs::WINDOWS_1256,
171 24 => encoding_rs::WINDOWS_1257,
172 25 => encoding_rs::WINDOWS_1258,
173 26 => encoding_rs::EUC_KR,
174 27 => encoding_rs::EUC_JP,
175 28 => encoding_rs::ISO_2022_JP,
176 29 => encoding_rs::GBK,
177 30 => encoding_rs::GB18030,
178 31 => encoding_rs::BIG5,
179 _ => encoding_rs::UTF_8,
180 }
181}
182
183/// Get an encoding from its name.
184pub fn encoding_from_name(name: &str) -> &'static Encoding {
185 match name {
186 "UTF-8" => encoding_rs::UTF_8,
187 "UTF-16 LE" => encoding_rs::UTF_16LE,
188 "UTF-16 BE" => encoding_rs::UTF_16BE,
189 "Windows-1252" => encoding_rs::WINDOWS_1252,
190 "Windows-1251" => encoding_rs::WINDOWS_1251,
191 "Windows-1250" => encoding_rs::WINDOWS_1250,
192 "ISO 8859-2" => encoding_rs::ISO_8859_2,
193 "ISO 8859-3" => encoding_rs::ISO_8859_3,
194 "ISO 8859-4" => encoding_rs::ISO_8859_4,
195 "ISO 8859-5" => encoding_rs::ISO_8859_5,
196 "ISO 8859-6" => encoding_rs::ISO_8859_6,
197 "ISO 8859-7" => encoding_rs::ISO_8859_7,
198 "ISO 8859-8" => encoding_rs::ISO_8859_8,
199 "ISO 8859-13" => encoding_rs::ISO_8859_13,
200 "ISO 8859-15" => encoding_rs::ISO_8859_15,
201 "KOI8-R" => encoding_rs::KOI8_R,
202 "KOI8-U" => encoding_rs::KOI8_U,
203 "MacRoman" => encoding_rs::MACINTOSH,
204 "Mac Cyrillic" => encoding_rs::X_MAC_CYRILLIC,
205 "Windows-874" => encoding_rs::WINDOWS_874,
206 "Windows-1253" => encoding_rs::WINDOWS_1253,
207 "Windows-1254" => encoding_rs::WINDOWS_1254,
208 "Windows-1255" => encoding_rs::WINDOWS_1255,
209 "Windows-1256" => encoding_rs::WINDOWS_1256,
210 "Windows-1257" => encoding_rs::WINDOWS_1257,
211 "Windows-1258" => encoding_rs::WINDOWS_1258,
212 "Windows-949" => encoding_rs::EUC_KR,
213 "EUC-JP" => encoding_rs::EUC_JP,
214 "ISO 2022-JP" => encoding_rs::ISO_2022_JP,
215 "GBK" => encoding_rs::GBK,
216 "GB18030" => encoding_rs::GB18030,
217 "Big5" => encoding_rs::BIG5,
218 "HZ-GB-2312" => encoding_rs::UTF_8, // encoding_rs doesn't support HZ, fallback to UTF-8
219 _ => encoding_rs::UTF_8, // Default to UTF-8 for unknown names
220 }
221}