This diff adds transpose-words to mg. It behaves slightly differently
from emacs when it comes to muliple iterations. Take this text for 
example:

abc def ghi
jkl mno pqr

If the cursor is on the 'd', then you do C-u 3 M-t, in emacs the
result will be:

abc ghi
jkl mno def pqr

The attached diff gives this result in mg:

abc ghi jkl
mno def pqr

Which personally I think is better. Also in emacs if you have this
situation:

123 456 789

abc def ghi
jkl mno pqr

And the cursor is on 'a', then you do C-u 3 M-t, the result will be:

123 456 abc def ghi

789
jkl mno pqr

Which I find quite zany when compared to the first example. The
attached diff for mg does this:

123 456 abc

def ghi 789
jkl mno pqr

Which makes more sense to me but perhaps it is just as zany... What do
people think? 

Mark

Index: def.h
===================================================================
RCS file: /cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.152
diff -u -p -u -p -r1.152 def.h
--- def.h       29 Oct 2015 19:46:47 -0000      1.152
+++ def.h       24 Dec 2015 09:27:00 -0000
@@ -602,6 +602,7 @@ int          capword(int, int);
 int             delfword(int, int);
 int             delbword(int, int);
 int             inword(void);
+int             transposeword(int, int);
 
 /* region.c X */
 int             killregion(int, int);
