Repository: asottile/babi

Issue:
Alt-UP crashes if the first line in the buffer is empty
To reproduce:
- open babi
- press enter
- press Alt-UP

This happens because there is no bound check in Alt-UP action implementation when counting the offset.

I can issue a pull request with slightly different implementation where the bound check is obvious. If you would like to keep the current code it suffices to add two more if statements.

Discussion:

Patch:
diff --git a/README.md b/README.md
index d954f11..edd28f2 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,7 @@ these are all of the current key bindings in babi
 - <kbd>^V</kbd> / <kbd>pagedown</kbd>: move down one page
 - <kbd>^-left</kbd> / <kbd>^-right</kbd>: jump by word
 - <kbd>^-home</kbd> / <kbd>^-end</kbd>: jump to beginning / end of file
+- <kbd>M-Up</kbd> / <kbd>M-Down</kbd>: jump to previous / next paragraph
 - <kbd>^_</kbd>: jump to line number
 - selection: <kbd>shift</kbd> + ...: extend the current selection
     - arrow keys
diff --git a/babi/file.py b/babi/file.py
index 88f3fff..b7ea4fb 100644
--- a/babi/file.py
+++ b/babi/file.py
@@ -514,7 +514,10 @@ class File:
     def alt_up(self, dim: Dim) -> None:
         if self.buf.y > 0:
             offset = 1
-            while self.buf[self.buf.y - offset] == '':
+            while (
+                self.buf[self.buf.y - offset] == '' and
+                self.buf.y - offset - 1 >= 0
+            ):
                 offset += 1
             if offset >= 2:
                 self.buf.y -= offset


Test patch:
diff --git a/tests/features/movement_test.py b/tests/features/movement_test.py
index 0050cdb..7a01a8c 100644
--- a/tests/features/movement_test.py
+++ b/tests/features/movement_test.py
@@ -488,6 +488,22 @@ yet_another_test = None
         h.await_cursor_position(x=0, y=1)
 
 
+def test_previous_paragraph_out_of_bounds(run, tmpdir):
+    src = '''\
+
+# blank line above
+
+'''
+    f = tmpdir.join('f')
+    f.write(src)
+
+    with run(str(f)) as h, and_exit(h):
+        h.press('M-Down')
+        h.await_cursor_position(x=0, y=2)
+        h.press('M-Up')
+        h.await_cursor_position(x=0, y=1)
+
+
 def test_goto_next_paragraph(run, tmpdir):
     src = '''\
 class A: