lib.rs

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