- 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
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.
"", *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 =
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");
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
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()
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. */
/* 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
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. */
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);
}
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
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
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;
#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. */
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);
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;