Index: funmap.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/funmap.c,v
retrieving revision 1.51
diff -u -p -u -p -r1.51 funmap.c
--- funmap.c    26 Sep 2015 15:03:15 -0000      1.51
+++ funmap.c    24 Dec 2015 09:27:00 -0000
@@ -201,6 +201,7 @@ static struct funmap functnames[] = {
        {togglereadonly, "toggle-read-only" },
        {twiddle, "transpose-chars",},
        {transposepara, "transpose-paragraphs",},
+       {transposeword, "transpose-words",},
        {undo, "undo",},
        {undo_add_boundary, "undo-boundary",},
        {undo_boundary_enable, "undo-boundary-toggle",},
Index: keymap.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/keymap.c,v
retrieving revision 1.57
diff -u -p -u -p -r1.57 keymap.c
--- keymap.c    26 Sep 2015 21:51:58 -0000      1.57
+++ keymap.c    24 Dec 2015 09:27:00 -0000
@@ -282,7 +282,7 @@ static PF metal[] = {
        fillpara,               /* q */
        backsearch,             /* r */
        forwsearch,             /* s */
-       rescan,                 /* t */
+       transposeword,          /* t */
        upperword,              /* u */
        backpage,               /* v */
        copyregion,             /* w */
Index: mg.1
===================================================================
RCS file: /cvs/src/usr.bin/mg/mg.1,v
retrieving revision 1.98
diff -u -p -u -p -r1.98 mg.1
--- mg.1        24 Dec 2015 09:07:47 -0000      1.98
+++ mg.1        24 Dec 2015 09:27:00 -0000
@@ -306,6 +306,8 @@ fill-paragraph
 search-backward
 .It M-s
 search-forward
+.It M-t
+transpose-words
 .It M-u
 upcase-word
 .It M-v
@@ -881,6 +883,12 @@ If multiple iterations are requested, th
 be moved
 .Va n
 paragraphs forward.
+.It transpose-words
+Transpose adjacent words.
+If multiple iterations are requested, the current word will
+be moved
+.Va n
+words forward.
 .It undo
 Undo the most recent action.
 If invoked again without an intervening command,
Index: word.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/word.c,v
retrieving revision 1.17
diff -u -p -u -p -r1.17 word.c
--- word.c      19 Mar 2015 21:22:15 -0000      1.17
+++ word.c      24 Dec 2015 09:27:00 -0000
@@ -10,11 +10,15 @@
 
 #include <sys/queue.h>
 #include <signal.h>
+#include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "def.h"
 
 RSIZE  countfword(void);
+int    grabword(char **);
 
 /*
  * Move the cursor backward by "n" words. All of the details of motion are
@@ -61,6 +65,158 @@ forwword(int f, int n)
                                return (TRUE);
                }
        }
+       return (TRUE);
+}
+
+/*
+ * Transpose 2 words.
+ */
+int
+transposeword(int f, int n)
+{
+       struct line     *tmp1_w_dotp = NULL;
+       struct line     *tmp2_w_dotp = NULL;
+       int              tmp2_w_doto = 0;
+       int              tmp1_w_dotline = 0;
+       int              tmp2_w_dotline = 0;
+       int              tmp1_w_doto;
+       int              i;             /* start-of-line space counter */
+       int              ret, s;
+       int              newline;
+       int              leave = 0;
+       int              tmp_len;
+       char            *word1 = NULL;
+       char            *word2 = NULL;
+       char            *chr;
+
+       if (n == 0)
+               return (TRUE);
+
+       if ((s = checkdirty(curbp)) != TRUE)
+               return (s);
+       if (curbp->b_flag & BFREADONLY) {
+               dobeep();
+               ewprintf("Buffer is read-only");
+               return (FALSE);
+       }
+
+       undo_boundary_enable(FFRAND, 0);
+
+       /* go backwards to find the start of a word to transpose. */
+       (void)backword(FFRAND, 1);
+       ret = grabword(&word1);
+       if (ret == ABORT) {
+               ewprintf("No word to the left to tranpose.");
+               return (FALSE);
+       }
+       if (ret < 0) {
+               dobeep();
+               ewprintf("Error copying word: %s", strerror(ret));
+               free(word1);
+               return (FALSE);
+       }
+       tmp_len = strlen(word1);
+
+       while (n-- > 0) {
+               i = 0;
+               newline = 0;
+
+               tmp1_w_doto = curwp->w_doto;
+               tmp1_w_dotline = curwp->w_dotline;
+               tmp1_w_dotp = curwp->w_dotp;
+
+               /* go forward and find next word. */
+               while (inword() == FALSE) {
+                       if (forwchar(FFRAND, 1) == FALSE) {
+                               leave = 1;
+                               if (tmp1_w_dotline < curwp->w_dotline)
+                                       curwp->w_dotline--;
+                               ewprintf("Don't have two things to transpose");
+                               break;
+                       }
+                       if (curwp->w_doto == 0) {
+                               newline = 1;
+                               i = 0;
+                       } else if (newline)
+                               i++;
+               }
+               if (leave) {
+                       tmp2_w_doto = tmp1_w_doto;
+                       tmp2_w_dotline = tmp1_w_dotline;
+                       tmp2_w_dotp = tmp1_w_dotp;
+                       break;
+               }
+               tmp2_w_doto = curwp->w_doto;
+               tmp2_w_dotline = curwp->w_dotline;
+               tmp2_w_dotp = curwp->w_dotp;
+
+               ret = grabword(&word2);
+               if (ret < 0) {
+                       dobeep();
+                       ewprintf("Error copying word: %s", strerror(ret));
+                       free(word1);
+                       return (FALSE);
+               }
+               tmp_len = strlen(word2);
+               tmp2_w_doto += tmp_len;
+
+               curwp->w_doto = tmp1_w_doto;
+               curwp->w_dotline = tmp1_w_dotline;
+               curwp->w_dotp = tmp1_w_dotp;
+
+               /* insert shuffled along word */
+               for (chr = word2; *chr != '\0'; ++chr)
+                       linsert(1, *chr);
+
+               if (newline)
+                       tmp2_w_doto = i;
+
+               curwp->w_doto = tmp2_w_doto;
+               curwp->w_dotline = tmp2_w_dotline;
+               curwp->w_dotp = tmp2_w_dotp;
+
+               word2 = NULL;
+       }
+       curwp->w_doto = tmp2_w_doto;
+       curwp->w_dotline = tmp2_w_dotline;
+       curwp->w_dotp = tmp2_w_dotp;
+
+       /* insert very first word in its new position */
+       for (chr = word1; *chr != '\0'; ++chr)
+               linsert(1, *chr);
+
+       if (leave)
+               (void)backword(FFRAND, 1);
+
+       free(word1);
+       free(word2);
+
+       undo_boundary_enable(FFRAND, 1);
+
+       return (TRUE);
+}
+
+/*
+ * copy and delete word.
+*/
+int
+grabword(char **word)
+{
+       int c;
+
+       while (inword() == TRUE) {
+               c = lgetc(curwp->w_dotp, curwp->w_doto);
+               if (*word == NULL) {
+                       if (asprintf(word, "%c", c) == -1)
+                               return (errno);
+               } else {
+                       if (asprintf(word, "%s%c", *word, c) == -1)
+                               return (errno);
+               }
+               (void)forwdel(FFRAND, 1);
+       }
+       if (*word == NULL)
+               return (ABORT);
        return (TRUE);
 }
 

Reply via email to