nvim_gtk/
shell_dlg.rs

1use std::cell::RefCell;
2
3use gtk;
4use gtk::prelude::*;
5use gtk::{ButtonsType, MessageDialog, MessageType};
6
7use neovim_lib::{CallError, NeovimApi, Value};
8use crate::shell::Shell;
9use crate::ui::{Components, UiMutex};
10
11pub fn can_close_window(comps: &UiMutex<Components>, shell: &RefCell<Shell>) -> bool {
12    let shell = shell.borrow();
13    match get_changed_buffers(&*shell) {
14        Ok(vec) => {
15            if !vec.is_empty() {
16                show_not_saved_dlg(comps, &*shell, &vec)
17            } else {
18                true
19            }
20        }
21        Err(ref err) => {
22            error!("Error getting info from nvim: {}", err);
23            true
24        }
25    }
26}
27
28fn show_not_saved_dlg(comps: &UiMutex<Components>, shell: &Shell, changed_bufs: &[String]) -> bool {
29    let mut changed_files = changed_bufs
30        .iter()
31        .map(|n| if n.is_empty() { "<No name>" } else { n })
32        .fold(String::new(), |acc, v| acc + v + "\n");
33    changed_files.pop();
34
35    let flags = gtk::DialogFlags::MODAL | gtk::DialogFlags::DESTROY_WITH_PARENT;
36    let dlg = MessageDialog::new(
37        Some(comps.borrow().window()),
38        flags,
39        MessageType::Question,
40        ButtonsType::None,
41        &format!("Save changes to '{}'?", changed_files),
42    );
43
44    dlg.add_buttons(&[
45        ("_Yes", gtk::ResponseType::Yes),
46        ("_No", gtk::ResponseType::No),
47        ("_Cancel", gtk::ResponseType::Cancel),
48    ]);
49
50    let res = match dlg.run() {
51        gtk::ResponseType::Yes => {
52            let state = shell.state.borrow();
53            let mut nvim = state.nvim().unwrap();
54            match nvim.command("wa") {
55                Err(ref err) => {
56                    error!("Error: {}", err);
57                    false
58                }
59                _ => true,
60            }
61        }
62        gtk::ResponseType::No => true,
63        gtk::ResponseType::Cancel | _ => false,
64    };
65
66    dlg.destroy();
67
68    res
69}
70
71fn get_changed_buffers(shell: &Shell) -> Result<Vec<String>, CallError> {
72    let state = shell.state.borrow();
73    let nvim = state.nvim();
74    if let Some(mut nvim) = nvim {
75        let buffers = nvim.list_bufs().unwrap();
76
77        Ok(buffers
78            .iter()
79            .map(|buf| {
80                (
81                    match buf.get_option(&mut nvim, "modified") {
82                        Ok(Value::Boolean(val)) => val,
83                        Ok(_) => {
84                            warn!("Value must be boolean");
85                            false
86                        }
87                        Err(ref err) => {
88                            error!("Something going wrong while getting buffer option: {}", err);
89                            false
90                        }
91                    },
92                    match buf.get_name(&mut nvim) {
93                        Ok(name) => name,
94                        Err(ref err) => {
95                            error!("Something going wrong while getting buffer name: {}", err);
96                            "<Error>".to_owned()
97                        }
98                    },
99                )
100            })
101            .filter(|e| e.0)
102            .map(|e| e.1)
103            .collect())
104    } else {
105        Ok(vec![])
106    }
107}