diff --git a/include/buffer.h b/include/buffer.h
index 5f7a3ad..38cbfd3 100644
--- a/include/buffer.h
+++ b/include/buffer.h
@@ -2,6 +2,7 @@
 #define BUFFER_H
 
 #include <stdbool.h>
+#include <stddef.h>
 
 #include "utils.h"
 
@@ -22,13 +23,16 @@ struct buffer {
 
 struct buffer *buffer_create(void);
 void buffer_read_file(struct buffer *buffer, const char *filename);
-void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars);
+void buffer_insert_row(struct buffer *buffer, const char *chars, int n_chars, int at);
+void buffer_delete_row(struct buffer *buffer, int at);
 ERRCODE buffer_write_file(struct buffer *buffer);
 
 void erow_update_rendering(struct erow *erow);
+void erow_append_string(struct erow *erow, const char *s, size_t s_len);
 void erow_insert_char(struct erow *erow, int at, char c);
 void erow_delete_char(struct erow *erow, int at);
 int erow_cx_to_rx(struct erow *erow, int cx);
 int erow_rx_to_cx(struct erow *erow, int rx);
+void erow_free(struct erow *erow);
 
 #endif // BUFFER_H
diff --git a/include/commands.h b/include/commands.h
index 1292cce..111f64b 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -5,6 +5,7 @@
 
 void command_quit(void);
 void command_move_cursor(KEY key);
+void command_insert_line(void);
 void command_insert_char(char c);
 void command_delete_char(void);
 void command_save_buffer(void);
diff --git a/src/buffer.c b/src/buffer.c
index 2900052..5055047 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -23,8 +23,7 @@ struct buffer *buffer_create(void) {
     return buffer;
 }
 
-// TODO: Handle file not existing
-void buffer_read_file(struct buffer *buffer, const char *filename) {
+void buffer_read_file(struct buffer *buffer, const char *filename) { // TODO: Add error handling
     if (buffer->filename)
         free(buffer->filename);
 
@@ -53,7 +52,7 @@ void buffer_read_file(struct buffer *buffer, const char *filename) {
             line_buffer[i] = c;
         }
 
-        buffer_append_row(buffer, line_buffer, i);
+        buffer_insert_row(buffer, line_buffer, i, buffer->n_rows);
         file_remaining = (c != EOF);
     }
 
@@ -95,18 +94,31 @@ END:
     return errcode;
 }
 
