@@ -664,7 +664,7 @@ pub fn _search_next(cx: &mut Context, extend: bool) {
664664 let query = query.first().unwrap();
665665 let (view, doc) = cx.current();
666666 let contents = doc.text().slice(..).to_string();
667− let regex = Regex::new(&query).unwrap();
667+ let regex = Regex::new(query).unwrap();
668668 _search(doc, view, &contents, ®ex, extend);
669669 }
670670}
@@ -809,7 +809,7 @@ pub fn append_mode(cx: &mut Context) {
809809 doc.set_selection(view.id, selection);
810810}
811811
812−const COMMAND_LIST: &[&str] = &["write", "open", "quit"];
812+const COMMAND_LIST: &[&str] = &["write", "open", "quit", "quit!"];
813813
814814pub fn command_mode(cx: &mut Context) {
815815 let prompt = Prompt::new(
@@ -856,6 +856,31 @@ pub fn command_mode(cx: &mut Context) {
856856
857857 match *parts.as_slice() {
858858 ["q"] | ["quit"] => {
859+ // last view and we have unsaved changes
860+ if editor.tree.views().count() == 1 {
861+ let modified: Vec<_> = editor
862+ .documents()
863+ .filter(|doc| doc.is_modified())
864+ .map(|doc| {
865+ doc.relative_path()
866+ .and_then(|path| path.to_str())
867+ .unwrap_or("[scratch]")
868+ })
869+ .collect();
870+
871+ if !modified.is_empty() {
872+ let err = format!(
873+ "{} unsaved buffer(s) remaining: {:?}",
874+ modified.len(),
875+ modified
876+ );
877+ editor.set_error(err);
878+ return;
879+ }
880+ }
881+ editor.close(editor.view().id, /* close_buffer */ false);
882+ }
883+ ["q!"] | ["quit!"] => {
859884 editor.close(editor.view().id, /* close_buffer */ false);
860885 }
861886 ["o", path] | ["open", path] => {