diff -r -U4 nano-2.1.10/src/browser.c nano-2.1.10+tabsize2/src/browser.c --- nano-2.1.10/src/browser.c 2009-01-25 07:26:47.000000000 +0000 +++ nano-2.1.10+tabsize2/src/browser.c 2009-09-26 19:04:09.000000000 +0100 @@ -625,9 +625,10 @@ * this to TRUE if we have fewer than 15 columns (i.e. * one column for padding, plus seven columns for a * filename other than ".."). */ char *disp = display_string(filetail, dots ? filetaillen - - longest + foomaxlen + 4 : 0, longest, FALSE); + longest + foomaxlen + 4 : 0, longest, FALSE, ALIGN_TAB, + 0); /* If we put an ellipsis before the filename, reserve * one column for padding, plus seven columns for "--", * "(dir)", or the file size, plus three columns for the * ellipsis. */ @@ -776,9 +777,10 @@ search_init_globals(); if (last_search[0] != '\0') { - char *disp = display_string(last_search, 0, COLS / 3, FALSE); + char *disp = display_string(last_search, 0, COLS / 3, FALSE, + ALIGN_TAB, 0); buf = charalloc(strlen(disp) + 7); /* We use (COLS / 3) here because we need to see more on the * line. */ diff -r -U4 nano-2.1.10/src/chars.c nano-2.1.10+tabsize2/src/chars.c --- nano-2.1.10/src/chars.c 2008-09-15 04:32:35.000000000 +0100 +++ nano-2.1.10+tabsize2/src/chars.c 2009-09-26 19:08:34.000000000 +0100 @@ -373,9 +373,10 @@ /* Parse a multibyte character from buf. Return the number of bytes * used. If chr isn't NULL, store the multibyte character in it. If * col isn't NULL, store the new display width in it. If *buf is '\t', * we expect col to have the current display width. */ -int parse_mbchar(const char *buf, char *chr, size_t *col) +int parse_mbchar(const char *buf, char *chr, size_t *col, + tabsize_type tab_type, size_t tab_base) { int buf_mb_len; assert(buf != NULL); @@ -404,10 +405,13 @@ /* Save the column width of the wide character in col. */ if (col != NULL) { /* If we have a tab, get its width in columns using the * current value of col. */ - if (*buf == '\t') - *col += tabsize - *col % tabsize; + if (*buf == '\t') { + assert(tab_type != ANY_TAB); + *col += tabsize[tab_type] - (*col - tab_base) + % tabsize[tab_type]; + } /* If we have a control character, get its width using one * column for the "^" that will be displayed in front of it, * and the width in columns of its visible equivalent as * returned by control_mbrep(). */ @@ -439,10 +443,13 @@ if (col != NULL) { /* If we have a tab, get its width in columns using the * current value of col. */ - if (*buf == '\t') - *col += tabsize - *col % tabsize; + if (*buf == '\t') { + assert(tab_type != ANY_TAB); + *col += tabsize[tab_type] - (*col - tab_base) + % tabsize[tab_type]; + } /* If we have a control character, it's two columns wide: * one column for the "^" that will be displayed in front of * it, and one column for its visible equivalent as returned * by control_mbrep(). */ @@ -469,9 +476,10 @@ /* There is no library function to move backward one multibyte * character. Here is the naive, O(pos) way to do it. */ while (TRUE) { - int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL, NULL); + int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL, NULL, + ANY_TAB, 0); if (pos_prev <= buf_mb_len) break; @@ -484,9 +492,9 @@ /* Return the index in buf of the beginning of the multibyte character * after the one at pos. */ size_t move_mbright(const char *buf, size_t pos) { - return pos + parse_mbchar(buf + pos, NULL, NULL); + return pos + parse_mbchar(buf + pos, NULL, NULL, ANY_TAB, 0); } #ifndef HAVE_STRCASECMP /* This function is equivalent to strcasecmp(). */ @@ -541,17 +549,17 @@ move_mbright(s1, 0), s2 += move_mbright(s2, 0), n--) { bool bad_s1_mb = FALSE, bad_s2_mb = FALSE; int s1_mb_len, s2_mb_len; - s1_mb_len = parse_mbchar(s1, s1_mb, NULL); + s1_mb_len = parse_mbchar(s1, s1_mb, NULL, ANY_TAB, 0); if (mbtowc(&ws1, s1_mb, s1_mb_len) < 0) { mbtowc(NULL, NULL, 0); ws1 = (unsigned char)*s1_mb; bad_s1_mb = TRUE; } - s2_mb_len = parse_mbchar(s2, s2_mb, NULL); + s2_mb_len = parse_mbchar(s2, s2_mb, NULL, ANY_TAB, 0); if (mbtowc(&ws2, s2_mb, s2_mb_len) < 0) { mbtowc(NULL, NULL, 0); ws2 = (unsigned char)*s2_mb; @@ -786,9 +794,9 @@ bad_c_mb = TRUE; } while (*s != '\0') { - int s_mb_len = parse_mbchar(s, s_mb, NULL); + int s_mb_len = parse_mbchar(s, s_mb, NULL, ANY_TAB, 0); if (mbtowc(&ws, s_mb, s_mb_len) < 0) { mbtowc(NULL, NULL, 0); ws = (unsigned char)*s; @@ -909,9 +917,9 @@ bool retval = FALSE; char *chr_mb = charalloc(MB_CUR_MAX); for (; *s != '\0'; s += move_mbright(s, 0)) { - parse_mbchar(s, chr_mb, NULL); + parse_mbchar(s, chr_mb, NULL, ANY_TAB, 0); if (is_blank_mbchar(chr_mb)) { retval = TRUE; break; diff -r -U4 nano-2.1.10/src/files.c nano-2.1.10+tabsize2/src/files.c --- nano-2.1.10/src/files.c 2009-05-03 02:40:33.000000000 +0100 +++ nano-2.1.10+tabsize2/src/files.c 2009-09-26 19:08:47.000000000 +0100 @@ -2392,11 +2392,11 @@ for (match = 1; match < num_matches; match++) { /* Get the number of single-byte characters that all the * matches have in common. */ match1_mb_len = parse_mbchar(matches[0] + common_len, - match1_mb, NULL); + match1_mb, NULL, ANY_TAB, 0); match2_mb_len = parse_mbchar(matches[match] + - common_len, match2_mb, NULL); + common_len, match2_mb, NULL, ANY_TAB, 0); match1_mb[match1_mb_len] = '\0'; match2_mb[match2_mb_len] = '\0'; if (strcmp(match1_mb, match2_mb) != 0) break; @@ -2404,9 +2404,10 @@ if (match < num_matches || matches[0][common_len] == '\0') break; - common_len += parse_mbchar(buf + common_len, NULL, NULL); + common_len += parse_mbchar(buf + common_len, NULL, NULL, + ANY_TAB, 0); } free(match1_mb); free(match2_mb); @@ -2492,9 +2493,9 @@ break; } disp = display_string(matches[match], 0, longest_name, - FALSE); + FALSE, ALIGN_TAB, 0); waddstr(edit, disp); free(disp); if ((match + 1) % ncols == 0) diff -r -U4 nano-2.1.10/src/global.c nano-2.1.10+tabsize2/src/global.c --- nano-2.1.10/src/global.c 2009-07-12 04:36:57.000000000 +0100 +++ nano-2.1.10+tabsize2/src/global.c 2009-09-26 14:38:07.000000000 +0100 @@ -123,11 +123,12 @@ char *answer = NULL; /* The answer string used by the statusbar prompt. */ -ssize_t tabsize = -1; - /* The width of a tab in spaces. The default value is set in - * main(). */ +ssize_t tabsize[2] = { -1, -1 }; + /* The width of a tab in spaces, at the start of each line. + * The width of a tab in spaces, after any non-tab characters. + * The default value is set in main(). */ #ifndef NANO_TINY char *backup_dir = NULL; /* The directory where we store backup files. */ diff -r -U4 nano-2.1.10/src/move.c nano-2.1.10+tabsize2/src/move.c --- nano-2.1.10/src/move.c 2009-01-25 07:26:47.000000000 +0000 +++ nano-2.1.10+tabsize2/src/move.c 2009-09-26 19:09:03.000000000 +0100 @@ -218,9 +218,9 @@ /* Move forward until we find the character after the last letter of * the current word. */ while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + - openfile->current_x, char_mb, NULL); + openfile->current_x, char_mb, NULL, ANY_TAB, 0); /* If we've found it, stop moving forward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) @@ -245,9 +245,9 @@ for (; openfile->current != NULL; openfile->current = openfile->current->next) { while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + - openfile->current_x, char_mb, NULL); + openfile->current_x, char_mb, NULL, ANY_TAB, 0); /* If we've found it, stop moving forward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) @@ -313,9 +313,9 @@ /* Move backward until we find the character before the first letter * of the current word. */ while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + - openfile->current_x, char_mb, NULL); + openfile->current_x, char_mb, NULL, ANY_TAB, 0); /* If we've found it, stop moving backward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) @@ -343,9 +343,9 @@ for (; openfile->current != NULL; openfile->current = openfile->current->prev) { while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + - openfile->current_x, char_mb, NULL); + openfile->current_x, char_mb, NULL, ANY_TAB, 0); /* If we've found it, stop moving backward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) @@ -383,9 +383,9 @@ openfile->current_x); while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + - openfile->current_x, char_mb, NULL); + openfile->current_x, char_mb, NULL, ANY_TAB, 0); /* If we've found it, stop moving backward through the * current line. */ if (!is_word_mbchar(char_mb, allow_punct)) diff -r -U4 nano-2.1.10/src/nano.c nano-2.1.10+tabsize2/src/nano.c --- nano-2.1.10/src/nano.c 2009-07-12 04:36:57.000000000 +0100 +++ nano-2.1.10+tabsize2/src/nano.c 2009-09-26 19:13:39.000000000 +0100 @@ -1863,9 +1863,10 @@ } } /* Interpret the next multibyte character. */ - char_buf_len = parse_mbchar(output + i, char_buf, NULL); + char_buf_len = parse_mbchar(output + i, char_buf, NULL, + ANY_TAB, 0); i += char_buf_len; /* If allow_cntrls is FALSE, filter out an ASCII control @@ -2135,13 +2136,15 @@ SET(SMOOTH_SCROLL); break; #endif case 'T': - if (!parse_num(optarg, &tabsize) || tabsize <= 0) { + if (!parse_num(optarg, &tabsize[INDENT_TAB]) + || tabsize[INDENT_TAB] <= 0) { fprintf(stderr, _("Requested tab size \"%s\" is invalid"), optarg); fprintf(stderr, "\n"); exit(1); } + tabsize[ALIGN_TAB] = tabsize[INDENT_TAB]; break; #ifndef NANO_TINY case 'U': SET(QUICK_BLANK); @@ -2275,9 +2278,9 @@ #endif #ifndef DISABLE_SPELLER char *alt_speller_cpy = alt_speller; #endif - ssize_t tabsize_cpy = tabsize; + ssize_t tabsize_cpy[2] = { tabsize[0], tabsize[1] }; long flags_cpy = flags; #ifndef DISABLE_OPERATINGDIR operating_dir = NULL; @@ -2326,10 +2329,12 @@ free(alt_speller); alt_speller = alt_speller_cpy; } #endif - if (tabsize_cpy != -1) - tabsize = tabsize_cpy; + if (tabsize_cpy[INDENT_TAB] != -1) + tabsize[INDENT_TAB] = tabsize_cpy[INDENT_TAB]; + if (tabsize_cpy[ALIGN_TAB] != -1) + tabsize[ALIGN_TAB] = tabsize_cpy[ALIGN_TAB]; flags |= flags_cpy; } #ifdef DISABLE_ROOTWRAPPING /* If we don't have any rcfiles, --disable-wrapping-as-root is used, @@ -2433,10 +2438,12 @@ } #endif /* If tabsize wasn't specified, set its default value. */ - if (tabsize == -1) - tabsize = WIDTH_OF_TAB; + if (tabsize[INDENT_TAB] == -1) + tabsize[INDENT_TAB] = WIDTH_OF_TAB; + if (tabsize[ALIGN_TAB] == -1) + tabsize[ALIGN_TAB] = tabsize[INDENT_TAB]; /* Back up the old terminal settings so that they can be restored. */ tcgetattr(0, &oldterm); diff -r -U4 nano-2.1.10/src/nano.h nano-2.1.10+tabsize2/src/nano.h --- nano-2.1.10/src/nano.h 2009-07-03 04:51:25.000000000 +0100 +++ nano-2.1.10+tabsize2/src/nano.h 2009-09-26 19:07:10.000000000 +0100 @@ -182,8 +182,14 @@ typedef enum { ADD, DEL, REPLACE, SPLIT, UNSPLIT, CUT, UNCUT, ENTER, INSERT, OTHER } undo_type; +#ifndef NANO_TINY +typedef enum { + INDENT_TAB, ALIGN_TAB, ANY_TAB +} tabsize_type; +#endif + #ifdef ENABLE_COLOR typedef struct colortype { short fg; /* This syntax's foreground color. */ diff -r -U4 nano-2.1.10/src/prompt.c nano-2.1.10+tabsize2/src/prompt.c --- nano-2.1.10/src/prompt.c 2009-01-25 07:26:47.000000000 +0000 +++ nano-2.1.10+tabsize2/src/prompt.c 2009-09-26 19:09:19.000000000 +0100 @@ -309,9 +309,10 @@ } } /* Interpret the next multibyte character. */ - char_buf_len = parse_mbchar(output + i, char_buf, NULL); + char_buf_len = parse_mbchar(output + i, char_buf, NULL, + ANY_TAB, 0); i += char_buf_len; /* If allow_cntrls is FALSE, filter out an ASCII control @@ -427,9 +428,9 @@ statusbar_pww = statusbar_xplustabs(); if (answer[statusbar_x] != '\0') { int char_buf_len = parse_mbchar(answer + statusbar_x, NULL, - NULL); + NULL, 0, 0); size_t line_len = strlen(answer + statusbar_x); assert(statusbar_x < strlen(answer)); @@ -480,9 +481,10 @@ /* Move forward until we find the character after the last letter of * the current word. */ while (!end_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL, + 0, 0); /* If we've found it, stop moving forward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) @@ -504,9 +506,10 @@ else statusbar_x += char_mb_len; while (!end_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL, + 0, 0); /* If we've found it, stop moving forward through the current * line. */ if (is_word_mbchar(char_mb, allow_punct)) @@ -545,9 +548,10 @@ /* Move backward until we find the character before the first letter * of the current word. */ while (!begin_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL, + 0, 0); /* If we've found it, stop moving backward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) @@ -570,9 +574,10 @@ else statusbar_x = move_mbleft(answer, statusbar_x); while (!begin_line) { - char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); + char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL, + 0, 0); /* If we've found it, stop moving backward through the current * line. */ if (is_word_mbchar(char_mb, allow_punct)) @@ -593,9 +598,9 @@ statusbar_x = move_mbleft(answer, statusbar_x); while (!begin_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, - NULL); + NULL, 0, 0); /* If we've found it, stop moving backward through the * current line. */ if (!is_word_mbchar(char_mb, allow_punct)) @@ -747,9 +752,9 @@ mbmatchhalf = mbstrlen(matchbrackets) / 2; for (i = 0; i < mbmatchhalf; i++) matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, - NULL); + NULL, 0, 0); reverse = ((ch - matchbrackets) >= matchhalf); /* If we're on an opening bracket, set wanted_ch to the character @@ -767,10 +772,10 @@ mbmatchhalf--; } - ch_len = parse_mbchar(ch, NULL, NULL); - wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL); + ch_len = parse_mbchar(ch, NULL, NULL, 0, 0); + wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL, 0, 0); /* Fill bracket_set in with the values of ch and wanted_ch. */ bracket_set = charalloc((mb_cur_max() * 2) + 1); strncpy(bracket_set, ch, ch_len); @@ -782,9 +787,9 @@ while (TRUE) { if (find_statusbar_bracket_match(reverse, bracket_set)) { /* If we found an identical bracket, increment count. If we * found a complementary bracket, decrement it. */ - parse_mbchar(answer + statusbar_x, found_ch, NULL); + parse_mbchar(answer + statusbar_x, found_ch, NULL, 0, 0); count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1; /* If count is zero, we've found a matching bracket. Update * the statusbar prompt and get out. */ @@ -862,9 +867,9 @@ waddch(bottomwin, ':'); waddch(bottomwin, (page_start == 0) ? ' ' : '$'); expanded = display_string(curranswer, page_start, COLS - start_col - - 1, FALSE); + 1, FALSE, ALIGN_TAB, 0); waddstr(bottomwin, expanded); free(expanded); wattroff(bottomwin, reverse_attr); diff -r -U4 nano-2.1.10/src/proto.h nano-2.1.10+tabsize2/src/proto.h --- nano-2.1.10/src/proto.h 2009-07-12 04:36:57.000000000 +0100 +++ nano-2.1.10+tabsize2/src/proto.h 2009-09-26 19:00:59.000000000 +0100 @@ -79,9 +79,9 @@ #endif extern bool nodelay_mode; extern char *answer; -extern ssize_t tabsize; +extern ssize_t tabsize[2]; #ifndef NANO_TINY extern char *backup_dir; #endif @@ -172,9 +172,10 @@ char *mbrep(const char *c, char *crep, int *crep_len); int mbwidth(const char *c); int mb_cur_max(void); char *make_mbchar(long chr, int *chr_mb_len); -int parse_mbchar(const char *buf, char *chr, size_t *col); +int parse_mbchar(const char *buf, char *chr, size_t *col, + tabsize_type tab_type, size_t tab_base); size_t move_mbleft(const char *buf, size_t pos); size_t move_mbright(const char *buf, size_t pos); #ifndef HAVE_STRCASECMP int nstrcasecmp(const char *s1, const char *s2); @@ -640,10 +641,12 @@ , bool newln #endif ); #endif -#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY) +#if !defined(NANO_TINY) size_t indent_length(const char *line); +bool calc_tabsize(const char *line, size_t current_x, + tabsize_type *tab_type, size_t *tab_base); #endif #ifndef DISABLE_JUSTIFY void justify_format(filestruct *paragraph, size_t skip); size_t quote_length(const char *line); @@ -755,9 +758,9 @@ void blank_statusbar(void); void blank_bottombars(void); void check_statusblank(void); char *display_string(const char *buf, size_t start_col, size_t len, bool - dollars); + dollars, tabsize_type tab_type, size_t tab_base); void titlebar(const char *path); void set_modified(void); void statusbar(const char *msg, ...); void bottombars(int menu); diff -r -U4 nano-2.1.10/src/rcfile.c nano-2.1.10+tabsize2/src/rcfile.c --- nano-2.1.10/src/rcfile.c 2009-07-12 07:13:34.000000000 +0100 +++ nano-2.1.10+tabsize2/src/rcfile.c 2009-09-26 19:14:51.000000000 +0100 @@ -992,12 +992,13 @@ whitespace = NULL; } else { whitespace_len[0] = parse_mbchar(whitespace, NULL, - NULL); + NULL, ANY_TAB, 0); whitespace_len[1] = parse_mbchar(whitespace + - whitespace_len[0], NULL, NULL); + whitespace_len[0], NULL, NULL, + ANY_TAB, 0); } } else #endif #ifndef DISABLE_JUSTIFY @@ -1035,15 +1036,36 @@ else #endif if (strcasecmp(rcopts[i].name, "tabsize") == 0) { - if (!parse_num(option, &tabsize) || - tabsize <= 0) { + bool ok = TRUE; + + if (!parse_num(option, + &tabsize[INDENT_TAB]) + || tabsize[INDENT_TAB] <= 0) { rcfile_error( N_("Requested tab size \"%s\" is invalid"), option); - tabsize = -1; - } else + tabsize[INDENT_TAB] = -1; + ok = FALSE; + } + + if (ptr[0] != '\0') { + char *option2 = ptr; + ptr = parse_next_word(ptr); + + if (!parse_num(option2, + &tabsize[ALIGN_TAB]) + || tabsize[ALIGN_TAB] <= 0) { + rcfile_error( + N_("Requested second tab size \"%s\" is invalid"), + option2); + tabsize[ALIGN_TAB] = -1; + ok = FALSE; + } + } + + if (ok == TRUE) free(option); } else assert(FALSE); } diff -r -U4 nano-2.1.10/src/search.c nano-2.1.10+tabsize2/src/search.c --- nano-2.1.10/src/search.c 2009-02-17 02:03:41.000000000 +0000 +++ nano-2.1.10+tabsize2/src/search.c 2009-09-26 19:09:53.000000000 +0100 @@ -89,9 +89,9 @@ int numchars; assert(str != NULL); - disp = display_string(str, 0, (COLS / 2) + 1, FALSE); + disp = display_string(str, 0, (COLS / 2) + 1, FALSE, ALIGN_TAB, 0); numchars = actual_x(disp, mbstrnlen(disp, COLS / 2)); statusbar(_("\"%.*s%s\" not found"), numchars, disp, (disp[numchars] == '\0') ? "" : "..."); @@ -160,9 +160,10 @@ search_init_globals(); if (last_search[0] != '\0') { - char *disp = display_string(last_search, 0, COLS / 3, FALSE); + char *disp = display_string(last_search, 0, COLS / 3, FALSE, + ALIGN_TAB, 0); buf = charalloc(strlen(disp) + 7); /* We use (COLS / 3) here because we need to see more on the * line. */ @@ -771,12 +772,20 @@ if (numreplaced == -1) numreplaced = 0; if (!replaceall) { + tabsize_type tab_type; + size_t tab_base; size_t xpt = xplustabs(); - char *exp_word = display_string(openfile->current->data, + char *exp_word; + + calc_tabsize(openfile->current->data, + openfile->current_x, &tab_type, &tab_base); + + exp_word = display_string(openfile->current->data, xpt, strnlenpt(openfile->current->data, - openfile->current_x + match_len) - xpt, FALSE); + openfile->current_x + match_len) - xpt, FALSE, + tab_type, tab_base); curs_set(0); do_replace_highlight(TRUE, exp_word); @@ -1229,9 +1238,9 @@ mbmatchhalf = mbstrlen(matchbrackets) / 2; for (i = 0; i < mbmatchhalf; i++) matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, - NULL); + NULL, ANY_TAB, 0); reverse = ((ch - matchbrackets) >= matchhalf); /* If we're on an opening bracket, set wanted_ch to the character @@ -1249,10 +1258,10 @@ mbmatchhalf--; } - ch_len = parse_mbchar(ch, NULL, NULL); - wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL); + ch_len = parse_mbchar(ch, NULL, NULL, ANY_TAB, 0); + wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL, ANY_TAB, 0); /* Fill bracket_set in with the values of ch and wanted_ch. */ bracket_set = charalloc((mb_cur_max() * 2) + 1); strncpy(bracket_set, ch, ch_len); @@ -1265,9 +1274,9 @@ if (find_bracket_match(reverse, bracket_set)) { /* If we found an identical bracket, increment count. If we * found a complementary bracket, decrement it. */ parse_mbchar(openfile->current->data + openfile->current_x, - found_ch, NULL); + found_ch, NULL, ANY_TAB, 0); count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1; /* If count is zero, we've found a matching bracket. Update * the screen and get out. */ diff -r -U4 nano-2.1.10/src/text.c nano-2.1.10+tabsize2/src/text.c --- nano-2.1.10/src/text.c 2009-07-27 05:16:25.000000000 +0100 +++ nano-2.1.10+tabsize2/src/text.c 2009-09-26 19:15:25.000000000 +0100 @@ -79,9 +79,9 @@ openfile->placewewant = xplustabs(); if (openfile->current->data[openfile->current_x] != '\0') { int char_buf_len = parse_mbchar(openfile->current->data + - openfile->current_x, NULL, NULL); + openfile->current_x, NULL, NULL, ANY_TAB, 0); size_t line_len = strlen(openfile->current->data + openfile->current_x); assert(openfile->current_x < strlen(openfile->current->data)); @@ -164,13 +164,23 @@ #ifndef NANO_TINY if (ISSET(TABS_TO_SPACES)) { char *output; size_t output_len = 0, new_pww = xplustabs(); + tabsize_type tab_type; + size_t tab_base; + bool at_base = calc_tabsize(openfile->current->data, + openfile->current_x, &tab_type, &tab_base); + /* If tab size currently changes at the point of insertion, + * the indent tab size should be used. */ + if (at_base) { + tab_type = INDENT_TAB; + tab_base = 0; + } do { new_pww++; output_len++; - } while (new_pww % tabsize != 0); + } while ((new_pww - tab_base) % tabsize[tab_type] != 0); output = charalloc(output_len + 1); charset(output, ' ', output_len); @@ -243,10 +253,10 @@ line_indent_len = cols; } else { /* Set the indentation to (cols / tabsize) tabs and (cols % * tabsize) spaces. */ - size_t num_tabs = cols / tabsize; - size_t num_spaces = cols % tabsize; + size_t num_tabs = cols / tabsize[INDENT_TAB]; + size_t num_spaces = cols % tabsize[INDENT_TAB]; charset(line_indent, '\t', num_tabs); charset(line_indent + num_tabs, ' ', num_spaces); @@ -346,16 +356,16 @@ /* Indent the current line, or all lines covered by the mark if the mark * is on, tabsize columns. */ void do_indent_void(void) { - do_indent(tabsize); + do_indent(tabsize[INDENT_TAB]); } /* Unindent the current line, or all lines covered by the mark if the * mark is on, tabsize columns. */ void do_unindent(void) { - do_indent(-tabsize); + do_indent(-tabsize[INDENT_TAB]); } /* undo a cut, or re-do an uncut */ void undo_cut(undo *u) @@ -1348,14 +1358,19 @@ ssize_t cur_loc = 0; /* Current index in line. */ size_t cur_pos = 0; /* Current column position in line. */ + size_t tab_base = 0; + /* Current tab base. */ + tabsize_type tab_type = INDENT_TAB; + /* Current tab type. */ int line_len; assert(line != NULL); while (*line != '\0' && goal >= cur_pos) { - line_len = parse_mbchar(line, NULL, &cur_pos); + line_len = parse_mbchar(line, NULL, &cur_pos, tab_type, + tab_base); if (is_blank_mbchar(line) #ifndef DISABLE_HELP || (newln && *line == '\n') @@ -1366,8 +1381,11 @@ #ifndef DISABLE_HELP if (newln && *line == '\n') break; #endif + } else if (tab_type == 0) { + tab_type = ALIGN_TAB; + tab_base = cur_pos; } line += line_len; cur_loc += line_len; @@ -1391,9 +1409,9 @@ bool found_blank = FALSE; ssize_t found_blank_loc = 0; while (*line != '\0') { - line_len = parse_mbchar(line, NULL, NULL); + line_len = parse_mbchar(line, NULL, NULL, ANY_TAB, 0); if (is_blank_mbchar(line) #ifndef DISABLE_HELP || (newln && *line == '\n') @@ -1414,9 +1432,9 @@ /* 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); + line_len = parse_mbchar(line, NULL, NULL, ANY_TAB, 0); line += line_len; while (*line != '\0' && (is_blank_mbchar(line) #ifndef DISABLE_HELP @@ -1427,9 +1445,9 @@ if (newln && *line == '\n') break; #endif - line_len = parse_mbchar(line, NULL, NULL); + line_len = parse_mbchar(line, NULL, NULL, ANY_TAB, 0); line += line_len; blank_loc += line_len; } @@ -1437,9 +1455,9 @@ return blank_loc; } #endif /* !DISABLE_HELP || !DISABLE_WRAPJUSTIFY */ -#if !defined(NANO_TINY) || !defined(DISABLE_JUSTIFY) +#if !defined(NANO_TINY) /* The "indentation" of a line is the whitespace between the quote part * and the non-whitespace of the line. */ size_t indent_length(const char *line) { @@ -1451,9 +1469,9 @@ blank_mb = charalloc(mb_cur_max()); while (*line != '\0') { - blank_mb_len = parse_mbchar(line, blank_mb, NULL); + blank_mb_len = parse_mbchar(line, blank_mb, NULL, ANY_TAB, 0); if (!is_blank_mbchar(blank_mb)) break; @@ -1464,8 +1482,47 @@ free(blank_mb); return len; } + +/* Calculate tab_type and tab_base as at current_x in the line. + * Returns TRUE if current_x is also at tab_base. */ +bool calc_tabsize(const char *line, size_t current_x, + tabsize_type *tab_type, size_t *tab_base) +{ + size_t prev_len, len = 0; + char *blank_mb; + int blank_mb_len; + + assert(line != NULL); + + *tab_type = INDENT_TAB; + *tab_base = 0; + blank_mb = charalloc(mb_cur_max()); + + while (*line != '\0') { + prev_len = len; + blank_mb_len = parse_mbchar(line, blank_mb, &len, *tab_type, + *tab_base); + + if (!is_blank_mbchar(blank_mb)) { + *tab_type = ALIGN_TAB; + *tab_base = prev_len; + + break; + } + + if (current_x <= 0) + break; + + current_x -= blank_mb_len; + line += blank_mb_len; + } + + free(blank_mb); + + return (current_x <= 0 && *tab_base == prev_len) ? TRUE : FALSE; +} #endif /* !NANO_TINY || !DISABLE_JUSTIFY */ #ifndef DISABLE_JUSTIFY /* justify_format() replaces blanks with spaces and multiple spaces by 1 @@ -1502,16 +1559,16 @@ /* If this character is blank, change it to a space if * necessary, and skip over all blanks after it. */ if (is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); *new_end = ' '; new_end++; end += end_len; while (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); end += end_len; shift += end_len; @@ -1527,9 +1584,9 @@ * bracket and then followed by blanks, change no more than two * of the blanks to spaces if necessary, and skip over all * blanks after them. */ } else if (mbstrchr(punct, end) != NULL) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); while (end_len > 0) { *new_end = *end; new_end++; @@ -1537,9 +1594,9 @@ end_len--; } if (*end != '\0' && mbstrchr(brackets, end) != NULL) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); while (end_len > 0) { *new_end = *end; new_end++; @@ -1548,25 +1605,25 @@ } } if (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); *new_end = ' '; new_end++; end += end_len; } if (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); *new_end = ' '; new_end++; end += end_len; } while (*end != '\0' && is_blank_mbchar(end)) { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); end += end_len; shift += end_len; @@ -1580,9 +1637,9 @@ } /* If this character is neither blank nor punctuation, leave it * unchanged. */ } else { - end_len = parse_mbchar(end, NULL, NULL); + end_len = parse_mbchar(end, NULL, NULL, ANY_TAB, 0); while (end_len > 0) { *new_end = *end; new_end++; @@ -2428,12 +2485,20 @@ while (findnextstr(TRUE, FALSE, openfile->fileage, 0, word, &match_len)) { if (is_whole_word(openfile->current_x, openfile->current->data, word)) { + tabsize_type tab_type; + size_t tab_base; size_t xpt = xplustabs(); - char *exp_word = display_string(openfile->current->data, + char *exp_word; + + calc_tabsize(openfile->current->data, + openfile->current_x, &tab_type, &tab_base); + + exp_word = display_string(openfile->current->data, xpt, strnlenpt(openfile->current->data, - openfile->current_x + match_len) - xpt, FALSE); + openfile->current_x + match_len) - xpt, FALSE, + tab_type, tab_base); edit_refresh(); do_replace_highlight(TRUE, exp_word); diff -r -U4 nano-2.1.10/src/utils.c nano-2.1.10+tabsize2/src/utils.c --- nano-2.1.10/src/utils.c 2009-06-06 05:39:12.000000000 +0100 +++ nano-2.1.10+tabsize2/src/utils.c 2009-09-26 19:10:55.000000000 +0100 @@ -301,10 +301,10 @@ bool retval; assert(buf != NULL && pos <= strlen(buf) && word != NULL); - parse_mbchar(buf + move_mbleft(buf, pos), p, NULL); - parse_mbchar(buf + word_end, r, NULL); + parse_mbchar(buf + move_mbleft(buf, pos), p, NULL, ANY_TAB, 0); + parse_mbchar(buf + word_end, r, NULL, ANY_TAB, 0); /* If we're at the beginning of the line or the character before the * word isn't a non-punctuation "word" character, and if we're at * the end of the line or the character after the word isn't a @@ -483,17 +483,27 @@ size_t i = 0; /* The position in s, returned. */ size_t len = 0; /* The screen display width to s[i]. */ + tabsize_type tab_type = INDENT_TAB; + /* The current tab type. */ + size_t tab_base = 0; + /* The current tab base. */ assert(s != NULL); while (*s != '\0') { - int s_len = parse_mbchar(s, NULL, &len); + size_t prev_len = len; + int s_len = parse_mbchar(s, NULL, &len, tab_type, tab_base); if (len > column) break; + if (tab_type == 0 && !is_blank_mbchar(s)) { + tab_type = ALIGN_TAB; + tab_base = prev_len; + } + i += s_len; s += s_len; } @@ -506,16 +516,26 @@ size_t strnlenpt(const char *s, size_t maxlen) { size_t len = 0; /* The screen display width to s[i]. */ + tabsize_type tab_type = INDENT_TAB; + /* The current tab type. */ + size_t tab_base = 0; + /* The current tab base. */ if (maxlen == 0) return 0; assert(s != NULL); while (*s != '\0') { - int s_len = parse_mbchar(s, NULL, &len); + size_t prev_len = len; + int s_len = parse_mbchar(s, NULL, &len, tab_type, tab_base); + + if (tab_type == 0 && !is_blank_mbchar(s)) { + tab_type = ALIGN_TAB; + tab_base = prev_len; + } s += s_len; if (maxlen <= s_len) diff -r -U4 nano-2.1.10/src/winio.c nano-2.1.10+tabsize2/src/winio.c --- nano-2.1.10/src/winio.c 2009-07-03 04:37:46.000000000 +0100 +++ nano-2.1.10+tabsize2/src/winio.c 2009-09-26 19:11:10.000000000 +0100 @@ -1896,11 +1896,12 @@ * extending for at most len columns. start_col is zero-based. len is * one-based, so len == 0 means you get "" returned. The returned * string is dynamically allocated, and should be freed. If dollars is * TRUE, the caller might put "$" at the beginning or end of the line if - * it's too long. */ + * it's too long. The current tab base and tab type must be specified. + */ char *display_string(const char *buf, size_t start_col, size_t len, bool - dollars) + dollars, tabsize_type tab_type, size_t tab_base) { size_t start_index; /* Index in buf of the first character shown. */ size_t column; @@ -1941,18 +1942,25 @@ * mb_cur_max() bytes + (tabsize - 1) bytes + 1 byte ('\0') * * Since tabsize has a minimum value of 1, it can substitute for 1 * byte above. */ - alloc_len = (mb_cur_max() + tabsize + 1) * MAX_BUF_SIZE; + alloc_len = (mb_cur_max() + tabsize[tab_type] + 1) * MAX_BUF_SIZE; converted = charalloc(alloc_len); index = 0; if (buf[start_index] != '\0' && buf[start_index] != '\t' && (column < start_col || (dollars && column > 0))) { /* We don't display all of buf[start_index] since it starts to * the left of the screen. */ - buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL); + buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL, + ANY_TAB, 0); + + /* Handle tab type changing. */ + if (tab_type == 0 && !is_blank_mbchar(buf + start_index)) { + tab_type = ALIGN_TAB; + tab_base = start_col; + } if (is_cntrl_mbchar(buf_mb)) { if (column < start_col) { char *ctrl_buf_mb = charalloc(mb_cur_max()); @@ -1986,15 +1994,24 @@ #endif } while (buf[start_index] != '\0') { - buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL); + buf_mb_len = parse_mbchar(buf + start_index, buf_mb, NULL, + ANY_TAB, 0); + + /* Handle tab type changing. */ + if (tab_type == 0 && !is_blank_mbchar(buf + start_index)) { + tab_type = ALIGN_TAB; + tab_base = start_col; + } /* Make sure there's enough room for the next character, whether * it's a multibyte control character, a non-control multibyte * character, a tab character, or a null terminator. */ - if (index + mb_cur_max() + tabsize + 1 >= alloc_len - 1) { - alloc_len += (mb_cur_max() + tabsize + 1) * MAX_BUF_SIZE; + if (index + mb_cur_max() + tabsize[tab_type] + 1 + >= alloc_len - 1) { + alloc_len += (mb_cur_max() + tabsize[tab_type] + 1) + * MAX_BUF_SIZE; converted = charealloc(converted, alloc_len); } /* If buf contains a tab character, interpret it. */ @@ -2008,9 +2025,9 @@ } else #endif converted[index++] = ' '; start_col++; - while (start_col % tabsize != 0) { + while ((start_col - tab_base) % tabsize[tab_type] != 0) { converted[index++] = ' '; start_col++; } /* If buf contains a control character, interpret it. If buf @@ -2201,9 +2218,10 @@ space -= 3; } else start_col = 0; - exppath = display_string(path, start_col, space, FALSE); + exppath = display_string(path, start_col, space, FALSE, + ALIGN_TAB, 0); } /* If dots is TRUE, we will display something like "File: * ...ename". */ @@ -2291,9 +2309,9 @@ #endif bar = charalloc(mb_cur_max() * (COLS - 3)); vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap); va_end(ap); - foo = display_string(bar, 0, COLS - 4, FALSE); + foo = display_string(bar, 0, COLS - 4, FALSE, ALIGN_TAB, 0); #if !defined(NANO_TINY) && defined(ENABLE_NANORC) if (old_whitespace) SET(WHITESPACE_DISPLAY); #endif @@ -2839,9 +2857,10 @@ page_start = get_page_start(index); /* Expand the line, replacing tabs with spaces, and control * characters with their displayed forms. */ - converted = display_string(fileptr->data, page_start, COLS, TRUE); + converted = display_string(fileptr->data, page_start, COLS, TRUE, + INDENT_TAB, 0); /* Paint the line. */ edit_draw(fileptr, converted, line, page_start); free(converted);