-void buffer_append_row(struct buffer *buffer, const char *chars, int n_chars) {
+void buffer_insert_row(struct buffer *buffer, const char *chars, int n_chars, int at) { // TODO: Make this take an erow
     buffer->rows = realloc(buffer->rows, sizeof(struct erow) * (buffer->n_rows + 1));
-    struct erow *new_row = &buffer->rows[buffer->n_rows++];
+    memmove(buffer->rows + at, buffer->rows + at + 1, sizeof(struct erow) * (buffer->n_rows - at));
+    struct erow *erow = buffer->rows + at;
 
-    new_row->chars = malloc(n_chars);
-    memcpy(new_row->chars, chars, n_chars);
-    new_row->n_chars = n_chars;
+    erow->chars = malloc(n_chars);
+    memcpy(erow->chars, chars, n_chars);
+    erow->n_chars = n_chars;
 
-    new_row->rchars = NULL;
-    new_row->n_rchars = 0;
+    erow->rchars = NULL;
+    erow->n_rchars = 0;
 
-    erow_update_rendering(new_row);
+    erow_update_rendering(erow);
+
+    buffer->modified = true;
+    buffer->n_rows++;
+}
+
+void buffer_delete_row(struct buffer *buffer, int at) {
+    if (!(0 <= at && at < buffer->n_rows))
+        return;
+
+    erow_free(buffer->rows + at);
+    memmove(buffer->rows + at, buffer->rows + at + 1, sizeof(struct erow) * (buffer->n_rows - at - 1));
+    buffer->n_rows--;
 
     buffer->modified = true;
 }
@@ -117,10 +129,8 @@ void buffer_free(struct buffer *buffer) {
 }
 
 static void buffer_free_rows(struct buffer *buffer) {
-    for (int i = 0; i < buffer->n_rows; i++) {
-        if (buffer->rows->chars) free(buffer->rows->chars);
-        if (buffer->rows->rchars) free(buffer->rows->rchars);
-    }
+    for (int i = 0; i < buffer->n_rows; i++)
+        erow_free(buffer->rows + i);
 }
 
 static char *buffer_get_string(struct buffer *buffer, size_t *len_p) {
@@ -179,9 +189,19 @@ void erow_update_rendering(struct erow *erow) {
     free(line_buffer);
 }
 
+void erow_append_string(struct erow *erow, const char *s, size_t s_len) {
+    erow->n_chars = erow->n_chars + s_len;
+    erow->chars = realloc(erow->chars, erow->n_chars);
+
+    memcpy(erow->chars + erow->n_chars - s_len, s, s_len);
+    erow_update_rendering(erow);
+
+    E.current_buf->modified = true; // TODO
+}
+
 void erow_insert_char(struct erow *erow, int at, char c) {
-    if (at < 0) at = 0;
-    if (at > erow->n_chars) at = erow->n_chars;
+    if (!(0 <= at && at <= erow->n_chars))
+        return;
 
     erow->chars = realloc(erow->chars, erow->n_chars + 1);
     memmove(erow->chars + at + 1, erow->chars + at, erow->n_chars - at);
@@ -191,24 +211,20 @@ void erow_insert_char(struct erow *erow, int at, char c) {
 
     erow_update_rendering(erow);
 
-    // TODO: Seems like a bad idea
-    E.current_buf->modified = true;
+    E.current_buf->modified = true; // TODO
 }
 
 void erow_delete_char(struct erow *erow, int at) {
-    if (at < 0) at = 0;
-    if (at > erow->n_chars) at = erow->n_chars;
+    if (!(0 <= at && at < erow->n_chars))
+        return;
 
-    if (at != 0) {
-        memmove(erow->chars + at, erow->chars + at + 1, erow->n_chars - at);
-        erow->n_chars--;
-        erow->chars = realloc(erow->chars, erow->n_chars);
-        E.cx--;
-        erow_update_rendering(erow);
-    }
+    memmove(erow->chars + at, erow->chars + at + 1, erow->n_chars - at);
+    erow->n_chars--;
+    erow->chars = realloc(erow->chars, erow->n_chars);
+    E.cx--;
+    erow_update_rendering(erow);
 
-    // TODO
-    E.current_buf->modified = true;
+    E.current_buf->modified = true; // TODO
 }
 
 int erow_cx_to_rx(struct erow *erow, int cx) {
@@ -242,3 +258,8 @@ int erow_rx_to_cx(struct erow *erow, int rx) {
 
     return (_rx >= rx ? cx : erow->n_chars);
 }
+
+void erow_free(struct erow *erow) {
+    if (erow->chars) free(erow->chars);
+    if (erow->rchars) free(erow->rchars);
+}
diff --git a/src/commands.c b/src/commands.c
index 8fab52c..031b602 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -28,8 +28,8 @@ void command_move_cursor(KEY key) {
     struct erow *rows = E.current_buf->rows;
     int n_rows = E.current_buf->n_rows;
 
-    struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
-    int max_x = (current_row ? current_row->n_chars : 0);
+    struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
+    int max_x = (erow ? erow->n_chars : 0);
 
     switch (key) {
         case ARROW_LEFT:
@@ -70,21 +70,43 @@ void command_move_cursor(KEY key) {
     cursor_adjust_viewport();
 }
 
+void command_insert_line(void) {
+    buffer_insert_row(E.current_buf, NULL, 0, ++E.cy);
+
+    E.cx = 0;
+    E.rx = 0;
+}
+
 void command_insert_char(char c) {
     if (E.cy == E.current_buf->n_rows)
-        buffer_append_row(E.current_buf, NULL, 0);
+        buffer_insert_row(E.current_buf, NULL, 0, E.current_buf->n_rows);
 
     erow_insert_char(E.current_buf->rows+E.cy, E.cx++, c);
     E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx);
 }
 
-void command_delete_char(void) {
-    struct erow *row = E.current_buf->rows + E.cy;
+void command_delete_char(void) { // TODO
+    if (E.cx == 0 && E.cy == 0) return;
+    if (E.cy == E.current_buf->n_rows) {
+        E.cx = E.current_buf->rows[--E.cy].n_chars;
+        E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx);
+        return;
+    }
 
-    if (E.cx == 0) {
-        // TODO
-    } else
-        erow_delete_char(row, E.cx);
+    if (E.cx > 0) {
+        erow_delete_char(E.current_buf->rows+E.cy, E.cx - 1);
+    }
+    else {
+        struct erow *c_row = E.current_buf->rows + E.cy;
+        struct erow *p_row = E.current_buf->rows + E.cy - 1;
+
+        E.cx = p_row->n_chars;
+
+        erow_append_string(p_row, c_row->chars, c_row->n_chars);
+        buffer_delete_row(E.current_buf, E.cy);
+
+        E.cy--;
+    }
 
     E.rx = erow_cx_to_rx(E.current_buf->rows+E.cy, E.cx);
 }
@@ -102,8 +124,8 @@ static void cursor_check_file_bounds(bool horizontal) {
     struct erow *rows = E.current_buf->rows;
     int n_rows = E.current_buf->n_rows;
 
-    struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
-    int max_x = (current_row ? current_row->n_chars : 0);
+    struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
+    int max_x = (erow ? erow->n_chars : 0);
 
     if (E.cy < 0)
         E.cy = 0;
@@ -114,8 +136,8 @@ static void cursor_check_file_bounds(bool horizontal) {
     if (E.cx < 0) {
         if (E.cy > 0 && horizontal)
         {
-            current_row = &rows[--E.cy];
-            max_x = current_row->n_chars;
+            erow = &rows[--E.cy];
+            max_x = erow->n_chars;
 
             E.cx = max_x;
         }
@@ -134,13 +156,13 @@ static void cursor_update_rx(bool horizontal) {
     struct erow *rows = E.current_buf->rows;
     int n_rows = E.current_buf->n_rows;
 
-    struct erow *current_row = (rows && E.cy < n_rows ? rows + E.cy : NULL);
-    int max_x = (current_row ? current_row->n_chars : 0);
+    struct erow *erow = (rows && E.cy < n_rows ? rows + E.cy : NULL);
+    int max_x = (erow ? erow->n_chars : 0);
 
     static int saved_rx = 0;
-    if (horizontal) saved_rx = erow_cx_to_rx(current_row, E.cx);
+    if (horizontal) saved_rx = erow_cx_to_rx(erow, E.cx);
     else {
-        E.cx = erow_rx_to_cx(current_row, saved_rx);
+        E.cx = erow_rx_to_cx(erow, saved_rx);
         if (E.cx > max_x)
             E.cx = max_x;
     }
diff --git a/src/input.c b/src/input.c
index d5502e9..37fec91 100644
--- a/src/input.c
+++ b/src/input.c
@@ -30,12 +30,13 @@ void input_process_key(void) {
             break;
 
         case '\r':
-            // TODO
+            command_insert_line();
             break;
 
+        case DEL:
+            command_move_cursor(ARROW_RIGHT);
         case BACKSPACE:
         case CTRL_KEY('H'):
-        case DEL:
             command_delete_char();
             break;
 
diff --git a/src/ui.c b/src/ui.c
index 2ca0151..6be551c 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -43,10 +43,10 @@ static void ui_draw_rows(struct append_buf *draw_buf) {
         bool no_file = (E.current_buf->n_rows == 0);
 
         if (in_file) {
-            struct erow curr_row = E.current_buf->rows[y + E.row_off];
-            int max_len = MIN(curr_row.n_rchars - E.col_off, E.screencols);
+            struct erow erow = E.current_buf->rows[y + E.row_off];
+            int max_len = MIN(erow.n_rchars - E.col_off, E.screencols);
 
-            ab_append(draw_buf, curr_row.rchars + E.col_off, MAX(max_len, 0));
+            ab_append(draw_buf, erow.rchars + E.col_off, MAX(max_len, 0));
         } else if (no_file && y == E.screenrows / 2) {
             char welcome[64];
             int len = snprintf(welcome, sizeof(welcome),