Index: src/global.c =================================================================== --- src/global.c (revision 5095) +++ src/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: src/proto.h =================================================================== --- src/proto.h (revision 5095) +++ src/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: src/text.c =================================================================== --- src/text.c (revision 5095) +++ src/text.c (working copy) @@ -370,6 +370,86 @@ 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; + int i, spaces, tabs, tabs_needed, ws_len, new_len; + char *olddata; + + 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; + + /* Reshape the new line data */ + new_len = line_len - i + tabs_needed; + char *newdata = charalloc(new_len + 1); + charset(newdata, '\t', tabs_needed); + memcpy(newdata + tabs_needed, f->data + ws_len, line_len - ws_len); + null_at(&newdata, new_len); + olddata = f->data; + f->data = newdata; + free(olddata); + + openfile->totsize -= line_len - new_len; + + /* Adjust the cursor position if we're after the new length */ + if (openfile->mark_set && f == openfile->mark_begin && + openfile->mark_begin_x >= ws_len) + openfile->mark_begin_x -= line_len - new_len + (spaces/tabsize); + + if (openfile->current_x >= ws_len) + openfile->current_x -= line_len - new_len + (spaces/tabsize); + + /* Mark the file as modified. */ + set_modified(); + + /* Update the screen. */ + edit_refresh_needed = TRUE; + } +} + #define redo_paste undo_cut #define undo_paste redo_cut