Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision b67c7d64e02df739bde0adb28c242a4847afbe31)
+++ uspace/app/edit/edit.c	(revision 0f24c57e045c0cbbc79a5fa384ea221044ac03db)
@@ -74,4 +74,7 @@
 	tag_t caret_pos;
 
+	/** Start of selection */
+	tag_t sel_start;
+
 	/** 
 	 * Ideal column where the caret should try to get. This is used
@@ -107,4 +110,7 @@
 static void key_handle_unmod(console_event_t const *ev);
 static void key_handle_ctrl(console_event_t const *ev);
+static void key_handle_shift(console_event_t const *ev);
+static void key_handle_movement(unsigned int key, bool shift);
+
 static int file_save(char const *fname);
 static void file_save_as(void);
@@ -113,4 +119,5 @@
     spt_t const *epos);
 static char *filename_prompt(char const *prompt, char const *init_value);
+
 static void pane_text_display(void);
 static void pane_row_display(void);
@@ -118,4 +125,5 @@
 static void pane_status_display(void);
 static void pane_caret_display(void);
+
 static void insert_char(wchar_t c);
 static void delete_char_before(void);
@@ -123,6 +131,14 @@
 static void caret_update(void);
 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
+
+static bool selection_active(void);
+static void selection_delete(void);
+
 static void pt_get_sof(spt_t *pt);
 static void pt_get_eof(spt_t *pt);
+static int tag_cmp(tag_t const *a, tag_t const *b);
+static int spt_cmp(spt_t const *a, spt_t const *b);
+static int coord_cmp(coord_t const *a, coord_t const *b);
+
 static void status_display(char const *str);
 
@@ -172,4 +188,8 @@
 	caret_move(-ED_INFTY, -ED_INFTY, dir_before);
 
+	/* Place selection start tag. */
+	tag_get_pt(&pane.caret_pos, &pt);
+	sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+
 	/* Initial display */
 	console_clear(con);
@@ -190,7 +210,12 @@
 			/* Handle key press. */
 			if (((ev.mods & KM_ALT) == 0) &&
+			    ((ev.mods & KM_SHIFT) == 0) &&
 			     (ev.mods & KM_CTRL) != 0) {
 				key_handle_ctrl(&ev);
-			} else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
+			} else if (((ev.mods & KM_ALT) == 0) &&
+			    ((ev.mods & KM_CTRL) == 0) &&
+			     (ev.mods & KM_SHIFT) != 0) {
+				key_handle_shift(&ev);
+			} else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
 				key_handle_unmod(&ev);
 			}
@@ -207,5 +232,4 @@
 		if (pane.rflags & REDRAW_CARET)
 			pane_caret_display();
-			
 	}
 
