diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs
index bbd1cea4..ffd16daf 100644
--- a/helix-core/src/auto_pairs.rs
+++ b/helix-core/src/auto_pairs.rs
@@ -3,7 +3,7 @@ use smallvec::SmallVec;
 
 // Heavily based on https://github.com/codemirror/closebrackets/
 
-const PAIRS: &[(char, char)] = &[
+pub const PAIRS: &[(char, char)] = &[
     ('(', ')'),
     ('{', '}'),
     ('[', ']'),
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index aebdb465..a273fc6f 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1471,17 +1471,52 @@ pub mod insert {
     pub fn insert_newline(cx: &mut Context) {
         let (view, doc) = cx.current();
         let text = doc.text().slice(..);
-        let transaction =
-            Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
-                let pos = range.head;
-                // TODO: offset range.head by 1? when calculating?
-                let indent_level = indent::suggested_indent_for_pos(doc.syntax(), text, pos, true);
-                let indent = doc.indent_unit().repeat(indent_level);
-                let mut text = String::with_capacity(1 + indent.len());
+
+        let contents = doc.text();
+        let selection = doc.selection(view.id);
+        let mut ranges = SmallVec::with_capacity(selection.len());
+
+        let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
+            let pos = range.head;
+
+            let prev = if pos == 0 {
+                ' '
+            } else {
+                contents.char(pos - 1)
+            };
+            let curr = contents.char(pos);
+
+            // TODO: offset range.head by 1? when calculating?
+            let indent_level =
+                indent::suggested_indent_for_pos(doc.syntax(), text, pos.saturating_sub(1), true);
+            let indent = doc.indent_unit().repeat(indent_level);
+            let mut text = String::with_capacity(1 + indent.len());
+            text.push('\n');
+            text.push_str(&indent);
+
+            let head = pos + text.len();
+
+            ranges.push(Range::new(
+                if range.is_empty() { head } else { range.anchor },
+                head,
+            ));
+
+            // if between a bracket pair
+            if helix_core::auto_pairs::PAIRS.contains(&(prev, curr)) {
+                // another newline, indent the end bracket one level less
+                let indent = doc.indent_unit().repeat(indent_level.saturating_sub(1));
                 text.push('\n');
                 text.push_str(&indent);
+
                 (pos, pos, Some(text.into()))
-            });
+            } else {
+                (pos, pos, Some(text.into()))
+            }
+        });
+
+        transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
+        //
+
         doc.apply(&transaction, view.id);
     }