Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d6b5c13281 | |||
|
|
ef35ea72cf | ||
|
|
8804b6dcd4 | ||
|
|
86b8388889 | ||
|
|
812c48dde4 | ||
|
|
f0f1c94afa | ||
|
|
75b312ded1 | ||
|
|
e65b0ba654 | ||
|
|
d3dd403dc7 | ||
|
|
7f4c2c6a25 | ||
| 4fefb91028 | |||
|
|
cb1b3a28ab | ||
|
|
f7d8735b6b | ||
|
|
fc42ab9b46 | ||
|
|
7f17777a4b | ||
|
|
bcdb27416c | ||
|
|
15c6396d42 | ||
|
|
2c19345e58 | ||
|
|
69a7dd86ec | ||
| 1c4bfb6446 | |||
| 070b784a49 | |||
| 18eb6bae01 | |||
| b5809f3793 | |||
| 9980a98607 | |||
| 442bd49137 | |||
| 263c7fefbf | |||
| 02249f1655 | |||
| ac58a97a92 | |||
| 140f2d72cb | |||
| b81dca5014 | |||
| 0ac593a9ce | |||
| 8daf175b09 | |||
| 49935c0456 | |||
| b145ce016b | |||
| 226108a59f | |||
| 01b30a5a0e | |||
| 05fa7110ec |
14
configure.ac
14
configure.ac
@ -128,6 +128,20 @@ if test "x$enable_color" != xno; then
|
||||
color_support=yes
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(folding,
|
||||
AS_HELP_STRING([--disable-folding], [Disable line folding support]))
|
||||
if test "x$enable_tiny" = xyes; then
|
||||
if test "x$enable_folding" = xyes; then
|
||||
AC_MSG_ERROR([
|
||||
*** --enable-folding cannot work with --enable-tiny])
|
||||
else
|
||||
enable_folding=no
|
||||
fi
|
||||
fi
|
||||
if test "x$enable_folding" != xno; then
|
||||
AC_DEFINE(ENABLE_FOLDING, 1, [Define this to have line folding support.])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(comment,
|
||||
AS_HELP_STRING([--disable-comment], [Disable the comment/uncomment function]))
|
||||
if test "x$enable_tiny" = xyes; then
|
||||
|
||||
@ -222,10 +222,10 @@
|
||||
<blockquote><p>Try holding down the Shift key and selecting or pasting the text as you normally would.</p></blockquote>
|
||||
<h3><a name="4.6"></a>4.6. When I paste text into a document, each line gets indented further than the last. Why? And how can I stop this?</h3>
|
||||
<blockquote><p>You have the <i>autoindent</i> feature turned on. Hit <b>Meta-I</b> to turn it off, paste your text, and then hit <b>Meta-I</b> again to turn it back on.</p>
|
||||
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste, so you no longer need to toggle it off and on manually.</p></blockquote>
|
||||
<p><i>Update:</i> Since version 4.8, nano will suppress auto-indentation during a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need to toggle it off and on manually.</p></blockquote>
|
||||
<h3><a name="4.7"></a>4.7. When I paste from Windows into a remote nano, nano rewraps the lines. What gives?</h3>
|
||||
<blockquote><p>When pasting from Windows, in some situations linefeeds are sent instead of carriage returns (Enters). And linefeeds are <b>^J</b>s, which make nano justify (rewrap) the current paragraph. To prevent these linefeeds from causing these unwanted justifications, add this line to your .nanorc on the remote Linux box: <b>unbind ^J main</b> or <b>bind ^J enter main</b>, depending on whether the paste contains CR + LF or only LF.</p>
|
||||
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste, so you no longer need the above workaround.</p></blockquote>
|
||||
<p><i>Update:</i> Since version 4.8, nano will ignore linefeed characters in a paste (when your terminal understands <a href="https://en.wikipedia.org/wiki/Bracketed-paste">bracketed pastes</a>), so you no longer need the above workaround.</p></blockquote>
|
||||
<h3><a name="4.8"></a>4.8. I've compiled nano with color support, but I don't see any color when I run it!</h3>
|
||||
<blockquote><p>If you want nano to actually use color, you have to specify the color configurations you want it to use in your .nanorc. Several example configurations are in the <b>syntax/</b> subdirectory of the nano source, which are normally installed to <b>/usr/local/share/nano/</b>. To enable all of them, uncomment the line <b># include "/usr/local/share/nano/*.nanorc"</b> in your nanorc. See also section <a href="#3.9">3.9</a>.</p></blockquote>
|
||||
<h3><a name="4.9"></a>4.9. How do I make nano my default editor (in Pine, mutt, etc.)?</h3>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
.TH NANO 1 "version 7.2" "January 2023"
|
||||
|
||||
.SH NAME
|
||||
nano \- Nano's ANOther editor, inspired by Pico
|
||||
nano \- Nano's ANOther text editor, inspired by Pico
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B nano
|
||||
@ -28,10 +28,10 @@ nano \- Nano's ANOther editor, inspired by Pico
|
||||
.B nano
|
||||
.RI [ options "] [" file [\fB: line [\fB: column "]]]..."
|
||||
.sp
|
||||
.BR nano " [" \fIoptions "] [[" + [ crCR ]( / | ? ) \fIstring "] " \fIfile ]...
|
||||
.BR nano " [" \fIoptions "] [[" + [ crCR ]{ / | ? } \fIstring "] " \fIfile ]...
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBnano\fP is a small and friendly editor. It copies the look and feel
|
||||
\fBnano\fP is a small and friendly text editor. It copies the look and feel
|
||||
of Pico, but is free software, and implements several features that Pico
|
||||
lacks, such as: opening multiple files, scrolling per line, undo/redo,
|
||||
syntax coloring, line numbering, and soft-wrapping overlong lines.
|
||||
|
||||
@ -35,7 +35,7 @@ The complete manual for the GNU nano text editor.
|
||||
|
||||
@page
|
||||
|
||||
This manual documents the GNU @command{nano} editor.
|
||||
This manual documents the GNU @command{nano} text editor.
|
||||
@sp 1
|
||||
The contents of this manual are part of the GNU @command{nano} distribution.
|
||||
|
||||
@ -163,7 +163,7 @@ A more complete command synopsis thus is:
|
||||
|
||||
@blankline
|
||||
@example
|
||||
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR](/|?)STRING] FILE]@dots{}}
|
||||
@code{nano [OPTION]@dots{} [[+LINE[,COLUMN]|+[crCR]@{/|?@}STRING] FILE]@dots{}}
|
||||
@end example
|
||||
@blankline
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ nanorc \- GNU nano's configuration file
|
||||
|
||||
.SH DESCRIPTION
|
||||
The \fInanorc\fP files contain the default settings for \fBnano\fP,
|
||||
a small and friendly editor. During startup, if \fB\-\-rcfile\fR
|
||||
a small and friendly text editor. During startup, if \fB\-\-rcfile\fR
|
||||
is not given, \fBnano\fR will read two files: first the
|
||||
system-wide settings, from \fI/etc/nanorc\fP (the exact path might be
|
||||
different on your system), and then the user-specific settings, either
|
||||
|
||||
10
doc/rnano.1
10
doc/rnano.1
@ -32,15 +32,19 @@ access to the filesystem nor to a command shell.
|
||||
.sp
|
||||
In restricted mode, \fBnano\fR will:
|
||||
.IP \[bu] 2
|
||||
not make backups;
|
||||
.IP \[bu]
|
||||
not allow suspending;
|
||||
.IP \[bu]
|
||||
not allow spell checking;
|
||||
.IP \[bu]
|
||||
not read nor write the history files;
|
||||
.IP \[bu]
|
||||
not allow saving the current buffer under a different name;
|
||||
.IP \[bu]
|
||||
not allow inserting another file or opening a new buffer;
|
||||
.IP \[bu]
|
||||
not allow appending or prepending to any file;
|
||||
.IP \[bu]
|
||||
not make backup files nor do spell checking.
|
||||
not allow appending or prepending to any file.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
||||
@ -30,6 +30,7 @@ nano_SOURCES = \
|
||||
color.c \
|
||||
cut.c \
|
||||
files.c \
|
||||
folding.c \
|
||||
global.c \
|
||||
help.c \
|
||||
history.c \
|
||||
|
||||
@ -436,7 +436,10 @@ char *browse(char *path)
|
||||
|
||||
titlebar(path);
|
||||
|
||||
while (TRUE) {
|
||||
if (list_length == 0) {
|
||||
statusline(ALERT, _("No entries"));
|
||||
napms(1200);
|
||||
} else while (TRUE) {
|
||||
functionptrtype function;
|
||||
int kbinput;
|
||||
|
||||
|
||||
28
src/cut.c
28
src/cut.c
@ -48,6 +48,7 @@ void do_deletion(undo_type action)
|
||||
memmove(&openfile->current->data[openfile->current_x],
|
||||
&openfile->current->data[openfile->current_x + charlen],
|
||||
line_len - charlen + 1);
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
#ifndef NANO_TINY
|
||||
/* When softwrapping, a changed number of chunks requires a refresh. */
|
||||
if (ISSET(SOFTWRAP) && extra_chunks_in(openfile->current) != old_amount)
|
||||
@ -62,6 +63,9 @@ void do_deletion(undo_type action)
|
||||
} else if (openfile->current != openfile->filebot) {
|
||||
linestruct *joining = openfile->current->next;
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
UNFOLD_SEGMENT(joining);
|
||||
|
||||
/* If there is a magic line, and we're before it: don't eat it. */
|
||||
if (joining == openfile->filebot && openfile->current_x != 0 &&
|
||||
!ISSET(NO_NEWLINES)) {
|
||||
@ -143,7 +147,8 @@ void do_backspace(void)
|
||||
openfile->current_x = step_left(openfile->current->data, openfile->current_x);
|
||||
do_deletion(BACK);
|
||||
} else if (openfile->current != openfile->filetop) {
|
||||
do_left();
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
do_deletion(BACK);
|
||||
}
|
||||
}
|
||||
@ -192,7 +197,7 @@ void chop_word(bool forward)
|
||||
* on the edge of the original line, then put the cursor on that
|
||||
* edge instead, so that lines will not be joined unexpectedly. */
|
||||
if (!forward) {
|
||||
do_prev_word();
|
||||
do_prev_word(ALLOW_FOLDED);
|
||||
if (openfile->current != is_current) {
|
||||
if (is_current_x > 0) {
|
||||
openfile->current = is_current;
|
||||
@ -201,13 +206,14 @@ void chop_word(bool forward)
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
} else {
|
||||
do_next_word(ISSET(AFTER_ENDS));
|
||||
do_next_word(ISSET(AFTER_ENDS), ALLOW_FOLDED);
|
||||
if (openfile->current != is_current &&
|
||||
is_current->data[is_current_x] != '\0') {
|
||||
openfile->current = is_current;
|
||||
openfile->current_x = strlen(is_current->data);
|
||||
}
|
||||
}
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Set the mark at the start of that word. */
|
||||
openfile->mark = openfile->current;
|
||||
@ -262,9 +268,20 @@ void extract_segment(linestruct *top, size_t top_x, linestruct *bot, size_t bot_
|
||||
if (top == bot && top_x == bot_x)
|
||||
return;
|
||||
|
||||
/* In case bot is the start of a folded segment.
|
||||
* Folds within [top, bot] are taken care of in the following loop */
|
||||
UNFOLD_SEGMENT(bot);
|
||||
|
||||
if (top != bot)
|
||||
for (linestruct *line = top->next; line != bot->next; line = line->next)
|
||||
#ifdef ENABLE_FOLDING
|
||||
top->folded = FALSE;
|
||||
#endif
|
||||
for (linestruct *line = top->next; line != bot->next; line = line->next){
|
||||
had_anchor |= line->has_anchor;
|
||||
#ifdef ENABLE_FOLDING
|
||||
line->folded = FALSE;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (top == bot) {
|
||||
@ -378,6 +395,8 @@ void ingraft_buffer(linestruct *topline)
|
||||
#endif
|
||||
linestruct *botline = topline;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
while (botline->next != NULL)
|
||||
botline = botline->next;
|
||||
|
||||
@ -728,6 +747,7 @@ void paste_text(void)
|
||||
statusline(AHEM, _("Cutbuffer is empty"));
|
||||
return;
|
||||
}
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_undo(PASTE, NULL);
|
||||
|
||||
@ -214,12 +214,15 @@
|
||||
#define SHIFT_DELETE 0x45D
|
||||
#define SHIFT_TAB 0x45F
|
||||
|
||||
#define FOCUS_IN 0x491
|
||||
#define FOCUS_OUT 0x499
|
||||
|
||||
/* Special keycodes for when a string bind has been partially implanted
|
||||
* or has an unpaired opening brace, or when a function in a string bind
|
||||
* needs execution or a specified function name is invalid. */
|
||||
#define MORE_PLANTS 0x4EA
|
||||
#define MISSING_BRACE 0x4EB
|
||||
#define PLANTED_COMMAND 0x4EC
|
||||
#define PLANTED_A_COMMAND 0x4EC
|
||||
#define NO_SUCH_FUNCTION 0x4EF
|
||||
|
||||
/* A special keycode for when <Tab> is pressed while the mark is on. */
|
||||
@ -273,6 +276,15 @@
|
||||
#define MSOME MMAIN|MBROWSER
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
#define UNFOLD_SEGMENT(line) unfold_folded_segment(line)
|
||||
#else
|
||||
#define UNFOLD_SEGMENT(line)
|
||||
#endif
|
||||
|
||||
#define ALLOW_FOLDED TRUE
|
||||
#define DISALLOW_FOLDED FALSE
|
||||
|
||||
/* Enumeration types. */
|
||||
typedef enum {
|
||||
UNSPECIFIED, NIX_FILE, DOS_FILE, MAC_FILE
|
||||
@ -374,6 +386,12 @@ enum {
|
||||
ZERO
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
FOUND_BRACKET = 0,
|
||||
NOT_FOUND_BRACKET,
|
||||
NOT_A_BRACKET
|
||||
} bracket_search_result;
|
||||
|
||||
/* Structure types. */
|
||||
#ifdef ENABLE_COLOR
|
||||
typedef struct colortype {
|
||||
@ -480,6 +498,10 @@ typedef struct linestruct {
|
||||
bool has_anchor;
|
||||
/* Whether the user has placed an anchor at this line. */
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
bool folded;
|
||||
/* Whether or not this line is in a fold segment */
|
||||
#endif
|
||||
} linestruct;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
|
||||
@ -535,7 +535,8 @@ void mention_name_and_linecount(void)
|
||||
if (ISSET(MINIBAR)) {
|
||||
report_size = TRUE;
|
||||
return;
|
||||
}
|
||||
} else if (ISSET(ZERO))
|
||||
return;
|
||||
|
||||
if (openfile->fmt > NIX_FILE)
|
||||
/* TRANSLATORS: First %s is file name, second %s is file format. */
|
||||
@ -681,6 +682,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)
|
||||
if (ISSET(SOFTWRAP))
|
||||
was_leftedge = leftedge_for(xplustabs(), openfile->current);
|
||||
#endif
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Create an empty buffer. */
|
||||
topline = make_new_node(NULL);
|
||||
|
||||
138
src/folding.c
Normal file
138
src/folding.c
Normal file
@ -0,0 +1,138 @@
|
||||
/**************************************************************************
|
||||
* folding.c -- This file is part of GNU nano. *
|
||||
* *
|
||||
* Copyright (C) 2022 rexy712 *
|
||||
* *
|
||||
* GNU nano is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published *
|
||||
* by the Free Software Foundation, either version 3 of the License, *
|
||||
* or (at your option) any later version. *
|
||||
* *
|
||||
* GNU nano is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty *
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* See the GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see http://www.gnu.org/licenses/. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "prototypes.h"
|
||||
|
||||
#include <ctype.h>
|
||||
/* isspace */
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
|
||||
/* Remove a folded segment from the given line until end of segment */
|
||||
void unfold_folded_segment_from(linestruct *line)
|
||||
{
|
||||
if (line != NULL)
|
||||
refresh_needed = TRUE;
|
||||
for(;line != NULL && line->folded;line = line->next)
|
||||
line->folded = FALSE;
|
||||
}
|
||||
|
||||
/* Remove a folded segment containing the given line */
|
||||
void unfold_folded_segment(linestruct *line)
|
||||
{
|
||||
unfold_folded_segment_from(get_start_of_folded_segment(line));
|
||||
}
|
||||
|
||||
/* Get the first member of the folded segment */
|
||||
linestruct *get_start_of_folded_segment(linestruct *line)
|
||||
{
|
||||
if (!line->folded)
|
||||
return line;
|
||||
|
||||
while (line->prev != NULL && line->prev->folded)
|
||||
line = line->prev;
|
||||
|
||||
return line;
|
||||
}
|
||||
/* Get the last member of the folded segment */
|
||||
linestruct *get_end_of_folded_segment(linestruct *line)
|
||||
{
|
||||
if (!line->folded)
|
||||
return line;
|
||||
|
||||
while (line->next != NULL && line->next->folded)
|
||||
line = line->next;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Get the span length of a folded_segment */
|
||||
int get_folded_segment_length(linestruct *line)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
if (!line->folded)
|
||||
return 0;
|
||||
|
||||
line = get_start_of_folded_segment(line);
|
||||
for (;line->next != NULL && line->next->folded;line = line->next)
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* Remove any folded_segments within the range [top, bottom].
|
||||
* Returns true if any segments are removed. */
|
||||
bool do_unfold_segment(linestruct *line)
|
||||
{
|
||||
/* Attempt to find a bracketed region first.
|
||||
* If not, top is unmodified. */
|
||||
if (!line->folded) {
|
||||
linestruct *bot;
|
||||
find_bracketed_region(openfile->current, &line, &bot);
|
||||
}
|
||||
|
||||
if (line->folded) {
|
||||
unfold_folded_segment(line);
|
||||
move_cursor_to_proper_column();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Fold the currently selected lines unless the current selection
|
||||
* already contains a folded_segment. In that case, remove any
|
||||
* segments that are selected. */
|
||||
void do_fold_segment(void)
|
||||
{
|
||||
linestruct *top, *bot;
|
||||
get_range(&top, &bot);
|
||||
|
||||
if (top == bot) {
|
||||
/* First try to unfold if this line/bracketed region is folded */
|
||||
if (do_unfold_segment(top))
|
||||
return;
|
||||
|
||||
/* When not selecting multiple lines, try to find bounding
|
||||
* brackets to act as top and bot. */
|
||||
if (!find_bracketed_region(openfile->current, &top, &bot)) {
|
||||
statusline(AHEM, _("No valid region found for automatic fold"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (linestruct* line = top;line != bot->next;line = line->next)
|
||||
line->folded = TRUE;
|
||||
|
||||
if (top->lineno < openfile->edittop->lineno &&
|
||||
bot->lineno > openfile->edittop->lineno)
|
||||
openfile->edittop = top;
|
||||
|
||||
/* Place the cursor at the start of the fold segment.
|
||||
* Anywhere else within the segment is invalid. */
|
||||
if (openfile->current->folded)
|
||||
openfile->current = get_start_of_folded_segment(top);
|
||||
openfile->mark = NULL;
|
||||
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_FOLDING */
|
||||
75
src/global.c
75
src/global.c
@ -107,6 +107,7 @@ int altpageup, altpagedown;
|
||||
int altinsert, altdelete;
|
||||
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
|
||||
#endif
|
||||
int mousefocusin, mousefocusout;
|
||||
|
||||
#ifdef ENABLED_WRAPORJUSTIFY
|
||||
ssize_t fill = -COLUMNS_FROM_EOL;
|
||||
@ -266,9 +267,12 @@ char *startup_problem = NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_NANORC
|
||||
char *custom_nanorc = NULL;
|
||||
/* The argument of the --rcfile option, when given. */
|
||||
|
||||
char *commandname = NULL;
|
||||
/* The name (of a function) between braces in a string bind. */
|
||||
keystruct *planted_shortcut = NULL;
|
||||
/* The function that the above name resolves to, if any. */
|
||||
#endif
|
||||
|
||||
bool spotlighted = FALSE;
|
||||
@ -464,7 +468,7 @@ const keystruct *get_shortcut(const int keycode)
|
||||
return NULL;
|
||||
#endif
|
||||
#ifdef ENABLE_NANORC
|
||||
if (keycode == PLANTED_COMMAND)
|
||||
if (keycode == PLANTED_A_COMMAND)
|
||||
return planted_shortcut;
|
||||
#endif
|
||||
|
||||
@ -642,6 +646,9 @@ void shortcut_init(void)
|
||||
const char *savefile_gist = N_("Save file without prompting");
|
||||
const char *findprev_gist = N_("Search next occurrence backward");
|
||||
const char *findnext_gist = N_("Search next occurrence forward");
|
||||
#ifdef ENABLE_FOLDING
|
||||
const char *fold_gist = N_("Fold/unfold the currently selected lines");
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
const char *recordmacro_gist = N_("Start/stop recording a macro");
|
||||
const char *runmacro_gist = N_("Run the last recorded macro");
|
||||
@ -978,7 +985,10 @@ void shortcut_init(void)
|
||||
add_to_funcs(do_verbatim_input, MMAIN,
|
||||
N_("Verbatim"), WHENHELP(verbatim_gist), BLANKAFTER);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
#ifdef NANO_TINY
|
||||
add_to_funcs(do_search_backward, MMAIN,
|
||||
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
|
||||
#else
|
||||
add_to_funcs(do_indent, MMAIN,
|
||||
N_("Indent"), WHENHELP(indent_gist), TOGETHER);
|
||||
add_to_funcs(do_unindent, MMAIN,
|
||||
@ -998,7 +1008,14 @@ void shortcut_init(void)
|
||||
N_("Record"), WHENHELP(recordmacro_gist), TOGETHER);
|
||||
add_to_funcs(run_macro, MMAIN,
|
||||
N_("Run Macro"), WHENHELP(runmacro_gist), BLANKAFTER);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
add_to_funcs(do_fold_segment, MMAIN, N_("Fold"),
|
||||
WHENHELP(fold_gist), BLANKAFTER);
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
add_to_funcs(zap_text, MMAIN,
|
||||
/* TRANSLATORS: This refers to deleting a line or marked region. */
|
||||
N_("Zap"), WHENHELP(zap_gist), BLANKAFTER);
|
||||
@ -1010,29 +1027,27 @@ void shortcut_init(void)
|
||||
add_to_funcs(to_next_anchor, MMAIN,
|
||||
N_("Down to anchor"), WHENHELP(nextanchor_gist), BLANKAFTER);
|
||||
|
||||
if (!ISSET(RESTRICTED)) {
|
||||
#ifdef ENABLE_SPELLER
|
||||
add_to_funcs(do_spell, MMAIN,
|
||||
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
|
||||
add_to_funcs(do_spell, MMAIN,
|
||||
N_("Spell Check"), WHENHELP(spell_gist), TOGETHER);
|
||||
#endif
|
||||
#ifdef ENABLE_LINTER
|
||||
add_to_funcs(do_linter, MMAIN,
|
||||
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
|
||||
add_to_funcs(do_linter, MMAIN,
|
||||
N_("Linter"), WHENHELP(lint_gist), TOGETHER);
|
||||
#endif
|
||||
#ifdef ENABLE_FORMATTER
|
||||
add_to_funcs(do_formatter, MMAIN,
|
||||
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
|
||||
add_to_funcs(do_formatter, MMAIN,
|
||||
N_("Formatter"), WHENHELP(formatter_gist), BLANKAFTER);
|
||||
#endif
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
/* Although not allowed in restricted mode, keep execution rebindable. */
|
||||
if (ISSET(RESTRICTED))
|
||||
add_to_funcs(do_execute, MMAIN,
|
||||
N_("Execute"), WHENHELP(execute_gist), TOGETHER);
|
||||
|
||||
#ifdef NANO_TINY
|
||||
add_to_funcs(do_search_backward, MMAIN,
|
||||
N_("Where Was"), WHENHELP(wherewas_gist), BLANKAFTER);
|
||||
#else
|
||||
add_to_funcs(do_suspend, MMAIN,
|
||||
N_("Suspend"), WHENHELP(suspend_gist), TOGETHER);
|
||||
#endif
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
#ifdef ENABLE_HELP
|
||||
add_to_funcs(full_refresh, MMAIN,
|
||||
N_("Refresh"), WHENHELP(refresh_gist), TOGETHER);
|
||||
@ -1103,16 +1118,15 @@ void shortcut_init(void)
|
||||
N_("No Conversion"), WHENHELP(convert_gist), BLANKAFTER);
|
||||
|
||||
/* Command execution is only available when not in restricted mode. */
|
||||
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE)) {
|
||||
if (!ISSET(RESTRICTED) && !ISSET(VIEW_MODE))
|
||||
add_to_funcs(flip_execute, MINSERTFILE,
|
||||
N_("Execute Command"), WHENHELP(execute_gist), BLANKAFTER);
|
||||
|
||||
add_to_funcs(cut_till_eof, MEXECUTE,
|
||||
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
|
||||
add_to_funcs(cut_till_eof, MEXECUTE,
|
||||
N_("Cut Till End"), WHENHELP(cuttilleof_gist), BLANKAFTER);
|
||||
|
||||
add_to_funcs(do_suspend, MEXECUTE,
|
||||
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
|
||||
}
|
||||
add_to_funcs(do_suspend, MEXECUTE,
|
||||
N_("Suspend"), WHENHELP(suspend_gist), BLANKAFTER);
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
#ifdef ENABLE_BROWSER
|
||||
@ -1208,6 +1222,9 @@ void shortcut_init(void)
|
||||
#ifdef ENABLE_FORMATTER
|
||||
add_to_sclist(MMAIN, "M-F", 0, do_formatter, 0);
|
||||
add_to_sclist(MEXECUTE, "^O", 0, do_formatter, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
add_to_sclist(MMAIN, "M-[", 0, do_fold_segment, 0);
|
||||
#endif
|
||||
add_to_sclist(MMAIN, "^C", 0, report_cursor_position, 0);
|
||||
add_to_sclist(MMAIN, SLASH_OR_DASH, 0, do_gotolinecolumn, 0);
|
||||
@ -1341,10 +1358,10 @@ void shortcut_init(void)
|
||||
add_to_sclist(MMAIN|MHELP, "M-=", 0, do_scroll_down, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-<", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-,", 0, switch_to_prev_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M->", 0, switch_to_next_buffer, 0);
|
||||
add_to_sclist(MMAIN, "M-.", 0, switch_to_next_buffer, 0);
|
||||
#endif
|
||||
add_to_sclist(MMOST, "M-V", 0, do_verbatim_input, 0);
|
||||
#ifndef NANO_TINY
|
||||
@ -1462,24 +1479,22 @@ void shortcut_init(void)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
|
||||
#ifdef ENABLE_BROWSER
|
||||
/* Only when not in restricted mode, allow entering the file browser. */
|
||||
if (!ISSET(RESTRICTED))
|
||||
add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", 0, to_files, 0);
|
||||
#endif
|
||||
add_to_sclist(MBROWSER|MHELP, "^C", 0, do_exit, 0);
|
||||
/* Allow exiting from the file browser and the help viewer with
|
||||
* the same key as they were entered. */
|
||||
#ifdef ENABLE_BROWSER
|
||||
/* Allow exiting the file browser with the same key as used for entry. */
|
||||
add_to_sclist(MBROWSER, "^T", 0, do_exit, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_HELP
|
||||
/* Allow exiting the help viewer with the same keys as used for entry. */
|
||||
add_to_sclist(MHELP, "^G", 0, do_exit, 0);
|
||||
add_to_sclist(MHELP, "F1", KEY_F(1), do_exit, 0);
|
||||
add_to_sclist(MHELP, "Home", KEY_HOME, to_first_line, 0);
|
||||
add_to_sclist(MHELP, "End", KEY_END, to_last_line, 0);
|
||||
#endif
|
||||
#ifdef ENABLE_COLOR
|
||||
#ifdef ENABLE_LINTER
|
||||
add_to_sclist(MLINTER, "^X", 0, do_cancel, 0);
|
||||
#endif
|
||||
add_to_sclist(MMOST & ~MFINDINHELP, "F1", KEY_F(1), do_help, 0);
|
||||
|
||||
119
src/move.c
119
src/move.c
@ -37,7 +37,13 @@ void to_first_line(void)
|
||||
void to_last_line(void)
|
||||
{
|
||||
openfile->current = openfile->filebot;
|
||||
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current = get_start_of_folded_segment(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
} else
|
||||
#endif
|
||||
openfile->current_x = (inhelp) ? 0 : strlen(openfile->filebot->data);
|
||||
openfile->placewewant = xplustabs();
|
||||
|
||||
/* Set the last line of the screen as the target for the cursor. */
|
||||
@ -112,6 +118,15 @@ void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
|
||||
openfile->placewewant = *leftedge + target;
|
||||
}
|
||||
|
||||
/* Move the cursor position on the current line to the desired column */
|
||||
void move_cursor_to_proper_column(void)
|
||||
{
|
||||
size_t leftedge;
|
||||
size_t target_column;
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
set_proper_index_and_pww(&leftedge, target_column, TRUE);
|
||||
}
|
||||
|
||||
/* Move up almost one screenful. */
|
||||
void do_page_up(void)
|
||||
{
|
||||
@ -235,19 +250,28 @@ void to_para_end(void)
|
||||
void to_prev_block(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
linestruct *line_step = get_prev_visible_line(openfile->current);
|
||||
bool is_text = FALSE, seen_text = FALSE;
|
||||
|
||||
/* Skip backward until first blank line after some nonblank line(s). */
|
||||
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
|
||||
openfile->current = openfile->current->prev;
|
||||
while (line_step != NULL && (!seen_text || is_text)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_prev_visible_line(line_step);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
continue;
|
||||
#endif
|
||||
is_text = !white_string(openfile->current->data);
|
||||
seen_text = seen_text || is_text;
|
||||
}
|
||||
|
||||
/* Step forward one line again if we passed text but this line is blank. */
|
||||
if (seen_text && openfile->current->next != NULL &&
|
||||
white_string(openfile->current->data))
|
||||
openfile->current = openfile->current->next;
|
||||
line_step = get_next_visible_line(openfile->current);
|
||||
if (seen_text && line_step != NULL &&
|
||||
white_string(openfile->current->data)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_next_visible_line(line_step);
|
||||
}
|
||||
|
||||
openfile->current_x = 0;
|
||||
edit_redraw(was_current, CENTERING);
|
||||
@ -257,12 +281,18 @@ void to_prev_block(void)
|
||||
void to_next_block(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
linestruct *line_step = get_next_visible_line(openfile->current);
|
||||
bool is_white = white_string(openfile->current->data);
|
||||
bool seen_white = is_white;
|
||||
|
||||
/* Skip forward until first nonblank line after some blank line(s). */
|
||||
while (openfile->current->next != NULL && (!seen_white || is_white)) {
|
||||
openfile->current = openfile->current->next;
|
||||
while (line_step != NULL && (!seen_white || is_white)) {
|
||||
openfile->current = line_step;
|
||||
line_step = get_next_visible_line(line_step);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
continue;
|
||||
#endif
|
||||
is_white = white_string(openfile->current->data);
|
||||
seen_white = seen_white || is_white;
|
||||
}
|
||||
@ -274,19 +304,34 @@ void to_next_block(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Move to the previous word. */
|
||||
void do_prev_word(void)
|
||||
/* Move to the previous word.
|
||||
* when allow_folded as true, will move to previous word even if inside
|
||||
* a folded segment */
|
||||
void do_prev_word(bool allow_folded)
|
||||
{
|
||||
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||
bool seen_a_word = FALSE, step_forward = FALSE;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded && openfile->current->folded) {
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
#endif
|
||||
/* Move backward until we pass over the start of a word. */
|
||||
while (TRUE) {
|
||||
/* If at the head of a line, move to the end of the preceding one. */
|
||||
if (openfile->current_x == 0) {
|
||||
if (openfile->current->prev == NULL)
|
||||
break;
|
||||
openfile->current = openfile->current->prev;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded) {
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
if (openfile->current->folded)
|
||||
openfile->current = openfile->current->prev;
|
||||
} else
|
||||
#endif
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
|
||||
@ -315,11 +360,14 @@ void do_prev_word(void)
|
||||
/* Move one character forward again to sit on the start of the word. */
|
||||
openfile->current_x = step_right(openfile->current->data,
|
||||
openfile->current_x);
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
}
|
||||
|
||||
/* Move to the next word. If after_ends is TRUE, stop at the ends of words
|
||||
* instead of at their beginnings. Return TRUE if we started on a word. */
|
||||
bool do_next_word(bool after_ends)
|
||||
* instead of at their beginnings. If allow_folded is true, go to next word
|
||||
* even if it's inside a folded segment.
|
||||
* Return TRUE if we started on a word. */
|
||||
bool do_next_word(bool after_ends, bool allow_folded)
|
||||
{
|
||||
bool punctuation_as_letters = ISSET(WORD_BOUNDS);
|
||||
bool started_on_word = is_word_char(openfile->current->data +
|
||||
@ -329,6 +377,12 @@ bool do_next_word(bool after_ends)
|
||||
bool seen_word = started_on_word;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded && openfile->current->folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
#endif
|
||||
/* Move forward until we reach the start of a word. */
|
||||
while (TRUE) {
|
||||
/* If at the end of a line, move to the beginning of the next one. */
|
||||
@ -336,7 +390,17 @@ bool do_next_word(bool after_ends)
|
||||
/* When at end of file, stop. */
|
||||
if (openfile->current->next == NULL)
|
||||
break;
|
||||
openfile->current = openfile->current->next;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!allow_folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
if (openfile->current->folded) {
|
||||
/* get_next_visible_line() gives the start of a segment, so skip to the end */
|
||||
openfile->current = get_end_of_folded_segment(openfile->current);
|
||||
openfile->current = openfile->current->next;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
openfile->current = openfile->current->next;
|
||||
openfile->current_x = 0;
|
||||
seen_space = TRUE;
|
||||
} else {
|
||||
@ -376,6 +440,8 @@ bool do_next_word(bool after_ends)
|
||||
}
|
||||
}
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
return started_on_word;
|
||||
}
|
||||
|
||||
@ -384,7 +450,7 @@ void to_prev_word(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
do_prev_word();
|
||||
do_prev_word(DISALLOW_FOLDED);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
@ -395,7 +461,7 @@ void to_next_word(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
do_next_word(ISSET(AFTER_ENDS));
|
||||
do_next_word(ISSET(AFTER_ENDS), DISALLOW_FOLDED);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
@ -413,6 +479,11 @@ void do_home(void)
|
||||
size_t leftedge = 0;
|
||||
size_t left_x = 0;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
leftedge = leftedge_for(was_column, openfile->current);
|
||||
left_x = proper_x(openfile->current, &leftedge, FALSE, leftedge, NULL);
|
||||
@ -470,6 +541,11 @@ void do_end(void)
|
||||
size_t line_len = strlen(openfile->current->data);
|
||||
bool moved_off_chunk = TRUE;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
bool kickoff = TRUE;
|
||||
@ -612,7 +688,7 @@ void do_left(void)
|
||||
openfile->current_x);
|
||||
#endif
|
||||
} else if (openfile->current != openfile->filetop) {
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current = get_prev_visible_line(openfile->current);
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
|
||||
@ -624,6 +700,13 @@ void do_right(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
if (openfile->current == NULL)
|
||||
openfile->current = was_current;
|
||||
} else
|
||||
#endif
|
||||
if (openfile->current->data[openfile->current_x] != '\0') {
|
||||
openfile->current_x = step_right(openfile->current->data,
|
||||
openfile->current_x);
|
||||
@ -634,7 +717,7 @@ void do_right(void)
|
||||
openfile->current_x);
|
||||
#endif
|
||||
} else if (openfile->current != openfile->filebot) {
|
||||
openfile->current = openfile->current->next;
|
||||
openfile->current = get_next_visible_line(openfile->current);
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
|
||||
|
||||
10
src/nano.c
10
src/nano.c
@ -78,6 +78,9 @@ linestruct *make_new_node(linestruct *prevnode)
|
||||
#ifndef NANO_TINY
|
||||
newnode->has_anchor = FALSE;
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
newnode->folded = FALSE;
|
||||
#endif
|
||||
|
||||
return newnode;
|
||||
}
|
||||
@ -117,6 +120,7 @@ void delete_node(linestruct *line)
|
||||
/* Disconnect a node from a linked list of linestructs and delete it. */
|
||||
void unlink_node(linestruct *line)
|
||||
{
|
||||
UNFOLD_SEGMENT(line);
|
||||
if (line->prev != NULL)
|
||||
line->prev->next = line->next;
|
||||
if (line->next != NULL)
|
||||
@ -156,6 +160,9 @@ linestruct *copy_node(const linestruct *src)
|
||||
#ifndef NANO_TINY
|
||||
dst->has_anchor = src->has_anchor;
|
||||
#endif
|
||||
#ifdef ENABLE_FOLDING
|
||||
dst->folded = src->folded;
|
||||
#endif
|
||||
|
||||
return dst;
|
||||
}
|
||||
@ -1461,6 +1468,7 @@ void inject(char *burst, size_t count)
|
||||
#ifndef NANO_TINY
|
||||
size_t original_row = 0;
|
||||
size_t old_amount = 0;
|
||||
UNFOLD_SEGMENT(thisline);
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
if (openfile->current_y == editwinrows - 1)
|
||||
@ -2426,6 +2434,8 @@ int main(int argc, char **argv)
|
||||
shiftaltup = get_keycode("kUP4", SHIFT_ALT_UP);
|
||||
shiftaltdown = get_keycode("kDN4", SHIFT_ALT_DOWN);
|
||||
#endif
|
||||
mousefocusin = get_keycode("kxIN", FOCUS_IN);
|
||||
mousefocusout = get_keycode("kxOUT", FOCUS_OUT);
|
||||
|
||||
#ifdef HAVE_SET_ESCDELAY
|
||||
/* Tell ncurses to pass the Esc key quickly. */
|
||||
|
||||
@ -80,6 +80,7 @@ extern int altinsert, altdelete;
|
||||
extern int shiftaltleft, shiftaltright;
|
||||
extern int shiftaltup, shiftaltdown;
|
||||
#endif
|
||||
extern int mousefocusin, mousefocusout;
|
||||
|
||||
#ifdef ENABLED_WRAPORJUSTIFY
|
||||
extern ssize_t fill;
|
||||
@ -365,8 +366,8 @@ void to_para_end(void);
|
||||
#endif
|
||||
void to_prev_block(void);
|
||||
void to_next_block(void);
|
||||
void do_prev_word(void);
|
||||
bool do_next_word(bool after_ends);
|
||||
void do_prev_word(bool allow_folded);
|
||||
bool do_next_word(bool after_ends, bool allow_folded);
|
||||
void to_prev_word(void);
|
||||
void to_next_word(void);
|
||||
void do_home(void);
|
||||
@ -380,6 +381,7 @@ void do_center(void);
|
||||
#endif
|
||||
void do_left(void);
|
||||
void do_right(void);
|
||||
void move_cursor_to_proper_column(void);
|
||||
|
||||
/* Most functions in nano.c. */
|
||||
linestruct *make_new_node(linestruct *prevnode);
|
||||
@ -476,6 +478,9 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
||||
bool interactive);
|
||||
void do_gotolinecolumn(void);
|
||||
#ifndef NANO_TINY
|
||||
int find_matching_bracket_pos(linestruct **line, size_t *xpos);
|
||||
bool find_bracketed_region(linestruct *in_region,
|
||||
linestruct **top, linestruct **bot);
|
||||
void do_find_bracket(void);
|
||||
void put_or_lift_anchor(void);
|
||||
void to_prev_anchor(void);
|
||||
@ -579,6 +584,8 @@ linestruct *line_from_number(ssize_t number);
|
||||
#endif
|
||||
|
||||
/* Most functions in winio.c. */
|
||||
linestruct *get_next_visible_line(linestruct *line);
|
||||
linestruct *get_prev_visible_line(linestruct *line);
|
||||
#ifndef NANO_TINY
|
||||
void record_macro(void);
|
||||
void run_macro(void);
|
||||
@ -610,6 +617,7 @@ void warn_and_briefly_pause(const char *msg);
|
||||
void bottombars(int menu);
|
||||
void post_one_key(const char *keystroke, const char *tag, int width);
|
||||
void place_the_cursor(void);
|
||||
int update_line_at(linestruct *line, size_t index, int row);
|
||||
int update_line(linestruct *line, size_t index);
|
||||
#ifndef NANO_TINY
|
||||
int update_softwrapped_line(linestruct *line);
|
||||
@ -674,3 +682,13 @@ void flip_newbuffer(void);
|
||||
#endif
|
||||
void discard_buffer(void);
|
||||
void do_cancel(void);
|
||||
|
||||
/* Most functions in folding.c. */
|
||||
#ifdef ENABLE_FOLDING
|
||||
void do_fold_segment(void);
|
||||
void unfold_folded_segment(linestruct *line);
|
||||
void unfold_folded_segment_from(linestruct *line);
|
||||
linestruct *get_start_of_folded_segment(linestruct* line);
|
||||
linestruct *get_end_of_folded_segment(linestruct* line);
|
||||
int get_folded_segment_length(linestruct *line);
|
||||
#endif
|
||||
|
||||
16
src/rcfile.c
16
src/rcfile.c
@ -991,16 +991,22 @@ void parse_includes(char *ptr)
|
||||
}
|
||||
|
||||
/* Return the index of the color that is closest to the given RGB levels,
|
||||
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color. */
|
||||
* assuming that the terminal uses the 6x6x6 color cube of xterm-256color.
|
||||
* When red == green == blue, return an index in the xterm gray scale. */
|
||||
short closest_index_color(short red, short green, short blue)
|
||||
{
|
||||
/* Translation table, from 16 intended levels to 6 available levels. */
|
||||
/* Translation table, from 16 intended color levels to 6 available levels. */
|
||||
static const short level[] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
|
||||
|
||||
if (COLORS == 256)
|
||||
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
|
||||
else
|
||||
/* Translation table, from 14 intended gray levels to 24 available levels. */
|
||||
static const short gray[] = { 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 15, 18, 21, 23 };
|
||||
|
||||
if (COLORS != 256)
|
||||
return THE_DEFAULT;
|
||||
else if (red == green && green == blue && 0 < red && red < 0xF)
|
||||
return 232 + gray[red - 1];
|
||||
else
|
||||
return (36 * level[red] + 6 * level[green] + level[blue] + 16);
|
||||
}
|
||||
|
||||
#define COLORCOUNT 34
|
||||
|
||||
244
src/search.c
244
src/search.c
@ -308,6 +308,8 @@ int findnextstr(const char *needle, bool whole_word_only, int modus,
|
||||
}
|
||||
}
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
found_x = found - line->data;
|
||||
|
||||
nodelay(midwin, FALSE);
|
||||
@ -754,6 +756,7 @@ void goto_line_posx(ssize_t linenumber, size_t pos_x)
|
||||
|
||||
openfile->current_x = pos_x;
|
||||
openfile->placewewant = xplustabs();
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
@ -808,16 +811,25 @@ void goto_line_and_column(ssize_t line, ssize_t column, bool retain_answer,
|
||||
line = 1;
|
||||
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
recook |= perturbed;
|
||||
#ifndef NANO_TINY
|
||||
linestruct *edit_bottom = openfile->edittop;
|
||||
for (int i = 0;edit_bottom != openfile->filebot && i < editwinrows;++i)
|
||||
edit_bottom = get_next_visible_line(edit_bottom);
|
||||
if (line > edit_bottom->lineno ||
|
||||
(ISSET(SOFTWRAP) && line > openfile->current->lineno))
|
||||
#else
|
||||
if (line > openfile->edittop->lineno + editwinrows)
|
||||
#endif
|
||||
recook |= perturbed;
|
||||
#endif /* ENABLE_COLOR */
|
||||
|
||||
/* Iterate to the requested line. */
|
||||
for (openfile->current = openfile->filetop; line > 1 &&
|
||||
openfile->current != openfile->filebot; line--)
|
||||
openfile->current = openfile->current->next;
|
||||
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
|
||||
/* Take a negative column number to mean: from the end of the line. */
|
||||
if (column < 0)
|
||||
column = breadth(openfile->current->data) + column + 2;
|
||||
@ -872,23 +884,110 @@ void do_gotolinecolumn(void)
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Search backwards for a line ending with a bracket, including the current line.
|
||||
* top is an in/out parameter. The passed value is the start line for searching.
|
||||
* xpos is an out parameter. It is the position in the line where the bracket is
|
||||
* found. bracket_half is the halfway mark in the matchbrackets array. This way in
|
||||
* a loop the halfway value isn't recomputed. */
|
||||
bool find_start_of_bracketed_region(linestruct **top, size_t *xpos, size_t bracket_half)
|
||||
{
|
||||
/* Search backwards for a line ending with a bracket, including the current line */
|
||||
for (;(*top) != NULL;*top = (*top)->prev) {
|
||||
char *found;
|
||||
const char *bracket;
|
||||
int len = strlen((*top)->data);
|
||||
|
||||
/* Find the last bracket on the search line */
|
||||
found = mbrevstrpbrk((*top)->data, matchbrackets, (*top)->data + len);
|
||||
if (found == NULL)
|
||||
continue;
|
||||
|
||||
*xpos = found - (*top)->data;
|
||||
bracket = mbstrchr(matchbrackets, found);
|
||||
|
||||
/* We're looking for opening braces, not closing */
|
||||
if (bracket >= matchbrackets + bracket_half)
|
||||
continue;
|
||||
|
||||
/* Check if this is the last character in the line */
|
||||
char *next = (*top)->data + step_right((*top)->data, *xpos);
|
||||
if (*next == '\0')
|
||||
return TRUE;
|
||||
}
|
||||
*xpos = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get the halfway point in matchbrackets, where open and close
|
||||
* brackets meet. */
|
||||
size_t get_matchbrackets_halfway(void)
|
||||
{
|
||||
size_t charcount = mbstrlen(matchbrackets) / 2;
|
||||
size_t halfway = 0;
|
||||
|
||||
for (size_t i = 0;i < charcount;++i)
|
||||
halfway += char_length(matchbrackets + halfway);
|
||||
return halfway;
|
||||
}
|
||||
/* Get a region surrounding the line in_region. A region here is defined
|
||||
* as a block of text starting with an opening bracket at the end of a line,
|
||||
* and ending with a matching closing bracket.
|
||||
* top and bot are out parameters. Returns the top/bottom line of the region.
|
||||
* top_pos and bot_pos are out parameters. Returns the position within the
|
||||
* top and bottom lines where the brackets are found. */
|
||||
bool find_bracketed_region(linestruct *in_region,
|
||||
linestruct **top, linestruct **bot)
|
||||
{
|
||||
size_t bracket_half = get_matchbrackets_halfway();
|
||||
size_t top_pos;
|
||||
size_t bot_pos;
|
||||
linestruct *was_top = *top;
|
||||
linestruct *was_bot = *bot;
|
||||
*top = in_region;
|
||||
|
||||
for (;find_start_of_bracketed_region(top, &top_pos, bracket_half)
|
||||
;*top = (*top)->prev)
|
||||
{
|
||||
*bot = *top;
|
||||
bot_pos = top_pos;
|
||||
|
||||
if (!find_matching_bracket_pos(bot, &bot_pos)) {
|
||||
if ((*bot)->lineno < in_region->lineno)
|
||||
continue;
|
||||
|
||||
int linedist = (*bot)->lineno - (*top)->lineno;
|
||||
|
||||
if (linedist >= 2) {
|
||||
*top = (*top)->next;
|
||||
*bot = (*bot)->prev;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
*top = was_top;
|
||||
*bot = was_bot;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* Search, starting from the current position, for any of the two characters
|
||||
* in bracket_pair. If reverse is TRUE, search backwards, otherwise forwards.
|
||||
* Return TRUE when one of the brackets was found, and FALSE otherwise. */
|
||||
bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
bool find_a_bracket(bool reverse, const char *bracket_pair,
|
||||
linestruct **inout_line, size_t *xpos)
|
||||
{
|
||||
linestruct *line = openfile->current;
|
||||
linestruct *line = *inout_line;
|
||||
const char *pointer, *found;
|
||||
|
||||
if (reverse) {
|
||||
/* First step away from the current bracket. */
|
||||
if (openfile->current_x == 0) {
|
||||
if (*xpos == 0) {
|
||||
line = line->prev;
|
||||
if (line == NULL)
|
||||
return FALSE;
|
||||
pointer = line->data + strlen(line->data);
|
||||
} else
|
||||
pointer = line->data + step_left(line->data, openfile->current_x);
|
||||
pointer = line->data + step_left(line->data, *xpos);
|
||||
|
||||
/* Now seek for any of the two brackets we are interested in. */
|
||||
while (!(found = mbrevstrpbrk(line->data, bracket_pair, pointer))) {
|
||||
@ -898,7 +997,7 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
pointer = line->data + strlen(line->data);
|
||||
}
|
||||
} else {
|
||||
pointer = line->data + step_right(line->data, openfile->current_x);
|
||||
pointer = line->data + step_right(line->data, *xpos);
|
||||
|
||||
while (!(found = mbstrpbrk(pointer, bracket_pair))) {
|
||||
line = line->next;
|
||||
@ -908,45 +1007,24 @@ bool find_a_bracket(bool reverse, const char *bracket_pair)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the current position to the found bracket. */
|
||||
openfile->current = line;
|
||||
openfile->current_x = found - line->data;
|
||||
/* Set the found position to the found bracket. */
|
||||
*inout_line = line;
|
||||
*xpos = found - line->data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Search for a match to the bracket at the current cursor position, if
|
||||
* there is one. */
|
||||
void do_find_bracket(void)
|
||||
/* Search for the given bracket's compliment within matchbrackets.
|
||||
* ch must be a pointer to within matchbrackets.
|
||||
* reverse is true if the found compliment came before ch in matchbrackets. */
|
||||
const char *get_bracket_compliment(const char *ch, bool *reverse)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
size_t was_current_x = openfile->current_x;
|
||||
/* The current cursor position, in case we don't find a complement. */
|
||||
const char *ch;
|
||||
/* The location in matchbrackets of the bracket under the cursor. */
|
||||
int ch_len;
|
||||
/* The length of ch in bytes. */
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
int wanted_ch_len;
|
||||
/* The length of wanted_ch in bytes. */
|
||||
char bracket_pair[MAXCHARLEN * 2 + 1];
|
||||
/* The pair of characters in ch and wanted_ch. */
|
||||
size_t halfway = 0;
|
||||
/* The index in matchbrackets where the closing brackets start. */
|
||||
size_t charcount = mbstrlen(matchbrackets) / 2;
|
||||
/* Half the number of characters in matchbrackets. */
|
||||
size_t balance = 1;
|
||||
/* The initial bracket count. */
|
||||
bool reverse;
|
||||
/* The direction we search. */
|
||||
|
||||
ch = mbstrchr(matchbrackets, openfile->current->data + openfile->current_x);
|
||||
|
||||
if (ch == NULL) {
|
||||
statusline(AHEM, _("Not a bracket"));
|
||||
return;
|
||||
}
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
size_t halfway = 0;
|
||||
/* The index in matchbrackets where the closing brackets start. */
|
||||
|
||||
/* Find the halfway point in matchbrackets, where the closing ones start. */
|
||||
for (size_t i = 0; i < charcount; i++)
|
||||
@ -954,19 +1032,35 @@ void do_find_bracket(void)
|
||||
|
||||
/* When on a closing bracket, we have to search backwards for a matching
|
||||
* opening bracket; otherwise, forward for a matching closing bracket. */
|
||||
reverse = (ch >= (matchbrackets + halfway));
|
||||
*reverse = (ch >= (matchbrackets + halfway));
|
||||
|
||||
/* Step half the number of total characters either backwards or forwards
|
||||
* through matchbrackets to find the wanted complementary bracket. */
|
||||
wanted_ch = ch;
|
||||
while (charcount-- > 0) {
|
||||
if (reverse)
|
||||
if (*reverse)
|
||||
wanted_ch = matchbrackets + step_left(matchbrackets,
|
||||
wanted_ch - matchbrackets);
|
||||
else
|
||||
wanted_ch += char_length(wanted_ch);
|
||||
}
|
||||
|
||||
return wanted_ch;
|
||||
}
|
||||
|
||||
/* Create a bracket pair string from the given bracket in ch, assigning
|
||||
* the result to bracket_pair. Reverse is set to true if we need to
|
||||
* search backward for a match. */
|
||||
void create_bracket_pair(char *bracket_pair, const char *ch,
|
||||
int ch_len, bool* reverse)
|
||||
{
|
||||
const char *wanted_ch;
|
||||
/* The location in matchbrackets of the complementing bracket. */
|
||||
int wanted_ch_len;
|
||||
/* The length of wanted_ch in bytes. */
|
||||
|
||||
wanted_ch = get_bracket_compliment(ch, reverse);
|
||||
|
||||
ch_len = char_length(ch);
|
||||
wanted_ch_len = char_length(wanted_ch);
|
||||
|
||||
@ -974,24 +1068,65 @@ void do_find_bracket(void)
|
||||
strncpy(bracket_pair, ch, ch_len);
|
||||
strncpy(bracket_pair + ch_len, wanted_ch, wanted_ch_len);
|
||||
bracket_pair[ch_len + wanted_ch_len] = '\0';
|
||||
}
|
||||
|
||||
while (find_a_bracket(reverse, bracket_pair)) {
|
||||
/* Increment/decrement balance for an identical/other bracket. */
|
||||
balance += (strncmp(openfile->current->data + openfile->current_x,
|
||||
ch, ch_len) == 0) ? 1 : -1;
|
||||
/* Get the bracket match position for the character currently under the cursor.
|
||||
* If there is no bracket beneath the cursor, return NOT_A_BRACKET. If there is
|
||||
* no match found, return NOT_FOUND_BRACKET. Otherwise returns FOUND_BRACKET
|
||||
* and sets line and xpos to the found line and offset respectively. */
|
||||
int find_matching_bracket_pos(linestruct **line, size_t *xpos)
|
||||
{
|
||||
const char *br_ch;
|
||||
/* The location in matchbrackets of the bracket under the cursor. */
|
||||
int br_ch_len;
|
||||
/* The length of br_ch in bytes. */
|
||||
char bracket_pair[MAXCHARLEN * 2 + 1];
|
||||
/* The pair of characters in ch and wanted_ch. */
|
||||
size_t balance = 1;
|
||||
/* The initial bracket count. */
|
||||
bool reversed;
|
||||
/* The direction we search. */
|
||||
|
||||
/* When balance reached zero, we've found the complementary bracket. */
|
||||
if (balance == 0) {
|
||||
edit_redraw(was_current, FLOWING);
|
||||
return;
|
||||
}
|
||||
br_ch = mbstrchr(matchbrackets, (*line)->data + (*xpos));
|
||||
|
||||
if (br_ch == NULL)
|
||||
return NOT_A_BRACKET;
|
||||
|
||||
br_ch_len = char_length(br_ch);
|
||||
create_bracket_pair(bracket_pair, br_ch, br_ch_len, &reversed);
|
||||
|
||||
|
||||
while (find_a_bracket(reversed, bracket_pair, line, xpos)) {
|
||||
balance += (strncmp((*line)->data + *xpos,
|
||||
br_ch, br_ch_len) == 0) ? 1 : -1;
|
||||
if (balance == 0)
|
||||
return FOUND_BRACKET;
|
||||
|
||||
}
|
||||
return NOT_FOUND_BRACKET;
|
||||
}
|
||||
|
||||
/* Search for a match to the bracket at the current cursor position, if
|
||||
* there is one. */
|
||||
void do_find_bracket(void)
|
||||
{
|
||||
linestruct *was_current = openfile->current;
|
||||
size_t was_current_x = openfile->current_x;
|
||||
|
||||
int res = find_matching_bracket_pos(&openfile->current,
|
||||
&openfile->current_x);
|
||||
if (res == FOUND_BRACKET) {
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
edit_redraw(was_current, FLOWING);
|
||||
return;
|
||||
}
|
||||
|
||||
statusline(AHEM, _("No matching bracket"));
|
||||
|
||||
/* Restore the cursor position. */
|
||||
openfile->current = was_current;
|
||||
openfile->current_x = was_current_x;
|
||||
|
||||
statusline(AHEM, res == NOT_FOUND_BRACKET ?
|
||||
_("No matching bracket") :
|
||||
_("Not a bracket"));
|
||||
}
|
||||
|
||||
/* Place an anchor at the current line when none exists, otherwise remove it. */
|
||||
@ -1015,6 +1150,7 @@ void go_to_and_confirm(linestruct *line)
|
||||
if (line != openfile->current) {
|
||||
openfile->current = line;
|
||||
openfile->current_x = 0;
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
#ifdef ENABLE_COLOR
|
||||
if (line->lineno > openfile->edittop->lineno + editwinrows ||
|
||||
(ISSET(SOFTWRAP) && line->lineno > was_current->lineno))
|
||||
|
||||
20
src/text.c
20
src/text.c
@ -96,6 +96,8 @@ void indent_a_line(linestruct *line, char *indentation)
|
||||
if (indent_len == 0)
|
||||
return;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
/* Add the fabricated indentation to the beginning of the line. */
|
||||
line->data = nrealloc(line->data, length + indent_len + 1);
|
||||
memmove(line->data + indent_len, line->data, length + 1);
|
||||
@ -226,6 +228,8 @@ void unindent_a_line(linestruct *line, size_t indent_len)
|
||||
if (indent_len == 0)
|
||||
return;
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
/* Remove the first tab's worth of whitespace from this line. */
|
||||
memmove(line->data, line->data + indent_len, length - indent_len + 1);
|
||||
|
||||
@ -317,6 +321,8 @@ bool comment_line(undo_type action, linestruct *line, const char *comment_seq)
|
||||
/* Length of postfix. */
|
||||
size_t line_len = strlen(line->data);
|
||||
|
||||
UNFOLD_SEGMENT(line);
|
||||
|
||||
if (!ISSET(NO_NEWLINES) && line == openfile->filebot)
|
||||
return FALSE;
|
||||
|
||||
@ -416,8 +422,9 @@ void do_comment(void)
|
||||
/* 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))
|
||||
if (comment_line(action, line, comment_seq)) {
|
||||
update_multiline_undo(line->lineno, "");
|
||||
}
|
||||
|
||||
set_modified();
|
||||
ensure_firstcolumn_is_aligned();
|
||||
@ -859,6 +866,13 @@ void do_enter(void)
|
||||
{
|
||||
linestruct *newnode = make_new_node(openfile->current);
|
||||
size_t extra = 0;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
newnode->folded = TRUE;
|
||||
openfile->current->folded = FALSE;
|
||||
}
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
linestruct *sampleline = openfile->current;
|
||||
bool allblanks = FALSE;
|
||||
@ -1585,6 +1599,7 @@ void concat_paragraph(linestruct *line, size_t count)
|
||||
line->data = nrealloc(line->data,
|
||||
line_len + next_line_len - next_lead_len + 1);
|
||||
strcat(line->data, next_line->data + next_lead_len);
|
||||
UNFOLD_SEGMENT(line);
|
||||
#ifndef NANO_TINY
|
||||
line->has_anchor |= next_line->has_anchor;
|
||||
#endif
|
||||
@ -2852,6 +2867,7 @@ void do_linter(void)
|
||||
|
||||
/* Place the cursor to indicate the affected line. */
|
||||
place_the_cursor();
|
||||
UNFOLD_SEGMENT(openfile->current);
|
||||
wnoutrefresh(midwin);
|
||||
|
||||
kbinput = get_kbinput(footwin, VISIBLE);
|
||||
@ -2993,7 +3009,7 @@ void count_lines_words_and_characters(void)
|
||||
* incrementing the word count for each successful step. */
|
||||
while (openfile->current->lineno < botline->lineno ||
|
||||
(openfile->current == botline && openfile->current_x < bot_x)) {
|
||||
if (do_next_word(FALSE))
|
||||
if (do_next_word(FALSE, ALLOW_FOLDED))
|
||||
words++;
|
||||
}
|
||||
|
||||
|
||||
309
src/winio.c
309
src/winio.c
@ -140,6 +140,55 @@ void run_macro(void)
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
/* Return the current offset of target from openfile->edittop */
|
||||
int get_row_from_edittop(linestruct *target)
|
||||
{
|
||||
#ifdef ENABLE_FOLDING
|
||||
linestruct *line = openfile->edittop;
|
||||
int row = 0;
|
||||
while (line != NULL && line != target && row < editwinrows) {
|
||||
line = get_end_of_folded_segment(line);
|
||||
line = line->next;
|
||||
++row;
|
||||
}
|
||||
return row;
|
||||
#else
|
||||
return target->lineno - openfile->edittop->lineno;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the next line, taking fold segments into account */
|
||||
linestruct *get_next_visible_line(linestruct *line)
|
||||
{
|
||||
if (!line)
|
||||
return NULL;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
line = get_end_of_folded_segment(line);
|
||||
if (line == NULL)
|
||||
return NULL;
|
||||
#endif
|
||||
return line->next;
|
||||
}
|
||||
|
||||
/* Return the previous line, taking fold segments into account */
|
||||
linestruct *get_prev_visible_line(linestruct *line)
|
||||
{
|
||||
if (!line)
|
||||
return NULL;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded) {
|
||||
line = get_start_of_folded_segment(line);
|
||||
return line == NULL ? NULL : line->prev;
|
||||
}
|
||||
if (line->prev != NULL && line->prev->folded)
|
||||
return get_start_of_folded_segment(line->prev);
|
||||
|
||||
#endif
|
||||
return line->prev;
|
||||
}
|
||||
|
||||
/* Allocate the requested space for the keystroke buffer. */
|
||||
void reserve_space_for(size_t newsize)
|
||||
{
|
||||
@ -380,7 +429,7 @@ int get_code_from_plantation(void)
|
||||
if (*plants_pointer != '\0')
|
||||
put_back(MORE_PLANTS);
|
||||
|
||||
return PLANTED_COMMAND;
|
||||
return PLANTED_A_COMMAND;
|
||||
} else {
|
||||
char *opening = strchr(plants_pointer, '{');
|
||||
char firstbyte = *plants_pointer;
|
||||
@ -1245,6 +1294,10 @@ int parse_kbinput(WINDOW *frame)
|
||||
return INDENT_KEY;
|
||||
#endif
|
||||
|
||||
/* Spurious codes from VTE -- see https://sv.gnu.org/bugs/?64578. */
|
||||
if (keycode == mousefocusin || keycode == mousefocusout)
|
||||
return ERR;
|
||||
|
||||
switch (keycode) {
|
||||
case KEY_SLEFT:
|
||||
shift_held = TRUE;
|
||||
@ -2489,20 +2542,37 @@ void place_the_cursor(void)
|
||||
|
||||
/* Calculate how many rows the lines from edittop to current use. */
|
||||
while (line != NULL && line != openfile->current) {
|
||||
row += 1 + extra_chunks_in(line);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded) {
|
||||
line = get_end_of_folded_segment(line);
|
||||
++row;
|
||||
} else
|
||||
#endif
|
||||
row += 1 + extra_chunks_in(line);
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
/* Add the number of wraps in the current line before the cursor. */
|
||||
row += get_chunk_and_edge(column, openfile->current, &leftedge);
|
||||
column -= leftedge;
|
||||
} else
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (!openfile->current->folded)
|
||||
#endif
|
||||
{
|
||||
/* Add the number of wraps in the current line before the cursor. */
|
||||
row += get_chunk_and_edge(column, openfile->current, &leftedge);
|
||||
column -= leftedge;
|
||||
}
|
||||
} else
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
row = openfile->current->lineno - openfile->edittop->lineno;
|
||||
row = get_row_from_edittop(openfile->current);
|
||||
column -= get_page_start(column);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (openfile->current->folded) {
|
||||
openfile->current_x = 0;
|
||||
column = 0;
|
||||
}
|
||||
#endif
|
||||
if (row < editwinrows)
|
||||
wmove(midwin, row, margin + column);
|
||||
#ifndef NANO_TINY
|
||||
@ -2516,17 +2586,20 @@ void place_the_cursor(void)
|
||||
/* The number of bytes after which to stop painting, to avoid major slowdowns. */
|
||||
#define PAINT_LIMIT 2000
|
||||
|
||||
/* Draw the given text on the given row of the edit window. line is the
|
||||
* line to be drawn, and converted is the actual string to be written with
|
||||
* tabs and control characters replaced by strings of regular characters.
|
||||
* from_col is the column number of the first character of this "page". */
|
||||
void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
{
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
/* Draw the line number for the given line, but only if line numbering is on.
|
||||
* For folded segments, draws a '-' instead of a line number.
|
||||
* Also draws a mark indicating where anchors are set. */
|
||||
void draw_linenumber(int row, const linestruct* line, size_t from_col){
|
||||
/* If line numbering is switched on, put a line number in front of
|
||||
* the text -- but only for the parts that are not softwrapped. */
|
||||
if (margin > 0) {
|
||||
wattron(midwin, interface_color_pair[LINE_NUMBER]);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
mvwprintw(midwin, row, 0, "%*c", margin - 1, '-');
|
||||
else
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP) && from_col != 0)
|
||||
mvwprintw(midwin, row, 0, "%*s", margin - 1, " ");
|
||||
@ -2546,8 +2619,20 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
#endif
|
||||
wprintw(midwin, " ");
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* ENABLE_LINENUMBERS */
|
||||
|
||||
/* Draw the given text on the given row of the edit window. line is the
|
||||
* line to be drawn, and converted is the actual string to be written with
|
||||
* tabs and control characters replaced by strings of regular characters.
|
||||
* from_col is the column number of the first character of this "page". */
|
||||
void draw_row(int row, const char *converted, linestruct *line,
|
||||
size_t from_col)
|
||||
{
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
draw_linenumber(row, line, from_col);
|
||||
#endif
|
||||
/* First simply write the converted line -- afterward we'll add colors
|
||||
* and the marking highlight on just the pieces that need it. */
|
||||
mvwaddstr(midwin, row, margin, converted);
|
||||
@ -2801,18 +2886,50 @@ void draw_row(int row, const char *converted, linestruct *line, size_t from_col)
|
||||
#endif /* !NANO_TINY */
|
||||
}
|
||||
|
||||
/* Redraw the given line so that the character at the given index is visible
|
||||
* -- if necessary, scroll the line horizontally (when not softwrapping).
|
||||
* Return the number of rows "consumed" (relevant when softwrapping). */
|
||||
int update_line(linestruct *line, size_t index)
|
||||
#ifdef ENABLE_FOLDING
|
||||
/* Draw a folded segment at the given row. */
|
||||
int update_folded_line(linestruct *line, int row)
|
||||
{
|
||||
const int seg_len = get_folded_segment_length(line);
|
||||
const int string_len = snprintf(NULL, 0, "%d lines folded", seg_len);
|
||||
const int fill_length = (editwincols > string_len) ?
|
||||
(editwincols - string_len) : 0;
|
||||
const int half_fill = fill_length / 2;
|
||||
|
||||
char *string = nmalloc(editwincols + 1);
|
||||
|
||||
memset(string, '-', half_fill);
|
||||
snprintf(string+half_fill, editwincols, "%d lines folded", seg_len);
|
||||
memset(string+half_fill+string_len, '-', fill_length - half_fill);
|
||||
string[editwincols] = '\0';
|
||||
|
||||
#ifdef ENABLE_LINENUMBERS
|
||||
draw_linenumber(row, line, 0);
|
||||
#endif
|
||||
|
||||
mvwaddstr(midwin, row, margin, string);
|
||||
|
||||
free(string);
|
||||
return 1;
|
||||
}
|
||||
#endif /* ENABLE_FOLDING */
|
||||
|
||||
|
||||
/* Redraw the given line at the given row so that the character at the
|
||||
* given index is visible -- if necessary, scroll the line horizontally
|
||||
* (when not softwrapping). Return the number of rows "consumed"
|
||||
* (relevant when softwrapping). */
|
||||
int update_line_at(linestruct *line, size_t index, int row)
|
||||
{
|
||||
int row;
|
||||
/* The row in the edit window we will be updating. */
|
||||
char *converted;
|
||||
/* The data of the line with tabs and control characters expanded. */
|
||||
size_t from_col;
|
||||
/* From which column a horizontally scrolled line is displayed. */
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
return update_folded_line(line, row);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP))
|
||||
return update_softwrapped_line(line);
|
||||
@ -2820,7 +2937,6 @@ int update_line(linestruct *line, size_t index)
|
||||
sequel_column = 0;
|
||||
#endif
|
||||
|
||||
row = line->lineno - openfile->edittop->lineno;
|
||||
from_col = get_page_start(wideness(line->data, index));
|
||||
|
||||
/* Expand the piece to be drawn to its representable form, and draw it. */
|
||||
@ -2843,6 +2959,15 @@ int update_line(linestruct *line, size_t index)
|
||||
spotlight(light_from_col, light_to_col);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Redraw the given line so that the character at the given index is visible
|
||||
* -- if necessary, scroll the line horizontally (when not softwrapping).
|
||||
* Return the number of rows "consumed" (relevant when softwrapping). */
|
||||
int update_line(linestruct *line, size_t index)
|
||||
{
|
||||
return update_line_at(line, index, get_row_from_edittop(line));
|
||||
}
|
||||
|
||||
#ifndef NANO_TINY
|
||||
@ -2875,8 +3000,13 @@ int update_softwrapped_line(linestruct *line)
|
||||
|
||||
/* Find out on which screen row the target line should be shown. */
|
||||
while (someline != line && someline != NULL) {
|
||||
row += 1 + extra_chunks_in(someline);
|
||||
someline = someline->next;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (someline->folded)
|
||||
++row;
|
||||
else
|
||||
#endif
|
||||
row += 1 + extra_chunks_in(someline);
|
||||
someline = get_next_visible_line(someline);
|
||||
}
|
||||
|
||||
/* If the first chunk is offscreen, don't even try to display it. */
|
||||
@ -2888,6 +3018,11 @@ int update_softwrapped_line(linestruct *line)
|
||||
|
||||
starting_row = row;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
return update_folded_line(line, row);
|
||||
#endif
|
||||
|
||||
while (!end_of_line && row < editwinrows) {
|
||||
to_col = get_softwrap_breakpoint(line->data, from_col, &kickoff, &end_of_line);
|
||||
|
||||
@ -2934,7 +3069,14 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
/* Recede through the requested number of chunks. */
|
||||
for (i = nrows; i > 0; i--) {
|
||||
size_t chunk = chunk_for(*leftedge, *line);
|
||||
size_t chunk;
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded)
|
||||
chunk = 0;
|
||||
else
|
||||
#endif
|
||||
chunk = chunk_for(*leftedge, *line);
|
||||
|
||||
*leftedge = 0;
|
||||
|
||||
@ -2945,16 +3087,25 @@ int go_back_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
break;
|
||||
|
||||
i -= chunk;
|
||||
*line = (*line)->prev;
|
||||
*line = get_prev_visible_line(*line);
|
||||
*leftedge = HIGHEST_POSITIVE;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded)
|
||||
*leftedge = 0;
|
||||
else
|
||||
#endif
|
||||
if (*leftedge == HIGHEST_POSITIVE)
|
||||
*leftedge = leftedge_for(*leftedge, *line);
|
||||
} else
|
||||
#endif
|
||||
for (i = nrows; i > 0 && (*line)->prev != NULL; i--)
|
||||
*line = (*line)->prev;
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
linestruct *prev = get_prev_visible_line(*line);
|
||||
for (i = nrows; i > 0 && prev != NULL; i--) {
|
||||
*line = prev;
|
||||
prev = get_prev_visible_line(prev);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -2974,6 +3125,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
|
||||
/* Advance through the requested number of chunks. */
|
||||
for (i = nrows; i > 0; i--) {
|
||||
#ifdef ENABLE_FOLDING
|
||||
if ((*line)->folded) {
|
||||
*line = get_next_visible_line(*line);
|
||||
current_leftedge = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool end_of_line = FALSE;
|
||||
|
||||
current_leftedge = get_softwrap_breakpoint((*line)->data,
|
||||
@ -2994,9 +3153,14 @@ int go_forward_chunks(int nrows, linestruct **line, size_t *leftedge)
|
||||
if (i < nrows)
|
||||
*leftedge = current_leftedge;
|
||||
} else
|
||||
#endif
|
||||
for (i = nrows; i > 0 && (*line)->next != NULL; i--)
|
||||
*line = (*line)->next;
|
||||
#endif /* !NANO_TINY */
|
||||
{
|
||||
linestruct *next = get_next_visible_line(*line);
|
||||
for (i = nrows; i > 0 && next != NULL; i--) {
|
||||
*line = next;
|
||||
next = get_next_visible_line(*line);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -3023,20 +3187,47 @@ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge)
|
||||
/* Draw a scroll bar on the righthand side of the screen. */
|
||||
void draw_scrollbar(void)
|
||||
{
|
||||
int fromline = openfile->edittop->lineno - 1;
|
||||
int totallines = openfile->filebot->lineno;
|
||||
int coveredlines = editwinrows;
|
||||
int fromline = openfile->edittop->lineno - 1;
|
||||
int coveredlines = 0;
|
||||
linestruct *line = openfile->edittop;
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
linestruct *line = openfile->edittop;
|
||||
int extras = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
|
||||
|
||||
while (line->lineno + extras < fromline + editwinrows && line->next) {
|
||||
line = line->next;
|
||||
extras += extra_chunks_in(line);
|
||||
int i = 0;
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i = extra_chunks_in(line) - chunk_for(openfile->firstcolumn, line);
|
||||
coveredlines = i;
|
||||
}
|
||||
|
||||
coveredlines = line->lineno - fromline;
|
||||
for (;i < editwinrows && line->next != NULL;++i) {
|
||||
line = get_next_visible_line(line);
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
i += extra_chunks_in(line);
|
||||
++coveredlines;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ENABLE_FOLDING
|
||||
for (int i = 0;i < editwinrows && line->next != NULL;++i) {
|
||||
if (line->folded)
|
||||
coveredlines += get_folded_segment_length(line);
|
||||
else
|
||||
++coveredlines;
|
||||
line = get_next_visible_line(line);
|
||||
}
|
||||
#else
|
||||
coveredlines = editwinrows;
|
||||
#endif /* ENABLE_FOLDING */
|
||||
}
|
||||
|
||||
int lowest = (fromline * editwinrows) / totallines;
|
||||
@ -3089,7 +3280,12 @@ void edit_scroll(bool direction)
|
||||
if (thebar)
|
||||
draw_scrollbar();
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
#ifdef ENABLE_FOLDING
|
||||
if (ISSET(SOFTWRAP) && !line->folded)
|
||||
#else
|
||||
if (ISSET(SOFTWRAP))
|
||||
#endif
|
||||
{
|
||||
/* Compensate for the earlier chunks of a softwrapped line. */
|
||||
nrows += chunk_for(leftedge, line);
|
||||
|
||||
@ -3101,10 +3297,11 @@ void edit_scroll(bool direction)
|
||||
|
||||
/* Draw new content on the blank row (and on the bordering row too
|
||||
* when it was deemed necessary). */
|
||||
int row = get_row_from_edittop(line);
|
||||
while (nrows > 0 && line != NULL) {
|
||||
nrows -= update_line(line, (line == openfile->current) ?
|
||||
openfile->current_x : 0);
|
||||
line = line->next;
|
||||
nrows -= update_line_at(line, (line == openfile->current) ?
|
||||
openfile->current_x : 0, row++);
|
||||
line = get_next_visible_line(line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3301,8 +3498,7 @@ bool current_is_below_screen(void)
|
||||
leftedge < leftedge_for(xplustabs(), openfile->current))));
|
||||
} else
|
||||
#endif
|
||||
return (openfile->current->lineno >=
|
||||
openfile->edittop->lineno + editwinrows - SHIM);
|
||||
return (get_row_from_edittop(openfile->current) >= editwinrows - SHIM);
|
||||
}
|
||||
|
||||
/* Return TRUE if current[current_x] is outside the viewport. */
|
||||
@ -3330,12 +3526,17 @@ void edit_redraw(linestruct *old_current, update_type manner)
|
||||
/* If the mark is on, update all lines between old_current and current. */
|
||||
if (openfile->mark) {
|
||||
linestruct *line = old_current;
|
||||
|
||||
int row = get_row_from_edittop(line);
|
||||
while (line != openfile->current) {
|
||||
update_line(line, 0);
|
||||
update_line_at(line, 0, row);
|
||||
|
||||
line = (line->lineno > openfile->current->lineno) ?
|
||||
line->prev : line->next;
|
||||
if (line->lineno > openfile->current->lineno) {
|
||||
line = get_prev_visible_line(line);
|
||||
--row;
|
||||
} else {
|
||||
line = get_next_visible_line(line);
|
||||
++row;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
@ -3390,9 +3591,13 @@ void edit_refresh(void)
|
||||
|
||||
while (row < editwinrows && line != NULL) {
|
||||
if (line == openfile->current)
|
||||
row += update_line(line, openfile->current_x);
|
||||
row += update_line_at(line, openfile->current_x, row);
|
||||
else
|
||||
row += update_line(line, 0);
|
||||
row += update_line_at(line, 0, row);
|
||||
|
||||
#ifdef ENABLE_FOLDING
|
||||
line = get_end_of_folded_segment(line);
|
||||
#endif
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user