Looks pretty good. I might add an undo boundary around the whole thing (I note emacs doesn't do this properly, at least on the version I have here)...
like so: Index: def.h =================================================================== RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.114 diff -u -r1.114 def.h --- def.h 17 Jan 2011 03:12:06 -0000 1.114 +++ def.h 17 Jan 2011 03:33:32 -0000 @@ -512,6 +512,7 @@ int backdel(int, int); int space_to_tabstop(int, int); int backtoindent(int, int); +int joinline(int, int); /* extend.c X */ int insert(int, int); Index: funmap.c =================================================================== RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.33 diff -u -r1.33 funmap.c --- funmap.c 17 Jan 2011 03:12:06 -0000 1.33 +++ funmap.c 17 Jan 2011 03:33:32 -0000 @@ -103,6 +103,7 @@ {fillword, "insert-with-wrap",}, {backisearch, "isearch-backward",}, {forwisearch, "isearch-forward",}, + {joinline, "join-line",}, {justone, "just-one-space",}, {ctrlg, "keyboard-quit",}, {killbuffer_cmd, "kill-buffer",}, Index: keymap.c =================================================================== RCS file: /cvs/src/usr.bin/mg/keymap.c,v retrieving revision 1.44 diff -u -r1.44 keymap.c --- keymap.c 17 Jan 2011 03:12:06 -0000 1.44 +++ keymap.c 17 Jan 2011 03:33:32 -0000 @@ -228,7 +228,7 @@ NULL, /* [ */ delwhite, /* \ */ rescan, /* ] */ - rescan, /* ^ */ + joinline, /* ^ */ rescan, /* _ */ rescan, /* ` */ rescan, /* a */ Index: mg.1 =================================================================== RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.48 diff -u -r1.48 mg.1 --- mg.1 17 Jan 2011 03:12:06 -0000 1.48 +++ mg.1 17 Jan 2011 03:33:33 -0000 @@ -220,6 +220,8 @@ end-of-buffer .It M-\e delete-horizontal-space +.It M-^ +join-line .It M-b backward-word .It M-c @@ -510,6 +512,9 @@ isearch ignores any explicit arguments. If invoked during macro definition or evaluation, the non-incremental search-forward is invoked instead. +.It join-line +Join the current line to the previous. If called with an argument, +join the next line to the current one. .It just-one-space Delete any whitespace around dot, then insert a space. .It keyboard-quit Index: random.c =================================================================== RCS file: /cvs/src/usr.bin/mg/random.c,v retrieving revision 1.27 diff -u -r1.27 random.c --- random.c 17 Jan 2011 03:12:06 -0000 1.27 +++ random.c 17 Jan 2011 03:33:33 -0000 @@ -453,3 +453,33 @@ ++curwp->w_doto; return (TRUE); } + +/* + * Join the current line to the previous, or with arg, the next line + * to the current one. If the former line is not empty, leave exactly + * one space at the joint. Otherwise, leave no whitespace. + */ +int +joinline(int f, int n) +{ + int doto; + + undo_boundary_enable(FFRAND, 0); + if (f & FFARG) { + gotoeol(FFRAND, 1); + forwdel(FFRAND, 1); + } else { + gotobol(FFRAND, 1); + backdel(FFRAND, 1); + } + + delwhite(FFRAND, 1); + + if ((doto = curwp->w_doto) > 0) { + linsert(1, ' '); + curwp->w_doto = doto; + } + undo_boundary_enable(FFRAND, 1); + + return (TRUE); +}