Index: uspace/app/edit/edit.c
===================================================================
--- uspace/app/edit/edit.c	(revision 0f24c57e045c0cbbc79a5fa384ea221044ac03db)
+++ uspace/app/edit/edit.c	(revision 0b772f546b9cf05519bdb05442348d3c2e79f3bd)
@@ -45,4 +45,5 @@
 #include <align.h>
 #include <macros.h>
+#include <clipboard.h>
 #include <bool.h>
 
@@ -119,4 +120,5 @@
     spt_t const *epos);
 static char *filename_prompt(char const *prompt, char const *init_value);
+static char *range_get_str(spt_t const *spos, spt_t const *epos);
 
 static void pane_text_display(void);
@@ -133,5 +135,8 @@
 
 static bool selection_active(void);
+static void selection_get_points(spt_t *pa, spt_t *pb);
 static void selection_delete(void);
+static void selection_copy(void);
+static void insert_clipboard_data(void);
 
 static void pt_get_sof(spt_t *pt);
@@ -321,4 +326,13 @@
 	case KC_E:
 		file_save_as();
+		break;
+	case KC_C:
+		selection_copy();
+		break;
+	case KC_V:
+		selection_delete();
+		insert_clipboard_data();
+		pane.rflags |= REDRAW_TEXT;
+		caret_update();
 		break;
 	default:
@@ -579,4 +593,40 @@
 }
 
+/** Return contents of range as a new string. */
+static char *range_get_str(spt_t const *spos, spt_t const *epos)
+{
+	char *buf;
+	spt_t sp, bep;
+	size_t bytes;
+	size_t buf_size, bpos;
+
+	buf_size = 1;
+
+	buf = malloc(buf_size);
+	if (buf == NULL)
+		return NULL;
+
+	bpos = 0;
+	sp = *spos;
+
+	while (true) {
+		sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
+		    &bep);
+		bytes = str_size(&buf[bpos]);
+		bpos += bytes;
+		sp = bep;
+
+		if (spt_equal(&bep, epos))
+			break;
+
+		buf_size *= 2;
+		buf = realloc(buf, buf_size);
+		if (buf == NULL)
+			return NULL;
+	}
+
+	return buf;
+}
+
 static void pane_text_display(void)
 {
@@ -913,4 +963,18 @@
 }
 
+static void selection_get_points(spt_t *pa, spt_t *pb)
+{
+	spt_t pt;
+
+	tag_get_pt(&pane.sel_start, pa);
+	tag_get_pt(&pane.caret_pos, pb);
+
+	if (spt_cmp(pa, pb) > 0) {
+		pt = *pa;
+		*pa = *pb;
+		*pb = pt;
+	}
+}
+
 /** Delete selected text. */
 static void selection_delete(void)
@@ -940,4 +1004,41 @@
 }
 
+static void selection_copy(void)
+{
+	spt_t pa, pb;
+	char *str;
+
+	selection_get_points(&pa, &pb);
+	str = range_get_str(&pa, &pb);
+	if (str == NULL || clipboard_put_str(str) != EOK) {
+		status_display("Copying to clipboard failed!");
+	}
+	free(str);
+}
+
+static void insert_clipboard_data(void)
+{
+	char *str;
+	size_t off;
+	wchar_t c;
+	int rc;
+
+	rc = clipboard_get_str(&str);
+	if (rc != EOK || str == NULL)
+		return;
+
+	off = 0;
+
+	while (true) {
+		c = str_decode(str, &off, STR_NO_LIMIT);
+		if (c == '\0')
+			break;
+
+		insert_char(c);
+	}
+
+	free(str);
+}
+
 /** Get start-of-file s-point. */
 static void pt_get_sof(spt_t *pt)
