about summary refs log tree commit diff stats
path: root/src/LYStrings.c
diff options
context:
space:
mode:
authorThomas E. Dickey <dickey@invisible-island.net>2008-09-04 00:27:30 -0400
committerThomas E. Dickey <dickey@invisible-island.net>2008-09-04 00:27:30 -0400
commit3ec9560de810415534fac8c4e49caa5def1176de (patch)
treef238951bef9a2931374325014a0dbcd2d297b65c /src/LYStrings.c
parentf06e47e4c02793186e0cb85966d7e4aac63c0618 (diff)
downloadlynx-snapshots-3ec9560de810415534fac8c4e49caa5def1176de.tar.gz
snapshot of project "lynx", label v2-8-7dev_9g
Diffstat (limited to 'src/LYStrings.c')
-rw-r--r--src/LYStrings.c366
1 files changed, 242 insertions, 124 deletions
diff --git a/src/LYStrings.c b/src/LYStrings.c
index bb0d7a09..3ac742a1 100644
--- a/src/LYStrings.c
+++ b/src/LYStrings.c
@@ -1,4 +1,4 @@
-/* $LynxId: LYStrings.c,v 1.135 2008/08/31 18:54:07 tom Exp $ */
+/* $LynxId: LYStrings.c,v 1.146 2008/09/04 00:21:11 tom Exp $ */
 #include <HTUtils.h>
 #include <HTCJK.h>
 #include <UCAux.h>
@@ -47,6 +47,12 @@
 #define BUTTON_CTRL	0	/* Quick hack */
 #endif
 
+#ifdef DEBUG_EDIT
+#define CTRACE_EDIT(p) CTRACE(p)
+#else
+#define CTRACE_EDIT(p)		/*nothing */
+#endif
+
 /*
  * The edit_history lists allow the user to press tab when entering URL to get
  * the closest match in the closet
@@ -2808,21 +2814,27 @@ void LYTrimAllStartfile(char *buffer)
 #define EDREC	 EditFieldData
 
 /*
- * Shorthand to get rid of all most of the "edit->suchandsos".
+ * Shorthand to get rid of the "edit->suchandsos".
  */
+#define IsDirty  edit->dirty
+#define IsHidden edit->hidden
+#define StartX	 edit->sx
+#define StartY	 edit->sy
 #define Buf	 edit->buffer
-#define Pos	 edit->pos
-#define StrLen	 edit->strlen
+#define Pos	 edit->pos	/* current editing position (bytes) */
+#define StrLen	 edit->strlen	/* length (bytes) */
 #define MaxLen	 edit->maxlen
 #define DspWdth  edit->dspwdth
-#define DspStart edit->xpan
+#define DspStart edit->xpan	/* display-start (columns) */
 #define Margin	 edit->margin
+#define PanOn	 edit->panon
+#define PadChar  edit->pad
 #ifdef ENHANCED_LINEEDIT
 #define Mark	 edit->mark
 #endif
 
 #ifdef ENHANCED_LINEEDIT
