diff options
author | Vincent Labrecque <vincent@cvs.openbsd.org> | 2004-01-27 23:43:38 +0000 |
---|---|---|
committer | Vincent Labrecque <vincent@cvs.openbsd.org> | 2004-01-27 23:43:38 +0000 |
commit | e74444ac8c3df6c289e0fe81f8466811a97542b8 (patch) | |
tree | 7ded3509c315f39fea753dd3ea40459ed3326487 | |
parent | 14e46dc65bfb2b0776e81e7abcd339f507b7321b (diff) |
make mail-mode more intelligent on middle-of-line insertions, and add a
comment to change the wrapping column. (mail-set-margin)
tested by henning and phessler, thanks!
-rw-r--r-- | usr.bin/mg/def.h | 4 | ||||
-rw-r--r-- | usr.bin/mg/line.c | 102 | ||||
-rw-r--r-- | usr.bin/mg/mail.c | 102 | ||||
-rw-r--r-- | usr.bin/mg/main.c | 6 | ||||
-rw-r--r-- | usr.bin/mg/window.c | 3 |
5 files changed, 191 insertions, 26 deletions
diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h index c4aff6a7945..4969cc0219a 100644 --- a/usr.bin/mg/def.h +++ b/usr.bin/mg/def.h @@ -1,4 +1,4 @@ -/* $OpenBSD: def.h,v 1.53 2003/11/29 17:28:40 vincent Exp $ */ +/* $OpenBSD: def.h,v 1.54 2004/01/27 23:43:37 vincent Exp $ */ #include <sys/queue.h> @@ -205,6 +205,7 @@ typedef struct MGWIN { int w_undopos; /* Where we were during the last undo action */ struct undo_rec *w_undoptr; + struct LINE *w_wrapline; } MGWIN; #define w_wndp w_list.l_p.l_wp #define w_name w_list.l_name @@ -349,6 +350,7 @@ LINE *lalloc(int); int lrealloc(LINE *, int); void lfree(LINE *); void lchange(int); +int linsert_str(const char *, int); int linsert(int, int); int lnewline(void); int ldelete(RSIZE, int); diff --git a/usr.bin/mg/line.c b/usr.bin/mg/line.c index cb656a0a8a2..bf5768212ba 100644 --- a/usr.bin/mg/line.c +++ b/usr.bin/mg/line.c @@ -1,4 +1,4 @@ -/* $OpenBSD: line.c,v 1.19 2003/11/09 01:11:14 vincent Exp $ */ +/* $OpenBSD: line.c,v 1.20 2004/01/27 23:43:37 vincent Exp $ */ /* * Text line handling. @@ -148,6 +148,96 @@ lchange(int flag) } /* + * Insert "n" bytes from "s" at the current location of dot. + * In the easy case all that happens is the text is stored in the line. + * In the hard case, the line has to be reallocated. When the window list + * is updated, take special care; I screwed it up once. You always update + * dot in the current window. You update mark and a dot in another window + * if it is greater than the place where you did the insert. Return TRUE + * if all is well, and FALSE on errors. + */ +int +linsert_str(const char *s, int n) +{ + LINE *lp1; + MGWIN *wp; + RSIZE i; + int doto; + + if (curbp->b_flag & BFREADONLY) { + ewprintf("Buffer is read only"); + return FALSE; + } + + if (!n) + return (TRUE); + + lchange(WFHARD); + + /* current line */ + lp1 = curwp->w_dotp; + + /* special case for the end */ + if (lp1 == curbp->b_linep) { + LINE *lp2, *lp3; + + /* now should only happen in empty buffer */ + if (curwp->w_doto != 0) + panic("bug: linsert_str"); + /* allocate a new line */ + if ((lp2 = lalloc(n)) == NULL) + return FALSE; + /* previous line */ + lp3 = lp1->l_bp; + /* link in */ + lp3->l_fp = lp2; + lp2->l_fp = lp1; + lp1->l_bp = lp2; + lp2->l_bp = lp3; + for (i = 0; i < n; ++i) + lp2->l_text[i] = s[i]; + for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { + if (wp->w_linep == lp1) + wp->w_linep = lp2; + if (wp->w_dotp == lp1) + wp->w_dotp = lp2; + if (wp->w_markp == lp1) + wp->w_markp = lp2; + } + undo_add_insert(lp2, 0, n); + curwp->w_doto = n; + return TRUE; + } + /* save for later */ + doto = curwp->w_doto; + + if ((lp1->l_used + n) > lp1->l_size) { + if (lrealloc(lp1, lp1->l_used + n) == FALSE) + return FALSE; + } + lp1->l_used += n; + if (lp1->l_used != n) + memmove(&lp1->l_text[doto + n], &lp1->l_text[doto], + lp1->l_used - n - doto); + + /* Add the characters */ + for (i = 0; i < n; ++i) + lp1->l_text[doto + i] = s[i]; + for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { + if (wp->w_dotp == lp1) { + if (wp == curwp || wp->w_doto > doto) + wp->w_doto += n; + } + if (wp->w_markp == lp1) { + if (wp->w_marko > doto) + wp->w_marko += n; + } + } + undo_add_insert(curwp->w_dotp, doto, n); + return TRUE; +} + +/* * Insert "n" copies of the character "c" at the current location of dot. * In the easy case all that happens is the text is stored in the line. * In the hard case, the line has to be reallocated. When the window list @@ -164,6 +254,9 @@ linsert(int n, int c) RSIZE i; int doto; + if (!n) + return (TRUE); + if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return FALSE; @@ -343,6 +436,7 @@ ldelete(RSIZE n, int kflag) return FALSE; /* Size of the chunk */ chunk = dotp->l_used - doto; + if (chunk > n) chunk = n; /* End of line, merge */ @@ -360,7 +454,6 @@ ldelete(RSIZE n, int kflag) lchange(WFEDIT); /* Scrunch text */ cp1 = &dotp->l_text[doto]; - cp2 = cp1 + chunk; if (kflag == KFORW) { while (ksize - kused < chunk) if (kgrow(FALSE) == FALSE) @@ -375,8 +468,9 @@ ldelete(RSIZE n, int kflag) kstart -= chunk; } else if (kflag != KNONE) panic("broken ldelete call"); - while (cp2 != &dotp->l_text[dotp->l_used]) - *cp1++ = *cp2++; + for (cp2 = cp1 + chunk; cp2 < &dotp->l_text[dotp->l_used]; + cp2++) + *cp1++ = *cp2; dotp->l_used -= (int)chunk; for (wp = wheadp; wp != NULL; wp = wp->w_wndp) { if (wp->w_dotp == dotp && wp->w_doto >= doto) { diff --git a/usr.bin/mg/mail.c b/usr.bin/mg/mail.c index a0c23e0a36f..7ed6c036e60 100644 --- a/usr.bin/mg/mail.c +++ b/usr.bin/mg/mail.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mail.c,v 1.2 2004/01/12 22:55:00 vincent Exp $ */ +/* $OpenBSD: mail.c,v 1.3 2004/01/27 23:43:37 vincent Exp $ */ /* * This file is in the public domain. * @@ -10,11 +10,11 @@ #include "kbd.h" #include "funmap.h" -#define LIMIT 72 - static int fake_self_insert(int, int); static int mail(int, int); +int limit = 72; + /* mappings for all "printable" characters ('-' -> '~') */ static PF mail_fake[] = { fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, @@ -40,7 +40,7 @@ static PF mail_fake[] = { fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, fake_self_insert, - fake_self_insert, fake_self_insert, fake_self_insert, + fake_self_insert, fake_self_insert, fake_self_insert }; static struct KEYMAPE (1 + IMAPEXT) mailmap = { @@ -52,10 +52,27 @@ static struct KEYMAPE (1 + IMAPEXT) mailmap = { } }; +int +mail_set_limit(int f, int n) +{ + char buf[32]; + int s; + + if ((f & FFARG) != 0) { + limit = n; + } else { + if ((s = ereply("Margin: ", buf, sizeof(buf))) != TRUE) + return s; + limit = atoi(buf); + } + return TRUE; +} + void mail_init(void) { funmap_add(mail, "mail-mode"); + funmap_add(mail_set_limit, "mail-set-margin"); maps_add((KEYMAP *)&mailmap, "mail-mode"); } @@ -77,22 +94,73 @@ mail(int f, int n) static int fake_self_insert(int f, int n) { - if (curwp->w_doto >= LIMIT - 1) { - int save = curwp->w_doto; + int len = llength(curwp->w_dotp), col; + if (len + 1 > limit) { /* - * Find the last word boundary. + * find the column at which we should cut, taking + * word boundaries into account */ - while (curwp->w_doto > 0 && - !isspace(curwp->w_dotp->l_text[curwp->w_doto - 1])) - curwp->w_doto--; - /* - * handle lines without any spaces correctly! - */ - if (curwp->w_doto == 0 && !isspace(curwp->w_dotp->l_text[0])) - curwp->w_doto = save; - newline(FFRAND, 1); - gotoeol(0, 1); + for (col = limit; col > 0; col--) + if (isspace(curwp->w_dotp->l_text[col])) { + col++; /* XXX - skip the space */ + break; + } + + if (curbp->b_doto == len) { + /* + * user is appending to the line; simple case. + */ + if (col) { + curwp->w_doto = col; + lnewline(); + gotoeol(0, 1); + } + curwp->w_wrapline = NULL; + } else if ((len - col) > 0) { + /* + * user is shifting words by inserting in the middle. + */ + const char *trail; + int save_doto = curwp->w_doto; + LINE *save_dotp = curwp->w_dotp; + int tlen = len - col; + + trail = curwp->w_dotp->l_text + col; + + /* + * Create a new line or reuse the last wrapping line + * unless we could fill it. + */ + if (curwp->w_wrapline != lforw(curwp->w_dotp) || + llength(curwp->w_wrapline) + tlen >= limit) { + curwp->w_doto = col; + lnewline(); + curwp->w_wrapline = curwp->w_dotp; + curwp->w_dotp = save_dotp; + } else { + curwp->w_dotp = curwp->w_wrapline; + curwp->w_doto = 0; + + /* insert trail */ + linsert_str(trail, tlen); + + /* delete trail */ + curwp->w_dotp = save_dotp; + curwp->w_doto = col; + ldelete(tlen, KNONE); /* don't store in kill ring */ + } + + /* + * readjust dot to point at where the user expects + * it to be after an insertion. + */ + curwp->w_doto = save_doto; + if (curwp->w_doto >= col) { + curwp->w_dotp = curwp->w_wrapline; + curwp->w_doto -= col; + } + } } selfinsert(f, n); return (TRUE); diff --git a/usr.bin/mg/main.c b/usr.bin/mg/main.c index 8bd4f80d77a..7757426c48d 100644 --- a/usr.bin/mg/main.c +++ b/usr.bin/mg/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.27 2003/12/04 01:52:01 vincent Exp $ */ +/* $OpenBSD: main.c,v 1.28 2004/01/27 23:43:37 vincent Exp $ */ /* * Mainline. @@ -169,8 +169,8 @@ edinit(PF init_fcn) curwp = wp; wp->w_wndp = NULL; /* Initialize window. */ wp->w_linep = wp->w_dotp = bp->b_linep; - wp->w_ntrows = nrow - 2; /* 2 = mode, echo. */ - wp->w_flag = WFMODE | WFHARD; /* Full. */ + wp->w_ntrows = nrow - 2; /* 2 = mode, echo. */ + wp->w_flag = WFMODE | WFHARD; /* Full. */ if (init_fcn) init_fcn(0, 1); diff --git a/usr.bin/mg/window.c b/usr.bin/mg/window.c index d4cddce1905..8b42ae45a48 100644 --- a/usr.bin/mg/window.c +++ b/usr.bin/mg/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.14 2003/11/29 17:28:39 vincent Exp $ */ +/* $OpenBSD: window.c,v 1.15 2004/01/27 23:43:37 vincent Exp $ */ /* * Window handling. @@ -22,6 +22,7 @@ new_window(BUFFER *bp) wp->w_marko = 0; wp->w_flag = 0; wp->w_force = 0; + wp->w_wrapline = NULL; if (bp) bp->b_nwnd++; LIST_INIT(&wp->w_undo); |