Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21a54a3cf6 | ||
|
|
a0147c5a72 | ||
|
|
553940760e | ||
|
|
faa0eb991e | ||
|
|
f54cd02652 | ||
|
|
6dd308d0fb | ||
|
|
4872f42cd2 | ||
|
|
62007c84c6 | ||
|
|
d0f37205af | ||
|
|
f05874ea23 | ||
|
|
0d9080a22c | ||
|
|
1ae90e205a | ||
|
|
d53086d38d | ||
|
|
0b6bb37c56 | ||
|
|
c43a6fdcc1 | ||
|
|
0c613cb1ac | ||
|
|
1e5064ef84 | ||
|
|
5b40bad629 | ||
|
|
45f8fc77e0 | ||
|
|
94347f0811 | ||
|
|
1a4a3de68b | ||
|
|
bf8bd02558 | ||
|
|
544d426d86 | ||
|
|
30a984661b | ||
|
|
7ab8a4d835 | ||
|
|
0353a24400 | ||
|
|
d4304ca88c | ||
|
|
02d8da3bdd | ||
|
|
7a09b655c1 | ||
|
|
c8b26baee8 | ||
|
|
bb394990cd | ||
|
|
7c5d099c6f | ||
|
|
152cc24d1f | ||
|
|
8965103a4d | ||
|
|
d0d293b8af | ||
|
|
839743fd24 | ||
|
|
0b30835dd0 | ||
|
|
a865c25eea | ||
|
|
cf1129a8b4 | ||
|
|
0cd833e64b | ||
|
|
cbf226476d |
48
ChangeLog
48
ChangeLog
@@ -1,3 +1,51 @@
|
||||
Changes between v2.9.5 and v2.9.6:
|
||||
----------------------------------
|
||||
|
||||
Benno Schulenberg (39):
|
||||
build: do not prefix an alternative rcfilename with a dot
|
||||
build: fix compilation when configured with --disable-help
|
||||
bump version numbers and add a news item for the 2.9.6 release
|
||||
command-execution: do not crash when opening the pipe would fail
|
||||
completion: correctly do a signed comparison, to avoid a segfault
|
||||
files: prevent a hang when a call to sigaction() would fail
|
||||
formatting, linting: redetermine the argument list for every run
|
||||
gnulib: update to its current upstream state
|
||||
memory: use a reallocation to reduce the amount of leakage
|
||||
prompt: recognize Yes/No/All in English when the locale gives no match
|
||||
rcfile: skip color commands where some color name is invalid
|
||||
scrolling: don't redraw entire edit window when cursor goes offscreen
|
||||
search: always go forward by default, also when coming from Goto-Line
|
||||
search: use a better value to mean "nothing was typed"
|
||||
speller: don't add an extra newline when saving the text to a tempfile
|
||||
syntax: po: highlight also other escaped characters, not just \n
|
||||
syntax: sh: colorize options only when they are preceded by whitespace
|
||||
tweaks: adjust the translator hint about Yes/No/All
|
||||
tweaks: correct or improve a couple of comments
|
||||
tweaks: elide a function that is called just once
|
||||
tweaks: fix a typo, remove a blank line, and improve some comments
|
||||
tweaks: frob a couple of comments
|
||||
tweaks: group some more of the empty functions together
|
||||
tweaks: improve some comments, and exit with nonzero status upon error
|
||||
tweaks: improve the ordering of a couple of functions
|
||||
tweaks: invert two conditions and reshuffle, to reduce duplication
|
||||
tweaks: move a function to its proper location
|
||||
tweaks: move a function to its proper location
|
||||
tweaks: rearrange a few if statements more symmetrically
|
||||
tweaks: remove the group handling for undoing/redoing (un)indents
|
||||
tweaks: rename a function, to be more distinct from its caller
|
||||
tweaks: rename a function, to be more fitting and descriptive
|
||||
tweaks: rename a variable, for clarity
|
||||
tweaks: rename a variable, to be a bit more fitting
|
||||
tweaks: rename a variable, to be more clear and to match another
|
||||
tweaks: rename a variable, to match another and to be more visible
|
||||
tweaks: reshuffle two declarations
|
||||
tweaks: set the correct flags just once for each spell-fixing session
|
||||
tweaks: use meaningful names instead of puzzling values
|
||||
|
||||
Liu Hao (1):
|
||||
replacing: always clear the backwards flag for ^\, just like for ^W
|
||||
|
||||
|
||||
Changes between v2.9.4 and v2.9.5:
|
||||
----------------------------------
|
||||
|
||||
|
||||
9
NEWS
9
NEWS
@@ -1,3 +1,12 @@
|
||||
2018.04.27 - GNU nano 2.9.6 "Gomance" fixes a crash in word completion,
|
||||
makes --enable-altrcname work again, improves the fluidity
|
||||
of scrolling when using the touchpad, tweaks the syntaxes
|
||||
for shell scripts and PO files, makes a replacing session
|
||||
go always forward by default, no longer inserts a newline
|
||||
after an external spell check of a selected region, always
|
||||
accepts the English Y and N (and A) at a yes-no prompt in
|
||||
any locale, and solves a few hypothetical bugs.
|
||||
|
||||
2018.03.29 - GNU nano 2.9.5 "Kiša pada" changes the way the Scroll-Up
|
||||
and Scroll-Down commands work (M-- and M-+): instead of
|
||||
keeping the cursor in the same screen position they now
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Generate configure & friends for GIT users.
|
||||
|
||||
gnulib_url="git://git.sv.gnu.org/gnulib.git"
|
||||
gnulib_hash="59e59d99bc1ca635d178778b9b4ee544330775c4"
|
||||
gnulib_hash="214bf852d8dab02bf62900e61facef2c9f48f2f4"
|
||||
|
||||
modules="
|
||||
futimens
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
AC_INIT([GNU nano], [2.9.5], [nano-devel@gnu.org], [nano])
|
||||
AC_INIT([GNU nano], [2.9.6], [nano-devel@gnu.org], [nano])
|
||||
AC_CONFIG_SRCDIR([src/nano.c])
|
||||
AC_CANONICAL_HOST
|
||||
AM_INIT_AUTOMAKE([1.14])
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<h3><a name="1.3"></a>1.3. Why the name change from TIP?</h3>
|
||||
<blockquote><p>On January 10, 2000, TIP was officially renamed to nano because of a namespace conflict with another program called 'tip'. The original 'tip' program "establishes a full duplex terminal connection to a remote host", and was included with many older Unix systems (and newer ones like Solaris). The conflict was not noticed at first because there is no 'tip' utility included with most GNU/Linux distributions (where nano was developed).</p></blockquote>
|
||||
<h3><a name="1.4"></a>1.4. What is the current version of nano?</h3>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>2.9.5</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>2.9.6</b>. Of course, you should always check the <a href="https://nano-editor.org/">nano homepage</a> to see what the latest and greatest version is.</p></blockquote>
|
||||
<h3><a name="1.5"></a>1.5. I want to read the man page without having to download the program!</h3>
|
||||
<blockquote><p>Jeez, demanding, aren't we? Okay, look <a href="https://nano-editor.org/dist/latest/nano.1.html">here</a>.</p></blockquote>
|
||||
<hr width="100%">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <http://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH NANO 1 "version 2.9.5" "March 2018"
|
||||
.TH NANO 1 "version 2.9.6" "April 2018"
|
||||
|
||||
.SH NAME
|
||||
nano \- Nano's ANOther editor, an enhanced free Pico clone
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
@smallbook
|
||||
@set EDITION 0.5
|
||||
@set VERSION 2.9.5
|
||||
@set UPDATED March 2018
|
||||
@set VERSION 2.9.6
|
||||
@set UPDATED April 2018
|
||||
|
||||
@dircategory Editors
|
||||
@direntry
|
||||
@@ -23,7 +23,7 @@
|
||||
@titlepage
|
||||
@title GNU @command{nano}
|
||||
@subtitle a small and friendly text editor
|
||||
@subtitle version 2.9.5
|
||||
@subtitle version 2.9.6
|
||||
|
||||
@author Chris Allegretta
|
||||
@page
|
||||
@@ -63,7 +63,7 @@ e-mail: @email{chrisa@@asty.org}@*
|
||||
@node Top
|
||||
@top
|
||||
|
||||
This manual documents the GNU @command{nano} editor, version 2.9.5.
|
||||
This manual documents the GNU @command{nano} editor, version 2.9.6.
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <http://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH NANORC 5 "version 2.9.5" "March 2018"
|
||||
.TH NANORC 5 "version 2.9.6" "April 2018"
|
||||
|
||||
.SH NAME
|
||||
nanorc \- GNU nano's configuration file
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <http://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH RNANO 1 "version 2.9.5" "March 2018"
|
||||
.TH RNANO 1 "version 2.9.6" "April 2018"
|
||||
|
||||
.SH NAME
|
||||
rnano \- a restricted nano
|
||||
|
||||
709
po/nano.pot
709
po/nano.pot
File diff suppressed because it is too large
Load Diff
707
po/pt_BR.po
707
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
748
po/zh_CN.po
748
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
737
po/zh_TW.po
737
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
@@ -60,9 +60,9 @@ void set_colorpairs(void)
|
||||
colortype *combo = color_combo[i];
|
||||
|
||||
if (combo != NULL) {
|
||||
if (combo->fg == -1 && !using_defaults)
|
||||
if (combo->fg == USE_THE_DEFAULT && !using_defaults)
|
||||
combo->fg = COLOR_WHITE;
|
||||
if (combo->bg == -1 && !using_defaults)
|
||||
if (combo->bg == USE_THE_DEFAULT && !using_defaults)
|
||||
combo->bg = COLOR_BLACK;
|
||||
init_pair(i + 1, combo->fg, combo->bg);
|
||||
interface_color_pair[i] = COLOR_PAIR(i + 1) | A_BANDAID |
|
||||
@@ -125,10 +125,10 @@ void color_init(void)
|
||||
foreground = ink->fg;
|
||||
background = ink->bg;
|
||||
|
||||
if (foreground == -1 && !using_defaults)
|
||||
if (foreground == USE_THE_DEFAULT && !using_defaults)
|
||||
foreground = COLOR_WHITE;
|
||||
|
||||
if (background == -1 && !using_defaults)
|
||||
if (background == USE_THE_DEFAULT && !using_defaults)
|
||||
background = COLOR_BLACK;
|
||||
|
||||
init_pair(ink->pairnum, foreground, background);
|
||||
|
||||
49
src/global.c
49
src/global.c
@@ -46,11 +46,6 @@ bool focusing = TRUE;
|
||||
bool as_an_at = TRUE;
|
||||
/* Whether a 0x0A byte should be shown as a ^@ instead of a ^J. */
|
||||
|
||||
int margin = 0;
|
||||
/* The amount of space reserved at the left for line numbers. */
|
||||
int editwincols = -1;
|
||||
/* The number of usable columns in the edit window: COLS - margin. */
|
||||
|
||||
bool suppress_cursorpos = FALSE;
|
||||
/* Should we skip constant position display for current keystroke? */
|
||||
|
||||
@@ -98,18 +93,22 @@ char *present_path = NULL;
|
||||
|
||||
unsigned flags[4] = {0, 0, 0, 0};
|
||||
/* Our flag containing the states of all global options. */
|
||||
|
||||
WINDOW *topwin = NULL;
|
||||
/* The top portion of the window, where we display the version
|
||||
* number of nano, the name of the current file, and whether the
|
||||
* current file has been modified. */
|
||||
/* The top portion of the screen, showing the version number of nano,
|
||||
* the name of the file, and whether the buffer was modified. */
|
||||
WINDOW *edit = NULL;
|
||||
/* The middle portion of the window, i.e. the edit window, where
|
||||
* we display the current file we're editing. */
|
||||
/* The middle portion of the screen: the edit window, showing the
|
||||
* contents of the current buffer, the file we are editing. */
|
||||
WINDOW *bottomwin = NULL;
|
||||
/* The bottom portion of the window, where we display statusbar
|
||||
/* The bottom portion of the screen, where we display statusbar
|
||||
* messages, the statusbar prompt, and a list of shortcuts. */
|
||||
int editwinrows = 0;
|
||||
/* How many rows does the edit window take up? */
|
||||
int editwincols = -1;
|
||||
/* The number of usable columns in the edit window: COLS - margin. */
|
||||
int margin = 0;
|
||||
/* The amount of space reserved at the left for line numbers. */
|
||||
|
||||
filestruct *cutbuffer = NULL;
|
||||
/* The buffer where we store cut text. */
|
||||
@@ -266,7 +265,7 @@ size_t length_of_list(int menu)
|
||||
#define BLANKAFTER TRUE /* A blank line after this one. */
|
||||
#define TOGETHER FALSE
|
||||
|
||||
/* Just throw this here. */
|
||||
/* Empty functions, for the most part corresponding to toggles. */
|
||||
void case_sens_void(void)
|
||||
{
|
||||
}
|
||||
@@ -291,6 +290,9 @@ void goto_dir_void(void)
|
||||
}
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
void do_toggle_void(void)
|
||||
{
|
||||
}
|
||||
void dos_format_void(void)
|
||||
{
|
||||
}
|
||||
@@ -318,6 +320,9 @@ void flip_newbuffer(void)
|
||||
void discard_buffer(void)
|
||||
{
|
||||
}
|
||||
void do_cancel(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Add a function to the function list. */
|
||||
void add_to_funcs(void (*func)(void), int menus, const char *desc, const char *help,
|
||||
@@ -392,7 +397,6 @@ const sc *first_sc_for(int menu, void (*func)(void))
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Whoops, returning null given func %ld in menu %x\n", (long)func, menu);
|
||||
#endif
|
||||
/* Otherwise... */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -576,6 +580,8 @@ void shortcut_init(void)
|
||||
const char *lastline_gist = N_("Go to the last line of the file");
|
||||
#ifndef NANO_TINY
|
||||
const char *bracket_gist = N_("Go to the matching bracket");
|
||||
#endif
|
||||
#ifdef ENABLE_HELP
|
||||
const char *scrollup_gist =
|
||||
N_("Scroll up one line without moving the cursor textually");
|
||||
const char *scrolldown_gist =
|
||||
@@ -859,7 +865,7 @@ void shortcut_init(void)
|
||||
prevline_tag, WITHORSANS(prevline_gist), TOGETHER, VIEW);
|
||||
add_to_funcs(do_down, MMAIN|MHELP|MBROWSER,
|
||||
nextline_tag, WITHORSANS(nextline_gist), TOGETHER, VIEW);
|
||||
#ifndef NANO_TINY
|
||||
#ifdef ENABLE_HELP
|
||||
add_to_funcs(do_scroll_up, MMAIN,
|
||||
N_("Scroll Up"), WITHORSANS(scrollup_gist), TOGETHER, VIEW);
|
||||
add_to_funcs(do_scroll_down, MMAIN,
|
||||
@@ -1206,7 +1212,7 @@ void shortcut_init(void)
|
||||
add_to_sclist(MMAIN, "M-)", 0, do_para_end_void, 0);
|
||||
add_to_sclist(MMAIN, "M-0", 0, do_para_end_void, 0);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
#ifdef ENABLE_HELP
|
||||
add_to_sclist(MMAIN, "M--", 0, do_scroll_up, 0);
|
||||
add_to_sclist(MMAIN, "M-_", 0, do_scroll_up, 0);
|
||||
add_to_sclist(MMAIN, "M-+", 0, do_scroll_down, 0);
|
||||
@@ -1387,8 +1393,7 @@ const subnfunc *sctofunc(const sc *s)
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Now let's come up with a single (hopefully) function to get a string
|
||||
* for each flag. */
|
||||
/* Return the textual description that corresponds to the given flag. */
|
||||
const char *flagtostr(int flag)
|
||||
{
|
||||
switch (flag) {
|
||||
@@ -1526,10 +1531,6 @@ sc *strtosc(const char *input)
|
||||
s->func = do_indent;
|
||||
else if (!strcasecmp(input, "unindent"))
|
||||
s->func = do_unindent;
|
||||
else if (!strcasecmp(input, "scrollup"))
|
||||
s->func = do_scroll_up;
|
||||
else if (!strcasecmp(input, "scrolldown"))
|
||||
s->func = do_scroll_down;
|
||||
else if (!strcasecmp(input, "cutwordleft"))
|
||||
s->func = do_cut_prev_word;
|
||||
else if (!strcasecmp(input, "cutwordright"))
|
||||
@@ -1559,6 +1560,12 @@ sc *strtosc(const char *input)
|
||||
else if (!strcasecmp(input, "down") ||
|
||||
!strcasecmp(input, "nextline"))
|
||||
s->func = do_down;
|
||||
#ifdef ENABLE_HELP
|
||||
else if (!strcasecmp(input, "scrollup"))
|
||||
s->func = do_scroll_up;
|
||||
else if (!strcasecmp(input, "scrolldown"))
|
||||
s->func = do_scroll_down;
|
||||
#endif
|
||||
else if (!strcasecmp(input, "prevword"))
|
||||
s->func = do_prev_word_void;
|
||||
else if (!strcasecmp(input, "nextword"))
|
||||
|
||||
@@ -227,7 +227,7 @@ char *get_history_completion(filestruct **h, char *s, size_t len)
|
||||
* match, or len is 0. Return s. */
|
||||
return (char *)s;
|
||||
}
|
||||
#endif /* ENSABLE_TABCOMP */
|
||||
#endif /* ENABLE_TABCOMP */
|
||||
|
||||
void history_error(const char *msg, ...)
|
||||
{
|
||||
|
||||
10
src/move.c
10
src/move.c
@@ -495,7 +495,10 @@ void do_up(void)
|
||||
|
||||
set_proper_index_and_pww(&leftedge, target_column, FALSE);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
if (openfile->current_y == 0 && ISSET(SMOOTH_SCROLL))
|
||||
edit_scroll(BACKWARD);
|
||||
else
|
||||
edit_redraw(was_current, FLOWING);
|
||||
|
||||
/* <Up> should not change placewewant, so restore it. */
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
@@ -515,7 +518,10 @@ void do_down(void)
|
||||
|
||||
set_proper_index_and_pww(&leftedge, target_column, TRUE);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
if (openfile->current_y == editwinrows - 1 && ISSET(SMOOTH_SCROLL))
|
||||
edit_scroll(FORWARD);
|
||||
else
|
||||
edit_redraw(was_current, FLOWING);
|
||||
|
||||
/* <Down> should not change placewewant, so restore it. */
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
|
||||
21
src/nano.c
21
src/nano.c
@@ -1087,12 +1087,6 @@ void close_and_go(void)
|
||||
finish();
|
||||
}
|
||||
|
||||
/* Another placeholder for function mapping. */
|
||||
void do_cancel(void)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
/* Make a note that reading from stdin was concluded with ^C. */
|
||||
RETSIGTYPE make_a_note(int signal)
|
||||
{
|
||||
@@ -1105,7 +1099,7 @@ bool scoop_stdin(void)
|
||||
struct sigaction oldaction, newaction;
|
||||
/* Original and temporary handlers for SIGINT. */
|
||||
bool setup_failed = FALSE;
|
||||
/* Whether setting up the SIGINT handler failed. */
|
||||
/* Whether setting up the temporary SIGINT handler failed. */
|
||||
FILE *stream;
|
||||
int thetty;
|
||||
|
||||
@@ -1124,12 +1118,12 @@ bool scoop_stdin(void)
|
||||
/* Set things up so that SIGINT will cancel the reading. */
|
||||
if (sigaction(SIGINT, NULL, &newaction) == -1) {
|
||||
setup_failed = TRUE;
|
||||
nperror("sigaction");
|
||||
perror("sigaction");
|
||||
} else {
|
||||
newaction.sa_handler = make_a_note;
|
||||
if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
|
||||
setup_failed = TRUE;
|
||||
nperror("sigaction");
|
||||
perror("sigaction");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1162,7 +1156,7 @@ bool scoop_stdin(void)
|
||||
|
||||
/* If it was changed, restore the handler for SIGINT. */
|
||||
if (!setup_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
|
||||
nperror("sigaction");
|
||||
perror("sigaction");
|
||||
|
||||
terminal_init();
|
||||
doupdate();
|
||||
@@ -1401,12 +1395,6 @@ void do_toggle(int flag)
|
||||
statusline(HUSH, "%s %s", _(flagtostr(flag)),
|
||||
enabled ? _("enabled") : _("disabled"));
|
||||
}
|
||||
|
||||
/* Bleh. */
|
||||
void do_toggle_void(void)
|
||||
{
|
||||
;
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
/* Disable extended input and output processing in our terminal
|
||||
@@ -1499,7 +1487,6 @@ void terminal_init(void)
|
||||
|
||||
if (!newterm_set) {
|
||||
#endif
|
||||
|
||||
raw();
|
||||
nonl();
|
||||
noecho();
|
||||
|
||||
@@ -142,6 +142,11 @@
|
||||
#define REPLACING 1
|
||||
#define INREGION 2
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
#define USE_THE_DEFAULT -1
|
||||
#define BAD_COLOR -2
|
||||
#endif
|
||||
|
||||
/* Enumeration types. */
|
||||
typedef enum {
|
||||
NIX_FILE, DOS_FILE, MAC_FILE
|
||||
|
||||
20
src/prompt.c
20
src/prompt.c
@@ -659,18 +659,13 @@ int do_prompt(bool allow_tabs, bool allow_files,
|
||||
int do_yesno_prompt(bool all, const char *msg)
|
||||
{
|
||||
int response = -2, width = 16;
|
||||
|
||||
/* TRANSLATORS: For the next three strings, if possible, specify
|
||||
* the single-byte letters for both your language and English.
|
||||
* For example, in French: "OoYy", for both "Oui" and "Yes". */
|
||||
/* TRANSLATORS: For the next three strings, specify the single-byte
|
||||
* starting letters of the translations for "Yes", "No", and "All".
|
||||
* Of each string, the first letter is shown in the help lines. */
|
||||
const char *yesstr = _("Yy");
|
||||
const char *nostr = _("Nn");
|
||||
const char *allstr = _("Aa");
|
||||
|
||||
/* The above three variables consist of all the single-byte characters
|
||||
* that are accepted for the corresponding answer. Of each variable,
|
||||
* the first character is displayed in the help lines. */
|
||||
|
||||
while (response == -2) {
|
||||
int kbinput;
|
||||
|
||||
@@ -716,12 +711,21 @@ int do_yesno_prompt(bool all, const char *msg)
|
||||
kbinput = get_kbinput(bottomwin, !all);
|
||||
|
||||
/* See if the pressed key is in the Yes, No, or All strings. */
|
||||
#ifdef ENABLE_NLS
|
||||
if (strchr(yesstr, kbinput) != NULL)
|
||||
response = 1;
|
||||
else if (strchr(nostr, kbinput) != NULL)
|
||||
response = 0;
|
||||
else if (all && strchr(allstr, kbinput) != NULL)
|
||||
response = 2;
|
||||
else
|
||||
#endif
|
||||
if (strchr("Yy", kbinput) != NULL)
|
||||
response = 1;
|
||||
else if (strchr("Nn", kbinput) != NULL)
|
||||
response = 0;
|
||||
else if (all && strchr("Aa", kbinput) != NULL)
|
||||
response = 2;
|
||||
else if (func_from_key(&kbinput) == do_cancel)
|
||||
response = -1;
|
||||
#ifdef ENABLE_MOUSE
|
||||
|
||||
18
src/proto.h
18
src/proto.h
@@ -40,9 +40,6 @@ extern bool focusing;
|
||||
|
||||
extern bool as_an_at;
|
||||
|
||||
extern int margin;
|
||||
extern int editwincols;
|
||||
|
||||
extern bool suppress_cursorpos;
|
||||
|
||||
extern message_type lastmessage;
|
||||
@@ -91,10 +88,13 @@ extern char *last_search;
|
||||
extern char *present_path;
|
||||
|
||||
extern unsigned flags[4];
|
||||
|
||||
extern WINDOW *topwin;
|
||||
extern WINDOW *edit;
|
||||
extern WINDOW *bottomwin;
|
||||
extern int editwinrows;
|
||||
extern int editwincols;
|
||||
extern int margin;
|
||||
|
||||
extern filestruct *cutbuffer;
|
||||
extern filestruct *cutbottom;
|
||||
@@ -433,7 +433,6 @@ RETSIGTYPE handle_sigwinch(int signal);
|
||||
void regenerate_screen(void);
|
||||
void allow_sigwinch(bool allow);
|
||||
void do_toggle(int flag);
|
||||
void do_toggle_void(void);
|
||||
void enable_signals(void);
|
||||
#endif
|
||||
void disable_flow_control(void);
|
||||
@@ -471,7 +470,6 @@ int do_yesno_prompt(bool all, const char *msg);
|
||||
/* Most functions in rcfile.c. */
|
||||
#ifdef ENABLE_NANORC
|
||||
#ifdef ENABLE_COLOR
|
||||
bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright);
|
||||
void grab_and_store(const char *kind, char *ptr, regexlisttype **storage);
|
||||
#endif
|
||||
void parse_rcfile(FILE *rcstream, bool syntax_only);
|
||||
@@ -479,18 +477,18 @@ void do_rcfiles(void);
|
||||
#endif /* ENABLE_NANORC */
|
||||
|
||||
/* Most functions in search.c. */
|
||||
void not_found_msg(const char *str);
|
||||
void search_replace_abort(void);
|
||||
void tidy_up_after_search(void);
|
||||
int findnextstr(const char *needle, bool whole_word_only, int modus,
|
||||
size_t *match_len, bool skipone, const filestruct *begin, size_t begin_x);
|
||||
void do_search(void);
|
||||
void do_search_forward(void);
|
||||
void do_search_backward(void);
|
||||
void do_research(void);
|
||||
#ifndef NANO_TINY
|
||||
void do_findprevious(void);
|
||||
void do_findnext(void);
|
||||
#endif
|
||||
void do_research(void);
|
||||
void not_found_msg(const char *str);
|
||||
void go_looking(void);
|
||||
ssize_t do_replace_loop(const char *needle, bool whole_word_only,
|
||||
const filestruct *real_current, size_t *real_current_x);
|
||||
@@ -522,7 +520,6 @@ void do_unindent(void);
|
||||
bool white_string(const char *s);
|
||||
#ifdef ENABLE_COMMENT
|
||||
void do_comment(void);
|
||||
bool comment_line(undo_type action, filestruct *f, const char *comment_seq);
|
||||
#endif
|
||||
void do_undo(void);
|
||||
void do_redo(void);
|
||||
@@ -692,7 +689,6 @@ void do_credits(void);
|
||||
#endif
|
||||
|
||||
/* These are just name definitions. */
|
||||
void do_cancel(void);
|
||||
void case_sens_void(void);
|
||||
void regexp_void(void);
|
||||
void backwards_void(void);
|
||||
@@ -703,6 +699,7 @@ void to_files_void(void);
|
||||
void goto_dir_void(void);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
void do_toggle_void(void);
|
||||
void dos_format_void(void);
|
||||
void mac_format_void(void);
|
||||
void append_void(void);
|
||||
@@ -714,5 +711,6 @@ void flip_execute(void);
|
||||
void flip_newbuffer(void);
|
||||
#endif
|
||||
void discard_buffer(void);
|
||||
void do_cancel(void);
|
||||
|
||||
#endif /* !PROTO_H */
|
||||
|
||||
67
src/rcfile.c
67
src/rcfile.c
@@ -31,7 +31,10 @@
|
||||
#ifdef ENABLE_NANORC
|
||||
|
||||
#ifndef RCFILE_NAME
|
||||
#define HOME_RC_NAME ".nanorc"
|
||||
#define RCFILE_NAME "nanorc"
|
||||
#else
|
||||
#define HOME_RC_NAME RCFILE_NAME
|
||||
#endif
|
||||
|
||||
static const rcoption rcopts[] = {
|
||||
@@ -603,10 +606,38 @@ short color_to_short(const char *colorname, bool *bright)
|
||||
else if (strcasecmp(colorname, "black") == 0)
|
||||
return COLOR_BLACK;
|
||||
else if (strcasecmp(colorname, "normal") == 0)
|
||||
return -1;
|
||||
return USE_THE_DEFAULT;
|
||||
|
||||
rcfile_error(N_("Color \"%s\" not understood"), colorname);
|
||||
return -2;
|
||||
return BAD_COLOR;
|
||||
}
|
||||
|
||||
/* Parse the color name (or pair of color names) in the given string.
|
||||
* Return FALSE when any color name is invalid; otherwise return TRUE. */
|
||||
bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright)
|
||||
{
|
||||
char *comma = strchr(combostr, ',');
|
||||
|
||||
if (comma != NULL) {
|
||||
*bg = color_to_short(comma + 1, bright);
|
||||
if (*bright) {
|
||||
rcfile_error(N_("A background color cannot be bright"));
|
||||
return FALSE;
|
||||
}
|
||||
if (*bg == BAD_COLOR)
|
||||
return FALSE;
|
||||
*comma = '\0';
|
||||
} else
|
||||
*bg = USE_THE_DEFAULT;
|
||||
|
||||
if (comma != combostr) {
|
||||
*fg = color_to_short(combostr, bright);
|
||||
if (*fg == BAD_COLOR)
|
||||
return FALSE;
|
||||
} else
|
||||
*fg = USE_THE_DEFAULT;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse the color string in the line at ptr, and add it to the current
|
||||
@@ -736,36 +767,6 @@ void parse_colors(char *ptr, int rex_flags)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the color name, or pair of color names, in combostr. */
|
||||
bool parse_color_names(char *combostr, short *fg, short *bg, bool *bright)
|
||||
{
|
||||
char *comma = strchr(combostr, ',');
|
||||
|
||||
if (comma != NULL) {
|
||||
*bg = color_to_short(comma + 1, bright);
|
||||
if (*bright) {
|
||||
rcfile_error(N_("A background color cannot be bright"));
|
||||
return FALSE;
|
||||
}
|
||||
*comma = '\0';
|
||||
} else
|
||||
*bg = -1;
|
||||
|
||||
if (comma != combostr) {
|
||||
*fg = color_to_short(combostr, bright);
|
||||
|
||||
/* If the specified foreground color is bad, ignore the regexes. */
|
||||
if (*fg == -2)
|
||||
return FALSE;
|
||||
} else
|
||||
*fg = -1;
|
||||
|
||||
if (*bg == -2)
|
||||
*bg = -1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse the argument of an interface color option. */
|
||||
colortype *parse_interface_color(char *combostr)
|
||||
{
|
||||
@@ -1254,7 +1255,7 @@ void do_rcfiles(void)
|
||||
|
||||
/* Now try the to find a nanorc file in the user's home directory
|
||||
* or in the XDG configuration directories. */
|
||||
if (have_nanorc(homedir, "/." RCFILE_NAME))
|
||||
if (have_nanorc(homedir, "/" HOME_RC_NAME))
|
||||
parse_one_nanorc();
|
||||
else if (have_nanorc(xdgconfdir, "/nano/" RCFILE_NAME))
|
||||
parse_one_nanorc();
|
||||
|
||||
115
src/search.c
115
src/search.c
@@ -28,8 +28,8 @@
|
||||
|
||||
static bool came_full_circle = FALSE;
|
||||
/* Have we reached the starting line again while searching? */
|
||||
static bool regexp_compiled = FALSE;
|
||||
/* Have we compiled any regular expressions? */
|
||||
static bool have_compiled_regexp = FALSE;
|
||||
/* Whether we have compiled a regular expression for the search. */
|
||||
|
||||
/* Compile the given regular expression and store it in search_regexp.
|
||||
* Return TRUE if the expression is valid, and FALSE otherwise. */
|
||||
@@ -50,43 +50,23 @@ bool regexp_init(const char *regexp)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
regexp_compiled = TRUE;
|
||||
have_compiled_regexp = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Decompile the compiled regular expression we used in the last
|
||||
* search, if any. */
|
||||
void regexp_cleanup(void)
|
||||
/* Free a compiled regular expression, if one was compiled; and schedule a
|
||||
* full screen refresh when the mark is on, in case the cursor has moved. */
|
||||
void tidy_up_after_search(void)
|
||||
{
|
||||
if (regexp_compiled) {
|
||||
regexp_compiled = FALSE;
|
||||
if (have_compiled_regexp) {
|
||||
regfree(&search_regexp);
|
||||
have_compiled_regexp = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report on the status bar that the given string was not found. */
|
||||
void not_found_msg(const char *str)
|
||||
{
|
||||
char *disp = display_string(str, 0, (COLS / 2) + 1, FALSE);
|
||||
size_t numchars = actual_x(disp, strnlenpt(disp, COLS / 2));
|
||||
|
||||
statusline(HUSH, _("\"%.*s%s\" not found"), numchars, disp,
|
||||
(disp[numchars] == '\0') ? "" : "...");
|
||||
free(disp);
|
||||
}
|
||||
|
||||
/* Abort the current search or replace. Clean up by displaying the main
|
||||
* shortcut list, updating the screen if the mark was on before, and
|
||||
* decompiling the compiled regular expression we used in the last
|
||||
* search, if any. */
|
||||
void search_replace_abort(void)
|
||||
{
|
||||
#ifndef NANO_TINY
|
||||
if (openfile->mark)
|
||||
refresh_needed = TRUE;
|
||||
#endif
|
||||
regexp_cleanup();
|
||||
}
|
||||
|
||||
/* Prepare the prompt and ask the user what to search for. Keep looping
|
||||
@@ -135,7 +115,7 @@ void search_init(bool replacing, bool keep_the_answer)
|
||||
* nothing was searched for yet during this session, get out. */
|
||||
if (i == -1 || (i == -2 && *last_search == '\0')) {
|
||||
statusbar(_("Cancelled"));
|
||||
search_replace_abort();
|
||||
tidy_up_after_search();
|
||||
free(thedefault);
|
||||
return;
|
||||
}
|
||||
@@ -150,21 +130,18 @@ void search_init(bool replacing, bool keep_the_answer)
|
||||
#endif
|
||||
}
|
||||
|
||||
free(thedefault);
|
||||
|
||||
/* If doing a regular-expression search, compile the
|
||||
* search string, and get out when it's invalid. */
|
||||
if (ISSET(USE_REGEXP) && !regexp_init(last_search)) {
|
||||
search_replace_abort();
|
||||
return;
|
||||
/* When not doing a regular-expression search, just search;
|
||||
* otherwise compile the search string, and only search when
|
||||
* the expression is valid. */
|
||||
if (!ISSET(USE_REGEXP) || regexp_init(last_search)) {
|
||||
if (replacing)
|
||||
ask_for_replacement();
|
||||
else
|
||||
go_looking();
|
||||
}
|
||||
|
||||
if (replacing)
|
||||
ask_for_replacement();
|
||||
else
|
||||
go_looking();
|
||||
|
||||
search_replace_abort();
|
||||
tidy_up_after_search();
|
||||
free(thedefault);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,7 +161,7 @@ void search_init(bool replacing, bool keep_the_answer)
|
||||
if (func == flip_goto)
|
||||
do_gotolinecolumn(openfile->current->lineno,
|
||||
openfile->placewewant + 1, TRUE, TRUE);
|
||||
search_replace_abort();
|
||||
tidy_up_after_search();
|
||||
free(thedefault);
|
||||
return;
|
||||
}
|
||||
@@ -228,7 +205,7 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
|
||||
lastkbcheck = time(NULL);
|
||||
|
||||
/* Consume all waiting keystrokes until a Cancel. */
|
||||
while (input) {
|
||||
while (input != ERR) {
|
||||
if (func_from_key(&input) == do_cancel) {
|
||||
statusbar(_("Cancelled"));
|
||||
enable_waiting();
|
||||
@@ -363,22 +340,6 @@ void do_search_backward(void)
|
||||
do_search();
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Search in the backward direction for the next occurrence. */
|
||||
void do_findprevious(void)
|
||||
{
|
||||
SET(BACKWARDS_SEARCH);
|
||||
do_research();
|
||||
}
|
||||
|
||||
/* Search in the forward direction for the next occurrence. */
|
||||
void do_findnext(void)
|
||||
{
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
do_research();
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
/* Search for the last string without prompting. */
|
||||
void do_research(void)
|
||||
{
|
||||
@@ -402,7 +363,34 @@ void do_research(void)
|
||||
|
||||
go_looking();
|
||||
|
||||
search_replace_abort();
|
||||
tidy_up_after_search();
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Search in the backward direction for the next occurrence. */
|
||||
void do_findprevious(void)
|
||||
{
|
||||
SET(BACKWARDS_SEARCH);
|
||||
do_research();
|
||||
}
|
||||
|
||||
/* Search in the forward direction for the next occurrence. */
|
||||
void do_findnext(void)
|
||||
{
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
do_research();
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
/* Report on the status bar that the given string was not found. */
|
||||
void not_found_msg(const char *str)
|
||||
{
|
||||
char *disp = display_string(str, 0, (COLS / 2) + 1, FALSE);
|
||||
size_t numchars = actual_x(disp, strnlenpt(disp, COLS / 2));
|
||||
|
||||
statusline(HUSH, _("\"%.*s%s\" not found"), numchars, disp,
|
||||
(disp[numchars] == '\0') ? "" : "...");
|
||||
free(disp);
|
||||
}
|
||||
|
||||
/* Search for the global string 'last_search'. Inform the user when
|
||||
@@ -702,8 +690,10 @@ void do_replace(void)
|
||||
{
|
||||
if (ISSET(VIEW_MODE))
|
||||
print_view_warning();
|
||||
else
|
||||
else {
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
search_init(TRUE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ask the user what the already given search string should be replaced with. */
|
||||
@@ -782,6 +772,7 @@ void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
|
||||
}
|
||||
|
||||
if (func_from_key(&i) == flip_goto) {
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
/* Retain what the user typed so far and switch to searching. */
|
||||
search_init(FALSE, TRUE);
|
||||
return;
|
||||
|
||||
330
src/text.c
330
src/text.c
@@ -320,11 +320,11 @@ void do_indent(void)
|
||||
|
||||
add_undo(INDENT);
|
||||
|
||||
/* Go through each of the lines, but skip empty ones. */
|
||||
/* Go through each of the lines, adding an indent to the non-empty ones,
|
||||
* and recording whatever was added in the undo item. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
char *real_indent = (line->data[0] == '\0') ? "" : indentation;
|
||||
|
||||
/* Indent a line, add undo data, and save the original indent. */
|
||||
indent_a_line(line, real_indent);
|
||||
update_multiline_undo(line->lineno, real_indent);
|
||||
}
|
||||
@@ -412,14 +412,14 @@ void do_unindent(void)
|
||||
|
||||
add_undo(UNINDENT);
|
||||
|
||||
/* Go through each of the lines and remove their leading indent. */
|
||||
/* Go through each of the lines, removing their leading indent where
|
||||
* possible, and saving the removed whitespace in the undo item. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
size_t indent_len = length_of_white(line->data);
|
||||
char *indentation = mallocstrncpy(NULL, line->data, indent_len + 1);
|
||||
|
||||
indentation[indent_len] = '\0';
|
||||
|
||||
/* Unindent a line, add undo data, and save the original indent. */
|
||||
unindent_a_line(line, indent_len);
|
||||
update_multiline_undo(line->lineno, indentation);
|
||||
|
||||
@@ -435,27 +435,25 @@ void do_unindent(void)
|
||||
void handle_indent_action(undo *u, bool undoing, bool add_indent)
|
||||
{
|
||||
undo_group *group = u->grouping;
|
||||
filestruct *line = fsfromline(group->top_line);
|
||||
|
||||
if (group->next != NULL)
|
||||
statusline(ALERT, "Multiple groups -- please report a bug");
|
||||
|
||||
/* When redoing, reposition the cursor and let the indenter adjust it. */
|
||||
if (!undoing)
|
||||
goto_line_posx(u->lineno, u->begin);
|
||||
|
||||
while (group) {
|
||||
filestruct *line = fsfromline(group->top_line);
|
||||
/* For each line in the group, add or remove the individual indent. */
|
||||
while (line && line->lineno <= group->bottom_line) {
|
||||
char *blanks = group->indentations[line->lineno - group->top_line];
|
||||
|
||||
/* For each line in the group, add or remove the individual indent. */
|
||||
while (line && line->lineno <= group->bottom_line) {
|
||||
char *blanks = group->indentations[line->lineno - group->top_line];
|
||||
if (undoing ^ add_indent)
|
||||
indent_a_line(line, blanks);
|
||||
else
|
||||
unindent_a_line(line, strlen(blanks));
|
||||
|
||||
if (undoing ^ add_indent)
|
||||
indent_a_line(line, blanks);
|
||||
else
|
||||
unindent_a_line(line, strlen(blanks));
|
||||
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
group = group->next;
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
/* When undoing, reposition the cursor to the recorded location. */
|
||||
@@ -476,66 +474,6 @@ bool white_string(const char *s)
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMMENT
|
||||
/* Comment or uncomment the current line or the marked lines. */
|
||||
void do_comment(void)
|
||||
{
|
||||
const char *comment_seq = GENERAL_COMMENT_CHARACTER;
|
||||
undo_type action = UNCOMMENT;
|
||||
filestruct *top, *bot, *line;
|
||||
bool empty, all_empty = TRUE;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (openfile->syntax)
|
||||
comment_seq = openfile->syntax->comment;
|
||||
|
||||
if (*comment_seq == '\0') {
|
||||
statusbar(_("Commenting is not supported for this file type"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine which lines to work on. */
|
||||
get_range((const filestruct **)&top, (const filestruct **)&bot);
|
||||
|
||||
/* If only the magic line is selected, don't do anything. */
|
||||
if (top == bot && bot == openfile->filebot && !ISSET(NO_NEWLINES)) {
|
||||
statusbar(_("Cannot comment past end of file"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out whether to comment or uncomment the selected line or lines. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
empty = white_string(line->data);
|
||||
|
||||
/* If this line is not blank and not commented, we comment all. */
|
||||
if (!empty && !comment_line(PREFLIGHT, line, comment_seq)) {
|
||||
action = COMMENT;
|
||||
break;
|
||||
}
|
||||
all_empty = all_empty && empty;
|
||||
}
|
||||
|
||||
/* If all selected lines are blank, we comment them. */
|
||||
action = all_empty ? COMMENT : action;
|
||||
|
||||
add_undo(action);
|
||||
|
||||
/* Store the comment sequence used for the operation, because it could
|
||||
* change when the file name changes; we need to know what it was. */
|
||||
openfile->current_undo->strdata = mallocstrcpy(NULL, comment_seq);
|
||||
|
||||
/* Process the selected line or lines. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
/* Comment/uncomment a line, and add undo data when line changed. */
|
||||
if (comment_line(action, line, comment_seq))
|
||||
update_multiline_undo(line->lineno, "");
|
||||
}
|
||||
|
||||
set_modified();
|
||||
refresh_needed = TRUE;
|
||||
shift_held = TRUE;
|
||||
}
|
||||
|
||||
/* Test whether the given line can be uncommented, or add or remove a comment,
|
||||
* depending on action. Return TRUE if the line is uncommentable, or when
|
||||
* anything was added or removed; FALSE otherwise. */
|
||||
@@ -598,6 +536,66 @@ bool comment_line(undo_type action, filestruct *line, const char *comment_seq)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Comment or uncomment the current line or the marked lines. */
|
||||
void do_comment(void)
|
||||
{
|
||||
const char *comment_seq = GENERAL_COMMENT_CHARACTER;
|
||||
undo_type action = UNCOMMENT;
|
||||
filestruct *top, *bot, *line;
|
||||
bool empty, all_empty = TRUE;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (openfile->syntax)
|
||||
comment_seq = openfile->syntax->comment;
|
||||
|
||||
if (*comment_seq == '\0') {
|
||||
statusbar(_("Commenting is not supported for this file type"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine which lines to work on. */
|
||||
get_range((const filestruct **)&top, (const filestruct **)&bot);
|
||||
|
||||
/* If only the magic line is selected, don't do anything. */
|
||||
if (top == bot && bot == openfile->filebot && !ISSET(NO_NEWLINES)) {
|
||||
statusbar(_("Cannot comment past end of file"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out whether to comment or uncomment the selected line or lines. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
empty = white_string(line->data);
|
||||
|
||||
/* If this line is not blank and not commented, we comment all. */
|
||||
if (!empty && !comment_line(PREFLIGHT, line, comment_seq)) {
|
||||
action = COMMENT;
|
||||
break;
|
||||
}
|
||||
all_empty = all_empty && empty;
|
||||
}
|
||||
|
||||
/* If all selected lines are blank, we comment them. */
|
||||
action = all_empty ? COMMENT : action;
|
||||
|
||||
add_undo(action);
|
||||
|
||||
/* Store the comment sequence used for the operation, because it could
|
||||
* change when the file name changes; we need to know what it was. */
|
||||
openfile->current_undo->strdata = mallocstrcpy(NULL, comment_seq);
|
||||
|
||||
/* Comment/uncomment each of the selected lines when possible, and
|
||||
* store undo data when a line changed. */
|
||||
for (line = top; line != bot->next; line = line->next) {
|
||||
if (comment_line(action, line, comment_seq))
|
||||
update_multiline_undo(line->lineno, "");
|
||||
}
|
||||
|
||||
set_modified();
|
||||
refresh_needed = TRUE;
|
||||
shift_held = TRUE;
|
||||
}
|
||||
|
||||
/* Perform an undo or redo for a comment or uncomment action. */
|
||||
void handle_comment_action(undo *u, bool undoing, bool add_comment)
|
||||
{
|
||||
@@ -1085,81 +1083,80 @@ RETSIGTYPE cancel_command(int signal)
|
||||
bool execute_command(const char *command)
|
||||
{
|
||||
int fd[2];
|
||||
FILE *f;
|
||||
FILE *stream;
|
||||
const char *shellenv;
|
||||
struct sigaction oldaction, newaction;
|
||||
/* Original and temporary handlers for SIGINT. */
|
||||
bool sig_failed = FALSE;
|
||||
/* Did sigaction() fail without changing the signal handlers? */
|
||||
bool setup_failed = FALSE;
|
||||
/* Whether setting up the temporary SIGINT handler failed. */
|
||||
|
||||
/* Make our pipes. */
|
||||
/* Create a pipe to read the command's output from. */
|
||||
if (pipe(fd) == -1) {
|
||||
statusbar(_("Could not create pipe"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check $SHELL for the shell to use. If it isn't set, use /bin/sh.
|
||||
* Note that $SHELL should contain only a path, with no arguments. */
|
||||
/* Check which shell to use. If none is specified, use /bin/sh. */
|
||||
shellenv = getenv("SHELL");
|
||||
if (shellenv == NULL)
|
||||
shellenv = (char *) "/bin/sh";
|
||||
|
||||
/* Fork a child. */
|
||||
/* Fork a child process to run the command in. */
|
||||
if ((pid = fork()) == 0) {
|
||||
/* Child: close the unused read end of the pipe. */
|
||||
close(fd[0]);
|
||||
|
||||
/* Connect the write end of the pipe to the process' output streams. */
|
||||
dup2(fd[1], fileno(stdout));
|
||||
dup2(fd[1], fileno(stderr));
|
||||
|
||||
/* If execl() returns at all, there was an error. */
|
||||
/* Run the given command inside the preferred shell. */
|
||||
execl(shellenv, tail(shellenv), "-c", command, NULL);
|
||||
exit(0);
|
||||
|
||||
/* If the exec call returns, there was an error. */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Continue as parent. */
|
||||
/* Parent: close the unused write end of the pipe. */
|
||||
close(fd[1]);
|
||||
|
||||
if (pid == -1) {
|
||||
close(fd[0]);
|
||||
statusbar(_("Could not fork"));
|
||||
close(fd[0]);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Before we start reading the forked command's output, we set
|
||||
* things up so that Ctrl-C will cancel the new process. */
|
||||
|
||||
/* Enable interpretation of the special control keys so that we get
|
||||
/* Re-enable interpretation of the special control keys so that we get
|
||||
* SIGINT when Ctrl-C is pressed. */
|
||||
enable_signals();
|
||||
|
||||
/* Set things up so that Ctrl-C will terminate the forked process. */
|
||||
if (sigaction(SIGINT, NULL, &newaction) == -1) {
|
||||
sig_failed = TRUE;
|
||||
setup_failed = TRUE;
|
||||
nperror("sigaction");
|
||||
} else {
|
||||
newaction.sa_handler = cancel_command;
|
||||
if (sigaction(SIGINT, &newaction, &oldaction) == -1) {
|
||||
sig_failed = TRUE;
|
||||
setup_failed = TRUE;
|
||||
nperror("sigaction");
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that now oldaction is the previous SIGINT signal handler,
|
||||
* to be restored later. */
|
||||
|
||||
f = fdopen(fd[0], "rb");
|
||||
if (f == NULL)
|
||||
nperror("fdopen");
|
||||
|
||||
read_file(f, 0, "stdin", TRUE);
|
||||
stream = fdopen(fd[0], "rb");
|
||||
if (stream == NULL)
|
||||
statusline(ALERT, _("Failed to open pipe: %s"), strerror(errno));
|
||||
else
|
||||
read_file(stream, 0, "pipe", TRUE);
|
||||
|
||||
if (wait(NULL) == -1)
|
||||
nperror("wait");
|
||||
|
||||
if (!sig_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
|
||||
/* If it was changed, restore the handler for SIGINT. */
|
||||
if (!setup_failed && sigaction(SIGINT, &oldaction, NULL) == -1)
|
||||
nperror("sigaction");
|
||||
|
||||
/* Restore the terminal to its previous state. In the process,
|
||||
* disable interpretation of the special control keys so that we can
|
||||
* use Ctrl-C for other things. */
|
||||
/* Restore the terminal to its desired state, and disable
|
||||
* interpretation of the special control keys again. */
|
||||
terminal_init();
|
||||
|
||||
return TRUE;
|
||||
@@ -1335,8 +1332,8 @@ void add_undo(undo_type action)
|
||||
}
|
||||
|
||||
/* Update a multiline undo item. This should be called once for each line
|
||||
* affected by a multiple-line-altering feature. The existing indentation
|
||||
* is saved separately for each line in the undo item. */
|
||||
* affected by a multiple-line-altering feature. The indentation that is
|
||||
* added or removed is saved separately for each line in the undo item. */
|
||||
void update_multiline_undo(ssize_t lineno, char *indentation)
|
||||
{
|
||||
undo *u = openfile->current_undo;
|
||||
@@ -2506,10 +2503,28 @@ void do_full_justify(void)
|
||||
}
|
||||
#endif /* ENABLE_JUSTIFY */
|
||||
|
||||
#if defined(ENABLE_SPELLER) || defined (ENABLE_COLOR)
|
||||
/* Set up an argument list for executing the given command. */
|
||||
void construct_argument_list(char ***arguments, char *command, char *filename)
|
||||
{
|
||||
char *copy_of_command = mallocstrcpy(NULL, command);
|
||||
char *element = strtok(copy_of_command, " ");
|
||||
int count = 2;
|
||||
|
||||
while (element != NULL) {
|
||||
*arguments = (char **)nrealloc(*arguments, ++count * sizeof(char *));
|
||||
(*arguments)[count - 3] = element;
|
||||
element = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
(*arguments)[count - 2] = filename;
|
||||
(*arguments)[count - 1] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SPELLER
|
||||
/* A word is misspelled in the file. Let the user replace it. We
|
||||
* return FALSE if the user cancels. */
|
||||
bool do_int_spell_fix(const char *word)
|
||||
/* Let the user edit the misspelled word. Return FALSE if the user cancels. */
|
||||
bool fix_spello(const char *word)
|
||||
{
|
||||
char *save_search;
|
||||
size_t firstcolumn_save = openfile->firstcolumn;
|
||||
@@ -2521,8 +2536,6 @@ bool do_int_spell_fix(const char *word)
|
||||
/* The return value of this function. */
|
||||
bool result;
|
||||
/* The return value of searching for a misspelled word. */
|
||||
unsigned stash[sizeof(flags) / sizeof(flags[0])];
|
||||
/* A storage place for the current flag settings. */
|
||||
#ifndef NANO_TINY
|
||||
bool right_side_up = FALSE;
|
||||
/* TRUE if (mark_begin, mark_begin_x) is the top of the mark,
|
||||
@@ -2531,14 +2544,6 @@ bool do_int_spell_fix(const char *word)
|
||||
size_t top_x, bot_x;
|
||||
#endif
|
||||
|
||||
/* Save the settings of the global flags. */
|
||||
memcpy(stash, flags, sizeof(flags));
|
||||
|
||||
/* Do the spell checking case sensitive, forward, and without regexes. */
|
||||
SET(CASE_SENSITIVE);
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
UNSET(USE_REGEXP);
|
||||
|
||||
/* Save the current search string, then set it to the misspelled word. */
|
||||
save_search = last_search;
|
||||
last_search = mallocstrcpy(NULL, word);
|
||||
@@ -2630,9 +2635,6 @@ bool do_int_spell_fix(const char *word)
|
||||
openfile->edittop = edittop_save;
|
||||
openfile->firstcolumn = firstcolumn_save;
|
||||
|
||||
/* Restore the settings of the global flags. */
|
||||
memcpy(flags, stash, sizeof(flags));
|
||||
|
||||
return proceed;
|
||||
}
|
||||
|
||||
@@ -2760,14 +2762,19 @@ const char *do_int_speller(const char *tempfile_name)
|
||||
*read_buff_ptr = '\0';
|
||||
close(uniq_fd[0]);
|
||||
|
||||
/* Process the spelling errors. */
|
||||
/* Do any replacements case sensitive, forward, and without regexes. */
|
||||
SET(CASE_SENSITIVE);
|
||||
UNSET(BACKWARDS_SEARCH);
|
||||
UNSET(USE_REGEXP);
|
||||
|
||||
read_buff_word = read_buff_ptr = read_buff;
|
||||
|
||||
/* Process each of the misspelled words. */
|
||||
while (*read_buff_ptr != '\0') {
|
||||
if ((*read_buff_ptr == '\r') || (*read_buff_ptr == '\n')) {
|
||||
*read_buff_ptr = '\0';
|
||||
if (read_buff_word != read_buff_ptr) {
|
||||
if (!do_int_spell_fix(read_buff_word)) {
|
||||
if (!fix_spello(read_buff_word)) {
|
||||
read_buff_word = read_buff_ptr;
|
||||
break;
|
||||
}
|
||||
@@ -2779,10 +2786,10 @@ const char *do_int_speller(const char *tempfile_name)
|
||||
|
||||
/* Special case: the last word doesn't end with '\r' or '\n'. */
|
||||
if (read_buff_word != read_buff_ptr)
|
||||
do_int_spell_fix(read_buff_word);
|
||||
fix_spello(read_buff_word);
|
||||
|
||||
free(read_buff);
|
||||
search_replace_abort();
|
||||
tidy_up_after_search();
|
||||
refresh_needed = TRUE;
|
||||
|
||||
/* Process the end of the three processes. */
|
||||
@@ -2826,8 +2833,6 @@ const char *do_alt_speller(char *tempfile_name)
|
||||
struct stat spellfileinfo;
|
||||
time_t timestamp;
|
||||
pid_t pid_spell;
|
||||
char *ptr;
|
||||
static int arglen = 3;
|
||||
static char **spellargs = NULL;
|
||||
|
||||
/* Get the timestamp and the size of the temporary file. */
|
||||
@@ -2841,20 +2846,7 @@ const char *do_alt_speller(char *tempfile_name)
|
||||
/* Exit from curses mode. */
|
||||
endwin();
|
||||
|
||||
/* Set up the argument list to pass to execvp(). */
|
||||
if (spellargs == NULL) {
|
||||
spellargs = (char **)nmalloc(arglen * sizeof(char *));
|
||||
|
||||
spellargs[0] = strtok(alt_speller, " ");
|
||||
while ((ptr = strtok(NULL, " ")) != NULL) {
|
||||
arglen++;
|
||||
spellargs = (char **)nrealloc(spellargs, arglen *
|
||||
sizeof(char *));
|
||||
spellargs[arglen - 3] = ptr;
|
||||
}
|
||||
spellargs[arglen - 1] = NULL;
|
||||
}
|
||||
spellargs[arglen - 2] = tempfile_name;
|
||||
construct_argument_list(&spellargs, alt_speller, tempfile_name);
|
||||
|
||||
/* Fork a child process and run the alternate spell program in it. */
|
||||
if ((pid_spell = fork()) == 0) {
|
||||
@@ -2944,6 +2936,8 @@ void do_spell(void)
|
||||
bool status;
|
||||
FILE *temp_file;
|
||||
char *temp;
|
||||
unsigned stash[sizeof(flags) / sizeof(flags[0])];
|
||||
/* A storage place for the current flag settings. */
|
||||
const char *spell_msg;
|
||||
|
||||
if (ISSET(RESTRICTED)) {
|
||||
@@ -2958,6 +2952,12 @@ void do_spell(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save the settings of the global flags. */
|
||||
memcpy(stash, flags, sizeof(flags));
|
||||
|
||||
/* Don't add an extra newline when writing out the (selected) text. */
|
||||
SET(NO_NEWLINES);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (openfile->mark)
|
||||
status = write_marked_file(temp, temp_file, TRUE, OVERWRITE);
|
||||
@@ -2979,6 +2979,9 @@ void do_spell(void)
|
||||
unlink(temp);
|
||||
free(temp);
|
||||
|
||||
/* Restore the settings of the global flags. */
|
||||
memcpy(flags, stash, sizeof(flags));
|
||||
|
||||
/* If the spell-checker printed any error messages onscreen, make
|
||||
* sure that they're cleared off. */
|
||||
total_refresh();
|
||||
@@ -3000,12 +3003,11 @@ void do_spell(void)
|
||||
* termination, and the error string otherwise. */
|
||||
void do_linter(void)
|
||||
{
|
||||
char *read_buff, *read_buff_ptr, *read_buff_word, *ptr, *lintcopy;
|
||||
char *read_buff, *read_buff_ptr, *read_buff_word;
|
||||
size_t pipe_buff_size, read_buff_size, read_buff_read, bytesread;
|
||||
size_t parsesuccess = 0;
|
||||
int lint_status, lint_fd[2];
|
||||
pid_t pid_lint;
|
||||
static int arglen = 3;
|
||||
static char **lintargs = NULL;
|
||||
lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL;
|
||||
|
||||
@@ -3034,7 +3036,6 @@ void do_linter(void)
|
||||
return;
|
||||
}
|
||||
|
||||
lintcopy = mallocstrcpy(NULL, openfile->syntax->linter);
|
||||
/* Create a pipe up front. */
|
||||
if (pipe(lint_fd) == -1) {
|
||||
statusbar(_("Could not create pipe"));
|
||||
@@ -3044,19 +3045,7 @@ void do_linter(void)
|
||||
blank_bottombars();
|
||||
statusbar(_("Invoking linter, please wait"));
|
||||
|
||||
/* Set up an argument list to pass to execvp(). */
|
||||
if (lintargs == NULL) {
|
||||
lintargs = (char **)nmalloc(arglen * sizeof(char *));
|
||||
|
||||
lintargs[0] = strtok(lintcopy, " ");
|
||||
while ((ptr = strtok(NULL, " ")) != NULL) {
|
||||
arglen++;
|
||||
lintargs = (char **)nrealloc(lintargs, arglen * sizeof(char *));
|
||||
lintargs[arglen - 3] = ptr;
|
||||
}
|
||||
lintargs[arglen - 1] = NULL;
|
||||
}
|
||||
lintargs[arglen - 2] = openfile->filename;
|
||||
construct_argument_list(&lintargs, openfile->syntax->linter, openfile->filename);
|
||||
|
||||
/* Start a new process to run the linter in. */
|
||||
if ((pid_lint = fork()) == 0) {
|
||||
@@ -3336,9 +3325,8 @@ void do_formatter(void)
|
||||
size_t pww_save = openfile->placewewant;
|
||||
bool was_at_eol = (openfile->current->data[openfile->current_x] == '\0');
|
||||
pid_t pid_format;
|
||||
static int arglen = 3;
|
||||
static char **formatargs = NULL;
|
||||
char *temp, *ptr, *finalstatus = NULL;
|
||||
char *temp, *finalstatus = NULL;
|
||||
|
||||
if (openfile->totsize == 0) {
|
||||
statusbar(_("Finished"));
|
||||
@@ -3367,19 +3355,7 @@ void do_formatter(void)
|
||||
blank_bottombars();
|
||||
statusbar(_("Invoking formatter, please wait"));
|
||||
|
||||
/* Set up an argument list to pass to execvp(). */
|
||||
if (formatargs == NULL) {
|
||||
formatargs = (char **)nmalloc(arglen * sizeof(char *));
|
||||
|
||||
formatargs[0] = strtok(openfile->syntax->formatter, " ");
|
||||
while ((ptr = strtok(NULL, " ")) != NULL) {
|
||||
arglen++;
|
||||
formatargs = (char **)nrealloc(formatargs, arglen * sizeof(char *));
|
||||
formatargs[arglen - 3] = ptr;
|
||||
}
|
||||
formatargs[arglen - 1] = NULL;
|
||||
}
|
||||
formatargs[arglen - 2] = temp;
|
||||
construct_argument_list(&formatargs, openfile->syntax->formatter, temp);
|
||||
|
||||
/* Start a new process for the formatter. */
|
||||
if ((pid_format = fork()) == 0) {
|
||||
@@ -3640,7 +3616,7 @@ void complete_a_word(void)
|
||||
/* The point where we can stop searching for shard. */
|
||||
|
||||
/* Traverse the whole line, looking for shard. */
|
||||
for (i = pletion_x; i < threshold; i++) {
|
||||
for (i = pletion_x; (int)i < threshold; i++) {
|
||||
/* If the first byte doesn't match, run on. */
|
||||
if (pletion_line->data[i] != shard[0])
|
||||
continue;
|
||||
|
||||
@@ -325,15 +325,18 @@ const char *strstrwrapper(const char *haystack, const char *needle,
|
||||
else
|
||||
return haystack + regmatches[0].rm_so;
|
||||
}
|
||||
|
||||
if (ISSET(CASE_SENSITIVE)) {
|
||||
if (ISSET(BACKWARDS_SEARCH))
|
||||
return revstrstr(haystack, needle, start);
|
||||
else
|
||||
return strstr(start, needle);
|
||||
} else if (ISSET(BACKWARDS_SEARCH))
|
||||
return mbrevstrcasestr(haystack, needle, start);
|
||||
}
|
||||
|
||||
return mbstrcasestr(start, needle);
|
||||
if (ISSET(BACKWARDS_SEARCH))
|
||||
return mbrevstrcasestr(haystack, needle, start);
|
||||
else
|
||||
return mbstrcasestr(start, needle);
|
||||
}
|
||||
|
||||
/* This is a wrapper for the perror() function. The wrapper temporarily
|
||||
|
||||
@@ -363,7 +363,7 @@ int parse_kbinput(WINDOW *win)
|
||||
kbinput = get_input(win, 1);
|
||||
|
||||
if (kbinput == NULL && !waiting_mode)
|
||||
return 0;
|
||||
return ERR;
|
||||
|
||||
while (kbinput == NULL)
|
||||
kbinput = get_input(win, 1);
|
||||
|
||||
@@ -20,9 +20,9 @@ color red " fuzzy(,|$)"
|
||||
color yellow " (no-)?[-[:alpha:]]+-format(,|$)"
|
||||
# Format specifiers.
|
||||
color brightmagenta "%([1-9]\$)?[a-z]*"
|
||||
# Quotes and newlines.
|
||||
# Quotes and escaped characters.
|
||||
color yellow "\""
|
||||
color cyan "\\n"
|
||||
color cyan "\\[abcefnrtv"\]"
|
||||
# Reminders.
|
||||
color brightwhite,yellow "(FIXME|TODO|XXX)"
|
||||
# Obsolete strings.
|
||||
|
||||
@@ -16,7 +16,7 @@ color green "[{}():;|`$<>!=&\\]" "(\]|\[)"
|
||||
color green "-(eq|ne|gt|lt|ge|le|ef|ot|nt)\>"
|
||||
|
||||
# Short and long options.
|
||||
color brightmagenta "-[A-Za-z]\>" "--[A-Za-z-]+\>"
|
||||
color brightmagenta "[[:blank:]]-[A-Za-z]\>" "[[:blank:]]--[A-Za-z-]+\>"
|
||||
|
||||
# Common commands.
|
||||
color brightblue "\<(awk|cat|cd|ch(grp|mod|own)|cp|cut|echo|env|grep|head|install|ln|make|mkdir|mv|popd|printf|pushd|rm|rmdir|sed|set|sort|tail|tar|touch|umask|unset)\>"
|
||||
|
||||
Reference in New Issue
Block a user