@@ -220,41 +244,59 @@
 	switch (ev->key) {
 	case KC_ENTER:
+		selection_delete();
 		insert_char('\n');
 		caret_update();
 		break;
 	case KC_LEFT:
-		caret_move(0, -1, dir_before);
-		break;
 	case KC_RIGHT:
-		caret_move(0, 0, dir_after);
-		break;
 	case KC_UP:
-		caret_move(-1, 0, dir_before);
-		break;
 	case KC_DOWN:
-		caret_move(+1, 0, dir_before);
-		break;
 	case KC_HOME:
-		caret_move(0, -ED_INFTY, dir_before);
-		break;
 	case KC_END:
-		caret_move(0, +ED_INFTY, dir_before);
-		break;
 	case KC_PAGE_UP:
-		caret_move(-pane.rows, 0, dir_before);
-		break;
 	case KC_PAGE_DOWN:
-		caret_move(+pane.rows, 0, dir_before);
+		key_handle_movement(ev->key, false);
 		break;
 	case KC_BACKSPACE:
-		delete_char_before();
+		if (selection_active())
+			selection_delete();
+		else
+			delete_char_before();
 		caret_update();
 		break;
 	case KC_DELETE:
-		delete_char_after();
+		if (selection_active())
+			selection_delete();
+		else
+			delete_char_after();
 		caret_update();
 		break;
 	default:
 		if (ev->c >= 32 || ev->c == '\t') {
+			selection_delete();
+			insert_char(ev->c);
+			caret_update();
+		}
+		break;
+	}
+}
+
+/** Handle Shift-key combination. */
+static void key_handle_shift(console_event_t const *ev)
+{
+	switch (ev->key) {
+	case KC_LEFT:
+	case KC_RIGHT:
+	case KC_UP:
+	case KC_DOWN:
+	case KC_HOME:
+	case KC_END:
+	case KC_PAGE_UP:
+	case KC_PAGE_DOWN:
+		key_handle_movement(ev->key, true);
+		break;
+	default:
+		if (ev->c >= 32 || ev->c == '\t') {
+			selection_delete();
 			insert_char(ev->c);
 			caret_update();
@@ -282,4 +324,68 @@
 	default:
 		break;
+	}
+}
+
+static void key_handle_movement(unsigned int key, bool select)
+{
+	spt_t pt;
+	spt_t caret_pt;
+	coord_t c_old, c_new;
+	bool had_sel;
+
+	/* Check if we had selection before. */
+	tag_get_pt(&pane.caret_pos, &caret_pt);
+	tag_get_pt(&pane.sel_start, &pt);
+	had_sel = !spt_equal(&caret_pt, &pt);
+
+	switch (key) {
+	case KC_LEFT:
+		caret_move(0, -1, dir_before);
+		break;
+	case KC_RIGHT:
+		caret_move(0, 0, dir_after);
+		break;
+	case KC_UP:
+		caret_move(-1, 0, dir_before);
+		break;
+	case KC_DOWN:
+		caret_move(+1, 0, dir_before);
+		break;
+	case KC_HOME:
+		caret_move(0, -ED_INFTY, dir_before);
+		break;
+	case KC_END:
+		caret_move(0, +ED_INFTY, dir_before);
+		break;
+	case KC_PAGE_UP:
+		caret_move(-pane.rows, 0, dir_before);
+		break;
+	case KC_PAGE_DOWN:
+		caret_move(+pane.rows, 0, dir_before);
+		break;
+	default:
+		break;
+	}
+
+	if (select == false) {
+		/* Move sel_start to the same point as caret. */
+		sheet_remove_tag(&doc.sh, &pane.sel_start);
+		tag_get_pt(&pane.caret_pos, &pt);
+		sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
+	}
+
+	if (select) {
+		tag_get_pt(&pane.caret_pos, &pt);
+		spt_get_coord(&caret_pt, &c_old);
+		spt_get_coord(&pt, &c_new);
+
+		if (c_old.row == c_new.row)
+			pane.rflags |= REDRAW_ROW;
+		else
+			pane.rflags |= REDRAW_TEXT;
+
+	} else if (had_sel == true) {
+		/* Redraw because text was unselected. */
+		pane.rflags |= REDRAW_TEXT;
 	}
 }
@@ -517,5 +623,5 @@
 {
 	int i, j, fill;
-	spt_t rb, re, dep;
+	spt_t rb, re, dep, pt;
 	coord_t rbc, rec;
 	char row_buf[ROW_BUF_SIZE];
@@ -523,4 +629,19 @@
 	size_t pos, size;
 	unsigned s_column;
+	coord_t csel_start, csel_end, ctmp;
+
+	/* Determine selection start and end. */
+
+	tag_get_pt(&pane.sel_start, &pt);
+	spt_get_coord(&pt, &csel_start);
+
+	tag_get_pt(&pane.caret_pos, &pt);
+	spt_get_coord(&pt, &csel_end);
+
+	if (coord_cmp(&csel_start, &csel_end) > 0) {
+		ctmp = csel_start;
+		csel_start = csel_end;
+		csel_end = ctmp;
+	}
 
 	/* Draw rows from the sheet. */
@@ -543,4 +664,11 @@
 		/* Display text from the buffer. */
 
+		if (coord_cmp(&csel_start, &rbc) <= 0 &&
+		    coord_cmp(&rbc, &csel_end) < 0) {
+			fflush(stdout);
+			console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+			fflush(stdout);
+		}
+
 		console_goto(con, 0, i);
 		size = str_size(row_buf);
@@ -548,4 +676,16 @@
 		s_column = 1;
 		while (pos < size) {
+			if (csel_start.row == rbc.row && csel_start.column == s_column) {
+				fflush(stdout);
+				console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
+				fflush(stdout);
+			}
+	
+			if (csel_end.row == rbc.row && csel_end.column == s_column) {
+				fflush(stdout);
+				console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+				fflush(stdout);
+			}
+	
 			c = str_decode(row_buf, &pos, size);
 			if (c != '\t') {
@@ -562,4 +702,10 @@
 		}
 
+		if (csel_end.row == rbc.row && csel_end.column == s_column) {
+			fflush(stdout);
+			console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
+			fflush(stdout);
+		}
+
 		/* Fill until the end of display area. */
 
@@ -572,4 +718,5 @@
 			putchar(' ');
 		fflush(stdout);
+		console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
 	}
 
@@ -760,4 +907,36 @@
 }
 
+/** Check for non-empty selection. */
+static bool selection_active(void)
+{
+	return (tag_cmp(&pane.caret_pos, &pane.sel_start) != 0);
+}
+
+/** Delete selected text. */
+static void selection_delete(void)
+{
+	spt_t pa, pb;
+	coord_t ca, cb;
+	int rel;
+
+	tag_get_pt(&pane.sel_start, &pa);
+	tag_get_pt(&pane.caret_pos, &pb);
+	spt_get_coord(&pa, &ca);
+	spt_get_coord(&pb, &cb);
+	rel = coord_cmp(&ca, &cb);
+
+	if (rel == 0)
+		return;
+
+	if (rel < 0)
+		sheet_delete(&doc.sh, &pa, &pb);
+	else
+		sheet_delete(&doc.sh, &pb, &pa);
+
+	if (ca.row == cb.row)
+		pane.rflags |= REDRAW_ROW;
+	else
+		pane.rflags |= REDRAW_TEXT;
+}
 
 /** Get start-of-file s-point. */
@@ -781,4 +960,35 @@
 
 	sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
+}
+
+/** Compare tags. */
+static int tag_cmp(tag_t const *a, tag_t const *b)
+{
+	spt_t pa, pb;
+
+	tag_get_pt(a, &pa);
+	tag_get_pt(b, &pb);
+
+	return spt_cmp(&pa, &pb);
+}
+
+/** Compare s-points. */
+static int spt_cmp(spt_t const *a, spt_t const *b)
+{
+	coord_t ca, cb;
+
+	spt_get_coord(a, &ca);
+	spt_get_coord(b, &cb);
+
+	return coord_cmp(&ca, &cb);
+}
+
+/** Compare coordinats. */
+static int coord_cmp(coord_t const *a, coord_t const *b)
+{
+	if (a->row - b->row != 0)
+		return a->row - b->row;
+
+	return a->column - b->column;
 }
 
