diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index ed34933d36b2a..9a976c4aacf7d 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -10,6 +10,8 @@ import std::map;
 import std::option;
 import std::option::some;
 import std::option::none;
+import std::str;
+import std::vec;
 
 tag os { os_win32; os_macos; os_linux; }
 
@@ -50,8 +52,12 @@ fn span_to_str(span sp, codemap::codemap cm) -> str {
 fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
                    codemap::codemap cm) {
     auto ss = "<input>:0:0:0:0";
+    let option::t[@file_lines] maybe_lines = none;
     alt (sp) {
-        case (some(?ssp)) { ss = span_to_str(ssp, cm); }
+        case (some(?ssp)) {
+            ss = span_to_str(ssp, cm);
+            maybe_lines = some(span_to_lines(ssp, cm));
+        }
         case (none) { }
     }
     io::stdout().write_str(ss + ": ");
@@ -63,6 +69,82 @@ fn emit_diagnostic(option::t[span] sp, str msg, str kind, u8 color,
         term::reset(io::stdout().get_buf_writer());
     }
     io::stdout().write_str(#fmt(" %s\n", msg));
+    alt (maybe_lines) {
+        case (some(?lines)) {
+            // FIXME: reading in the entire file is the worst possible way to
+            //        get access to the necessary lines.
+            auto rdr = io::file_reader(lines.name);
+            auto file = str::unsafe_from_bytes(rdr.read_whole_stream());
+            auto fm = codemap::get_filemap(cm, lines.name);
+
+            // arbitrarily only print up to six lines of the error
+            auto max_lines = 6u;
+            auto elided = false;
+            auto display_lines = lines.lines;
+            if (vec::len(display_lines) > max_lines) {
+                display_lines = vec::slice(display_lines, 0u, max_lines);
+                elided = true;
+            }
+            // Print the offending lines
+            for (uint line in display_lines) {
+                io::stdout().write_str(#fmt("%s:%u ", fm.name, line + 1u));
+                auto s = codemap::get_line(fm, line as int, file);
+                if (!str::ends_with(s, "\n")) {
+                    s += "\n";
+                }
+                io::stdout().write_str(s);
+            }
+            if (elided) {
+                auto last_line = display_lines.(vec::len(display_lines) - 1u);
+                auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
+                auto indent = str::char_len(s);
+                auto out = "";
+                while (indent > 0u) { out += " "; indent -= 1u; }
+                out += "...\n";
+                io::stdout().write_str(out);
+            }
+
+            // If there's one line at fault we can easily point to the problem
+            if (vec::len(lines.lines) == 1u) {
+                auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
+                auto digits = 0u;
+                auto num = lines.lines.(0) / 10u;
+
+                // how many digits must be indent past?
+                while (num > 0u) { num /= 10u; digits += 1u; }
+
+                // indent past |name:## | and the 0-offset column location
+                auto left = str::char_len(fm.name) + digits + lo.col + 3u;
+                auto s = "";
+                while (left > 0u) { str::push_char(s, ' '); left -= 1u; }
+
+                s += "^";
+                auto hi = codemap::lookup_pos(cm, option::get(sp).hi);
+                if (hi.col != lo.col) {
+                    // the ^ already takes up one space
+                    auto width = hi.col - lo.col - 1u;
+                    while (width > 0u) {
+                        str::push_char(s, '~');
+                        width -= 1u;
+                    }
+                }
+                io::stdout().write_str(s + "\n");
+            }
+        }
+        case (_) {}
+    }
+}
+
+type file_lines = rec(str name, vec[uint] lines);
+
+fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
+    auto lo = codemap::lookup_pos(cm, sp.lo);
+    auto hi = codemap::lookup_pos(cm, sp.hi);
+    auto lines = [];
+    for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
+        lines += [i];
+    }
+    ret @rec(name=lo.filename, lines=lines);
 }
 
 obj session(ast::crate_num cnum,
diff --git a/src/comp/front/codemap.rs b/src/comp/front/codemap.rs
index 3e1aa3c59400b..e550b6a9e1675 100644
--- a/src/comp/front/codemap.rs
+++ b/src/comp/front/codemap.rs
@@ -1,5 +1,6 @@
 
 import std::vec;
+import std::str;
 
 
 /* A codemap is a thing that maps uints to file/line/column positions
@@ -40,6 +41,29 @@ fn lookup_pos(codemap map, uint pos) -> loc {
     }
     ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
 }
+
+fn get_line(filemap fm, int line, &str file) -> str {
+    let uint end;
+    if ((line as uint) + 1u >= vec::len(fm.lines)) {
+        end = str::byte_len(file);
+    } else {
+        end = fm.lines.(line + 1);
+    }
+    auto begin = fm.lines.(line) - fm.start_pos;
+    end -= fm.start_pos;
+    ret str::slice(file, begin, end);
+}
+
+fn get_filemap(codemap cm, str filename) -> filemap {
+    for (filemap fm in cm.files) {
+        if (fm.name == filename) {
+            ret fm;
+        }
+    }
+    //XXjdm the following triggers a mismatched type bug
+    //      (or expected function, found _|_)
+    fail;// ("asking for " + filename + " which we don't know about");
+}
 //
 // Local Variables:
 // mode: rust