Index: global.c =================================================================== --- global.c (revision 5095) +++ global.c (working copy) @@ -544,6 +544,7 @@ N_("Copy the current line and store it in the cutbuffer"); const char *nano_indent_msg = N_("Indent the current line"); const char *nano_unindent_msg = N_("Unindent the current line"); + const char *nano_whitespace_to_tabs_msg = N_("Convert leading whitespace to tabs"); const char *nano_undo_msg = N_("Undo the last operation"); const char *nano_redo_msg = N_("Redo the last undone operation"); #endif @@ -799,7 +800,9 @@ add_to_funcs(do_indent_void, MMAIN, N_("Indent Text"), IFSCHELP(nano_indent_msg), TOGETHER, NOVIEW); add_to_funcs(do_unindent, MMAIN, - N_("Unindent Text"), IFSCHELP(nano_unindent_msg), BLANKAFTER, NOVIEW); + N_("Unindent Text"), IFSCHELP(nano_unindent_msg), TOGETHER, NOVIEW); + add_to_funcs(do_whitespace_to_tabs, MMAIN, + N_("Convert leading whitespace to tabs"), IFSCHELP(nano_whitespace_to_tabs_msg), BLANKAFTER, NOVIEW); add_to_funcs(do_undo, MMAIN, N_("Undo"), IFSCHELP(nano_undo_msg), TOGETHER, NOVIEW); @@ -1035,6 +1038,7 @@ add_to_sclist(MMAIN, "M-6", do_copy_text, 0); add_to_sclist(MMAIN, "M-}", do_indent_void, 0); add_to_sclist(MMAIN, "M-{", do_unindent, 0); + add_to_sclist(MMAIN, "M-1", do_whitespace_to_tabs, 0); add_to_sclist(MMAIN, "M-U", do_undo, 0); add_to_sclist(MMAIN, "M-E", do_redo, 0); #endif Index: proto.h =================================================================== --- proto.h (revision 5095) +++ proto.h (working copy) @@ -641,6 +641,7 @@ #ifndef NANO_TINY void do_indent(ssize_t cols); void do_indent_void(void); +void do_whitespace_to_tabs(void); void do_unindent(void); void do_undo(void); void do_redo(void); Index: text.c =================================================================== --- text.c (revision 5095) +++ text.c (working copy) @@ -370,6 +370,84 @@ do_indent(-tabsize); } +/* Convert leading whitespace to tabs on the current line or all + * lines covered by the mark if the mark is on. */ +void do_whitespace_to_tabs(void) +{ + filestruct *top, *bot, *f; + size_t top_x, bot_x, line_len, i, diff_len_ws, + spaces, tabs, tabs_needed, ws_len, new_len; + + assert(openfile->current != NULL && openfile->current->data != NULL); + + /* If tabsize is zero, get out. */ + if (tabsize == 0) + return; + + /* If the mark is on, use all lines covered by the mark. */ + if (openfile->mark_set) { + mark_order((const filestruct **)&top, &top_x, + (const filestruct **)&bot, &bot_x, NULL); + /* Otherwise, use the current line. */ + } else { + top = openfile->current; + bot = top; + } + + /* Go through each line of the text. */ + for (f = top; f != bot->next; f = f->next) { + + line_len = strlen(f->data); + spaces = 0; + tabs = 0; + + /* Calculate how much space the whitespace is using. */ + for (i = 0; i < line_len; i++) { + if (f->data[i] == ' ') { + spaces++; + } else if (f->data[i] == '\t') { + tabs++; + } else { + break; + } + } + + /* If there's no leading spaces there's nothing to do. */ + if (spaces == 0) + continue; + + ws_len = spaces + tabs; + + /* Round up to closest tab width. */ + tabs_needed = ((spaces + tabsize - 1) / tabsize) + tabs; + + new_len = line_len - ws_len + tabs_needed; + /* Fill up the first part with tabs. */ + charset(f->data, '\t', tabs_needed); + if (tabs_needed < ws_len) { + /* Move the line data to it's new position. */ + charmove(f->data + tabs_needed, f->data + ws_len, line_len - ws_len + 1); + } + + openfile->totsize -= line_len - new_len; + + /* Adjust the cursor position. */ + if (openfile->mark_set && f == openfile->mark_begin && + openfile->mark_begin_x >= ws_len) + openfile->mark_begin_x -= line_len - new_len + (spaces / tabsize); + + diff_len_ws = ws_len - tabs_needed; + if (openfile->current_x > 0 && openfile->current_x > diff_len_ws) + openfile->current_x -= diff_len_ws; + + /* Mark the file as modified. */ + set_modified(); + + /* Update the screen. */ + edit_refresh_needed = TRUE; + } +} + #define redo_paste undo_cut #define undo_paste redo_cut