diff --git a/src/edit/buffer.rs b/src/edit/buffer.rs
index a553d839988c16d0e90e2f42f0fd86b495a83d6b..514ff4e53d4de8d9ddc7f2920305ba179240d01a 100644
--- a/src/edit/buffer.rs
+++ b/src/edit/buffer.rs
@@ -59,6 +59,9 @@ pub trait TextBuffer<'a> {
     /// Get an iterator over the lines in the buffer.
     fn lines(&'a self) -> Self::LineIter;
 
+    /// Get an iterator over the line starting from a certain line
+    fn lines_from(&'a self, from: usize) -> Self::LineIter;
+
     /// Get the leading whitespaces of the nth line. Used for autoindenting.
     fn get_indent(&self, n: usize) -> &str;
 }
@@ -202,6 +205,13 @@ impl<'a> TextBuffer<'a> for SplitBuffer {
         }
     }
 
+    fn lines_from(&'a self, from: usize) -> SplitBufIter<'a> {
+        SplitBufIter {
+            buffer: self,
+            line: from,
+        }
+    }
+
     fn get_indent(&self, n: usize) -> &str {
         if let Some(ln) = self.get_line(n) {
             let mut len = 0;
diff --git a/src/io/graphics.rs b/src/io/graphics.rs
index e73010dac04c54ab2a31f6caa0060946d7674907..c5e932452dba2e55acff77d4d2ad857dfeaaee0f 100644
--- a/src/io/graphics.rs
+++ b/src/io/graphics.rs
@@ -9,60 +9,106 @@ use state::mode::{Mode, PrimitiveMode};
 #[cfg(feature = "orbital")]
 use orbclient::{Color, Renderer};
 
+use std::iter;
+
 #[cfg(feature = "orbital")]
 impl Editor {
     /// Redraw the window
     pub fn redraw(&mut self) {
-        // TODO: Only draw when relevant for the window
-        let (pos_x, pos_y) = self.pos();
+        let w = self.window.width() as usize;
+        let h = self.window.height() as usize;
 
-        let w = self.window.width();
-        let h = self.window.height();
+        let vert_offset: usize = 0;
 
-        if self.buffers.current_buffer_info().scroll_y > 0
-            && pos_y <= self.buffers.current_buffer_info().scroll_y
-        {
-            self.buffers.current_buffer_info_mut().scroll_y = pos_y - 1;
-        }
+        let horz_offset: usize = if self.options.line_numbers {
+            let len = self.buffers.current_buffer_info().raw_buffer.len();
+            let mut ret: usize = 3;
+            while len >= 10usize.pow((ret - 1) as u32) {
+                ret += 1;
+            }
+            ret
+        } else {
+            0
+        };
 
-        let window_lines = (h as usize / 16) - 2;
+        let max_vert_chars = h/self.char_height - 2 - vert_offset;
+        let max_horz_chars = w/self.char_width - horz_offset;
 
-        if pos_y > self.buffers.current_buffer_info().scroll_y + window_lines {
-            self.buffers.current_buffer_info_mut().scroll_y = pos_y - window_lines;
-        }
+        // Redraw window
+        self.window.set(Color::rgb(25, 25, 25));
+
+        let mut scr_lines: usize = 0;
+        let mut scr_chars: usize = 0;
 
-        let (scroll_x, scroll_y) = {
+        self.cursor_in_window(max_horz_chars, max_vert_chars);
+
+        let (_scroll_x, scroll_y) = {
             let current_buffer = self.buffers.current_buffer_info();
 
             (current_buffer.scroll_x, current_buffer.scroll_y)
         };
 
-        // Redraw window
+        let (pos_x, pos_y) = self.pos();
+
+        let (window_pos_x, window_pos_y) = self.coords_to_window_coords((pos_x, pos_y), max_horz_chars);
+
         self.window.set(Color::rgb(25, 25, 25));
 
         if self.options.line_marker {
             self.window.rect(
                 0,
-                (pos_y - scroll_y) as i32 * 16,
-                w,
+                ((window_pos_y + vert_offset) * self.char_height) as i32,
+                w as u32,
                 16,
                 Color::rgb(45, 45, 45),
             );
         }
 
         self.window.rect(
-            8 * (pos_x - scroll_x) as i32,
-            16 * (pos_y - scroll_y) as i32,
-            8,
-            16,
+            ((window_pos_x + horz_offset) * self.char_width)  as i32,
+            ((window_pos_y + vert_offset) * self.char_height) as i32,
+            self.char_width as u32,
+            self.char_height as u32,
             Color::rgb(255, 255, 255),
         );
 
         let mut string = false;
 
+        'outer: for (y, row) in self.buffers.current_buffer().lines_from(scroll_y).enumerate() {
+            // Print line numbers
+            if self.options.line_numbers {
+                let mut line_number = scroll_y + y as usize + 1;
+                // The amount of digits for this line number
+                let mut digit_nr: usize = 0;
+                while line_number >= 10usize.pow(digit_nr as u32) {
+                   digit_nr += 1;
+                }
+                // Print the digits for this line number
+                for i in 1..digit_nr + 1 {
+                    let digit = ((line_number % 10) as u8 + ('0' as u32) as u8) as char;
+                    line_number = (line_number - line_number % 10)/10 as usize;
+                    self.window.char(
+                        (self.char_width * (horz_offset - 1 - i)) as i32,
+                        (self.char_height * (scr_lines + vert_offset)) as i32,
+                        digit,
+                        Color::rgb(255, 255, 0),
+                    );
+                }
+            }
+            for (x, c) in row.chars().flat_map(|c| if c == '\t' {
+                                                    iter::repeat(' ').take(4)
+                                                    } else {
+                                                        iter::repeat(c).take(1)
+                                                    }).enumerate() {
+                // New screen line
+                if scr_chars >= max_horz_chars {
+                    scr_chars = 0;
+                    scr_lines += 1;
+                    if scr_lines > max_vert_chars {
+                        break 'outer;
+                    }
+                }
 
-        for (y, row) in self.buffers.current_buffer().lines().enumerate() {
-            for (x, c) in row.chars().enumerate() {
                 // TODO: Move outta here
                 let color = if self.options.highlight {
                     match c {
@@ -96,31 +142,86 @@ impl Editor {
                     (255, 255, 255)
                 };
 
-                let c = if c == '\t' { ' ' } else { c };
-
-                if pos_x == x && pos_y == y {
+                if pos_x == x && (pos_y - scroll_y) == y {
                     self.window.char(
-                        8 * (x as isize - scroll_x as isize) as i32,
-                        16 * (y as isize - scroll_y as isize) as i32,
+                        (self.char_width * (scr_chars + horz_offset)) as i32,
+                        (self.char_height * (scr_lines + vert_offset)) as i32,
                         c,
                         Color::rgb(color.0 / 3, color.1 / 3, color.2 / 3),
                     );
                 } else {
                     self.window.char(
-                        8 * (x as isize - scroll_x as isize) as i32,
-                        16 * (y as isize - scroll_y as isize) as i32,
+                        (self.char_width * (scr_chars + horz_offset)) as i32,
+                        (self.char_height * (scr_lines + vert_offset)) as i32,
                         c,
                         Color::rgb(color.0, color.1, color.2),
                     );
                 }
+                scr_chars += 1;
+            }
+            scr_lines += 1;
+            scr_chars = 0;
+            if scr_lines > max_vert_chars {
+                break;
             }
         }
-
+        self.redraw_status_bar();
         self.redraw_task = RedrawTask::None;
+        self.window.sync();
+    }
 
+    fn coords_to_window_coords(&mut self, point: (usize, usize), max_horz_chars: usize) -> (usize, usize) {
+        let (_, scroll_y) = {
+            let current_buffer = self.buffers.current_buffer_info();
 
-        self.redraw_status_bar();
-        self.window.sync();
+            (current_buffer.scroll_x, current_buffer.scroll_y)
+        };
+
+        let to_y = point.1 - scroll_y;
+
+        let mut ret_y = 0;
+
+        let ret_x = point.0 % max_horz_chars;
+        for (y, row) in self.buffers.current_buffer().lines_from(scroll_y).enumerate() {
+            if to_y > y {
+                ret_y += row.len() / max_horz_chars + 1;
+            } else {
+                ret_y += point.0 / max_horz_chars;
+                break;
+            }
+        }
+        (ret_x, ret_y)
+    }
+
+    // Ensure that the cursor is visible
+    fn cursor_in_window(&mut self, max_horz_chars: usize, max_vert_chars: usize) {
+        let (_pos_x, pos_y) = self.pos();
+        if self.buffers.current_buffer_info().scroll_y > 0
+            && pos_y <= self.buffers.current_buffer_info().scroll_y
+        {
+            self.buffers.current_buffer_info_mut().scroll_y = if pos_y == 0 {
+                pos_y
+            } else {
+                pos_y - 1
+            };
+            return;
+        }
+
+        let scroll_y = self.buffers.current_buffer_info().scroll_y;
+        let mut line_counter = 0;
+        let mut result_y = 0;
+
+        for (y, row) in self.buffers.current_buffer().lines_from(pos_y+1).rev().enumerate() {
+            if pos_y - y < scroll_y {
+                return;
+            }
+            line_counter += row.len() / max_horz_chars + 1;
+            if line_counter > max_vert_chars {
+                result_y = pos_y - y;
+                break;
+            }
+        }
+        self.buffers.current_buffer_info_mut().scroll_y = result_y;
     }
 
     /// Redraw the status bar
diff --git a/src/state/editor.rs b/src/state/editor.rs
index 5950e441bd0642c3e0ff2f9eb9b8a7877758cc2b..a7712e4a68e04550613ff50e39905c899287e424 100644
--- a/src/state/editor.rs
+++ b/src/state/editor.rs
@@ -177,6 +177,10 @@ pub struct Editor {
     pub redraw_task: RedrawTask,
     /// The previous instruction
     pub previous_instruction: Option<Inst>,
+    /// The character width in pixels
+    pub char_width: usize,
+    /// The character height in pixels
+    pub char_height: usize,
 }
 
 impl Editor {
@@ -196,6 +200,8 @@ impl Editor {
             key_state: KeyState::new(),
             redraw_task: RedrawTask::None,
             previous_instruction: None,
+            char_width: 8,
+            char_height: 16,
         };
 
         #[cfg(not(feature = "orbital"))]
@@ -207,6 +213,8 @@ impl Editor {
             key_state: KeyState::new(),
             redraw_task: RedrawTask::None,
             previous_instruction: None,
+            char_width: 8,
+            char_height: 16,
         };
 
         let mut files: Vec<String> = Vec::new();
diff --git a/src/state/options.rs b/src/state/options.rs
index f6ab37c12980b965e6c1dfb2df5da019d34185c1..43ce9a681d68d43a2f6e492a68ec6e0547b18010 100644
--- a/src/state/options.rs
+++ b/src/state/options.rs
@@ -10,6 +10,8 @@ pub struct Options {
     pub line_marker: bool,
     /// enables read-only mode
     pub readonly: bool,
+    /// Enable linenumbers
+    pub line_numbers: bool,
 }
 
 impl Options {
@@ -21,6 +23,7 @@ impl Options {
             highlight: true,
             line_marker: true,
             readonly: false,
+            line_numbers: false,
         }
     }
 
@@ -32,6 +35,7 @@ impl Options {
             "highlight" | "hl" => Some(&mut self.highlight),
             "line_marker" | "linemarker" | "linemark" | "lm" => Some(&mut self.line_marker),
             "readonly" | "ro" => Some(&mut self.readonly),
+            "line_numbers" | "ln" => Some(&mut self.line_numbers),
             _ => None,
         }
     }
@@ -44,6 +48,7 @@ impl Options {
             "highlight" | "hl" => Some(self.highlight),
             "line_marker" | "linemarker" | "linemark" | "lm" => Some(self.line_marker),
             "readonly" | "ro" => Some(self.readonly),
+            "line_numbers" | "ln" => Some(self.line_numbers),
             _ => None,
         }
     }