-static char killbuffer[1024] = "\0";
+static char killbuffer[MAX_EDIT] = "\0";
 #endif
 
 void LYSetupEdit(EDREC * edit, char *old,
@@ -2832,10 +2844,10 @@ void LYSetupEdit(EDREC * edit, char *old,
     /*
      * Initialize edit record
      */
-    LYGetYX(edit->sy, edit->sx);
-    edit->pad = ' ';
-    edit->dirty = TRUE;
-    edit->panon = FALSE;
+    LYGetYX(StartY, StartX);
+    PadChar = ' ';
+    IsDirty = TRUE;
+    PanOn = FALSE;
     edit->current_modifiers = 0;
 
     MaxLen = maxstr;
@@ -2849,7 +2861,7 @@ void LYSetupEdit(EDREC * edit, char *old,
 
     if (maxstr > maxdsp) {	/* Need panning? */
 	if (DspWdth > 4)	/* Else "{}" take up precious screen space */
-	    edit->panon = TRUE;
+	    PanOn = TRUE;
 
 	/*
 	 * Figure out margins.  If too big, we do a lot of unnecessary
@@ -2861,8 +2873,8 @@ void LYSetupEdit(EDREC * edit, char *old,
 	    Margin = 10;
     }
 
-    LYstrncpy(edit->buffer, old, maxstr);
-    StrLen = strlen(edit->buffer);
+    LYstrncpy(Buf, old, maxstr);
+    StrLen = strlen(Buf);
 }
 
 #ifdef SUPPORT_MULTIBYTE_EDIT
@@ -2901,8 +2913,9 @@ static int mbcs_glyphs(char *s, int len)
 	for (i = 0; s[i] && i < len; i++, glyphs++)
 	    if (is8bits(s[i]))
 		i++;
-    } else
+    } else {
 	glyphs = len;
+    }
     return glyphs;
 }
 
@@ -2924,12 +2937,40 @@ static int mbcs_skip(char *s, int pos)
 	for (p = i = 0; s[i] && p < pos; p++, i++)
 	    if (is8bits(s[i]))
 		i++;
-    } else
+    } else {
 	i = pos;
+    }
 
     return i;
 }
 
+/*
+ * Given a string that would display (at least) the given number of cells,
+ * determine the number of multibyte characters that comprised those cells.
+ */
+static int cell2char(char *s, int cells)
+{
+    int result = 0;
+    int len = strlen(s);
+    int pos;
+    int have;
+
+    CTRACE_EDIT((tfp, "cell2char(%d) %d:%s\n", cells, len, s));
+    /* FIXME - make this a binary search */
+    for (pos = 0; pos <= len; ++pos) {
+	have = LYstrExtent2(s, pos);
+	CTRACE_EDIT((tfp, "  %2d:%2d:%.*s\n", pos, have, pos, s));
+	if (have >= cells) {
+	    break;
+	}
+    }
+    if (pos > len)
+	pos = len;
+    result = mbcs_glyphs(s, pos);
+    CTRACE_EDIT((tfp, "->%d\n", result));
+    return result;
+}
+
 #endif /* SUPPORT_MULTIBYTE_EDIT */
 
 #ifdef EXP_KEYBOARD_LAYOUT
@@ -3035,7 +3076,7 @@ int LYEditInsert(EDREC * edit, unsigned const char *s,
     Pos += len;
     StrLen += len;
     if (edited)
-	edit->dirty = TRUE;
+	IsDirty = TRUE;
     if (overflow && maxMessage)
 	_statusline(MAXLEN_REACHED_DEL_OR_MOV);
 #ifdef ENHANCED_LINEEDIT
@@ -3049,13 +3090,14 @@ int LYEditInsert(EDREC * edit, unsigned const char *s,
     return edited;
 }
 
+/* returns 0    character processed
+ *         -ch  if action should be performed outside of line-editing mode
+ *         ch   otherwise
+ */
 int LYEdit1(EDREC * edit, int ch,
 	    int action,
 	    BOOL maxMessage)
-{				/* returns 0    character processed
-				 *         -ch  if action should be performed outside of line-editing mode
-				 *         ch   otherwise
-				 */
+{
     int i;
     int length;
     unsigned char uch;
@@ -3443,7 +3485,7 @@ int LYEdit1(EDREC * edit, int ch,
     default:
 	return (ch);
     }
-    edit->dirty = TRUE;
+    IsDirty = TRUE;
     StrLen = strlen(&Buf[0]);
     return (0);
 }
@@ -3521,40 +3563,87 @@ int get_popup_number(const char *msg,
 #  define TmpStyleOff(s)
 #endif /* defined USE_COLOR_STYLE */
 
-void LYRefreshEdit(EDREC * edit)
+static void fill_edited_line(int prompting GCC_UNUSED, int length, int ch)
 {
-    int i;
-    int length;
-    int nrdisplayed;
-    int padsize;
-    char *str;
+    TmpStyleOn(prompting ? s_prompt_edit_pad : s_aedit_pad);
+    while (length-- > 0)
+	LYaddch(UCH(ch));
+    TmpStyleOff(prompting ? s_prompt_edit_pad : s_aedit_pad);
+}
+
+static void remember_column(EDREC * edit, int offset)
+{
+    int y0, x0;
+
+#if defined(USE_SLANG)
+    y0 = 0;
+    x0 = offset;
+#elif defined(USE_CURSES_PADS)
+    getyx(LYwin, y0, x0);
+#else
+    getyx(stdscr, y0, x0);
+#endif
+    edit->offset2col[offset] = x0;
+}
 
-#ifdef SUPPORT_MULTIBYTE_EDIT
 /*
- * Multibyte string display code.
- * EDREC fields retain their values as byte offsets,
- * while glXXXX variables hold corresponding glyph counts.
+ * Multibyte string display subroutine.
+ * EDREC fields retain their values as byte offsets.
  * All external logic still works fine with byte values.
  */
-    int glDspStart, glPos, gllength;
-    int glnrdisplayed;
+void LYRefreshEdit(EDREC * edit)
+{
+    /* bytes and characters are not the same thing */
+    int all_bytes;
+    int pos_bytes = Pos;
+    int dpy_bytes;
+    int lft_bytes;		/* base of string which is displayed */
+
+    /* cells refer to display-columns on the screen */
+    int all_cells;		/* total of display-cells in Buf */
+    int dpy_cells;		/* number of cells which are displayed */
+    int lft_cells;		/* number of cells before display (on left) */
+    int pos_cells;		/* number of display-cells up to Pos */
+
+#ifdef SUPPORT_MULTIBYTE_EDIT
+    int all_chars;
+    int dpy_chars;
+    int lft_chars;
+    int pos_chars;
 #endif
 
+    /* other data */
+    int i;
+    int padsize;
+    char *str;
+    int lft_shift = 0;
+    int rgt_shift = 0;
+
 #ifdef USE_COLOR_STYLE
-    int estyle, prompting = 0;
+    int estyle;
 #endif
+    int prompting = 0;
 
-    if (!edit->dirty || (DspWdth == 0))
+    (void) pos_bytes;
+
+    /*
+     * If we've made no changes, or if there is nothing to display, just leave.
+     */
+    if (!IsDirty || (DspWdth == 0))
 	return;
-    edit->dirty = FALSE;
 
-    length = strlen(&Buf[0]);
-    edit->strlen = length;
+    IsDirty = FALSE;
+
+    all_bytes = strlen(&Buf[0]);
+    StrLen = all_bytes;
+
+    all_cells = LYstrCells(Buf);
+    pos_cells = LYstrExtent2(Buf, Pos);
 
 #ifdef SUPPORT_MULTIBYTE_EDIT
-    glDspStart = mbcs_glyphs(Buf, DspStart);
-    glPos = mbcs_glyphs(Buf, Pos);
-    gllength = mbcs_glyphs(Buf, length);
+    lft_chars = mbcs_glyphs(Buf, DspStart);
+    pos_chars = mbcs_glyphs(Buf, Pos);
+    all_chars = mbcs_glyphs(Buf, all_bytes);
 #endif
 
     /*
@@ -3563,7 +3652,7 @@ void LYRefreshEdit(EDREC * edit)
      *      +---------+=============+-----------+
      *      |         |M           M|           |   (M=margin)
      *      +---------+=============+-----------+
-     *      0         DspStart                   length
+     *      0         DspStart                   StrLen
      *
      * Insertion point can be anywhere between 0 and stringlength.  Figure out
      * new display starting point.
@@ -3573,47 +3662,93 @@ void LYRefreshEdit(EDREC * edit)
      * data entry at low baudrates.
      */
 
-#ifndef SUPPORT_MULTIBYTE_EDIT
-    if ((DspStart + DspWdth) <= length)
-	if (Pos >= (DspStart + DspWdth) - Margin)
-	    DspStart = (Pos - DspWdth) + Margin;
+    lft_bytes = DspStart;
+    lft_cells = LYstrExtent2(Buf, DspStart);
+
+    if ((lft_cells + DspWdth) <= all_cells) {
+	if (pos_cells >= (lft_cells + DspWdth) - Margin) {
+	    lft_cells = (pos_cells - DspWdth) + Margin;
+#ifdef SUPPORT_MULTIBYTE_EDIT
+	    lft_chars = cell2char(Buf, lft_cells);
+	    lft_bytes = mbcs_skip(Buf, lft_chars);
 #else
-    if ((glDspStart + DspWdth) <= gllength)
-	if (glPos >= (glDspStart + DspWdth) - Margin) {
-	    glDspStart = (glPos - DspWdth) + Margin;
-	    DspStart = mbcs_skip(Buf, glDspStart);
-	}
+	    lft_bytes = lft_cells;
 #endif /* SUPPORT_MULTIBYTE_EDIT */
+	}
+    }
 
-#ifndef SUPPORT_MULTIBYTE_EDIT
-    if (Pos < DspStart + Margin) {
-	DspStart = Pos - Margin;
-	if (DspStart < 0)
-	    DspStart = 0;
+    if (pos_cells < lft_cells + Margin) {
+	lft_cells = pos_cells - Margin;
+	if (lft_cells < 0)
+	    lft_cells = 0;
+#ifdef SUPPORT_MULTIBYTE_EDIT
+	lft_chars = cell2char(Buf, lft_cells);
+	lft_bytes = mbcs_skip(Buf, lft_chars);
+#else
+	lft_bytes = lft_cells;
+#endif /* SUPPORT_MULTIBYTE_EDIT */
     }
-#else /* SUPPORT_MULTIBYTE_EDIT */
-    if (glPos < glDspStart + Margin) {
-	glDspStart = glPos - Margin;
-	if (glDspStart < 0)
-	    glDspStart = 0;
-	DspStart = mbcs_skip(Buf, glDspStart);
+
+    LYmove(StartY, StartX);
+
+    /*
+     * Draw the left scrolling-indicator now, to avoid the complication of
+     * overwriting part of a multicolumn character which may lie in the first
+     * position.
+     */
+    if (PanOn && lft_cells) {
+	CTRACE_EDIT((tfp, "Draw left scroll-indicator\n"));
+	TmpStyleOn(prompting ? s_prompt_edit_arr : s_aedit_arr);
+	LYmove(StartY, StartX);
+	LYaddch(ACS_LARROW);
+	TmpStyleOff(prompting ? s_prompt_edit_arr : s_aedit_arr);
+	lft_shift = 1;
     }
-#endif /* SUPPORT_MULTIBYTE_EDIT */
 
-    str = &Buf[DspStart];
+    str = &Buf[lft_bytes];
+    DspStart = lft_bytes;
 
-#ifndef SUPPORT_MULTIBYTE_EDIT
-    nrdisplayed = length - DspStart;
-    if (nrdisplayed > DspWdth)
-	nrdisplayed = DspWdth;
+    dpy_cells = all_cells - lft_cells;
+    CTRACE_EDIT((tfp, "Comparing dpy_cells %d > (%d - %d)\n",
+		 dpy_cells, DspWdth, lft_shift));
+    if (dpy_cells > (DspWdth - lft_shift)) {
+	rgt_shift = 1;
+	dpy_cells = (DspWdth - lft_shift - rgt_shift);
+    }
+    for (;;) {
+#ifdef SUPPORT_MULTIBYTE_EDIT
+	dpy_chars = cell2char(str, dpy_cells);
+	dpy_bytes = mbcs_skip(str, dpy_chars);
 #else
-    glnrdisplayed = gllength - glDspStart;
-    if (glnrdisplayed > DspWdth)
-	glnrdisplayed = DspWdth;
-    nrdisplayed = mbcs_skip(Buf + DspStart, glnrdisplayed);
+	dpy_bytes = dpy_cells;
 #endif /* SUPPORT_MULTIBYTE_EDIT */
+	/*
+	 * The last character on the display may be multicolumn, and if we take
+	 * away a single cell for the right scroll-indicator, that would force
+	 * us to display fewer characters.  Check for that, and recompute.
+	 */
+	if (rgt_shift) {
+	    int old_cells = dpy_cells;
 
-    LYmove(edit->sy, edit->sx);
+	    dpy_cells = LYstrExtent2(str, dpy_bytes);
+	    if (dpy_cells > old_cells)
+		dpy_cells = old_cells - 1;
+
+	    CTRACE_EDIT((tfp, "Comparing cells %d vs %d\n", dpy_cells, old_cells));
+	    if (dpy_cells < old_cells) {
+		CTRACE_EDIT((tfp, "Recomputing...\n"));
+		continue;
+	    }
+	}
+	break;
+    }
+
+    CTRACE_EDIT((tfp, "BYTES left %2d pos %2d dpy %2d all %2d\n",
+		 lft_bytes, pos_bytes, dpy_bytes, all_bytes));
+    CTRACE_EDIT((tfp, "CELLS left %2d pos %2d dpy %2d all %2d\n",
+		 lft_cells, pos_cells, dpy_cells, all_cells));
+    CTRACE_EDIT((tfp, "CHARS left %2d pos %2d dpy %2d all %2d\n",
+		 lft_chars, pos_chars, dpy_chars, all_chars));
 
 #ifdef USE_COLOR_STYLE
     /*
@@ -3621,35 +3756,33 @@ void LYRefreshEdit(EDREC * edit)
      * be needed for color styles.  The curses function may be used directly to
      * avoid complications.  - kw
      */
-    if (edit->sy == (LYlines - 1))
+    if (StartY == (LYlines - 1))
 	prompting = 1;
-    if (prompting)
+    if (prompting) {
 	estyle = s_prompt_edit;
-    else
+    } else {
 	estyle = s_aedit;
+    }
     CTRACE2(TRACE_STYLE,
 	    (tfp, "STYLE.getstr: switching to <edit.%s>.\n",
 	     prompting ? "prompt" : "active"));
-    if (estyle != NOSTYLE)
+    if (estyle != NOSTYLE) {
 	curses_style(estyle, STACK_ON);
-    else
+    } else {
 	wattrset(LYwin, A_NORMAL);	/* need to do something about colors? */
+    }
 #endif
-    if (edit->hidden) {
-#ifndef SUPPORT_MULTIBYTE_EDIT
-	for (i = 0; i < nrdisplayed; i++)
-	    LYaddch('*');
-#else
-	for (i = 0; i < glnrdisplayed; i++)
-	    LYaddch('*');
-#endif
+    if (IsHidden) {
+	fill_edited_line(0, dpy_cells, '*');
     } else {
 #if defined(ENHANCED_LINEEDIT) && defined(USE_COLOR_STYLE)
 	if (Mark >= 0 && DspStart > Mark)
 	    TmpStyleOn(prompting ? s_prompt_sel : s_aedit_sel);
 #endif
-	for (i = 0; i < nrdisplayed; i++) {
+	remember_column(edit, 0);
+	for (i = 0; i < dpy_bytes; i++) {
 #if defined(ENHANCED_LINEEDIT) && defined(USE_COLOR_STYLE)
+	    /* FIXME - make this work with multibyte-chars */
 	    if (Mark >= 0 && ((DspStart + i == Mark && Pos > Mark)
 			      || (DspStart + i == Pos && Pos < Mark)))
 		TmpStyleOn(prompting ? s_prompt_sel : s_aedit_sel);
@@ -3664,59 +3797,44 @@ void LYRefreshEdit(EDREC * edit)
 		    !(LYCharSet_UC[current_char_set].like8859
 		      & UCT_R_8859SPECL))))) {
 		LYaddch(' ');
-	    } else
+	    } else {
 		LYaddch(UCH(str[i]));
+	    }
+	    remember_column(edit, i + 1);
 	}
 #if defined(ENHANCED_LINEEDIT) && defined(USE_COLOR_STYLE)
+	/* FIXME - make this work with multibyte-chars */
 	if (Mark >= 0 &&
-	    ((DspStart + nrdisplayed <= Mark && DspStart + nrdisplayed > Pos)
-	     || (DspStart + nrdisplayed > Mark
-		 && DspStart + nrdisplayed <= Pos)))
+	    ((DspStart + dpy_bytes <= Mark && DspStart + dpy_bytes > Pos)
+	     || (DspStart + dpy_bytes > Mark
+		 && DspStart + dpy_bytes <= Pos))) {
 	    TmpStyleOff(prompting ? s_prompt_sel : s_aedit_sel);
+	}
 #endif
     }
 
     /*
      * Erase rest of input area.
      */
-#ifndef SUPPORT_MULTIBYTE_EDIT
-    padsize = DspWdth - nrdisplayed;
-#else
-    padsize = DspWdth - glnrdisplayed;
-#endif
-    if (padsize) {
-	TmpStyleOn(prompting ? s_prompt_edit_pad : s_aedit_pad);
-	while (padsize--)
-	    LYaddch(UCH(edit->pad));
-	TmpStyleOff(prompting ? s_prompt_edit_pad : s_aedit_pad);
-    }
+    padsize = DspWdth - (edit->offset2col[dpy_bytes] - StartX);
+    fill_edited_line(prompting, padsize, PadChar);
 
     /*
      * Scrolling indicators.
      */
-    if (edit->panon) {
-	if ((DspStart + nrdisplayed) < length) {
-	    TmpStyleOn(prompting ? s_prompt_edit_arr : s_aedit_arr);
-#ifndef SUPPORT_MULTIBYTE_EDIT
-	    LYmove(edit->sy, edit->sx + nrdisplayed - 1);
-#else
-	    LYmove(edit->sy, edit->sx + glnrdisplayed - 1);
-#endif
-	    LYaddch(ACS_RARROW);
-	    TmpStyleOff(prompting ? s_prompt_edit_arr : s_aedit_arr);
-	}
-	if (DspStart) {
-	    TmpStyleOn(prompting ? s_prompt_edit_arr : s_aedit_arr);
-	    LYmove(edit->sy, edit->sx);
-	    LYaddch(ACS_LARROW);
-	    TmpStyleOff(prompting ? s_prompt_edit_arr : s_aedit_arr);
-	}
+    if (PanOn && dpy_bytes && rgt_shift) {
+	CTRACE((tfp, "Draw right-scroller offset (%d + %d)\n",
+		dpy_cells, lft_shift));
+	TmpStyleOn(prompting ? s_prompt_edit_arr : s_aedit_arr);
+	LYmove(StartY, StartX + dpy_cells + lft_shift);
+	LYaddch(ACS_RARROW);
+	TmpStyleOff(prompting ? s_prompt_edit_arr : s_aedit_arr);
     }
-#ifndef SUPPORT_MULTIBYTE_EDIT
-    LYmove(edit->sy, edit->sx + Pos - DspStart);
-#else
-    LYmove(edit->sy, edit->sx + glPos - glDspStart);
-#endif
+
+    /*
+     * Finally, move the cursor to the point where the next edit will occur.
+     */
+    LYmove(StartY, edit->offset2col[Pos - DspStart]);
 
 #ifdef USE_COLOR_STYLE
     if (estyle != NOSTYLE)