Index: commands.c
===================================================================
--- commands.c	(revision 7f0c26f7782b597747f2f3b58cf1b0d067a8dff0)
+++ commands.c	(revision a60edf29aa3019eac300fcdff11cfb2576f46f69)
@@ -889,4 +889,19 @@
 		  OWL_CTX_EDIT,
 		  "exchanges the point and the mark",
+		  "", ""),
+
+  OWLCMD_VOID_CTX("edit:copy-region-as-kill", owl_editwin_copy_region_as_kill,
+		  OWL_CTX_EDIT,
+		  "copy the text between the point and the mark",
+		  "", ""),
+
+  OWLCMD_VOID_CTX("edit:kill-region", owl_editwin_kill_region,
+		  OWL_CTX_EDIT,
+		  "kill text between the point and the mark",
+		  "", ""),
+
+  OWLCMD_VOID_CTX("edit:yank", owl_editwin_yank,
+		  OWL_CTX_EDIT,
+		  "insert the current text from the kill buffer",
 		  "", ""),
 
Index: editwin.c
===================================================================
--- editwin.c	(revision 7f0c26f7782b597747f2f3b58cf1b0d067a8dff0)
+++ editwin.c	(revision a60edf29aa3019eac300fcdff11cfb2576f46f69)
@@ -25,4 +25,5 @@
   int index;
   int mark;
+  char *killbuf;
   int goal_column;
   int topindex;
@@ -41,9 +42,9 @@
 };
 
-
 static void oe_reframe(owl_editwin *e);
 static void oe_save_excursion(owl_editwin *e, oe_excursion *x);
 static void oe_release_excursion(owl_editwin *e, oe_excursion *x);
 static void oe_restore_excursion(owl_editwin *e, oe_excursion *x);
+static void oe_restore_mark_only(owl_editwin *e, oe_excursion *x);
 static int oe_count_glyphs(char *s);
 static int oe_char_width(gunichar c, int column);
@@ -56,4 +57,6 @@
 static gunichar owl_editwin_get_char_at_point(owl_editwin *e);
 static int owl_editwin_replace(owl_editwin *e, int count, char *s);
+static char *oe_copy_buf(owl_editwin *e, char *buf, int len);
+static int oe_copy_region(owl_editwin *e);
 
 #define INCR 4096
@@ -113,4 +116,7 @@
   oe_set_index(e, 0);
   oe_set_mark(e, -1);
+  if (e->killbuf != NULL)
+    free(e->killbuf);
+  e->killbuf = NULL;
   e->goal_column = -1;
   e->cursorx = -1;
@@ -345,4 +351,13 @@
     e->mark = x->mark;
     e->lock = x->lock;
+
+    oe_release_excursion(e, x);
+  }
+}
+
+static void oe_restore_mark_only(owl_editwin *e, oe_excursion *x)
+{
+  if (x->valid == VALID_EXCURSION) {
+    e->mark = x->mark;
 
     oe_release_excursion(e, x);
@@ -544,5 +559,5 @@
   if (need > 0) {
     size = e->allocated + need + INCR - (need % INCR);
-    p = realloc(e->buff, size);
+    p = owl_realloc(e->buff, size);
     if (p == NULL) {
       /* XXX signal impending doom somehow and don't do anything */
@@ -915,19 +930,21 @@
 {
   oe_excursion x;
-  int distance;
 
   oe_save_excursion(e, &x);
-  distance = owl_editwin_forward_word(e);
-  oe_restore_excursion(e, &x);
-  owl_editwin_replace(e, distance, "");
+  oe_set_mark(e, e->index);
+  owl_editwin_forward_word(e);
+  owl_editwin_kill_region(e);
+  oe_restore_mark_only(e, &x);
 }
 
 void owl_editwin_delete_previousword(owl_editwin *e)
 {
-  /* go backwards to the last non-space character, then delete chars */
-  int distance;
-
-  distance = owl_editwin_backward_word(e);
-  owl_editwin_replace(e, -distance, "");
+  oe_excursion x;
+
+  oe_save_excursion(e, &x);
+  oe_set_mark(e, e->index);
+  owl_editwin_backward_word(e);
+  owl_editwin_kill_region(e);
+  oe_restore_mark_only(e, &x);
 }
 
@@ -943,7 +960,63 @@
 
   oe_save_excursion(e, &x);
+  owl_editwin_set_mark(e);
   distance = owl_editwin_move_to_end_of_line(e);
+  if (distance)
+    owl_editwin_kill_region(e);
+  else
+    owl_editwin_replace(e, 1, "");
   oe_restore_excursion(e, &x);
-  owl_editwin_replace(e, distance ? distance : 1, "");
+}
+
+void owl_editwin_yank(owl_editwin *e)
+{
+  if (e->killbuf != NULL)
+    owl_editwin_replace(e, 0, e->killbuf);
+}
+
+static char *oe_copy_buf(owl_editwin *e, char *buf, int len)
+{
+  char *p;
+
+  p = owl_malloc(len + 1);
+
+  if (p != NULL) {
+    owl_free(e->killbuf);
+    e->killbuf = p;
+    memcpy(e->killbuf, buf, len);
+    e->killbuf[len] = 0;
+  }
+
+  return p;
+}
+
+static int oe_copy_region(owl_editwin *e)
+{
+  char *p;
+  int start, end;
+
+  if (e->mark == -1)
+    return 0;
+
+  start = MIN(e->index, e->mark);
+  end = MAX(e->index, e->mark);
+
+  p = oe_copy_buf(e, e->buff + start, end - start);
+  if (p != NULL)
+    return end - start;
+  return 0;
+}
+
+void owl_editwin_copy_region_as_kill(owl_editwin *e)
+{
+  oe_copy_region(e);
+}
+
+void owl_editwin_kill_region(owl_editwin *e)
+{
+  if (e->index > e->mark)
+    owl_editwin_exchange_point_and_mark(e);
+
+  owl_editwin_replace(e, oe_copy_region(e), "");
 }
 
Index: keys.c
===================================================================
--- keys.c	(revision 7f0c26f7782b597747f2f3b58cf1b0d067a8dff0)
+++ keys.c	(revision a60edf29aa3019eac300fcdff11cfb2576f46f69)
@@ -86,4 +86,8 @@
   BIND_CMD("C-@",         "edit:set-mark", "");
   BIND_CMD("C-x C-x",     "edit:exchange-point-and-mark", "");
+
+  BIND_CMD("M-w",         "edit:copy-region-as-kill", "");
+  BIND_CMD("C-w",         "edit:kill-region", "");
+  BIND_CMD("C-y",         "edit:yank", "");
 
   BIND_CMD("C-l",         "( edit:recenter ; redisplay )", "");
