From 9bd56204ee775164c97bbc574ccd67b184a86555 Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Fri, 18 Mar 2005 21:29:33 +0000 Subject: [PATCH] add multibyte character support to help_line_len(), so that UTF-8 help text is wrapped properly git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2393 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 20 +++---- TODO | 4 +- src/nano.c | 154 ++++++++++++++++++++++++++++------------------------ src/proto.h | 7 ++- src/winio.c | 41 ++++++-------- 5 files changed, 116 insertions(+), 110 deletions(-) diff --git a/ChangeLog b/ChangeLog index f088b1c5..14a14972 100644 --- a/ChangeLog +++ b/ChangeLog @@ -99,12 +99,12 @@ CVS code - control_mbrep(), control_wrep(), mbwidth(), mb_cur_max(), make_mbchar(), mbstrlen(), mbstrnlen(), mbstrcasecmp(), mbstrncasecmp(), mbstrcasestr(), and mbrevstrcasestr(); - changes to help_init(), is_byte() (moved to chars.c), - is_blank_char() (moved to chars.c), is_cntrl_char() (moved to - chars.c), nstricmp() (renamed nstrcasecmp() and moved to - chars.c), nstrnicmp() (renamed nstrncasecmp() and moved to - chars.c), nstristr() (renamed nstrcasestr() and moved to - chars.c), revstrstr() (moved to chars.c), revstristr() + changes to help_init(), break_line(), is_byte() (moved to + chars.c), is_blank_char() (moved to chars.c), is_cntrl_char() + (moved to chars.c), nstricmp() (renamed nstrcasecmp() and + moved to chars.c), nstrnicmp() (renamed nstrncasecmp() and + moved to chars.c), nstristr() (renamed nstrcasestr() and moved + to chars.c), revstrstr() (moved to chars.c), revstristr() (renamed revstrcasestr() and moved to chars.c), nstrnlen() (moved to chars.c), parse_char() (renamed parse_mbchar() and moved to chars.c), move_left() (renamed move_mbleft() and @@ -116,9 +116,9 @@ CVS code - unget_input(), unget_kbinput(), get_input(), parse_kbinput(), unparse_kbinput(), parse_verbatim_kbinput(), do_statusbar_input(), do_statusbar_home(), - do_statusbar_verbatim_kbinput(), do_statusbar_output(), and - display_string(); removal of buffer_to_keys() and - keys_to_buffer(). (DLR) + do_statusbar_verbatim_kbinput(), do_statusbar_output(), + do_help(), help_line_len(), and display_string(); removal of + buffer_to_keys() and keys_to_buffer(). (DLR) - Add -O/--morespace command line option, plus a corresponding Meta-O toggle and a "morespace" rcfile option. When these are used, the normally-unused blank line below the titlebar will @@ -188,7 +188,7 @@ CVS code - make whitespace display mode work with multibyte characters, and add a few related documentation updates. New function make_mbstring(); changes to make_mbchar(), make_mbstring(), - do_help(), main(), parse_rcfile(), and display_string(). (DLR) + main(), parse_rcfile(), display_string(), and do_help(). (DLR) - cut.c: do_cut_text() - If keep_cutbuffer is FALSE, only blow away the text in the diff --git a/TODO b/TODO index 48698f44..0ea981fb 100644 --- a/TODO +++ b/TODO @@ -2,8 +2,8 @@ TODO file (? means the feature may be implemented, but not definitely) ----------------------------------------------------------------------------- For version 1.4: -- UTF-8 support. [DONE except for edit window text wrapping, help window - text wrapping, and the NO_CONVERT flag.] +- UTF-8 support. [DONE except for edit window text wrapping and the + NO_CONVERT flag, which should allow editing UTF-8 as raw bytes.] - Support for paragraph searches. [DONE] - Support for justifying the entire file at once. [DONE] - Support for filename searches in the file browser. diff --git a/src/nano.c b/src/nano.c index a9ce1540..9d20772d 100644 --- a/src/nano.c +++ b/src/nano.c @@ -2323,6 +2323,86 @@ void do_spell(void) } #endif /* !DISABLE_SPELLER */ +#if !defined(DISABLE_HELP) || !defined(DISABLE_JUSTIFY) +/* We are trying to break a chunk off line. We find the last blank such + * that the display length to there is at most goal + 1. If there is no + * such blank, and force is TRUE, then we find the first blank. Anyway, + * we then take the last blank in that group of blanks. The terminating + * '\0' counts as a blank, as does a '\n' if newline is TRUE. */ +ssize_t break_line(const char *line, ssize_t goal, bool newline, bool + force) +{ + ssize_t blank_loc = -1; + /* Current tentative return value. Index of the last blank we + * found with short enough display width. */ + ssize_t cur_loc = 0; + /* Current index in line. */ + int line_len; + + assert(line != NULL); + + while (*line != '\0' && goal >= 0) { + size_t pos = 0; + + line_len = parse_mbchar(line, NULL, NULL, &pos); + + if (is_blank_mbchar(line) || (newline && *line == '\n')) { + blank_loc = cur_loc; + + if (newline && *line == '\n') + break; + } + + goal -= pos; + line += line_len; + cur_loc += line_len; + } + + if (goal >= 0) + /* In fact, the whole line displays shorter than goal. */ + return cur_loc; + + if (blank_loc == -1) { + /* No blank was found that was short enough. */ + if (force) { + bool found_blank = FALSE; + + while (*line != '\0') { + line_len = parse_mbchar(line, NULL, NULL, NULL); + + if (is_blank_mbchar(line) || + (newline && *line == '\n')) { + if (!found_blank) + found_blank = TRUE; + } else if (found_blank) + return cur_loc - line_len; + + line += line_len; + cur_loc += line_len; + } + + return -1; + } + } + + /* Move to the last blank after blank_loc, if there is one. */ + line -= cur_loc; + line += blank_loc; + line_len = parse_mbchar(line, NULL, NULL, NULL); + line += line_len; + + while (*line != '\0' && (is_blank_mbchar(line) || + (newline && *line == '\n'))) { + line_len = parse_mbchar(line, NULL, NULL, NULL); + + line += line_len; + blank_loc += line_len; + } + + return blank_loc; +} +#endif /* !DISABLE_HELP || !DISABLE_JUSTIFY */ + #if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY) /* The "indentation" of a line is the whitespace between the quote part * and the non-whitespace of the line. */ @@ -2759,77 +2839,6 @@ filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t return first_line; } -/* We are trying to break a chunk off line. We find the last blank such - * that the display length to there is at most goal + 1. If there is no - * such blank, and force is TRUE, then we find the first blank. Anyway, - * we then take the last blank in that group of blanks. The terminating - * '\0' counts as a blank. */ -ssize_t break_line(const char *line, ssize_t goal, bool force) -{ - ssize_t blank_loc = -1; - /* Current tentative return value. Index of the last blank we - * found with short enough display width. */ - ssize_t cur_loc = 0; - /* Current index in line. */ - int line_len; - - assert(line != NULL); - - while (*line != '\0' && goal >= 0) { - size_t pos = 0; - - line_len = parse_mbchar(line, NULL, NULL, &pos); - - if (is_blank_mbchar(line)) - blank_loc = cur_loc; - - goal -= pos; - line += line_len; - cur_loc += line_len; - } - - if (goal >= 0) - /* In fact, the whole line displays shorter than goal. */ - return cur_loc; - - if (blank_loc == -1) { - /* No blank was found that was short enough. */ - if (force) { - bool found_blank = FALSE; - - while (*line != '\0') { - line_len = parse_mbchar(line, NULL, NULL, NULL); - - if (is_blank_mbchar(line)) { - if (!found_blank) - found_blank = TRUE; - } else if (found_blank) - return cur_loc - line_len; - - line += line_len; - cur_loc += line_len; - } - - return -1; - } - } - - /* Move to the last blank after blank_loc, if there is one. */ - line -= cur_loc; - line += blank_loc; - line_len = parse_mbchar(line, NULL, NULL, NULL); - line += line_len; - - while (*line != '\0' && is_blank_mbchar(line)) { - line_len = parse_mbchar(line, NULL, NULL, NULL); - - line += line_len; - blank_loc += line_len; - } - - return blank_loc; -} - /* Find the beginning of the current paragraph if we're in one, or the * beginning of the next paragraph if we're not. Afterwards, save the * quote length and paragraph length in *quote and *par. Return TRUE if @@ -3082,7 +3091,8 @@ void do_justify(bool full_justify) /* If this line is too long, try to wrap it to the next line * to make it short enough. */ break_pos = break_line(current->data + indent_len, - fill - strnlenpt(current->data, indent_len), TRUE); + fill - strnlenpt(current->data, indent_len), FALSE, + TRUE); /* We can't break the line, or don't need to, so get out. */ if (break_pos == -1 || break_pos + indent_len == line_len) diff --git a/src/proto.h b/src/proto.h index c4339783..f15e0b3f 100644 --- a/src/proto.h +++ b/src/proto.h @@ -413,6 +413,10 @@ const char *do_int_speller(const char *tempfile_name); const char *do_alt_speller(char *tempfile_name); void do_spell(void); #endif +#if !defined(DISABLE_HELP) || !defined(DISABLE_JUSTIFY) +ssize_t break_line(const char *line, ssize_t goal, bool newline, bool + force); +#endif #if !defined(NANO_SMALL) || !defined(DISABLE_JUSTIFY) size_t indent_length(const char *line); #endif @@ -431,7 +435,6 @@ void do_para_end(bool allow_update); void do_para_end_void(void); filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t quote_len); -ssize_t break_line(const char *line, ssize_t goal, bool force); bool find_paragraph(size_t *const quote, size_t *const par); void do_justify(bool full_justify); void do_justify_void(void); @@ -680,7 +683,7 @@ void display_main_list(void); void do_cursorpos(bool constant); void do_cursorpos_void(void); #ifndef DISABLE_HELP -int help_line_len(const char *ptr); +size_t help_line_len(const char *ptr); void do_help(void); #endif void do_replace_highlight(bool highlight_flag, const char *word); diff --git a/src/winio.c b/src/winio.c index f1cd5a26..8f475304 100644 --- a/src/winio.c +++ b/src/winio.c @@ -3826,31 +3826,26 @@ void do_cursorpos_void(void) #ifndef DISABLE_HELP /* Calculate the next line of help_text, starting at ptr. */ -int help_line_len(const char *ptr) +size_t help_line_len(const char *ptr) { - int j = 0; + int help_cols = (COLS > 80) ? COLS - 8 : 72; - while (*ptr != '\n' && *ptr != '\0' && j < COLS - 5) { - ptr++; - j++; - } - if (j == COLS - 5) { - /* Don't wrap at the first of two spaces following a period. */ - if (*ptr == ' ' && *(ptr + 1) == ' ') - j++; - /* Don't print half a word if we've run out of space. */ - while (*ptr != ' ' && j > 0) { - ptr--; - j--; - } - /* A word longer than (COLS - 5) chars just gets broken. */ - if (j == 0) - j = COLS - 5; - } + /* Try to break the line at (COLS - 8) columns if we have more than + * 80 columns, and at 72 columns otherwise. */ + size_t retval = break_line(ptr, help_cols, TRUE, TRUE); + size_t retval_save = retval; - assert(j >= 0 && j <= COLS - 4 && (j > 0 || *ptr == '\n')); + /* Get the length of the entire line up to a null or a newline. */ + while (*(ptr + retval) != '\0' && *(ptr + retval) != '\n') + retval += move_mbright(ptr + retval, 0); - return j; + /* If the entire line doesn't go more than 8 columns beyond where we + * tried to break it, we should display it as-is. Otherwise, we + * should display it only up to the break. */ + if (strnlenpt(ptr, retval) > help_cols + 8) + retval = retval_save; + + return retval; } /* Our dynamic, shortcut-list-compliant help function. */ @@ -3944,8 +3939,6 @@ void do_help(void) blank_edit(); } - assert(COLS > 5); - /* Calculate where in the text we should be, based on the * page. */ for (i = 0; i < line; i++) { @@ -3955,7 +3948,7 @@ void do_help(void) } for (i = 0; i < editwinrows && *ptr != '\0'; i++) { - int j = help_line_len(ptr); + size_t j = help_line_len(ptr); mvwaddnstr(edit, i, 0, ptr, j); ptr += j;