diff options
author | Thomas E. Dickey <dickey@invisible-island.net> | 2008-09-04 00:27:30 -0400 |
---|---|---|
committer | Thomas E. Dickey <dickey@invisible-island.net> | 2008-09-04 00:27:30 -0400 |
commit | 3ec9560de810415534fac8c4e49caa5def1176de (patch) | |
tree | f238951bef9a2931374325014a0dbcd2d297b65c /src/LYStrings.c | |
parent | f06e47e4c02793186e0cb85966d7e4aac63c0618 (diff) | |
download | lynx-snapshots-3ec9560de810415534fac8c4e49caa5def1176de.tar.gz |
snapshot of project "lynx", label v2-8-7dev_9g
Diffstat (limited to 'src/LYStrings.c')
-rw-r--r-- | src/LYStrings.c | 366 |
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) |