summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Labrecque <vincent@cvs.openbsd.org>2004-01-27 23:43:38 +0000
committerVincent Labrecque <vincent@cvs.openbsd.org>2004-01-27 23:43:38 +0000
commite74444ac8c3df6c289e0fe81f8466811a97542b8 (patch)
tree7ded3509c315f39fea753dd3ea40459ed3326487
parent14e46dc65bfb2b0776e81e7abcd339f507b7321b (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.h4
-rw-r--r--usr.bin/mg/line.c102
-rw-r--r--usr.bin/mg/mail.c102
-rw-r--r--usr.bin/mg/main.c6
-rw-r--r--usr.bin/mg/window.c3
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);