diff options
author | James McCoy <jamessan@jamessan.com> | 2020-08-08 08:57:35 -0400 |
---|---|---|
committer | James McCoy <jamessan@jamessan.com> | 2020-08-08 08:57:35 -0400 |
commit | 840c12c10741d8f70e1787534fb6ea6d2b70edee (patch) | |
tree | f89ad27acbbf0b36db7ac08eeae0b8362da1fabb /src/nvim/spell.c | |
parent | e813ec79c201c85c5af3b10c051ae92ab5cb8606 (diff) | |
parent | f26df8bb66158baacb79c79822babaf137607cd6 (diff) | |
download | rneovim-840c12c10741d8f70e1787534fb6ea6d2b70edee.tar.gz rneovim-840c12c10741d8f70e1787534fb6ea6d2b70edee.tar.bz2 rneovim-840c12c10741d8f70e1787534fb6ea6d2b70edee.zip |
Merge remote-tracking branch 'upstream/master' into libcallnr
Diffstat (limited to 'src/nvim/spell.c')
-rw-r--r-- | src/nvim/spell.c | 429 |
1 files changed, 99 insertions, 330 deletions
diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 724a0332bc..95948dac78 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -848,7 +848,7 @@ static void find_word(matchinf_T *mip, int mode) mip->mi_compflags[mip->mi_complen] = ((unsigned)flags >> 24); mip->mi_compflags[mip->mi_complen + 1] = NUL; if (word_ends) { - char_u fword[MAXWLEN]; + char_u fword[MAXWLEN] = { 0 }; if (slang->sl_compsylmax < MAXWLEN) { // "fword" is only needed for checking syllables. @@ -1026,26 +1026,25 @@ match_checkcompoundpattern ( // Returns true if "flags" is a valid sequence of compound flags and "word" // does not have too many syllables. -static bool can_compound(slang_T *slang, char_u *word, char_u *flags) +static bool can_compound(slang_T *slang, const char_u *word, + const char_u *flags) + FUNC_ATTR_NONNULL_ALL { - char_u uflags[MAXWLEN * 2]; - int i; - char_u *p; + char_u uflags[MAXWLEN * 2] = { 0 }; - if (slang->sl_compprog == NULL) + if (slang->sl_compprog == NULL) { return false; - if (enc_utf8) { - // Need to convert the single byte flags to utf8 characters. - p = uflags; - for (i = 0; flags[i] != NUL; i++) { - p += utf_char2bytes(flags[i], p); - } - *p = NUL; - p = uflags; - } else - p = flags; - if (!vim_regexec_prog(&slang->sl_compprog, false, p, 0)) + } + // Need to convert the single byte flags to utf8 characters. + char_u *p = uflags; + for (int i = 0; flags[i] != NUL; i++) { + p += utf_char2bytes(flags[i], p); + } + *p = NUL; + p = uflags; + if (!vim_regexec_prog(&slang->sl_compprog, false, p, 0)) { return false; + } // Count the number of syllables. This may be slow, do it last. If there // are too many syllables AND the number of compound words is above @@ -1910,11 +1909,11 @@ int init_syl_tab(slang_T *slang) // Count the number of syllables in "word". // When "word" contains spaces the syllables after the last space are counted. // Returns zero if syllables are not defines. -static int count_syllables(slang_T *slang, char_u *word) +static int count_syllables(slang_T *slang, const char_u *word) + FUNC_ATTR_NONNULL_ALL { int cnt = 0; bool skip = false; - char_u *p; int len; syl_item_T *syl; int c; @@ -1922,7 +1921,7 @@ static int count_syllables(slang_T *slang, char_u *word) if (slang->sl_syllable == NULL) return 0; - for (p = word; *p != NUL; p += len) { + for (const char_u *p = word; *p != NUL; p += len) { // When running into a space reset counter. if (*p == ' ') { len = 1; @@ -2008,6 +2007,10 @@ char_u *did_set_spelllang(win_T *wp) region = NULL; len = (int)STRLEN(lang); + if (!valid_spelllang(lang)) { + continue; + } + if (STRCMP(lang, "cjk") == 0) { wp->w_s->b_cjk = 1; continue; @@ -2031,7 +2034,8 @@ char_u *did_set_spelllang(win_T *wp) // Check if we loaded this language before. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare(lang, slang->sl_fname, false) == kEqualFiles) { + if (path_full_compare(lang, slang->sl_fname, false, true) + == kEqualFiles) { break; } } @@ -2076,7 +2080,7 @@ char_u *did_set_spelllang(win_T *wp) // Loop over the languages, there can be several files for "lang". for (slang = first_lang; slang != NULL; slang = slang->sl_next) { if (filename - ? path_full_compare(lang, slang->sl_fname, false) == kEqualFiles + ? path_full_compare(lang, slang->sl_fname, false, true) == kEqualFiles : STRICMP(lang, slang->sl_name) == 0) { region_mask = REGION_ALL; if (!filename && region != NULL) { @@ -2129,7 +2133,7 @@ char_u *did_set_spelllang(win_T *wp) for (c = 0; c < ga.ga_len; ++c) { p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; if (p != NULL - && path_full_compare(spf_name, p, false) == kEqualFiles) { + && path_full_compare(spf_name, p, false, true) == kEqualFiles) { break; } } @@ -2139,7 +2143,8 @@ char_u *did_set_spelllang(win_T *wp) // Check if it was loaded already. for (slang = first_lang; slang != NULL; slang = slang->sl_next) { - if (path_full_compare(spf_name, slang->sl_fname, false) == kEqualFiles) { + if (path_full_compare(spf_name, slang->sl_fname, false, true) + == kEqualFiles) { break; } } @@ -2568,36 +2573,33 @@ void init_spell_chartab(void) /// Thus this only works properly when past the first character of the word. /// /// @param wp Buffer used. -static bool spell_iswordp(char_u *p, win_T *wp) +static bool spell_iswordp(const char_u *p, const win_T *wp) + FUNC_ATTR_NONNULL_ALL { - char_u *s; - int l; int c; - if (has_mbyte) { - l = MB_PTR2LEN(p); - s = p; - if (l == 1) { - // be quick for ASCII - if (wp->w_s->b_spell_ismw[*p]) - s = p + 1; // skip a mid-word character - } else { - c = utf_ptr2char(p); - if (c < 256 ? wp->w_s->b_spell_ismw[c] - : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) { - s = p + l; - } + const int l = utfc_ptr2len(p); + const char_u *s = p; + if (l == 1) { + // be quick for ASCII + if (wp->w_s->b_spell_ismw[*p]) { + s = p + 1; // skip a mid-word character } - - c = utf_ptr2char(s); - if (c > 255) { - return spell_mb_isword_class(mb_get_class(s), wp); + } else { + c = utf_ptr2char(p); + if (c < 256 + ? wp->w_s->b_spell_ismw[c] + : (wp->w_s->b_spell_ismw_mb != NULL + && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) { + s = p + l; } - return spelltab.st_isw[c]; } - return spelltab.st_isw[wp->w_s->b_spell_ismw[*p] ? p[1] : p[0]]; + c = utf_ptr2char(s); + if (c > 255) { + return spell_mb_isword_class(mb_get_class(s), wp); + } + return spelltab.st_isw[c]; } // Returns true if "p" points to a word character. @@ -2615,7 +2617,8 @@ bool spell_iswordp_nmw(const char_u *p, win_T *wp) // Only for characters above 255. // Unicode subscript and superscript are not considered word characters. // See also utf_class() in mbyte.c. -static bool spell_mb_isword_class(int cl, win_T *wp) +static bool spell_mb_isword_class(int cl, const win_T *wp) + FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { if (wp->w_s->b_cjk) // East Asian characters are not considered word characters. @@ -2625,9 +2628,10 @@ static bool spell_mb_isword_class(int cl, win_T *wp) // Returns true if "p" points to a word character. // Wide version of spell_iswordp(). -static bool spell_iswordp_w(int *p, win_T *wp) +static bool spell_iswordp_w(const int *p, const win_T *wp) + FUNC_ATTR_NONNULL_ALL { - int *s; + const int *s; if (*p < 256 ? wp->w_s->b_spell_ismw[*p] : (wp->w_s->b_spell_ismw_mb != NULL @@ -2823,9 +2827,6 @@ void spell_suggest(int count) smsg(_("Sorry, only %" PRId64 " suggestions"), (int64_t)sug.su_ga.ga_len); } else { - XFREE_CLEAR(repl_from); - XFREE_CLEAR(repl_to); - // When 'rightleft' is set the list is drawn right-left. cmdmsg_rl = curwin->w_p_rl; if (cmdmsg_rl) @@ -2905,6 +2906,9 @@ void spell_suggest(int count) if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK) { // Save the from and to text for :spellrepall. + XFREE_CLEAR(repl_from); + XFREE_CLEAR(repl_to); + stp = &SUG(sug.su_ga, selected - 1); if (sug.su_badlen > stp->st_orglen) { // Replacing less than "su_badlen", append the remainder to @@ -2926,8 +2930,6 @@ void spell_suggest(int count) memmove(p, line, c); STRCPY(p + c, stp->st_word); STRCAT(p, sug.su_badptr + stp->st_orglen); - ml_replace(curwin->w_cursor.lnum, p, false); - curwin->w_cursor.col = c; // For redo we use a change-word command. ResetRedobuff(); @@ -2936,7 +2938,10 @@ void spell_suggest(int count) stp->st_wordlen + sug.su_badlen - stp->st_orglen); AppendCharToRedobuff(ESC); - // After this "p" may be invalid. + // "p" may be freed here + ml_replace(curwin->w_cursor.lnum, p, false); + curwin->w_cursor.col = c; + changed_bytes(curwin->w_cursor.lnum, c); } else curwin->w_cursor = prev_cursor; @@ -3031,7 +3036,7 @@ void ex_spellrepall(exarg_T *eap) sub_nlines = 0; curwin->w_cursor.lnum = 0; while (!got_int) { - if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL, NULL) == 0 + if (do_search(NULL, '/', frompat, 1L, SEARCH_KEEP, NULL) == 0 || u_save_cursor() == FAIL) { break; } @@ -3602,7 +3607,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so { char_u tword[MAXWLEN]; // good word collected so far trystate_T stack[MAXWLEN]; - char_u preword[MAXWLEN * 3]; // word found with proper case; + char_u preword[MAXWLEN * 3] = { 0 }; // word found with proper case; // concatenation of prefix compound // words and split word. NUL terminated // when going deeper but not when coming @@ -3757,7 +3762,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so tword[sp->ts_twordlen] = NUL; if (sp->ts_prefixdepth <= PFD_NOTSPECIAL - && (sp->ts_flags & TSF_PREFIXOK) == 0) { + && (sp->ts_flags & TSF_PREFIXOK) == 0 + && pbyts != NULL) { // There was a prefix before the word. Check that the prefix // can be used with this word. // Count the length of the NULs in the prefix. If there are @@ -4116,7 +4122,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so && goodword_ends) { int l; - l = MB_PTR2LEN(fword + sp->ts_fidx); + l = utfc_ptr2len(fword + sp->ts_fidx); if (fword_ends) { // Copy the skipped character to preword. memmove(preword + sp->ts_prewordlen, @@ -4262,14 +4268,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Correct ts_fidx for the byte length of the // character (we didn't check that before). sp->ts_fidx = sp->ts_fcharstart - + MB_PTR2LEN(fword + sp->ts_fcharstart); + + utfc_ptr2len(fword + sp->ts_fcharstart); // For changing a composing character adjust // the score from SCORE_SUBST to // SCORE_SUBCOMP. - if (enc_utf8 - && utf_iscomposing(utf_ptr2char(tword + sp->ts_twordlen - - sp->ts_tcharlen)) + if (utf_iscomposing(utf_ptr2char(tword + sp->ts_twordlen + - sp->ts_tcharlen)) && utf_iscomposing(utf_ptr2char(fword + sp->ts_fcharstart))) { sp->ts_score -= SCORE_SUBST - SCORE_SUBCOMP; @@ -4361,7 +4366,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // a bit illogical for soundfold tree but it does give better // results. c = utf_ptr2char(fword + sp->ts_fidx); - stack[depth].ts_fidx += MB_PTR2LEN(fword + sp->ts_fidx); + stack[depth].ts_fidx += utfc_ptr2len(fword + sp->ts_fidx); if (utf_iscomposing(c)) { stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP; } else if (c == utf_ptr2char(fword + stack[depth].ts_fidx)) { @@ -4531,9 +4536,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNSWAP: // Undo the STATE_SWAP swap: "21" -> "12". p = fword + sp->ts_fidx; - n = MB_PTR2LEN(p); + n = utfc_ptr2len(p); c = utf_ptr2char(p + n); - memmove(p + MB_PTR2LEN(p + n), p, n); + memmove(p + utfc_ptr2len(p + n), p, n); utf_char2bytes(c, p); FALLTHROUGH; @@ -4587,11 +4592,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNSWAP3: // Undo STATE_SWAP3: "321" -> "123" p = fword + sp->ts_fidx; - n = MB_PTR2LEN(p); + n = utfc_ptr2len(p); c2 = utf_ptr2char(p + n); - fl = MB_PTR2LEN(p + n); + fl = utfc_ptr2len(p + n); c = utf_ptr2char(p + n + fl); - tl = MB_PTR2LEN(p + n + fl); + tl = utfc_ptr2len(p + n + fl); memmove(p + fl + tl, p, n); utf_char2bytes(c, p); utf_char2bytes(c2, p + tl); @@ -4635,10 +4640,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNROT3L: // Undo ROT3L: "231" -> "123" p = fword + sp->ts_fidx; - n = MB_PTR2LEN(p); - n += MB_PTR2LEN(p + n); + n = utfc_ptr2len(p); + n += utfc_ptr2len(p + n); c = utf_ptr2char(p + n); - tl = MB_PTR2LEN(p + n); + tl = utfc_ptr2len(p + n); memmove(p + tl, p, n); utf_char2bytes(c, p); @@ -4673,9 +4678,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // Undo ROT3R: "312" -> "123" p = fword + sp->ts_fidx; c = utf_ptr2char(p); - tl = MB_PTR2LEN(p); - n = MB_PTR2LEN(p + tl); - n += MB_PTR2LEN(p + tl + n); + tl = utfc_ptr2len(p); + n = utfc_ptr2len(p + tl); + n += utfc_ptr2len(p + tl + n); memmove(p, p + tl, n); utf_char2bytes(c, p + n); @@ -5758,19 +5763,22 @@ cleanup_suggestions ( int maxscore, int keep // nr of suggestions to keep ) + FUNC_ATTR_NONNULL_ALL { suggest_T *stp = &SUG(*gap, 0); - // Sort the list. - qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); + if (gap->ga_len > 0) { + // Sort the list. + qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); - // Truncate the list to the number of suggestions that will be displayed. - if (gap->ga_len > keep) { - for (int i = keep; i < gap->ga_len; ++i) { - xfree(stp[i].st_word); + // Truncate the list to the number of suggestions that will be displayed. + if (gap->ga_len > keep) { + for (int i = keep; i < gap->ga_len; i++) { + xfree(stp[i].st_word); + } + gap->ga_len = keep; + return stp[keep - 1].st_score; } - gap->ga_len = keep; - return stp[keep - 1].st_score; } return maxscore; } @@ -5834,10 +5842,7 @@ void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res) word = fword; } - if (has_mbyte) - spell_soundfold_wsal(slang, word, res); - else - spell_soundfold_sal(slang, word, res); + spell_soundfold_wsal(slang, word, res); } } @@ -5857,7 +5862,7 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) // 255, sl_sal the rest. for (s = inword; *s != NUL; ) { c = mb_cptr2char_adv((const char_u **)&s); - if (enc_utf8 ? utf_class(c) == 0 : ascii_iswhite(c)) { + if (utf_class(c) == 0) { c = ' '; } else if (c < 256) { c = slang->sl_sal_first[c]; @@ -5902,250 +5907,13 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res) res[ri] = NUL; } -static void spell_soundfold_sal(slang_T *slang, char_u *inword, char_u *res) -{ - salitem_T *smp; - char_u word[MAXWLEN]; - char_u *s = inword; - char_u *t; - char_u *pf; - int i, j, z; - int reslen; - int n, k = 0; - int z0; - int k0; - int n0; - int c; - int pri; - int p0 = -333; - int c0; - - // Remove accents, if wanted. We actually remove all non-word characters. - // But keep white space. We need a copy, the word may be changed here. - if (slang->sl_rem_accents) { - t = word; - while (*s != NUL) { - if (ascii_iswhite(*s)) { - *t++ = ' '; - s = skipwhite(s); - } else { - if (spell_iswordp_nmw(s, curwin)) - *t++ = *s; - ++s; - } - } - *t = NUL; - } else - STRLCPY(word, s, MAXWLEN); - - smp = (salitem_T *)slang->sl_sal.ga_data; - - // This comes from Aspell phonet.cpp. Converted from C++ to C. - // Changed to keep spaces. - i = reslen = z = 0; - while ((c = word[i]) != NUL) { - // Start with the first rule that has the character in the word. - n = slang->sl_sal_first[c]; - z0 = 0; - - if (n >= 0) { - // check all rules for the same letter - for (; (s = smp[n].sm_lead)[0] == c; ++n) { - // Quickly skip entries that don't match the word. Most - // entries are less then three chars, optimize for that. - k = smp[n].sm_leadlen; - if (k > 1) { - if (word[i + 1] != s[1]) - continue; - if (k > 2) { - for (j = 2; j < k; ++j) - if (word[i + j] != s[j]) - break; - if (j < k) - continue; - } - } - - if ((pf = smp[n].sm_oneof) != NULL) { - // Check for match with one of the chars in "sm_oneof". - while (*pf != NUL && *pf != word[i + k]) - ++pf; - if (*pf == NUL) - continue; - ++k; - } - s = smp[n].sm_rules; - pri = 5; // default priority - - p0 = *s; - k0 = k; - while (*s == '-' && k > 1) { - k--; - s++; - } - if (*s == '<') - s++; - if (ascii_isdigit(*s)) { - // determine priority - pri = *s - '0'; - s++; - } - if (*s == '^' && *(s + 1) == '^') - s++; - - if (*s == NUL - || (*s == '^' - && (i == 0 || !(word[i - 1] == ' ' - || spell_iswordp(word + i - 1, curwin))) - && (*(s + 1) != '$' - || (!spell_iswordp(word + i + k0, curwin)))) - || (*s == '$' && i > 0 - && spell_iswordp(word + i - 1, curwin) - && (!spell_iswordp(word + i + k0, curwin)))) { - // search for followup rules, if: - // followup and k > 1 and NO '-' in searchstring - c0 = word[i + k - 1]; - n0 = slang->sl_sal_first[c0]; - - if (slang->sl_followup && k > 1 && n0 >= 0 - && p0 != '-' && word[i + k] != NUL) { - // test follow-up rule for "word[i + k]" - for (; (s = smp[n0].sm_lead)[0] == c0; ++n0) { - // Quickly skip entries that don't match the word. - k0 = smp[n0].sm_leadlen; - if (k0 > 1) { - if (word[i + k] != s[1]) - continue; - if (k0 > 2) { - pf = word + i + k + 1; - for (j = 2; j < k0; ++j) - if (*pf++ != s[j]) - break; - if (j < k0) - continue; - } - } - k0 += k - 1; - - if ((pf = smp[n0].sm_oneof) != NULL) { - // Check for match with one of the chars in - // "sm_oneof". - while (*pf != NUL && *pf != word[i + k0]) - ++pf; - if (*pf == NUL) - continue; - ++k0; - } - - p0 = 5; - s = smp[n0].sm_rules; - while (*s == '-') { - // "k0" gets NOT reduced because - // "if (k0 == k)" - s++; - } - if (*s == '<') - s++; - if (ascii_isdigit(*s)) { - p0 = *s - '0'; - s++; - } - - if (*s == NUL - // *s == '^' cuts - || (*s == '$' - && !spell_iswordp(word + i + k0, - curwin))) { - if (k0 == k) - // this is just a piece of the string - continue; - - if (p0 < pri) - // priority too low - continue; - // rule fits; stop search - break; - } - } - - if (p0 >= pri && smp[n0].sm_lead[0] == c0) - continue; - } - - // replace string - s = smp[n].sm_to; - if (s == NULL) - s = (char_u *)""; - pf = smp[n].sm_rules; - p0 = (vim_strchr(pf, '<') != NULL) ? 1 : 0; - if (p0 == 1 && z == 0) { - // rule with '<' is used - if (reslen > 0 && *s != NUL && (res[reslen - 1] == c - || res[reslen - 1] == *s)) - reslen--; - z0 = 1; - z = 1; - k0 = 0; - while (*s != NUL && word[i + k0] != NUL) { - word[i + k0] = *s; - k0++; - s++; - } - if (k > k0) - STRMOVE(word + i + k0, word + i + k); - - // new "actual letter" - c = word[i]; - } else { - // no '<' rule used - i += k - 1; - z = 0; - while (*s != NUL && s[1] != NUL && reslen < MAXWLEN) { - if (reslen == 0 || res[reslen - 1] != *s) - res[reslen++] = *s; - s++; - } - // new "actual letter" - c = *s; - if (strstr((char *)pf, "^^") != NULL) { - if (c != NUL) - res[reslen++] = c; - STRMOVE(word, word + i + 1); - i = 0; - z0 = 1; - } - } - break; - } - } - } else if (ascii_iswhite(c)) { - c = ' '; - k = 1; - } - - if (z0 == 0) { - if (k && !p0 && reslen < MAXWLEN && c != NUL - && (!slang->sl_collapse || reslen == 0 - || res[reslen - 1] != c)) - // condense only double letters - res[reslen++] = c; - - i++; - z = 0; - k = 0; - } - } - - res[reslen] = NUL; -} - // Turn "inword" into its sound-a-like equivalent in "res[MAXWLEN]". // Multi-byte version of spell_soundfold(). static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) { salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data; - int word[MAXWLEN]; - int wres[MAXWLEN]; + int word[MAXWLEN] = { 0 }; + int wres[MAXWLEN] = { 0 }; int l; int *ws; int *pf; @@ -6171,9 +5939,10 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) const char_u *t = s; c = mb_cptr2char_adv((const char_u **)&s); if (slang->sl_rem_accents) { - if (enc_utf8 ? utf_class(c) == 0 : ascii_iswhite(c)) { - if (did_white) + if (utf_class(c) == 0) { + if (did_white) { continue; + } c = ' '; did_white = true; } else { |