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}