From 8faf305d0ccee4ccdd6ba1e025eb56d4d73e05e1 Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Thu, 4 Sep 2003 20:25:29 +0000 Subject: [PATCH] add paragraph searching ability git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1538 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 6 +++ TODO | 2 +- global.c | 33 ++++++++---- nano.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++----- nano.h | 2 + proto.h | 5 ++ winio.c | 10 ++++ 7 files changed, 186 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6716e3be..2e551ef4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,12 @@ CVS code - - Add the ability to repeat the last search without prompting via Meta-W, and move the line wrapping toggle to Meta-L. New function do_research(). (Wouter van Hemel) + - Added the ability to move to the beginning or end of the + paragraph, which Pico has via ^W^W (previous paragraph) + and ^W^O (next paragraph). Modifications to do_justify(), + new functions do_para_operation(), do_para_begin(), and + do_para_end(). Note that the last three functions are + disabled if justification is disabled. (DLR) - files.c: do_browser() - Some of the Pico compatibility options in the file browser diff --git a/TODO b/TODO index 09698d2d..8c6f11d2 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,7 @@ TODO file (? means the feature may be implemented, but not definitely) For version 1.4: - UTF-8 support. -- Support for Pico's paragraph searching ability. +- Support for Pico's paragraph searching ability. [DONE] - Undo/Redo key? - Rebindable keys? - Keystroke to implement "Add next sequence as raw" like vi's ^V. diff --git a/global.c b/global.c index 648856b3..63892391 100644 --- a/global.c +++ b/global.c @@ -337,7 +337,8 @@ void shortcut_init(int unjustify) "", *nano_gotodir_msg = "", *nano_case_msg = "", *nano_reverse_msg = "", *nano_execute_msg = "", *nano_dos_msg = "", *nano_mac_msg = - "", *nano_backup_msg = "", *nano_editstr_msg = ""; + "", *nano_backup_msg = "", *nano_editstr_msg = + "", *nano_parabegin_msg = "", *nano_paraend_msg = ""; #ifdef ENABLE_MULTIBUFFER const char *nano_openprev_msg = "", *nano_opennext_msg = @@ -395,6 +396,8 @@ void shortcut_init(int unjustify) nano_mac_msg = _("Write file out in Mac format"); nano_backup_msg = _("Back up original file when saving"); nano_editstr_msg = _("Edit the previous search/replace strings"); + nano_parabegin_msg = _("Go to the beginning of the current paragraph"); + nano_paraend_msg = _("Go to the end of the current paragraph"); #ifdef HAVE_REGEX_H nano_regexp_msg = _("Use regular expressions"); nano_bracket_msg = _("Find other bracket"); @@ -585,44 +588,54 @@ void shortcut_init(int unjustify) sc_init_one(&whereis_list, NANO_HELP_KEY, _("Get Help"), IFHELP(nano_help_msg, 0), 0, 0, VIEW, do_help); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, NANO_CANCEL_KEY, _("Cancel"), IFHELP(nano_cancel_msg, 0), 0, 0, VIEW, 0); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, NANO_FIRSTLINE_KEY, _("First Line"), IFHELP(nano_firstline_msg, 0), 0, 0, VIEW, do_first_line); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, NANO_LASTLINE_KEY, _("Last Line"), IFHELP(nano_lastline_msg, 0), 0, 0, VIEW, do_last_line); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, NANO_OTHERSEARCH_KEY, _("Replace"), IFHELP(nano_replace_msg, 0), 0, 0, VIEW, do_replace); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, NANO_FROMSEARCHTOGOTO_KEY, _("Go To Line"), IFHELP(nano_goto_msg, 0), 0, 0, VIEW, do_gotoline_void); +#ifndef DISABLE_JUSTIFY + /* Translators: try to keep this string under 10 characters long */ + sc_init_one(&whereis_list, NANO_PARABEGIN_KEY, _("Beg of Par"), + IFHELP(nano_parabegin_msg, 0), 0, 0, VIEW, do_para_begin); + + /* Translators: try to keep this string under 10 characters long */ + sc_init_one(&whereis_list, NANO_PARAEND_KEY, _("End of Par"), + IFHELP(nano_paraend_msg, 0), 0, 0, VIEW, do_para_end); +#endif + #ifndef NANO_SMALL - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, TOGGLE_CASE_KEY, _("Case Sens"), IFHELP(nano_case_msg, 0), 0, 0, VIEW, 0); - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, TOGGLE_BACKWARDS_KEY, _("Direction"), IFHELP(nano_reverse_msg, 0), 0, 0, VIEW, 0); #ifdef HAVE_REGEX_H - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, TOGGLE_REGEXP_KEY, _("Regexp"), IFHELP(nano_regexp_msg, 0), 0, 0, VIEW, 0); #endif #ifndef NANO_SMALL - /* Translators: try to keep this string under 12 characters long */ + /* Translators: try to keep this string under 10 characters long */ sc_init_one(&whereis_list, KEY_UP, _("History"), IFHELP(nano_editstr_msg, 0), NANO_UP_KEY, 0, VIEW, 0); #endif diff --git a/nano.c b/nano.c index 202bab23..65c9bcbe 100644 --- a/nano.c +++ b/nano.c @@ -2244,17 +2244,17 @@ int break_line(const char *line, int goal, int force) space_loc++; return space_loc; } -#endif /* !DISABLE_JUSTIFY */ -/* This function justifies the current paragraph. */ -int do_justify(void) +/* This function performs operations on paragraphs: justify, go to + * beginning, and go to end. */ +int do_para_operation(int operation) { -#ifdef DISABLE_JUSTIFY - nano_disabled_msg(); - return 1; -#else - -/* To explain the justifying algorithm, I first need to define some +/* operation == 0 means we're justifying the paragraph, operation == 1 + * means we're moving to the beginning line of the paragraph, and + * operation == 2 means we're moving to the ending line of the + * paragraph. + * + * To explain the justifying algorithm, I first need to define some * phrases about paragraphs and quotation: * A line of text consists of a "quote part", followed by an * "indentation part", followed by text. The functions quote_length() @@ -2314,6 +2314,10 @@ int do_justify(void) filestruct *line; /* generic line of text */ size_t i; /* generic loop variable */ + static int no_restart = 0; + /* whether we're blocking restarting when searching for the + * beginning line of the paragraph */ + #ifdef HAVE_REGEX_H regex_t qreg; /* qreg is the compiled quotation regexp. * We no longer care about quotestr. */ @@ -2333,13 +2337,15 @@ int do_justify(void) /* Here is an assumption that is always true anyway. */ assert(current != NULL); + current_x = 0; + + restart_bps: /* Here we find the first line of the paragraph to justify. If the * current line is in a paragraph, then we move back to the first line. * Otherwise we move down to the first line that is in a paragraph. */ quote_len = quote_length(IFREG(current->data, &qreg)); indent_len = indent_length(current->data + quote_len); - current_x = 0; if (current->data[quote_len + indent_len] != '\0') { /* This line is part of a paragraph. So we must search back to * the first line of this paragraph. First we check items 1) and @@ -2365,6 +2371,25 @@ int do_justify(void) current = current->prev; current_y--; } + } else if (operation == 1) { + /* This line is not part of a paragraph. Move up until we get + * to a non "blank" line, and then move down once. */ + do { + /* There is no previous paragraph, so nothing to move to. */ + if (current->prev == NULL) { + placewewant = 0; + if (current_y < 0) + edit_update(current, CENTER); + else + edit_refresh(); + return 0; + } + current = current->prev; + current_y--; + quote_len = quote_length(IFREG(current->data, &qreg)); + indent_len = indent_length(current->data + quote_len); + } while (current->data[quote_len + indent_len] == '\0'); + current = current->next; } else { /* This line is not part of a paragraph. Move down until we get * to a non "blank" line. */ @@ -2410,12 +2435,29 @@ int do_justify(void) par_len++; } #ifdef HAVE_REGEX_H - /* We no longer need to check quotation. */ - regfree(&qreg); + /* We no longer need to check quotation, unless we're searching for + the beginning of the paragraph. */ + if (operation != 1) + regfree(&qreg); #endif /* Now par_len is the number of lines in this paragraph. Should never * call quotes_match() or quote_length() again. */ + /* If operation is nonzero, skip the justification, since we're only + * searching through the paragraph. If operation is 2, move down the + * number of lines in the paragraph, so that we end up at the + * paragraph's end. */ + if (operation != 0) { + if (operation == 2) { + while (par_len > 0) { + current = current->next; + current_y++; + par_len--; + } + } + goto skip_justify; + } + /* Next step, we loop through the lines of this paragraph, justifying * each one individually. */ SET(JUSTIFY_MODE); @@ -2572,8 +2614,8 @@ int do_justify(void) } UNSET(JUSTIFY_MODE); -/* We are now done justifying the paragraph. There are cleanup things to - * do, and we check for unjustify. */ +/* We are now done justifying the paragraph. There are cleanup things + * to do, and we check for unjustify. */ /* totlines, totsize, and current_y have been maintained above. We * now set last_par_line to the new end of the paragraph, update @@ -2586,6 +2628,67 @@ int do_justify(void) renumber(first_mod_line); } + skip_justify: + if (operation != 0) { + switch (operation) { + case 1: + /* We're on the same line we started on. Search for the + * first non-"blank" line before the line we're on (if + * there is one), continually restart that search from + * the current position until we find a line that's part + * of a paragraph, and then search once more from there, + * so that we end up on the first line of that + * paragraph. In the process, skip over lines + * consisting only of spacing characters, as searching + * for the end of the paragraph does. Then update the + * screen. */ + if (current != fileage && current == current_save && + !no_restart) { + while (current->prev != NULL) { + int j, j_space = 0; + current = current->prev; + current_y--; + for (j = 0; j < strlen(current->data); j++) { + if (isspace(current->data[j])) + j_space++; + else { + j = -1; + break; + } + } + if (j != j_space && strlen(current->data) >= + (quote_len + indent_len) && + current->data[quote_len + indent_len] != '\0') { + no_restart = 1; + break; + } + } + goto restart_bps; + } else + no_restart = 0; +#ifdef HAVE_REGEX_H + /* We no longer need to check quotation, if we were + searching for the beginning of the paragraph. */ + regfree(&qreg); +#endif + if (current_y < 0) + edit_update(current, CENTER); + else + edit_refresh(); + break; + case 2: + /* We've already moved to the end of the paragraph. + * Update the screen. */ + if (current_y > editwinrows - 1) + edit_update(current, CENTER); + else + edit_refresh(); + break; + } + if (operation != 0) + return 0; + } + if (current_y > editwinrows - 1) edit_update(current, CENTER); else @@ -2663,9 +2766,31 @@ int do_justify(void) display_main_list(); return 0; +} +#endif /* !DISABLE_JUSTIFY */ + +int do_justify(void) +{ +#ifdef DISABLE_JUSTIFY + nano_disabled_msg(); + return 1; +#else + return do_para_operation(0); #endif } +#ifndef DISABLE_JUSTIFY +int do_para_begin(void) +{ + return do_para_operation(1); +} + +int do_para_end(void) +{ + return do_para_operation(2); +} +#endif + int do_exit(void) { int i; diff --git a/nano.h b/nano.h index c5f729b2..25613a2f 100644 --- a/nano.h +++ b/nano.h @@ -389,6 +389,8 @@ know what you're doing */ #define NANO_EXTCMD_KEY NANO_CONTROL_X #define NANO_NEXTWORD_KEY NANO_CONTROL_SPACE #define NANO_PREVWORD_KEY NANO_ALT_SPACE +#define NANO_PARABEGIN_KEY NANO_CONTROL_W +#define NANO_PARAEND_KEY NANO_CONTROL_O #ifndef NANO_SMALL /* Toggles do not exist with NANO_SMALL. */ diff --git a/proto.h b/proto.h index fcca1e4a..a341abbd 100644 --- a/proto.h +++ b/proto.h @@ -311,8 +311,13 @@ filestruct *backup_lines(filestruct *first_line, size_t par_len, size_t quote_len); int breakable(const char *line, int goal); int break_line(const char *line, int goal, int force); +int do_para_operation(int operation); #endif /* !DISABLE_JUSTIFY */ int do_justify(void); +#ifndef DISABLE_JUSTIFY +int do_para_begin(void); +int do_para_end(void); +#endif int do_exit(void); void signal_init(void); RETSIGTYPE handle_hupterm(int signal); diff --git a/winio.c b/winio.c index 4ebf3fb1..e88d1c13 100644 --- a/winio.c +++ b/winio.c @@ -1447,6 +1447,16 @@ int statusq(int tabs, const shortcut *s, const char *def, do_last_line(); resetstatuspos = 1; break; +#ifndef DISABLE_JUSTIFY + case NANO_PARABEGIN_KEY: + do_para_begin(); + resetstatuspos = 1; + break; + case NANO_PARAEND_KEY: + do_para_end(); + resetstatuspos = 1; + break; +#endif case NANO_CANCEL_KEY: ret = -1; resetstatuspos = 1;