Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
758b4e66db | ||
|
|
a09eedf0a3 | ||
|
|
1a7ceb8774 | ||
|
|
69fcb001ea | ||
|
|
59451da3ac | ||
|
|
a850bb2513 | ||
|
|
047cf9be9c | ||
|
|
97896d30f1 | ||
|
|
fc367a32eb | ||
|
|
5e10528759 | ||
|
|
243380c4a2 | ||
|
|
49fb755cfc | ||
|
|
24a64d37dd | ||
|
|
a56a881c4b | ||
|
|
633343de24 | ||
|
|
5fcda555ea | ||
|
|
873f99d96a | ||
|
|
b38b020d18 | ||
|
|
54a92614b2 | ||
|
|
86e71fa09d | ||
|
|
5237a42d65 | ||
|
|
46ccc9ba6a | ||
|
|
e09dbf18b1 | ||
|
|
f08d169aa1 | ||
|
|
cf14ee2ef3 | ||
|
|
8555820afc | ||
|
|
e7bdfebdf4 | ||
|
|
4bbbb1859b | ||
|
|
6645351bfc | ||
|
|
a5981ab043 | ||
|
|
807f5c2e69 | ||
|
|
1b2a091de9 | ||
|
|
bd770ea2e7 | ||
|
|
c3de3ece32 | ||
|
|
8b86af3fef | ||
|
|
21a5978027 | ||
|
|
b4fd08fa5e | ||
|
|
252dc138a2 | ||
|
|
de57d8b722 | ||
|
|
dbbe267d71 | ||
|
|
eed0090e32 | ||
|
|
52e2e52db3 | ||
|
|
3f0e42c13b | ||
|
|
d8e5799e84 | ||
|
|
0f4716e168 | ||
|
|
749b1b3d79 | ||
|
|
566a2daf12 | ||
|
|
9f6c3a6269 | ||
|
|
6273768797 | ||
|
|
4562401505 | ||
|
|
1cc030f7c1 | ||
|
|
65d1655134 | ||
|
|
8e779b6e85 | ||
|
|
3ab943c49a | ||
|
|
ec20e3a7a8 | ||
|
|
dd88842d5a | ||
|
|
751e7f0fbe | ||
|
|
ee3254b614 | ||
|
|
938aa63dfa | ||
|
|
06ffcfaf40 | ||
|
|
f2317cc64e | ||
|
|
b281fd7a9d | ||
|
|
7e334c95cb | ||
|
|
11072ed587 | ||
|
|
67915f5dae | ||
|
|
884d410d9d | ||
|
|
1c1cbae6bc | ||
|
|
276ab2c85e | ||
|
|
80686bb525 | ||
|
|
969e99bc85 | ||
|
|
94b484ea97 | ||
|
|
ac2c81fad1 | ||
|
|
829a1a5050 | ||
|
|
5dcf375f33 | ||
|
|
50379cc4ff | ||
|
|
e2d3ee2364 | ||
|
|
beae2da10d | ||
|
|
79c836b11b | ||
|
|
c24432edc4 | ||
|
|
85bffcfeb9 | ||
|
|
381a386b01 | ||
|
|
6f9bb53b2d |
91
ChangeLog
91
ChangeLog
@@ -1,3 +1,94 @@
|
||||
Changes between v2.8.6 and v2.8.7:
|
||||
----------------------------------
|
||||
|
||||
Benno Schulenberg (54):
|
||||
bindings: hard-bind Alt+Up and Alt+Down to findprevious and findnext
|
||||
browser: correct the inverted search behavior for Alt+Up/Alt+Down
|
||||
bump version numbers and add a news item for the 2.8.7 release
|
||||
display: catch all cases where the cursor can be pushed offscreen
|
||||
display: don't doubly show tabs that cross a chunk boundary
|
||||
files: do not silently ignore an invalid backup directory, but die
|
||||
files: don't close a file descriptor when opening failed [coverity scan]
|
||||
files: don't try to open a negative file descriptor [coverity scan]
|
||||
gnulib: update to its current upstream state
|
||||
linting: don't try to put the cursor at a negative x position
|
||||
linting: skip the introductory message produced by 'gcc -fshow-column'
|
||||
mouse: one click of the wheel should move three lines, not three pages
|
||||
moving: don't push x forward when backward movement lands on a split tab
|
||||
moving: get <Up> unstuck when trying to pass over a sprawling tab
|
||||
moving: improve retention of the target column somewhat
|
||||
moving: the current chunk is always 0 when not in softwrap mode
|
||||
moving: use the correct formula for pushing the index forward
|
||||
rcfile: don't leak a shortcut when something goes wrong [coverity scan]
|
||||
softwrap: properly move up and down over tabs that are split over rows
|
||||
syntax: c: give labels some color too
|
||||
syntax: html: don't bother coloring tags that cross line boundaries
|
||||
syntax: python: don't require a character after an opening triple quote
|
||||
text: properly unindent lines that consist of only whitespace
|
||||
tweaks: a comma does not end a sentence, and is not part of a variable
|
||||
tweaks: adjust the indentation after the previous change
|
||||
tweaks: adjust the indentation after the previous change
|
||||
tweaks: adjust the indentation after the previous change
|
||||
tweaks: allow enough space for the Y/N/A characters [coverity scan]
|
||||
tweaks: avoid trying to stat a file that might be NULL [coverity scan]
|
||||
tweaks: close a file also in the error path [coverity scan]
|
||||
tweaks: condense or improve some comments
|
||||
tweaks: condense some logic, to elide a variable and a comment
|
||||
tweaks: do not leak the indentation when all lines are empty
|
||||
tweaks: don't close a descriptor when its stream has already been closed
|
||||
tweaks: drop some debugging stuff
|
||||
tweaks: drop some debugging stuff, and frob two comments
|
||||
tweaks: elide an unneeded pointer
|
||||
tweaks: elide the global variable 'full_operating_dir'
|
||||
tweaks: fix compilation with --enable-{tiny,help,multibuffer}
|
||||
tweaks: group all movement routines in corresponding pairs
|
||||
tweaks: keep the const qualifier of the syntax name [coverity scan]
|
||||
tweaks: remove includes that appear to be superfluous
|
||||
tweaks: rename a function, to let it make more sense
|
||||
tweaks: rename a label, to better match its task
|
||||
tweaks: renumber the special key codes, to be in sequence and grouped
|
||||
tweaks: reshuffle code and frob comments, to reduce the number of lines
|
||||
tweaks: reshuffle some code to harmonize two related functions
|
||||
tweaks: reshuffle some declarations and trim a few comments
|
||||
tweaks: restore an include that is necessary on some platforms
|
||||
tweaks: show "where is next" in the help lines of the file browser
|
||||
tweaks: simply set the proper scrolling mode, instead of imitating it
|
||||
tweaks: snip a superfluous clearing of the bottom bars after help
|
||||
tweaks: sort the includes, so it's a little easier to see what is there
|
||||
tweaks: specify more directly in what manner to move the viewport
|
||||
|
||||
David Lawrence Ramsey (23):
|
||||
browser: allow backward/forward re-searches with Alt+Up/Alt+Down
|
||||
display: constrain line numbers on softwrapped lines with sprawling tabs
|
||||
display: do show the visible character for a tab when it starts a row
|
||||
display: revamp how screen updates are done in the movement code
|
||||
moving: redraw not just the new current line but also the prior one
|
||||
small addition: allow customizing the color of selected text
|
||||
softwrap: correctly move vertically through overwide tabs
|
||||
softwrap: don't push a straddling tab to the next chunk
|
||||
softwrap: improve left/right navigation across line boundaries
|
||||
softwrap: make sure char_len is set when a tab is wider than a chunk
|
||||
softwrap: properly update the viewport when adding text at firstcolumn
|
||||
text: make indenting add to the beginning of the line
|
||||
text: make unindenting remove from the beginning of the line
|
||||
tweaks: adjust spacing and wording in sample.nanorc
|
||||
tweaks: correct a comment typo and an indentation error
|
||||
tweaks: harmonize some prototypes with their functions
|
||||
tweaks: remove unneeded parentheses and blank line and braces
|
||||
tweaks: replace a misplaced tab with a space
|
||||
tweaks: set the target row for smooth scrolling more directly
|
||||
tweaks: use charalloc() instead of (char *)nmalloc() * sizeof(char)
|
||||
weeding: drop the forreal parameter from place_the_cursor()
|
||||
weeding: remove redundant casts of nmalloc()
|
||||
weeding: remove the unused be_clever parameter from do_home()/do_end()
|
||||
|
||||
Rishabh Dave (1):
|
||||
new feature: allow pasting at all input prompts
|
||||
|
||||
Urja Rannikko (1):
|
||||
bindings: hard-bind Alt+Left and Alt+Right to buffer switching
|
||||
|
||||
|
||||
Changes between v2.8.5 and v2.8.6:
|
||||
----------------------------------
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ Improvements in GNU nano
|
||||
========================
|
||||
|
||||
Since 2.8.0:
|
||||
- Meta-Up/Meta-Down will search the previous/next occurrence.
|
||||
- ^U pastes the first line of the cutbuffer at a prompt.
|
||||
- Softwrapping can be done at whitespace (with --soft --atblanks).
|
||||
- The ^G help texts have become searchable (with ^W and M-W).
|
||||
- Ctrl+Home and Ctrl+End jump to start and end of file.
|
||||
|
||||
12
NEWS
12
NEWS
@@ -1,3 +1,13 @@
|
||||
2017.08.27 - GNU nano 2.8.7 "Fragrance" fixes a lockup when tabs are
|
||||
wider than the screen, makes indenting + unindenting
|
||||
more predictable by retaining relative indentations,
|
||||
allows pasting (^U) at a prompt, allows triple quotes
|
||||
in Python to not be followed by a character, does not
|
||||
scroll three pages on a roll of the mouse wheel, binds
|
||||
Alt+Up and Alt+Down to findprevious and findnext, and
|
||||
fixes some hard-to-describe issues with softwrapping
|
||||
and boundary-crossing tabs. Enjoy.
|
||||
|
||||
2017.07.21 - GNU nano 2.8.6 "Kekulé" offers a new feature: the ability
|
||||
to do softwrapping between words -- at whitespace --
|
||||
instead of always at the edge of the screen. This can
|
||||
@@ -307,7 +317,7 @@
|
||||
many many improvements to the core system, including
|
||||
substantial improvements to the undo/redo code, UTF-8
|
||||
handling, the configure script, and display of shortcuts
|
||||
on very wide terminals, New features include the
|
||||
on very wide terminals. New features include the
|
||||
ability to write to named pipes (--noread), as well as
|
||||
linter support (see the nanorc man page for details). Also
|
||||
included are much improved syntax highlighting code, and
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Generate configure & friends for GIT users.
|
||||
|
||||
gnulib_url="git://git.sv.gnu.org/gnulib.git"
|
||||
gnulib_hash="c7711db84f251d9e580d9fa53a070fa97ae89095"
|
||||
gnulib_hash="a1971db1d4fe4430a48475a751602f861812503e"
|
||||
|
||||
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.8.6], [nano-devel@gnu.org], [nano])
|
||||
AC_INIT([GNU nano], [2.8.7], [nano-devel@gnu.org], [nano])
|
||||
AC_CONFIG_SRCDIR([src/nano.c])
|
||||
AC_CANONICAL_HOST
|
||||
AM_INIT_AUTOMAKE([1.14])
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<h2><a name="1.3"></a>1.3. Why the name change from TIP?</h2>
|
||||
<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>
|
||||
<h2><a name="1.4"></a>1.4. What is the current version of nano?</h2>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>2.8.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>
|
||||
<blockquote><p>The current version of nano <i>should</i> be <b>2.8.7</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>
|
||||
<h2><a name="1.5"></a>1.5. I want to read the man page without having to download the program!</h2>
|
||||
<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.8.6" "July 2017"
|
||||
.TH NANO 1 "version 2.8.7" "August 2017"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
|
||||
.SH NAME
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
@smallbook
|
||||
@set EDITION 0.5
|
||||
@set VERSION 2.8.6
|
||||
@set UPDATED July 2017
|
||||
@set VERSION 2.8.7
|
||||
@set UPDATED August 2017
|
||||
|
||||
@dircategory Editors
|
||||
@direntry
|
||||
@@ -23,7 +23,7 @@
|
||||
@titlepage
|
||||
@title GNU @command{nano}
|
||||
@subtitle a small and friendly text editor
|
||||
@subtitle version 2.8.6
|
||||
@subtitle version 2.8.7
|
||||
|
||||
@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.8.6.
|
||||
This manual documents the GNU @command{nano} editor, version 2.8.7.
|
||||
|
||||
@menu
|
||||
* Introduction::
|
||||
@@ -707,9 +707,9 @@ Do backwards searches by default.
|
||||
|
||||
@item set boldtext
|
||||
Use bold instead of reverse video for the title bar, status bar, key combos,
|
||||
function tags, line numbers, and selected text. This can be overridden for
|
||||
the first five by setting the options @code{titlecolor}, @code{statuscolor},
|
||||
@code{keycolor}, @code{functioncolor}, and @code{numbercolor}.
|
||||
function tags, line numbers, and selected text. This can be overridden by
|
||||
setting the options @code{titlecolor}, @code{statuscolor}, @code{keycolor},
|
||||
@code{functioncolor}, @code{numbercolor}, and @code{selectedcolor}.
|
||||
|
||||
@item set brackets "@var{string}"
|
||||
Set the characters treated as closing brackets when justifying
|
||||
@@ -744,7 +744,7 @@ Valid names for foreground and background color are:
|
||||
@code{white}, @code{black}, @code{blue}, @code{green},
|
||||
@code{red}, @code{cyan}, @code{yellow}, and @code{magenta}.
|
||||
The name of the foreground color may be prefixed with @code{bright}.
|
||||
And either @var{fgcolor} or @var{,bgcolor} may be left out.
|
||||
And either @var{fgcolor} or ,@var{bgcolor} may be left out.
|
||||
|
||||
@item set historylog
|
||||
Enable the use of @file{~/.nano/search_history} for saving and reading
|
||||
@@ -852,6 +852,10 @@ won't work properly with this option enabled.
|
||||
@item set regexp
|
||||
Do extended regular expression searches by default.
|
||||
|
||||
@item set selectedcolor @var{fgcolor},@var{bgcolor}
|
||||
Use this color combination for selected text.
|
||||
@xref{@code{set functioncolor}} for valid color names.
|
||||
|
||||
@item set showcursor
|
||||
Put the cursor on the highlighted item in the file browser, to aid
|
||||
braille users.
|
||||
|
||||
12
doc/nanorc.5
12
doc/nanorc.5
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <http://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH NANORC 5 "version 2.8.6" "July 2017"
|
||||
.TH NANORC 5 "version 2.8.7" "August 2017"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
|
||||
.SH NAME
|
||||
@@ -79,9 +79,9 @@ Do backwards searches by default.
|
||||
.TP
|
||||
.B set boldtext
|
||||
Use bold instead of reverse video for the title bar, status bar, key combos,
|
||||
function tags, line numbers, and selected text. This can be overridden for
|
||||
the first five by setting the options \fBtitlecolor\fP, \fBstatuscolor\fP,
|
||||
\fBkeycolor\fP, \fBfunctioncolor\fP, and \fBnumbercolor\fP.
|
||||
function tags, line numbers, and selected text. This can be overridden by
|
||||
setting the options \fBtitlecolor\fP, \fBstatuscolor\fP, \fBkeycolor\fP,
|
||||
\fBfunctioncolor\fP, \fBnumbercolor\fP, and \fBselectedcolor\fP.
|
||||
.TP
|
||||
.B set brackets "\fIstring\fP"
|
||||
Set the characters treated as closing brackets when justifying
|
||||
@@ -220,6 +220,10 @@ won't work properly with this option enabled.
|
||||
.B set regexp
|
||||
Do extended regular expression searches by default.
|
||||
.TP
|
||||
.B set selectedcolor \fIfgcolor\fR,\fIbgcolor\fR
|
||||
Specify the color combination to use for selected text.
|
||||
See \fBset titlecolor\fR for more details.
|
||||
.TP
|
||||
.B set showcursor
|
||||
Put the cursor on the highlighted item in the file browser, to aid
|
||||
braille users.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" Documentation License along with this program. If not, see
|
||||
.\" <http://www.gnu.org/licenses/>.
|
||||
.\"
|
||||
.TH RNANO 1 "version 2.8.6" "July 2017"
|
||||
.TH RNANO 1 "version 2.8.7" "August 2017"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
|
||||
.SH NAME
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
# set linenumbers
|
||||
|
||||
## Enable vim-style lock-files. This is just to let a vim user know you
|
||||
## are editing a file [s]he is trying to edit and vice versa. There are
|
||||
## are editing a file [s]he is trying to edit and vice versa. There are
|
||||
## no plans to implement vim-style undo state in these files.
|
||||
# set locking
|
||||
|
||||
@@ -168,7 +168,7 @@
|
||||
# set softwrap
|
||||
|
||||
## Use this spelling checker instead of the internal one. This option
|
||||
## does not properly have a default value.
|
||||
## does not have a default value.
|
||||
# set speller "aspell -x -c"
|
||||
|
||||
## Allow nano to be suspended.
|
||||
@@ -208,12 +208,14 @@
|
||||
## These are examples; by default there are no colors.
|
||||
# set titlecolor brightwhite,blue
|
||||
# set statuscolor brightwhite,green
|
||||
# set selectedcolor brightwhite,magenta
|
||||
# set numbercolor cyan
|
||||
# set keycolor cyan
|
||||
# set functioncolor green
|
||||
## In root's .nanorc you might want to use:
|
||||
# set titlecolor brightwhite,red
|
||||
# set statuscolor brightwhite,red
|
||||
# set selectedcolor brightwhite,cyan
|
||||
# set numbercolor magenta
|
||||
# set keycolor brightmagenta
|
||||
# set functioncolor magenta
|
||||
@@ -267,11 +269,9 @@
|
||||
## Key bindings.
|
||||
## See nanorc(5) (section REBINDING KEYS) for more details on this.
|
||||
##
|
||||
## The following five functions are not bound to any key by default.
|
||||
## The following three functions are not bound to any key by default.
|
||||
## You may wish to choose different keys than the ones suggested here.
|
||||
# bind ^S savefile main
|
||||
# bind M-Q findprevious main
|
||||
# bind M-W findnext main
|
||||
# bind M-B cutwordleft main
|
||||
# bind M-N cutwordright main
|
||||
|
||||
|
||||
1076
po/nano.pot
1076
po/nano.pot
File diff suppressed because it is too large
Load Diff
1080
po/pt_BR.po
1080
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
1077
po/zh_CN.po
1077
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
1077
po/zh_TW.po
1077
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
@@ -21,11 +21,10 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef ENABLE_BROWSER
|
||||
|
||||
@@ -172,11 +171,15 @@ char *do_browser(char *path)
|
||||
say_there_is_no_help();
|
||||
#endif
|
||||
} else if (func == do_search) {
|
||||
/* Search for a filename. */
|
||||
do_filesearch();
|
||||
} else if (func == do_research) {
|
||||
/* Search for another filename. */
|
||||
do_fileresearch();
|
||||
do_fileresearch(TRUE);
|
||||
#ifndef NANO_TINY
|
||||
} else if (func == do_findprevious) {
|
||||
do_fileresearch(FALSE);
|
||||
} else if (func == do_findnext) {
|
||||
do_fileresearch(TRUE);
|
||||
#endif
|
||||
} else if (func == do_left) {
|
||||
if (selected > 0)
|
||||
selected--;
|
||||
@@ -249,11 +252,10 @@ char *do_browser(char *path)
|
||||
}
|
||||
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
if (check_operating_dir(path, FALSE)) {
|
||||
if (outside_of_confinement(path, FALSE)) {
|
||||
/* TRANSLATORS: This refers to the confining effect of the
|
||||
* option --operatingdir, not of --restricted. */
|
||||
statusline(ALERT, _("Can't go outside of %s"),
|
||||
full_operating_dir);
|
||||
statusline(ALERT, _("Can't go outside of %s"), operating_dir);
|
||||
path = mallocstrcpy(path, present_path);
|
||||
continue;
|
||||
}
|
||||
@@ -283,9 +285,8 @@ char *do_browser(char *path)
|
||||
/* Note: The selected file can be outside the operating
|
||||
* directory if it's ".." or if it's a symlink to a
|
||||
* directory outside the operating directory. */
|
||||
if (check_operating_dir(filelist[selected], FALSE)) {
|
||||
statusline(ALERT, _("Can't go outside of %s"),
|
||||
full_operating_dir);
|
||||
if (outside_of_confinement(filelist[selected], FALSE)) {
|
||||
statusline(ALERT, _("Can't go outside of %s"), operating_dir);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@@ -382,7 +383,7 @@ char *do_browse_from(const char *inpath)
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* If the resulting path isn't in the operating directory, use
|
||||
* the operating directory instead. */
|
||||
if (check_operating_dir(path, FALSE))
|
||||
if (outside_of_confinement(path, FALSE))
|
||||
path = mallocstrcpy(path, operating_dir);
|
||||
#endif
|
||||
|
||||
@@ -491,6 +492,9 @@ functionptrtype parse_browser_input(int *kbinput)
|
||||
case '/':
|
||||
return do_search;
|
||||
case 'N':
|
||||
#ifndef NANO_TINY
|
||||
return do_findprevious;
|
||||
#endif
|
||||
case 'n':
|
||||
return do_research;
|
||||
}
|
||||
@@ -539,7 +543,7 @@ void browser_refresh(void)
|
||||
/* If this is the selected item, start its highlighting, and
|
||||
* remember its location to be able to place the cursor on it. */
|
||||
if (i == selected) {
|
||||
wattron(edit, hilite_attribute);
|
||||
wattron(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
the_row = row;
|
||||
the_column = col;
|
||||
}
|
||||
@@ -611,7 +615,7 @@ void browser_refresh(void)
|
||||
|
||||
/* If this is the selected item, finish its highlighting. */
|
||||
if (i == selected)
|
||||
wattroff(edit, hilite_attribute);
|
||||
wattroff(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
|
||||
free(info);
|
||||
|
||||
@@ -700,8 +704,9 @@ int filesearch_init(void)
|
||||
return input;
|
||||
}
|
||||
|
||||
/* Look for the given needle in the list of files. */
|
||||
void findnextfile(const char *needle)
|
||||
/* Look for the given needle in the list of files. If forwards is TRUE,
|
||||
* search forward in the list; otherwise, search backward. */
|
||||
void findfile(const char *needle, bool forwards)
|
||||
{
|
||||
size_t looking_at = selected;
|
||||
/* The location in the file list of the filename we're looking at. */
|
||||
@@ -721,12 +726,16 @@ void findnextfile(const char *needle)
|
||||
/* Step through each filename in the list until a match is found or
|
||||
* we've come back to the point where we started. */
|
||||
while (TRUE) {
|
||||
/* Move to the next filename in the list, or back to the first. */
|
||||
if (looking_at < filelist_len - 1)
|
||||
looking_at++;
|
||||
else {
|
||||
looking_at = 0;
|
||||
statusbar(_("Search Wrapped"));
|
||||
if (forwards) {
|
||||
if (looking_at++ == filelist_len - 1) {
|
||||
looking_at = 0;
|
||||
statusbar(_("Search Wrapped"));
|
||||
}
|
||||
} else {
|
||||
if (looking_at-- == 0) {
|
||||
looking_at = filelist_len - 1;
|
||||
statusbar(_("Search Wrapped"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the bare filename, without the path. */
|
||||
@@ -773,16 +782,17 @@ void do_filesearch(void)
|
||||
update_history(&search_history, answer);
|
||||
#endif
|
||||
|
||||
findnextfile(answer);
|
||||
findfile(answer, TRUE);
|
||||
}
|
||||
|
||||
/* Search again for the last given filename, without prompting. */
|
||||
void do_fileresearch(void)
|
||||
/* Search again without prompting for the last given search string,
|
||||
* either forwards or backwards. */
|
||||
void do_fileresearch(bool forwards)
|
||||
{
|
||||
if (*last_search == '\0')
|
||||
statusbar(_("No current search pattern"));
|
||||
else
|
||||
findnextfile(last_search);
|
||||
findfile(last_search, forwards);
|
||||
}
|
||||
|
||||
/* Select the first file in the list. */
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef ENABLE_UTF8
|
||||
#include <wchar.h>
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_MAGIC_H
|
||||
#include <magic.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef DISABLE_COLOR
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "proto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static bool keep_cutbuffer = FALSE;
|
||||
/* Should we keep the contents of the cutbuffer? */
|
||||
@@ -291,9 +290,6 @@ void do_uncut_text(void)
|
||||
/* Mark the file as modified. */
|
||||
set_modified();
|
||||
|
||||
/* Update current_y to account for the inserted lines. */
|
||||
place_the_cursor(TRUE);
|
||||
|
||||
refresh_needed = TRUE;
|
||||
|
||||
#ifndef DISABLE_COLOR
|
||||
|
||||
293
src/files.c
293
src/files.c
@@ -21,17 +21,14 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LOCKBUFSIZE 8192
|
||||
|
||||
@@ -261,6 +258,7 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi
|
||||
if (wroteamt < lockdatalen) {
|
||||
statusline(MILD, _("Error writing lock file %s: %s"),
|
||||
lockfilename, ferror(filestream));
|
||||
fclose(filestream);
|
||||
goto free_the_data;
|
||||
}
|
||||
|
||||
@@ -434,9 +432,9 @@ bool open_buffer(const char *filename, bool undoable)
|
||||
as_an_at = FALSE;
|
||||
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
if (check_operating_dir(filename, FALSE)) {
|
||||
statusline(ALERT, _("Can't insert file from outside of %s"),
|
||||
full_operating_dir);
|
||||
if (outside_of_confinement(filename, FALSE)) {
|
||||
statusline(ALERT, _("Can't read file from outside of %s"),
|
||||
operating_dir);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
@@ -688,32 +686,30 @@ bool close_buffer(void)
|
||||
* warnings. */
|
||||
int is_file_writable(const char *filename)
|
||||
{
|
||||
struct stat fileinfo, fileinfo2;
|
||||
char *full_filename;
|
||||
struct stat fileinfo;
|
||||
int fd;
|
||||
FILE *f;
|
||||
char *full_filename;
|
||||
bool result = TRUE;
|
||||
|
||||
if (ISSET(VIEW_MODE))
|
||||
return TRUE;
|
||||
|
||||
/* Get the specified file's full path. */
|
||||
full_filename = get_full_path(filename);
|
||||
|
||||
/* Okay, if we can't stat the absolute path due to some component's
|
||||
* permissions, just try the relative one. */
|
||||
if (full_filename == NULL ||
|
||||
(stat(full_filename, &fileinfo) == -1 && stat(filename, &fileinfo2) != -1))
|
||||
/* If the absolute path is unusable, use the given relative one. */
|
||||
if (full_filename == NULL || stat(full_filename, &fileinfo) == -1)
|
||||
full_filename = mallocstrcpy(NULL, filename);
|
||||
|
||||
if ((fd = open(full_filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR |
|
||||
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1 ||
|
||||
(f = fdopen(fd, "a")) == NULL)
|
||||
S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1)
|
||||
result = FALSE;
|
||||
else
|
||||
else if ((f = fdopen(fd, "a")) == NULL) {
|
||||
result = FALSE;
|
||||
close(fd);
|
||||
} else
|
||||
fclose(f);
|
||||
|
||||
close(fd);
|
||||
free(full_filename);
|
||||
|
||||
return result;
|
||||
@@ -1188,9 +1184,6 @@ void do_insertfile(void)
|
||||
openfile->current_x != was_current_x)
|
||||
set_modified();
|
||||
|
||||
/* Update current_y to account for inserted lines. */
|
||||
place_the_cursor(TRUE);
|
||||
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
|
||||
@@ -1414,37 +1407,28 @@ char *safe_tempfile(FILE **f)
|
||||
}
|
||||
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* Initialize full_operating_dir based on operating_dir. */
|
||||
/* Change to the specified operating directory, when it's valid. */
|
||||
void init_operating_dir(void)
|
||||
{
|
||||
if (operating_dir == NULL)
|
||||
return;
|
||||
|
||||
full_operating_dir = get_full_path(operating_dir);
|
||||
operating_dir = free_and_assign(operating_dir, get_full_path(operating_dir));
|
||||
|
||||
/* If the operating directory is inaccessible, fail. */
|
||||
if (full_operating_dir == NULL || chdir(full_operating_dir) == -1)
|
||||
if (operating_dir == NULL || chdir(operating_dir) == -1)
|
||||
die(_("Invalid operating directory\n"));
|
||||
|
||||
snuggly_fit(&full_operating_dir);
|
||||
snuggly_fit(&operating_dir);
|
||||
}
|
||||
|
||||
/* Check to see if we're inside the operating directory. Return FALSE
|
||||
* if we are, or TRUE otherwise. If allow_tabcomp is TRUE, allow
|
||||
* incomplete names that would be matches for the operating directory,
|
||||
* so that tab completion will work. */
|
||||
bool check_operating_dir(const char *currpath, bool allow_tabcomp)
|
||||
/* Check whether the given path is outside of the operating directory.
|
||||
* Return TRUE if it is, and FALSE otherwise. If allow_tabcomp is TRUE,
|
||||
* incomplete names that can grow into matches for the operating directory
|
||||
* are considered to be inside, so that tab completion will work. */
|
||||
bool outside_of_confinement(const char *currpath, bool allow_tabcomp)
|
||||
{
|
||||
/* full_operating_dir is global for memory cleanup. It should have
|
||||
* already been initialized by init_operating_dir(). Also, a
|
||||
* relative operating directory path will only be handled properly
|
||||
* if this is done. */
|
||||
|
||||
char *fullpath;
|
||||
bool retval = FALSE;
|
||||
const char *whereami1, *whereami2 = NULL;
|
||||
bool is_inside, begins_to_be;
|
||||
|
||||
/* If no operating directory is set, don't bother doing anything. */
|
||||
/* If no operating directory is set, there is nothing to check. */
|
||||
if (operating_dir == NULL)
|
||||
return FALSE;
|
||||
|
||||
@@ -1455,26 +1439,17 @@ bool check_operating_dir(const char *currpath, bool allow_tabcomp)
|
||||
* is what the user typed somewhere. We don't want to report a
|
||||
* non-existent directory as being outside the operating directory,
|
||||
* so we return FALSE. If allow_tabcomp is TRUE, then currpath
|
||||
* exists, but is not executable. So we say it isn't in the
|
||||
* exists, but is not executable. So we say it is outside the
|
||||
* operating directory. */
|
||||
if (fullpath == NULL)
|
||||
return allow_tabcomp;
|
||||
|
||||
whereami1 = strstr(fullpath, full_operating_dir);
|
||||
if (allow_tabcomp)
|
||||
whereami2 = strstr(full_operating_dir, fullpath);
|
||||
|
||||
/* If both searches failed, we're outside the operating directory.
|
||||
* Otherwise, check the search results. If the full operating
|
||||
* directory path is not at the beginning of the full current path
|
||||
* (for normal usage) and vice versa (for tab completion, if we're
|
||||
* allowing it), we're outside the operating directory. */
|
||||
if (whereami1 != fullpath && whereami2 != full_operating_dir)
|
||||
retval = TRUE;
|
||||
is_inside = (strstr(fullpath, operating_dir) == fullpath);
|
||||
begins_to_be = (allow_tabcomp &&
|
||||
strstr(operating_dir, fullpath) == operating_dir);
|
||||
free(fullpath);
|
||||
|
||||
/* Otherwise, we're still inside it. */
|
||||
return retval;
|
||||
return (!is_inside && !begins_to_be);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1496,27 +1471,18 @@ int prompt_failed_backupwrite(const char *filename)
|
||||
return response;
|
||||
}
|
||||
|
||||
/* Transform the specified backup directory to an absolute path,
|
||||
* and verify that it is usable. */
|
||||
void init_backup_dir(void)
|
||||
{
|
||||
char *full_backup_dir;
|
||||
backup_dir = free_and_assign(backup_dir, get_full_path(backup_dir));
|
||||
|
||||
if (backup_dir == NULL)
|
||||
return;
|
||||
/* If we can't get an absolute path (which means it doesn't exist or
|
||||
isn't accessible), or it's not a directory, fail. */
|
||||
if (backup_dir == NULL || backup_dir[strlen(backup_dir) - 1] != '/')
|
||||
die(_("Invalid backup directory\n"));
|
||||
|
||||
full_backup_dir = get_full_path(backup_dir);
|
||||
|
||||
/* If get_full_path() failed or the backup directory is
|
||||
* inaccessible, unset backup_dir. */
|
||||
if (full_backup_dir == NULL ||
|
||||
full_backup_dir[strlen(full_backup_dir) - 1] != '/') {
|
||||
free(full_backup_dir);
|
||||
free(backup_dir);
|
||||
backup_dir = NULL;
|
||||
} else {
|
||||
free(backup_dir);
|
||||
backup_dir = full_backup_dir;
|
||||
snuggly_fit(&backup_dir);
|
||||
}
|
||||
snuggly_fit(&backup_dir);
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
@@ -1606,8 +1572,8 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* If we're writing a temporary file, we're probably going outside
|
||||
* the operating directory, so skip the operating directory test. */
|
||||
if (!tmp && check_operating_dir(realname, FALSE)) {
|
||||
statusline(ALERT, _("Can't write outside of %s"), full_operating_dir);
|
||||
if (!tmp && outside_of_confinement(realname, FALSE)) {
|
||||
statusline(ALERT, _("Can't write outside of %s"), operating_dir);
|
||||
goto cleanup_and_exit;
|
||||
}
|
||||
#endif
|
||||
@@ -1635,11 +1601,10 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
if (ISSET(BACKUP_FILE) && !tmp && realexists && openfile->current_stat &&
|
||||
(method != OVERWRITE || openfile->mark_set ||
|
||||
openfile->current_stat->st_mtime == st.st_mtime)) {
|
||||
int backup_fd;
|
||||
FILE *backup_file;
|
||||
char *backupname;
|
||||
static struct timespec filetime[2];
|
||||
int backup_cflags;
|
||||
char *backupname;
|
||||
int backup_cflags, backup_fd;
|
||||
FILE *backup_file = NULL;
|
||||
|
||||
/* Save the original file's access and modification times. */
|
||||
filetime[0].tv_sec = openfile->current_stat->st_atime;
|
||||
@@ -1653,7 +1618,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
statusline(ALERT, _("Error reading %s: %s"), realname,
|
||||
strerror(errno));
|
||||
/* If we can't read from the original file, go on, since
|
||||
* only saving the original file is better than saving
|
||||
* only saving the current buffer is better than saving
|
||||
* nothing. */
|
||||
goto skip_backup;
|
||||
}
|
||||
@@ -1667,13 +1632,10 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
if (backup_dir != NULL) {
|
||||
char *backuptemp = get_full_path(realname);
|
||||
|
||||
/* If we can't get a canonical absolute path, just use the
|
||||
* filename portion of the given path. Otherwise, replace
|
||||
* slashes with exclamation marks in the full path. */
|
||||
if (backuptemp == NULL)
|
||||
/* If get_full_path() failed, we don't have a
|
||||
* canonicalized absolute pathname, so just use the
|
||||
* filename portion of the pathname. We use tail() so
|
||||
* that e.g. ../backupname will be backed up in
|
||||
* backupdir/backupname~ instead of
|
||||
* backupdir/../backupname~. */
|
||||
backuptemp = mallocstrcpy(NULL, tail(realname));
|
||||
else {
|
||||
size_t i = 0;
|
||||
@@ -1694,10 +1656,9 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
free(backuptemp);
|
||||
free(backupname);
|
||||
/* If we can't write to the backup, DON'T go on, since
|
||||
* whatever caused the backup file to fail (e.g. disk
|
||||
* full may well cause the real file write to fail,
|
||||
* which means we could lose both the backup and the
|
||||
* original! */
|
||||
* whatever caused the backup-file write to fail (e.g.
|
||||
* disk full) may well cause the real file write to fail
|
||||
* too, which means we could lose the original! */
|
||||
goto cleanup_and_exit;
|
||||
} else {
|
||||
free(backupname);
|
||||
@@ -1727,18 +1688,14 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
|
||||
backup_fd = open(backupname, backup_cflags,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
/* Now we've got a safe file stream. If the previous open()
|
||||
* call failed, this will return NULL. */
|
||||
backup_file = fdopen(backup_fd, "wb");
|
||||
|
||||
if (backup_fd < 0 || backup_file == NULL) {
|
||||
if (backup_fd >= 0)
|
||||
backup_file = fdopen(backup_fd, "wb");
|
||||
|
||||
if (backup_file == NULL) {
|
||||
statusline(HUSH, _("Error writing backup file %s: %s"),
|
||||
backupname, strerror(errno));
|
||||
free(backupname);
|
||||
/* If we can't make a backup, DON'T go on, since whatever caused
|
||||
* the backup to fail (e.g. disk full) may well cause the real
|
||||
* file write to fail, in which case we could lose both the
|
||||
* backup and the original! */
|
||||
goto cleanup_and_exit;
|
||||
}
|
||||
|
||||
@@ -1800,8 +1757,7 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
if (f_open == NULL) {
|
||||
original_umask = umask(0);
|
||||
|
||||
/* If we create a temp file, we don't let anyone else access it.
|
||||
* We create a temp file if tmp is TRUE. */
|
||||
/* If we create a temp file, we don't let anyone else access it. */
|
||||
if (tmp)
|
||||
umask(S_IRWXG | S_IRWXO);
|
||||
else
|
||||
@@ -1972,9 +1928,9 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
/* If we must set the filename, and it changed, adjust things. */
|
||||
if (!nonamechange && strcmp(openfile->filename, realname) != 0) {
|
||||
#ifndef DISABLE_COLOR
|
||||
char *newname;
|
||||
char *oldname = openfile->syntax ? openfile->syntax->name : "";
|
||||
filestruct *line = openfile->fileage;
|
||||
const char *oldname, *newname;
|
||||
|
||||
oldname = openfile->syntax ? openfile->syntax->name : "";
|
||||
#endif
|
||||
openfile->filename = mallocstrcpy(openfile->filename, realname);
|
||||
|
||||
@@ -1987,9 +1943,12 @@ bool write_file(const char *name, FILE *f_open, bool tmp,
|
||||
|
||||
/* If the syntax changed, discard and recompute the multidata. */
|
||||
if (strcmp(oldname, newname) != 0) {
|
||||
for (; line != NULL; line = line->next) {
|
||||
filestruct *line = openfile->fileage;
|
||||
|
||||
while (line != NULL) {
|
||||
free(line->multidata);
|
||||
line->multidata = NULL;
|
||||
line = line->next;
|
||||
}
|
||||
precalc_multicolorinfo();
|
||||
refresh_needed = TRUE;
|
||||
@@ -2460,7 +2419,7 @@ char **username_tab_completion(const char *buf, size_t *num_matches,
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* ...unless the match exists outside the operating
|
||||
* directory, in which case just go to the next match. */
|
||||
if (check_operating_dir(userdata->pw_dir, TRUE))
|
||||
if (outside_of_confinement(userdata->pw_dir, TRUE))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
@@ -2546,14 +2505,12 @@ char **cwd_tab_completion(const char *buf, bool allow_files, size_t
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* ...unless the match exists outside the operating
|
||||
* directory, in which case just go to the next match. */
|
||||
if (check_operating_dir(tmp, TRUE))
|
||||
skip_match = TRUE;
|
||||
skip_match = outside_of_confinement(tmp, TRUE);
|
||||
#endif
|
||||
|
||||
/* ...or unless the match isn't a directory and allow_files
|
||||
* isn't set, in which case just go to the next match. */
|
||||
if (!allow_files && !is_dir(tmp))
|
||||
skip_match = TRUE;
|
||||
skip_match = skip_match || (!allow_files && !is_dir(tmp));
|
||||
|
||||
free(tmp);
|
||||
|
||||
@@ -2820,59 +2777,62 @@ int check_dotnano(void)
|
||||
/* Load the search and replace histories from ~/.nano/search_history. */
|
||||
void load_history(void)
|
||||
{
|
||||
char *nanohist = histfilename();
|
||||
char *searchhist = histfilename();
|
||||
char *legacyhist = legacyhistfilename();
|
||||
struct stat hstat;
|
||||
FILE *hist;
|
||||
|
||||
/* If no home directory was found, we can't do anything. */
|
||||
if (searchhist == NULL || legacyhist == NULL)
|
||||
return;
|
||||
|
||||
/* If there is an old history file, migrate it. */
|
||||
/* (To be removed in 2018.) */
|
||||
if (stat(legacyhist, &hstat) != -1 && stat(nanohist, &hstat) == -1) {
|
||||
if (rename(legacyhist, nanohist) == -1)
|
||||
if (stat(legacyhist, &hstat) != -1 && stat(searchhist, &hstat) == -1) {
|
||||
if (rename(legacyhist, searchhist) == -1)
|
||||
history_error(N_("Detected a legacy nano history file (%s) which I tried to move\n"
|
||||
"to the preferred location (%s) but encountered an error: %s"),
|
||||
legacyhist, nanohist, strerror(errno));
|
||||
legacyhist, searchhist, strerror(errno));
|
||||
else
|
||||
history_error(N_("Detected a legacy nano history file (%s) which I moved\n"
|
||||
"to the preferred location (%s)\n(see the nano FAQ about this change)"),
|
||||
legacyhist, nanohist);
|
||||
legacyhist, searchhist);
|
||||
}
|
||||
|
||||
/* Assume do_rcfile() has reported a missing home directory. */
|
||||
if (nanohist != NULL) {
|
||||
FILE *hist = fopen(nanohist, "rb");
|
||||
hist = fopen(searchhist, "rb");
|
||||
|
||||
if (hist == NULL) {
|
||||
if (errno != ENOENT) {
|
||||
/* Don't save history when we quit. */
|
||||
UNSET(HISTORYLOG);
|
||||
history_error(N_("Error reading %s: %s"), nanohist,
|
||||
if (hist == NULL) {
|
||||
if (errno != ENOENT) {
|
||||
/* When reading failed, don't save history when we quit. */
|
||||
UNSET(HISTORYLOG);
|
||||
history_error(N_("Error reading %s: %s"), searchhist,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
/* Load a history list (first the search history, then the
|
||||
* replace history) from the oldest entry to the newest.
|
||||
* Assume the last history entry is a blank line. */
|
||||
filestruct **history = &search_history;
|
||||
char *line = NULL;
|
||||
size_t buf_len = 0;
|
||||
ssize_t read;
|
||||
|
||||
while ((read = getline(&line, &buf_len, hist)) > 0) {
|
||||
line[--read] = '\0';
|
||||
if (read > 0) {
|
||||
/* Encode any embedded NUL as 0x0A. */
|
||||
unsunder(line, read);
|
||||
update_history(history, line);
|
||||
} else
|
||||
history = &replace_history;
|
||||
}
|
||||
|
||||
fclose(hist);
|
||||
free(line);
|
||||
}
|
||||
free(nanohist);
|
||||
free(legacyhist);
|
||||
} else {
|
||||
/* Load the two history lists -- first the search history, then
|
||||
* the replace history -- from the oldest entry to the newest.
|
||||
* The two lists are separated by an empty line. */
|
||||
filestruct **history = &search_history;
|
||||
char *line = NULL;
|
||||
size_t buf_len = 0;
|
||||
ssize_t read;
|
||||
|
||||
while ((read = getline(&line, &buf_len, hist)) > 0) {
|
||||
line[--read] = '\0';
|
||||
if (read > 0) {
|
||||
/* Encode any embedded NUL as 0x0A. */
|
||||
unsunder(line, read);
|
||||
update_history(history, line);
|
||||
} else
|
||||
history = &replace_history;
|
||||
}
|
||||
|
||||
fclose(hist);
|
||||
free(line);
|
||||
}
|
||||
|
||||
free(searchhist);
|
||||
free(legacyhist);
|
||||
}
|
||||
|
||||
/* Write the lines of a history list, starting with the line at head, to
|
||||
@@ -2901,35 +2861,36 @@ bool writehist(FILE *hist, const filestruct *head)
|
||||
/* Save the search and replace histories to ~/.nano/search_history. */
|
||||
void save_history(void)
|
||||
{
|
||||
char *nanohist;
|
||||
char *searchhist;
|
||||
FILE *hist;
|
||||
|
||||
/* Don't save unchanged or empty histories. */
|
||||
/* If the histories are unchanged or empty, don't bother saving them. */
|
||||
if (!history_has_changed() || (searchbot->lineno == 1 &&
|
||||
replacebot->lineno == 1))
|
||||
replacebot->lineno == 1))
|
||||
return;
|
||||
|
||||
nanohist = histfilename();
|
||||
searchhist = histfilename();
|
||||
|
||||
if (nanohist != NULL) {
|
||||
FILE *hist = fopen(nanohist, "wb");
|
||||
if (searchhist == NULL)
|
||||
return;
|
||||
|
||||
if (hist == NULL)
|
||||
fprintf(stderr, _("Error writing %s: %s\n"), nanohist,
|
||||
hist = fopen(searchhist, "wb");
|
||||
|
||||
if (hist == NULL)
|
||||
fprintf(stderr, _("Error writing %s: %s\n"), searchhist,
|
||||
strerror(errno));
|
||||
else {
|
||||
/* Make sure no one else can read from or write to the
|
||||
* history file. */
|
||||
chmod(nanohist, S_IRUSR | S_IWUSR);
|
||||
else {
|
||||
/* Don't allow others to read or write the history file. */
|
||||
chmod(searchhist, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (!writehist(hist, searchage) || !writehist(hist, replaceage))
|
||||
fprintf(stderr, _("Error writing %s: %s\n"), nanohist,
|
||||
if (!writehist(hist, searchage) || !writehist(hist, replaceage))
|
||||
fprintf(stderr, _("Error writing %s: %s\n"), searchhist,
|
||||
strerror(errno));
|
||||
|
||||
fclose(hist);
|
||||
}
|
||||
|
||||
free(nanohist);
|
||||
fclose(hist);
|
||||
}
|
||||
|
||||
free(searchhist);
|
||||
}
|
||||
|
||||
/* Save the recorded last file positions to ~/.nano/filepos_history. */
|
||||
|
||||
104
src/global.c
104
src/global.c
@@ -24,7 +24,6 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include "assert.h"
|
||||
|
||||
/* Global variables. */
|
||||
#ifndef NANO_TINY
|
||||
@@ -78,6 +77,7 @@ int controlleft, controlright, controlup, controldown, controlhome, controlend;
|
||||
#ifndef NANO_TINY
|
||||
int shiftcontrolleft, shiftcontrolright, shiftcontrolup, shiftcontroldown;
|
||||
int shiftcontrolhome, shiftcontrolend;
|
||||
int altleft, altright, altup, altdown;
|
||||
int shiftaltleft, shiftaltright, shiftaltup, shiftaltdown;
|
||||
#endif
|
||||
|
||||
@@ -166,10 +166,7 @@ const char *locking_suffix = ".swp";
|
||||
#endif
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
char *operating_dir = NULL;
|
||||
/* The relative path to the operating directory, which we can't
|
||||
* move outside of. */
|
||||
char *full_operating_dir = NULL;
|
||||
/* The full path to it. */
|
||||
/* The path to our confining "operating" directory, when given. */
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_SPELLER
|
||||
@@ -313,7 +310,7 @@ void discard_buffer(void)
|
||||
void add_to_funcs(void (*func)(void), int menus, const char *desc, const char *help,
|
||||
bool blank_after, bool viewok)
|
||||
{
|
||||
subnfunc *f = (subnfunc *)nmalloc(sizeof(subnfunc));
|
||||
subnfunc *f = nmalloc(sizeof(subnfunc));
|
||||
|
||||
if (allfuncs == NULL)
|
||||
allfuncs = f;
|
||||
@@ -344,7 +341,7 @@ void add_to_sclist(int menus, const char *scstring, const int keycode,
|
||||
#ifndef NANO_TINY
|
||||
static int counter = 0;
|
||||
#endif
|
||||
sc *s = (sc *)nmalloc(sizeof(sc));
|
||||
sc *s = nmalloc(sizeof(sc));
|
||||
|
||||
/* Start the list, or tack on the next item. */
|
||||
if (sclist == NULL)
|
||||
@@ -424,28 +421,45 @@ functionptrtype func_from_key(int *kbinput)
|
||||
void assign_keyinfo(sc *s, const char *keystring, const int keycode)
|
||||
{
|
||||
s->keystr = keystring;
|
||||
s->meta = (keystring[0] == 'M');
|
||||
s->meta = (keystring[0] == 'M' && keystring[2] != '\xE2');
|
||||
|
||||
assert(strlen(keystring) > 1 && (!s->meta || strlen(keystring) > 2));
|
||||
|
||||
if (keycode)
|
||||
s->keycode = keycode;
|
||||
else if (keystring[0] == '^') {
|
||||
else
|
||||
s->keycode = keycode_from_string(keystring);
|
||||
}
|
||||
|
||||
/* Parse the given keystring and return the corresponding keycode,
|
||||
* or return -1 when the string is invalid. */
|
||||
int keycode_from_string(const char *keystring)
|
||||
{
|
||||
if (keystring[0] == '^') {
|
||||
if (strcasecmp(keystring, "^Space") == 0)
|
||||
s->keycode = 0;
|
||||
return 0;
|
||||
if (strlen(keystring) == 2)
|
||||
return keystring[1] - 64;
|
||||
else
|
||||
s->keycode = keystring[1] - 64;
|
||||
} else if (s->meta) {
|
||||
return -1;
|
||||
} else if (keystring[0] == 'M') {
|
||||
if (strcasecmp(keystring, "M-Space") == 0)
|
||||
s->keycode = (int)' ';
|
||||
return (int)' ';
|
||||
if (keystring[1] == '-')
|
||||
return tolower((unsigned char)keystring[2]);
|
||||
else
|
||||
s->keycode = tolower((unsigned char)keystring[2]);
|
||||
} else if (keystring[0] == 'F')
|
||||
s->keycode = KEY_F0 + atoi(&keystring[1]);
|
||||
else if (!strcasecmp(keystring, "Ins"))
|
||||
s->keycode = KEY_IC;
|
||||
return -1;
|
||||
} else if (keystring[0] == 'F') {
|
||||
int fn = atoi(&keystring[1]);
|
||||
if (fn < 0 || fn > 63)
|
||||
return -1;
|
||||
return KEY_F0 + fn;
|
||||
} else if (!strcasecmp(keystring, "Ins"))
|
||||
return KEY_IC;
|
||||
else if (!strcasecmp(keystring, "Del"))
|
||||
s->keycode = KEY_DC;
|
||||
return KEY_DC;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -713,8 +727,14 @@ void shortcut_init(void)
|
||||
add_to_funcs(do_search, MBROWSER,
|
||||
whereis_tag, IFSCHELP(nano_browser_whereis_msg), TOGETHER, VIEW);
|
||||
|
||||
add_to_funcs(do_research, MBROWSER,
|
||||
whereis_next_tag, IFSCHELP(nano_whereis_next_msg), BLANKAFTER, VIEW);
|
||||
|
||||
add_to_funcs(goto_dir_void, MBROWSER,
|
||||
N_("Go To Dir"), IFSCHELP(nano_gotodir_msg), BLANKAFTER, VIEW);
|
||||
N_("Go To Dir"), IFSCHELP(nano_gotodir_msg), TOGETHER, VIEW);
|
||||
|
||||
add_to_funcs(total_refresh, MBROWSER,
|
||||
refresh_tag, IFSCHELP(nano_browser_refresh_msg), BLANKAFTER, VIEW);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_HELP
|
||||
@@ -828,9 +848,9 @@ void shortcut_init(void)
|
||||
add_to_funcs(do_next_word_void, MMAIN,
|
||||
N_("Next Word"), IFSCHELP(nano_nextword_msg), TOGETHER, VIEW);
|
||||
|
||||
add_to_funcs(do_home_void, MMAIN,
|
||||
add_to_funcs(do_home, MMAIN,
|
||||
N_("Home"), IFSCHELP(nano_home_msg), TOGETHER, VIEW);
|
||||
add_to_funcs(do_end_void, MMAIN,
|
||||
add_to_funcs(do_end, MMAIN,
|
||||
N_("End"), IFSCHELP(nano_end_msg), BLANKAFTER, VIEW);
|
||||
|
||||
add_to_funcs(do_up_void, MMAIN|MHELP|MBROWSER,
|
||||
@@ -1015,16 +1035,6 @@ void shortcut_init(void)
|
||||
N_("First File"), IFSCHELP(nano_firstfile_msg), TOGETHER, VIEW);
|
||||
add_to_funcs(do_last_file, (MBROWSER|MWHEREISFILE),
|
||||
N_("Last File"), IFSCHELP(nano_lastfile_msg), BLANKAFTER, VIEW);
|
||||
#endif
|
||||
|
||||
add_to_funcs(discard_buffer, MWRITEFILE,
|
||||
N_("Discard buffer"), IFSCHELP(nano_discard_buffer_msg), BLANKAFTER, NOVIEW);
|
||||
|
||||
#ifdef ENABLE_BROWSER
|
||||
add_to_funcs(do_research, MBROWSER,
|
||||
whereis_next_tag, IFSCHELP(nano_whereis_next_msg), TOGETHER, VIEW);
|
||||
add_to_funcs(total_refresh, MBROWSER,
|
||||
refresh_tag, IFSCHELP(nano_browser_refresh_msg), BLANKAFTER, VIEW);
|
||||
#ifndef NANO_TINY
|
||||
add_to_funcs(do_prev_word_void, MBROWSER,
|
||||
N_("Left Column"), IFSCHELP(nano_browser_lefthand_msg), TOGETHER, VIEW);
|
||||
@@ -1035,7 +1045,10 @@ void shortcut_init(void)
|
||||
add_to_funcs(do_next_block, MBROWSER,
|
||||
N_("Bottom Row"), IFSCHELP(nano_browser_bottomrow_msg), BLANKAFTER, VIEW);
|
||||
#endif
|
||||
#endif
|
||||
#endif /* ENABLE_BROWSER */
|
||||
|
||||
add_to_funcs(discard_buffer, MWRITEFILE,
|
||||
N_("Discard buffer"), IFSCHELP(nano_discard_buffer_msg), BLANKAFTER, NOVIEW);
|
||||
|
||||
#ifndef DISABLE_COLOR
|
||||
add_to_funcs(do_page_up, MLINTER,
|
||||
@@ -1063,8 +1076,8 @@ void shortcut_init(void)
|
||||
add_to_sclist(MMAIN, "F14", 0, do_replace, 0);
|
||||
add_to_sclist(MMOST, "^K", 0, do_cut_text_void, 0);
|
||||
add_to_sclist(MMOST, "F9", 0, do_cut_text_void, 0);
|
||||
add_to_sclist(MMAIN, "^U", 0, do_uncut_text, 0);
|
||||
add_to_sclist(MMAIN, "F10", 0, do_uncut_text, 0);
|
||||
add_to_sclist(MMOST, "^U", 0, do_uncut_text, 0);
|
||||
add_to_sclist(MMOST, "F10", 0, do_uncut_text, 0);
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
add_to_sclist(MMAIN, "^J", 0, do_justify_void, 0);
|
||||
add_to_sclist(MMAIN, "F4", 0, do_justify_void, 0);
|
||||
@@ -1125,6 +1138,14 @@ void shortcut_init(void)
|
||||
add_to_sclist(MMOST, "\xE2\x86\x92", KEY_RIGHT, do_right, 0);
|
||||
add_to_sclist(MSOME, "^\xE2\x86\x90", CONTROL_LEFT, do_prev_word_void, 0);
|
||||
add_to_sclist(MSOME, "^\xE2\x86\x92", CONTROL_RIGHT, do_next_word_void, 0);
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
add_to_sclist(MMAIN, "M-\xE2\x86\x90", ALT_LEFT, switch_to_prev_buffer_void, 0);
|
||||
add_to_sclist(MMAIN, "M-\xE2\x86\x92", ALT_RIGHT, switch_to_next_buffer_void, 0);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
add_to_sclist(MMAIN|MHELP|MBROWSER, "M-\xE2\x86\x91", ALT_UP, do_findprevious, 0);
|
||||
add_to_sclist(MMAIN|MHELP|MBROWSER, "M-\xE2\x86\x93", ALT_DOWN, do_findnext, 0);
|
||||
#endif
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -1135,10 +1156,10 @@ void shortcut_init(void)
|
||||
}
|
||||
add_to_sclist(MMOST, "M-Space", 0, do_prev_word_void, 0);
|
||||
add_to_sclist(MMOST, "^Space", 0, do_next_word_void, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "^A", 0, do_home_void, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "Home", KEY_HOME, do_home_void, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "^E", 0, do_end_void, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "End", KEY_END, do_end_void, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "^A", 0, do_home, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "Home", KEY_HOME, do_home, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "^E", 0, do_end, 0);
|
||||
add_to_sclist((MMOST & ~MBROWSER), "End", KEY_END, do_end, 0);
|
||||
add_to_sclist(MMAIN|MHELP|MBROWSER, "^P", 0, do_up_void, 0);
|
||||
add_to_sclist(MMAIN|MHELP|MBROWSER, "^N", 0, do_down_void, 0);
|
||||
#ifdef ENABLE_UTF8
|
||||
@@ -1526,9 +1547,9 @@ sc *strtosc(const char *input)
|
||||
else if (!strcasecmp(input, "nextword"))
|
||||
s->scfunc = do_next_word_void;
|
||||
else if (!strcasecmp(input, "home"))
|
||||
s->scfunc = do_home_void;
|
||||
s->scfunc = do_home;
|
||||
else if (!strcasecmp(input, "end"))
|
||||
s->scfunc = do_end_void;
|
||||
s->scfunc = do_end;
|
||||
else if (!strcasecmp(input, "prevblock"))
|
||||
s->scfunc = do_prev_block;
|
||||
else if (!strcasecmp(input, "nextblock"))
|
||||
@@ -1736,7 +1757,6 @@ void thanks_for_all_the_fish(void)
|
||||
#endif
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
free(operating_dir);
|
||||
free(full_operating_dir);
|
||||
#endif
|
||||
free(answer);
|
||||
free(last_search);
|
||||
|
||||
22
src/help.c
22
src/help.c
@@ -22,10 +22,8 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef ENABLE_HELP
|
||||
|
||||
@@ -210,8 +208,11 @@ void do_help(void)
|
||||
bottombars(MHELP);
|
||||
} else if (func == do_research) {
|
||||
do_research();
|
||||
currmenu = MHELP;
|
||||
#ifndef NANO_TINY
|
||||
} else if (func == do_findprevious) {
|
||||
do_findprevious();
|
||||
} else if (func == do_findnext) {
|
||||
do_findnext();
|
||||
} else if (kbinput == KEY_WINCH) {
|
||||
; /* Nothing to do. */
|
||||
#endif
|
||||
@@ -228,11 +229,9 @@ void do_help(void)
|
||||
unbound_key(kbinput);
|
||||
|
||||
/* If we searched and found something, let the cursor show it. */
|
||||
if (didfind == 1)
|
||||
curs_set(1);
|
||||
else
|
||||
curs_set(0);
|
||||
curs_set(didfind == 1 ? 1 : 0);
|
||||
|
||||
currmenu = MHELP;
|
||||
edit_refresh();
|
||||
|
||||
location = 0;
|
||||
@@ -260,8 +259,6 @@ void do_help(void)
|
||||
switch_to_prev_buffer_void();
|
||||
|
||||
if (ISSET(NO_HELP)) {
|
||||
blank_bottombars();
|
||||
wnoutrefresh(bottomwin);
|
||||
currmenu = oldmenu;
|
||||
window_init();
|
||||
} else
|
||||
@@ -514,7 +511,7 @@ void help_init(void)
|
||||
if (scsfound == 1) {
|
||||
sprintf(ptr, "%s ", s->keystr);
|
||||
/* Unicode arrows take three bytes instead of one. */
|
||||
if (s->keystr[0] == '\xE2' || s->keystr[1] == '\xE2')
|
||||
if (strstr(s->keystr, "\xE2") != NULL)
|
||||
ptr += 8;
|
||||
else
|
||||
ptr += 6;
|
||||
@@ -580,6 +577,9 @@ functionptrtype parse_help_input(int *kbinput)
|
||||
case '/':
|
||||
return do_search;
|
||||
case 'N':
|
||||
#ifndef NANO_TINY
|
||||
return do_findprevious;
|
||||
#endif
|
||||
case 'n':
|
||||
return do_research;
|
||||
case 'E':
|
||||
|
||||
294
src/move.c
294
src/move.c
@@ -22,7 +22,6 @@
|
||||
#include "proto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Move to the first line of the file. */
|
||||
void do_first_line(void)
|
||||
@@ -53,8 +52,10 @@ void get_edge_and_target(size_t *leftedge, size_t *target_column)
|
||||
{
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
size_t shim = editwincols * (1 + (tabsize / editwincols));
|
||||
|
||||
*leftedge = leftedge_for(xplustabs(), openfile->current);
|
||||
*target_column = openfile->placewewant - *leftedge;
|
||||
*target_column = (openfile->placewewant + shim - *leftedge) % editwincols;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -63,6 +64,51 @@ void get_edge_and_target(size_t *leftedge, size_t *target_column)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the index in line->data that corresponds to the given column on the
|
||||
* chunk that starts at the given leftedge. If the index lands on a tab, and
|
||||
* this tab starts on an earlier chunk, and the tab ends on this row OR we're
|
||||
* going forward, then increment the index and recalculate leftedge. */
|
||||
size_t proper_x(filestruct *line, size_t *leftedge, bool forward,
|
||||
size_t column, bool *shifted)
|
||||
{
|
||||
size_t index = actual_x(line->data, column);
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP) && line->data[index] == '\t' && (forward ||
|
||||
*leftedge / tabsize < (*leftedge + editwincols) / tabsize) &&
|
||||
*leftedge % tabsize != 0 && column < *leftedge + tabsize) {
|
||||
index++;
|
||||
|
||||
*leftedge = leftedge_for(strnlenpt(line->data, index), line);
|
||||
|
||||
if (shifted != NULL)
|
||||
*shifted = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Adjust the values for current_x and placewewant in case we have landed in
|
||||
* the middle of a tab that crosses a row boundary. */
|
||||
void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
|
||||
{
|
||||
bool shifted = FALSE;
|
||||
|
||||
openfile->current_x = proper_x(openfile->current, leftedge, forward,
|
||||
actual_last_column(*leftedge, target), &shifted);
|
||||
|
||||
/* If the index was incremented, try going to the target column. */
|
||||
if (shifted) {
|
||||
size_t newer_x = actual_x(openfile->current->data, *leftedge + target);
|
||||
|
||||
if (newer_x > openfile->current_x)
|
||||
openfile->current_x = newer_x;
|
||||
}
|
||||
|
||||
openfile->placewewant = *leftedge + target;
|
||||
}
|
||||
|
||||
/* Move up nearly one screenful. */
|
||||
void do_page_up(void)
|
||||
{
|
||||
@@ -73,13 +119,12 @@ void do_page_up(void)
|
||||
* beginning of the top line of the edit window, as Pico does. */
|
||||
if (!ISSET(SMOOTH_SCROLL)) {
|
||||
openfile->current = openfile->edittop;
|
||||
openfile->placewewant = openfile->firstcolumn;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
openfile->firstcolumn);
|
||||
openfile->current_y = 0;
|
||||
}
|
||||
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
leftedge = leftedge_for(openfile->firstcolumn, openfile->edittop);
|
||||
target_column = 0;
|
||||
} else
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
|
||||
/* Move up the required number of lines or chunks. If we can't, we're
|
||||
* at the top of the file, so put the cursor there and get out. */
|
||||
@@ -88,9 +133,7 @@ void do_page_up(void)
|
||||
return;
|
||||
}
|
||||
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
actual_last_column(leftedge, target_column));
|
||||
set_proper_index_and_pww(&leftedge, target_column, FALSE);
|
||||
|
||||
/* Move the viewport so that the cursor stays immobile, if possible. */
|
||||
adjust_viewport(STATIONARY);
|
||||
@@ -107,13 +150,12 @@ void do_page_down(void)
|
||||
* beginning of the top line of the edit window, as Pico does. */
|
||||
if (!ISSET(SMOOTH_SCROLL)) {
|
||||
openfile->current = openfile->edittop;
|
||||
openfile->placewewant = openfile->firstcolumn;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
openfile->firstcolumn);
|
||||
openfile->current_y = 0;
|
||||
}
|
||||
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
leftedge = leftedge_for(openfile->firstcolumn, openfile->edittop);
|
||||
target_column = 0;
|
||||
} else
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
|
||||
/* Move down the required number of lines or chunks. If we can't, we're
|
||||
* at the bottom of the file, so put the cursor there and get out. */
|
||||
@@ -122,9 +164,7 @@ void do_page_down(void)
|
||||
return;
|
||||
}
|
||||
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
actual_last_column(leftedge, target_column));
|
||||
set_proper_index_and_pww(&leftedge, target_column, TRUE);
|
||||
|
||||
/* Move the viewport so that the cursor stays immobile, if possible. */
|
||||
adjust_viewport(STATIONARY);
|
||||
@@ -147,13 +187,7 @@ void do_para_begin(bool update_screen)
|
||||
openfile->current_x = 0;
|
||||
|
||||
if (update_screen)
|
||||
edit_redraw(was_current);
|
||||
}
|
||||
|
||||
/* Move up to first start of a paragraph before the current line. */
|
||||
void do_para_begin_void(void)
|
||||
{
|
||||
do_para_begin(TRUE);
|
||||
edit_redraw(was_current, CENTERING);
|
||||
}
|
||||
|
||||
/* Move down to the beginning of the last line of the current paragraph.
|
||||
@@ -183,7 +217,13 @@ void do_para_end(bool update_screen)
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
|
||||
if (update_screen)
|
||||
edit_redraw(was_current);
|
||||
edit_redraw(was_current, CENTERING);
|
||||
}
|
||||
|
||||
/* Move up to first start of a paragraph before the current line. */
|
||||
void do_para_begin_void(void)
|
||||
{
|
||||
do_para_begin(TRUE);
|
||||
}
|
||||
|
||||
/* Move down to just after the first end of a paragraph. */
|
||||
@@ -212,7 +252,7 @@ void do_prev_block(void)
|
||||
openfile->current = openfile->current->next;
|
||||
|
||||
openfile->current_x = 0;
|
||||
edit_redraw(was_current);
|
||||
edit_redraw(was_current, CENTERING);
|
||||
}
|
||||
|
||||
/* Move to the next block of text in the file. */
|
||||
@@ -230,7 +270,7 @@ void do_next_block(void)
|
||||
}
|
||||
|
||||
openfile->current_x = 0;
|
||||
edit_redraw(was_current);
|
||||
edit_redraw(was_current, CENTERING);
|
||||
}
|
||||
|
||||
/* Move to the previous word in the file. If allow_punct is TRUE, treat
|
||||
@@ -273,17 +313,8 @@ void do_prev_word(bool allow_punct, bool update_screen)
|
||||
openfile->current_x = move_mbright(openfile->current->data,
|
||||
openfile->current_x);
|
||||
|
||||
if (update_screen) {
|
||||
focusing = FALSE;
|
||||
edit_redraw(was_current);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move to the previous word in the file, treating punctuation as part of a
|
||||
* word if the WORD_BOUNDS flag is set, and update the screen afterwards. */
|
||||
void do_prev_word_void(void)
|
||||
{
|
||||
do_prev_word(ISSET(WORD_BOUNDS), TRUE);
|
||||
if (update_screen)
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
|
||||
/* Move to the next word in the file. If allow_punct is TRUE, treat
|
||||
@@ -322,15 +353,20 @@ bool do_next_word(bool allow_punct, bool update_screen)
|
||||
break;
|
||||
}
|
||||
|
||||
if (update_screen) {
|
||||
focusing = FALSE;
|
||||
edit_redraw(was_current);
|
||||
}
|
||||
if (update_screen)
|
||||
edit_redraw(was_current, FLOWING);
|
||||
|
||||
/* Return whether we started on a word. */
|
||||
return started_on_word;
|
||||
}
|
||||
|
||||
/* Move to the previous word in the file, treating punctuation as part of a
|
||||
* word if the WORD_BOUNDS flag is set, and update the screen afterwards. */
|
||||
void do_prev_word_void(void)
|
||||
{
|
||||
do_prev_word(ISSET(WORD_BOUNDS), TRUE);
|
||||
}
|
||||
|
||||
/* Move to the next word in the file, treating punctuation as part of a word
|
||||
* if the WORD_BOUNDS flag is set, and update the screen afterwards. */
|
||||
void do_next_word_void(void)
|
||||
@@ -339,10 +375,9 @@ void do_next_word_void(void)
|
||||
}
|
||||
|
||||
/* Move to the beginning of the current line (or softwrapped chunk).
|
||||
* If be_clever is TRUE, do a smart home when wanted and possible,
|
||||
* and do a dynamic home when in softwrap mode and it's possible.
|
||||
* If be_clever is FALSE, just do a simple home. */
|
||||
void do_home(bool be_clever)
|
||||
* When enabled, do a smart home. When softwrapping, go the beginning
|
||||
* of the full line when already at the start of a chunk. */
|
||||
void do_home(void)
|
||||
{
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_column = xplustabs();
|
||||
@@ -353,10 +388,11 @@ void do_home(bool be_clever)
|
||||
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
leftedge = leftedge_for(was_column, openfile->current);
|
||||
leftedge_x = actual_x(openfile->current->data, leftedge);
|
||||
leftedge_x = proper_x(openfile->current, &leftedge, FALSE, leftedge,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (ISSET(SMART_HOME) && be_clever) {
|
||||
if (ISSET(SMART_HOME)) {
|
||||
size_t indent_x = indent_length(openfile->current->data);
|
||||
|
||||
if (openfile->current->data[indent_x] != '\0') {
|
||||
@@ -376,7 +412,7 @@ void do_home(bool be_clever)
|
||||
if (!moved && ISSET(SOFTWRAP)) {
|
||||
/* If already at the left edge of the screen, move fully home.
|
||||
* Otherwise, move to the left edge. */
|
||||
if (openfile->current_x == leftedge_x && be_clever)
|
||||
if (openfile->current_x == leftedge_x)
|
||||
openfile->current_x = 0;
|
||||
else {
|
||||
openfile->current_x = leftedge_x;
|
||||
@@ -392,23 +428,16 @@ void do_home(bool be_clever)
|
||||
|
||||
/* If we changed chunk, we might be offscreen. Otherwise,
|
||||
* update current if the mark is on or we changed "page". */
|
||||
if (ISSET(SOFTWRAP) && moved_off_chunk) {
|
||||
focusing = FALSE;
|
||||
edit_redraw(was_current);
|
||||
} else if (line_needs_update(was_column, openfile->placewewant))
|
||||
if (ISSET(SOFTWRAP) && moved_off_chunk)
|
||||
edit_redraw(was_current, FLOWING);
|
||||
else if (line_needs_update(was_column, openfile->placewewant))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
}
|
||||
|
||||
/* Do a (smart or dynamic) home. */
|
||||
void do_home_void(void)
|
||||
{
|
||||
do_home(TRUE);
|
||||
}
|
||||
|
||||
/* Move to the end of the current line (or softwrapped chunk).
|
||||
* If be_clever is TRUE, do a dynamic end when in softwrap mode and
|
||||
* it's possible. If be_clever is FALSE, just do a simple end. */
|
||||
void do_end(bool be_clever)
|
||||
* When softwrapping and alredy at the end of a chunk, go to the
|
||||
* end of the full line. */
|
||||
void do_end(void)
|
||||
{
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_column = xplustabs();
|
||||
@@ -434,7 +463,7 @@ void do_end(bool be_clever)
|
||||
|
||||
/* If already at the right edge of the screen, move fully to
|
||||
* the end of the line. Otherwise, move to the right edge. */
|
||||
if (openfile->current_x == rightedge_x && be_clever)
|
||||
if (openfile->current_x == rightedge_x)
|
||||
openfile->current_x = line_len;
|
||||
else {
|
||||
openfile->current_x = rightedge_x;
|
||||
@@ -450,25 +479,17 @@ void do_end(bool be_clever)
|
||||
|
||||
/* If we changed chunk, we might be offscreen. Otherwise,
|
||||
* update current if the mark is on or we changed "page". */
|
||||
if (ISSET(SOFTWRAP) && moved_off_chunk) {
|
||||
focusing = FALSE;
|
||||
edit_redraw(was_current);
|
||||
} else if (line_needs_update(was_column, openfile->placewewant))
|
||||
if (ISSET(SOFTWRAP) && moved_off_chunk)
|
||||
edit_redraw(was_current, FLOWING);
|
||||
else if (line_needs_update(was_column, openfile->placewewant))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
}
|
||||
|
||||
/* Do a (dynamic) end. */
|
||||
void do_end_void(void)
|
||||
{
|
||||
do_end(TRUE);
|
||||
}
|
||||
|
||||
/* Move the cursor to the preceding line or chunk. If scroll_only is TRUE,
|
||||
* also scroll the screen one row, so the cursor stays in the same spot. */
|
||||
void do_up(bool scroll_only)
|
||||
{
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_column = xplustabs();
|
||||
size_t leftedge, target_column;
|
||||
|
||||
/* When just scrolling and the top of the file is onscreen, get out. */
|
||||
@@ -482,34 +503,15 @@ void do_up(bool scroll_only)
|
||||
if (go_back_chunks(1, &openfile->current, &leftedge) > 0)
|
||||
return;
|
||||
|
||||
set_proper_index_and_pww(&leftedge, target_column, FALSE);
|
||||
|
||||
if (scroll_only)
|
||||
edit_scroll(UPWARD, 1);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
|
||||
/* <Up> should not change placewewant, so restore it. */
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
actual_last_column(leftedge, target_column));
|
||||
|
||||
/* When the cursor was on the first line of the edit window (or when just
|
||||
* scrolling without moving the cursor), scroll the edit window up -- one
|
||||
* line if we're in smooth scrolling mode, and half a page otherwise. */
|
||||
if (openfile->current_y == 0 || scroll_only)
|
||||
edit_scroll(UPWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ?
|
||||
1 : editwinrows / 2 + 1);
|
||||
|
||||
if (openfile->current_y > 0) {
|
||||
/* Redraw the prior line if it's not offscreen, and it's not the same
|
||||
* line as the current one, and the line was horizontally scrolled. */
|
||||
if ((!scroll_only || openfile->current_y < editwinrows - 1) &&
|
||||
openfile->current != was_current &&
|
||||
line_needs_update(was_column, 0))
|
||||
update_line(openfile->current->next, 0);
|
||||
/* Redraw the current line if it needs to be horizontally scrolled. */
|
||||
if (line_needs_update(0, xplustabs()))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
}
|
||||
}
|
||||
|
||||
/* Move up one line or chunk. */
|
||||
void do_up_void(void)
|
||||
{
|
||||
do_up(FALSE);
|
||||
}
|
||||
|
||||
/* Move the cursor to next line or chunk. If scroll_only is TRUE, also
|
||||
@@ -517,7 +519,6 @@ void do_up_void(void)
|
||||
void do_down(bool scroll_only)
|
||||
{
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_column = xplustabs();
|
||||
size_t leftedge, target_column;
|
||||
|
||||
get_edge_and_target(&leftedge, &target_column);
|
||||
@@ -526,28 +527,21 @@ void do_down(bool scroll_only)
|
||||
if (go_forward_chunks(1, &openfile->current, &leftedge) > 0)
|
||||
return;
|
||||
|
||||
set_proper_index_and_pww(&leftedge, target_column, TRUE);
|
||||
|
||||
if (scroll_only)
|
||||
edit_scroll(DOWNWARD, 1);
|
||||
|
||||
edit_redraw(was_current, FLOWING);
|
||||
|
||||
/* <Down> should not change placewewant, so restore it. */
|
||||
openfile->placewewant = leftedge + target_column;
|
||||
openfile->current_x = actual_x(openfile->current->data,
|
||||
actual_last_column(leftedge, target_column));
|
||||
}
|
||||
|
||||
/* When the cursor was on the last line of the edit window (or when just
|
||||
* scrolling without moving the cursor), scroll the edit window down -- one
|
||||
* line if we're in smooth scrolling mode, and half a page otherwise. */
|
||||
if (openfile->current_y == editwinrows - 1 || scroll_only)
|
||||
edit_scroll(DOWNWARD, (ISSET(SMOOTH_SCROLL) || scroll_only) ?
|
||||
1 : editwinrows / 2 + 1);
|
||||
|
||||
if (openfile->current_y < editwinrows - 1) {
|
||||
/* Redraw the prior line if it's not offscreen, and it's not the same
|
||||
* line as the current one, and the line was horizontally scrolled. */
|
||||
if ((!scroll_only || openfile->current_y > 0) &&
|
||||
openfile->current != was_current &&
|
||||
line_needs_update(was_column, 0))
|
||||
update_line(openfile->current->prev, 0);
|
||||
/* Redraw the current line if it needs to be horizontally scrolled. */
|
||||
if (line_needs_update(0, xplustabs()))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
}
|
||||
/* Move up one line or chunk. */
|
||||
void do_up_void(void)
|
||||
{
|
||||
do_up(FALSE);
|
||||
}
|
||||
|
||||
/* Move down one line or chunk. */
|
||||
@@ -573,73 +567,31 @@ void do_scroll_down(void)
|
||||
/* Move left one character. */
|
||||
void do_left(void)
|
||||
{
|
||||
size_t was_column = xplustabs();
|
||||
#ifndef NANO_TINY
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_chunk = chunk_for(was_column, was_current);
|
||||
#endif
|
||||
|
||||
if (openfile->current_x > 0)
|
||||
openfile->current_x = move_mbleft(openfile->current->data,
|
||||
openfile->current_x);
|
||||
else if (openfile->current != openfile->fileage) {
|
||||
do_up_void();
|
||||
do_end(FALSE);
|
||||
return;
|
||||
openfile->current = openfile->current->prev;
|
||||
openfile->current_x = strlen(openfile->current->data);
|
||||
}
|
||||
|
||||
openfile->placewewant = xplustabs();
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* If we were on the first line of the edit window, and we changed chunk,
|
||||
* we're now above the first line of the edit window, so scroll up. */
|
||||
if (ISSET(SOFTWRAP) && openfile->current_y == 0 &&
|
||||
openfile->current == was_current &&
|
||||
chunk_for(openfile->placewewant,
|
||||
openfile->current) != was_chunk) {
|
||||
edit_scroll(UPWARD, ISSET(SMOOTH_SCROLL) ? 1 : editwinrows / 2 + 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update current if the mark is on or it has changed "page". */
|
||||
if (line_needs_update(was_column, openfile->placewewant))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
|
||||
/* Move right one character. */
|
||||
void do_right(void)
|
||||
{
|
||||
size_t was_column = xplustabs();
|
||||
#ifndef NANO_TINY
|
||||
filestruct *was_current = openfile->current;
|
||||
size_t was_chunk = chunk_for(was_column, was_current);
|
||||
#endif
|
||||
|
||||
if (openfile->current->data[openfile->current_x] != '\0')
|
||||
openfile->current_x = move_mbright(openfile->current->data,
|
||||
openfile->current_x);
|
||||
else if (openfile->current != openfile->filebot) {
|
||||
do_home(FALSE);
|
||||
do_down_void();
|
||||
return;
|
||||
openfile->current = openfile->current->next;
|
||||
openfile->current_x = 0;
|
||||
}
|
||||
|
||||
openfile->placewewant = xplustabs();
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* If we were on the last line of the edit window, and we changed chunk,
|
||||
* we're now below the first line of the edit window, so scroll down. */
|
||||
if (ISSET(SOFTWRAP) && openfile->current_y == editwinrows - 1 &&
|
||||
openfile->current == was_current &&
|
||||
chunk_for(openfile->placewewant,
|
||||
openfile->current) != was_chunk) {
|
||||
edit_scroll(DOWNWARD, ISSET(SMOOTH_SCROLL) ? 1 : editwinrows / 2 + 1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update current if the mark is on or it has changed "page". */
|
||||
if (line_needs_update(was_column, openfile->placewewant))
|
||||
update_line(openfile->current, openfile->current_x);
|
||||
edit_redraw(was_current, FLOWING);
|
||||
}
|
||||
|
||||
56
src/nano.c
56
src/nano.c
@@ -22,24 +22,22 @@
|
||||
#include "proto.h"
|
||||
#include "revision.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#ifdef ENABLE_UTF8
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#ifndef NANO_TINY
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef ENABLE_UTF8
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ENABLE_MOUSE
|
||||
static int oldinterval = -1;
|
||||
@@ -1790,7 +1788,7 @@ int do_mouse(void)
|
||||
/* The cursor moved; clean the cutbuffer on the next cut. */
|
||||
cutbuffer_reset();
|
||||
|
||||
edit_redraw(current_save);
|
||||
edit_redraw(current_save, CENTERING);
|
||||
}
|
||||
|
||||
/* No more handling is needed. */
|
||||
@@ -1857,6 +1855,15 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
|
||||
if (openfile->mark_set && openfile->current == openfile->mark_begin &&
|
||||
openfile->current_x < openfile->mark_begin_x)
|
||||
openfile->mark_begin_x += char_len;
|
||||
|
||||
/* When the cursor is on the top row and not on the first chunk
|
||||
* of a line, adding text there might change the preceding chunk
|
||||
* and thus require an adjustment of firstcolumn. */
|
||||
if (openfile->current == openfile->edittop &&
|
||||
openfile->firstcolumn > 0) {
|
||||
ensure_firstcolumn_is_aligned();
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
openfile->current_x += char_len;
|
||||
@@ -2377,19 +2384,18 @@ int main(int argc, char **argv)
|
||||
#endif /* !DISABLE_HISTORIES */
|
||||
|
||||
#ifndef NANO_TINY
|
||||
/* Set up the backup directory (unless we're using restricted mode,
|
||||
* in which case backups are disabled, since they would allow
|
||||
* reading from or writing to files not specified on the command
|
||||
* line). This entails making sure it exists and is a directory, so
|
||||
* that backup files will be saved there. */
|
||||
if (!ISSET(RESTRICTED))
|
||||
/* If backups are enabled and a backup directory was specified and
|
||||
* we're not in restricted mode, make sure the path exists and is
|
||||
* a directory, so that backup files can be saved there. */
|
||||
if (ISSET(BACKUP_FILE) && backup_dir != NULL && !ISSET(RESTRICTED))
|
||||
init_backup_dir();
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
/* Set up the operating directory. This entails chdir()ing there,
|
||||
* so that file reads and writes will be based there. */
|
||||
init_operating_dir();
|
||||
if (operating_dir != NULL)
|
||||
init_operating_dir();
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
@@ -2496,6 +2502,7 @@ int main(int argc, char **argv)
|
||||
#else
|
||||
interface_color_pair[TITLE_BAR] = hilite_attribute;
|
||||
interface_color_pair[LINE_NUMBER] = hilite_attribute;
|
||||
interface_color_pair[SELECTED_TEXT] = hilite_attribute;
|
||||
interface_color_pair[STATUS_BAR] = hilite_attribute;
|
||||
interface_color_pair[KEY_COMBO] = hilite_attribute;
|
||||
interface_color_pair[FUNCTION_TAG] = A_NORMAL;
|
||||
@@ -2518,6 +2525,11 @@ int main(int argc, char **argv)
|
||||
/* Ask for the codes for Shift+Control+Home/End. */
|
||||
shiftcontrolhome = get_keycode("kHOM6", SHIFT_CONTROL_HOME);
|
||||
shiftcontrolend = get_keycode("kEND6", SHIFT_CONTROL_END);
|
||||
/* Ask for the codes for Alt+Left/Right/Up/Down. */
|
||||
altleft = get_keycode("kLFT3", ALT_LEFT);
|
||||
altright = get_keycode("kRIT3", ALT_RIGHT);
|
||||
altup = get_keycode("kUP3", ALT_UP);
|
||||
altdown = get_keycode("kDN3", ALT_DOWN);
|
||||
/* Ask for the codes for Shift+Alt+Left/Right/Up/Down. */
|
||||
shiftaltleft = get_keycode("kLFT4", SHIFT_ALT_LEFT);
|
||||
shiftaltright = get_keycode("kRIT4", SHIFT_ALT_RIGHT);
|
||||
@@ -2626,7 +2638,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Refresh just the cursor position or the entire edit window. */
|
||||
if (!refresh_needed) {
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
wnoutrefresh(edit);
|
||||
} else
|
||||
edit_refresh();
|
||||
|
||||
37
src/nano.h
37
src/nano.h
@@ -469,6 +469,7 @@ enum
|
||||
{
|
||||
TITLE_BAR = 0,
|
||||
LINE_NUMBER,
|
||||
SELECTED_TEXT,
|
||||
STATUS_BAR,
|
||||
KEY_COMBO,
|
||||
FUNCTION_TAG,
|
||||
@@ -559,22 +560,26 @@ enum
|
||||
#define CONTROL_RIGHT 0x402
|
||||
#define CONTROL_UP 0x403
|
||||
#define CONTROL_DOWN 0x404
|
||||
#define CONTROL_HOME 0x411
|
||||
#define CONTROL_END 0x412
|
||||
#define SHIFT_CONTROL_LEFT 0x405
|
||||
#define SHIFT_CONTROL_RIGHT 0x406
|
||||
#define SHIFT_CONTROL_UP 0x407
|
||||
#define SHIFT_CONTROL_DOWN 0x408
|
||||
#define SHIFT_CONTROL_HOME 0x413
|
||||
#define SHIFT_CONTROL_END 0x414
|
||||
#define SHIFT_ALT_LEFT 0x409
|
||||
#define SHIFT_ALT_RIGHT 0x40a
|
||||
#define SHIFT_ALT_UP 0x40b
|
||||
#define SHIFT_ALT_DOWN 0x40c
|
||||
#define SHIFT_PAGEUP 0x40d
|
||||
#define SHIFT_PAGEDOWN 0x40e
|
||||
#define SHIFT_HOME 0x40f
|
||||
#define SHIFT_END 0x410
|
||||
#define CONTROL_HOME 0x405
|
||||
#define CONTROL_END 0x406
|
||||
#define SHIFT_CONTROL_LEFT 0x411
|
||||
#define SHIFT_CONTROL_RIGHT 0x412
|
||||
#define SHIFT_CONTROL_UP 0x413
|
||||
#define SHIFT_CONTROL_DOWN 0x414
|
||||
#define SHIFT_CONTROL_HOME 0x415
|
||||
#define SHIFT_CONTROL_END 0x416
|
||||
#define ALT_LEFT 0x421
|
||||
#define ALT_RIGHT 0x422
|
||||
#define ALT_UP 0x423
|
||||
#define ALT_DOWN 0x424
|
||||
#define SHIFT_ALT_LEFT 0x431
|
||||
#define SHIFT_ALT_RIGHT 0x432
|
||||
#define SHIFT_ALT_UP 0x433
|
||||
#define SHIFT_ALT_DOWN 0x434
|
||||
#define SHIFT_HOME 0x455
|
||||
#define SHIFT_END 0x456
|
||||
#define SHIFT_PAGEUP 0x457
|
||||
#define SHIFT_PAGEDOWN 0x458
|
||||
|
||||
#ifdef USE_SLANG
|
||||
#ifdef ENABLE_UTF8
|
||||
|
||||
30
src/prompt.c
30
src/prompt.c
@@ -21,8 +21,6 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
static char *prompt = NULL;
|
||||
@@ -124,9 +122,9 @@ int do_statusbar_input(bool *ran_func, bool *finished)
|
||||
else if (s->scfunc == do_next_word_void)
|
||||
do_statusbar_next_word();
|
||||
#endif
|
||||
else if (s->scfunc == do_home_void)
|
||||
else if (s->scfunc == do_home)
|
||||
do_statusbar_home();
|
||||
else if (s->scfunc == do_end_void)
|
||||
else if (s->scfunc == do_end)
|
||||
do_statusbar_end();
|
||||
/* When in restricted mode at the "Write File" prompt and the
|
||||
* filename isn't blank, disallow any input and deletion. */
|
||||
@@ -145,7 +143,10 @@ int do_statusbar_input(bool *ran_func, bool *finished)
|
||||
do_statusbar_delete();
|
||||
else if (s->scfunc == do_backspace)
|
||||
do_statusbar_backspace();
|
||||
else {
|
||||
else if (s->scfunc == do_uncut_text) {
|
||||
if (cutbuffer != NULL)
|
||||
do_statusbar_uncut_text();
|
||||
} else {
|
||||
/* Handle any other shortcut in the current menu, setting
|
||||
* ran_func to TRUE if we try to run their associated functions,
|
||||
* and setting finished to TRUE to indicatethat we're done after
|
||||
@@ -363,6 +364,23 @@ size_t statusbar_xplustabs(void)
|
||||
return strnlenpt(answer, statusbar_x);
|
||||
}
|
||||
|
||||
/* Paste the first line of the cutbuffer into the current answer. */
|
||||
void do_statusbar_uncut_text(void)
|
||||
{
|
||||
size_t pastelen = strlen(cutbuffer->data);
|
||||
char *fusion = charalloc(strlen(answer) + pastelen + 1);
|
||||
|
||||
/* Concatenate: the current answer before the cursor, the first line
|
||||
* of the cutbuffer, plus the rest of the current answer. */
|
||||
strncpy(fusion, answer, statusbar_x);
|
||||
strncpy(fusion + statusbar_x, cutbuffer->data, pastelen);
|
||||
strcpy(fusion + statusbar_x + pastelen, answer + statusbar_x);
|
||||
|
||||
free(answer);
|
||||
answer = fusion;
|
||||
statusbar_x += pastelen;
|
||||
}
|
||||
|
||||
/* Return the column number of the first character of the answer that is
|
||||
* displayed in the statusbar when the cursor is at the given column,
|
||||
* with the available room for the answer starting at base. Note that
|
||||
@@ -691,7 +709,7 @@ int do_yesno_prompt(bool all, const char *msg)
|
||||
functionptrtype func;
|
||||
|
||||
if (!ISSET(NO_HELP)) {
|
||||
char shortstr[3];
|
||||
char shortstr[MAXCHARLEN + 2];
|
||||
/* Temporary string for (translated) " Y", " N" and " A". */
|
||||
|
||||
if (COLS < 32)
|
||||
|
||||
35
src/proto.h
35
src/proto.h
@@ -71,6 +71,10 @@ extern int shiftcontrolup;
|
||||
extern int shiftcontroldown;
|
||||
extern int shiftcontrolhome;
|
||||
extern int shiftcontrolend;
|
||||
extern int altleft;
|
||||
extern int altright;
|
||||
extern int altup;
|
||||
extern int altdown;
|
||||
extern int shiftaltleft;
|
||||
extern int shiftaltright;
|
||||
extern int shiftaltup;
|
||||
@@ -132,7 +136,6 @@ extern const char *locking_suffix;
|
||||
#endif
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
extern char *operating_dir;
|
||||
extern char *full_operating_dir;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_SPELLER
|
||||
@@ -183,7 +186,7 @@ functionptrtype parse_browser_input(int *kbinput);
|
||||
void browser_refresh(void);
|
||||
void browser_select_dirname(const char *needle);
|
||||
void do_filesearch(void);
|
||||
void do_fileresearch(void);
|
||||
void do_fileresearch(bool forwards);
|
||||
void do_first_file(void);
|
||||
void do_last_file(void);
|
||||
char *strip_last_component(const char *path);
|
||||
@@ -284,7 +287,7 @@ char *get_full_path(const char *origpath);
|
||||
char *safe_tempfile(FILE **f);
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
void init_operating_dir(void);
|
||||
bool check_operating_dir(const char *currpath, bool allow_tabcomp);
|
||||
bool outside_of_confinement(const char *currpath, bool allow_tabcomp);
|
||||
#endif
|
||||
#ifndef NANO_TINY
|
||||
void init_backup_dir(void);
|
||||
@@ -328,6 +331,7 @@ size_t length_of_list(int menu);
|
||||
const sc *first_sc_for(int menu, void (*func)(void));
|
||||
int the_code_for(void (*func)(void), int defaultval);
|
||||
functionptrtype func_from_key(int *kbinput);
|
||||
int keycode_from_string(const char *keystring);
|
||||
void assign_keyinfo(sc *s, const char *keystring, const int keycode);
|
||||
void print_sclist(void);
|
||||
void shortcut_init(void);
|
||||
@@ -353,30 +357,28 @@ size_t help_line_len(const char *ptr);
|
||||
#endif
|
||||
void do_help_void(void);
|
||||
|
||||
/* All functions in move.c. */
|
||||
/* Most functions in move.c. */
|
||||
void do_first_line(void);
|
||||
void do_last_line(void);
|
||||
void do_page_up(void);
|
||||
void do_page_down(void);
|
||||
#ifndef DISABLE_JUSTIFY
|
||||
void do_para_begin(bool update_screen);
|
||||
void do_para_begin_void(void);
|
||||
void do_para_end(bool update_screen);
|
||||
void do_para_begin_void(void);
|
||||
void do_para_end_void(void);
|
||||
#endif
|
||||
void do_prev_block(void);
|
||||
void do_next_block(void);
|
||||
void do_prev_word(bool allow_punct, bool update_screen);
|
||||
void do_prev_word_void(void);
|
||||
bool do_next_word(bool allow_punct, bool update_screen);
|
||||
void do_prev_word_void(void);
|
||||
void do_next_word_void(void);
|
||||
void do_home(bool be_clever);
|
||||
void do_home_void(void);
|
||||
void do_end(bool be_clever);
|
||||
void do_end_void(void);
|
||||
void do_home(void);
|
||||
void do_end(void);
|
||||
void do_up(bool scroll_only);
|
||||
void do_up_void(void);
|
||||
void do_down(bool scroll_only);
|
||||
void do_up_void(void);
|
||||
void do_down_void(void);
|
||||
#ifndef NANO_TINY
|
||||
void do_scroll_up(void);
|
||||
@@ -448,6 +450,7 @@ void do_statusbar_right(void);
|
||||
void do_statusbar_backspace(void);
|
||||
void do_statusbar_delete(void);
|
||||
void do_statusbar_cut_text(void);
|
||||
void do_statusbar_uncut_text(void);
|
||||
#ifndef NANO_TINY
|
||||
void do_statusbar_prev_word(void);
|
||||
void do_statusbar_next_word(void);
|
||||
@@ -600,9 +603,9 @@ char *mallocstrcpy(char *dest, const char *src);
|
||||
char *free_and_assign(char *dest, char *src);
|
||||
size_t get_page_start(size_t column);
|
||||
size_t xplustabs(void);
|
||||
size_t actual_x(const char *s, size_t column);
|
||||
size_t strnlenpt(const char *s, size_t maxlen);
|
||||
size_t strlenpt(const char *s);
|
||||
size_t actual_x(const char *text, size_t column);
|
||||
size_t strnlenpt(const char *text, size_t maxlen);
|
||||
size_t strlenpt(const char *text);
|
||||
void new_magicline(void);
|
||||
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
|
||||
void remove_magicline(void);
|
||||
@@ -649,7 +652,7 @@ void warn_and_shortly_pause(const char *msg);
|
||||
void statusline(message_type importance, const char *msg, ...);
|
||||
void bottombars(int menu);
|
||||
void onekey(const char *keystroke, const char *desc, int length);
|
||||
void place_the_cursor(bool forreal);
|
||||
void place_the_cursor(void);
|
||||
void edit_draw(filestruct *fileptr, const char *converted,
|
||||
int line, size_t from_col);
|
||||
int update_line(filestruct *fileptr, size_t index);
|
||||
@@ -671,7 +674,7 @@ size_t number_of_chunks_in(filestruct *line);
|
||||
void ensure_firstcolumn_is_aligned(void);
|
||||
#endif
|
||||
size_t actual_last_column(size_t leftedge, size_t column);
|
||||
void edit_redraw(filestruct *old_current);
|
||||
void edit_redraw(filestruct *old_current, update_type manner);
|
||||
void edit_refresh(void);
|
||||
void adjust_viewport(update_type location);
|
||||
void total_redraw(void);
|
||||
|
||||
51
src/rcfile.c
51
src/rcfile.c
@@ -22,13 +22,11 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <glob.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <glob.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef ENABLE_NANORC
|
||||
|
||||
@@ -116,6 +114,7 @@ static const rcoption rcopts[] = {
|
||||
#ifndef DISABLE_COLOR
|
||||
{"titlecolor", 0},
|
||||
{"numbercolor", 0},
|
||||
{"selectedcolor", 0},
|
||||
{"statuscolor", 0},
|
||||
{"keycolor", 0},
|
||||
{"functioncolor", 0},
|
||||
@@ -353,13 +352,13 @@ void parse_syntax(char *ptr)
|
||||
bool is_universal(void (*func)(void))
|
||||
{
|
||||
if (func == do_left || func == do_right ||
|
||||
func == do_home_void || func == do_end_void ||
|
||||
func == do_home || func == do_end ||
|
||||
#ifndef NANO_TINY
|
||||
func == do_prev_word_void || func == do_next_word_void ||
|
||||
#endif
|
||||
func == do_verbatim_input || func == do_cut_text_void ||
|
||||
func == do_delete || func == do_backspace ||
|
||||
func == do_tab || func == do_enter)
|
||||
func == do_cut_text_void || func == do_uncut_text ||
|
||||
func == do_tab || func == do_enter || func == do_verbatim_input)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
@@ -389,7 +388,7 @@ void parse_binding(char *ptr, bool dobind)
|
||||
|
||||
if (strlen(keycopy) < 2) {
|
||||
rcfile_error(N_("Key name is too short"));
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
|
||||
/* Uppercase only the first two or three characters of the key name. */
|
||||
@@ -400,7 +399,7 @@ void parse_binding(char *ptr, bool dobind)
|
||||
keycopy[2] = toupper((unsigned char)keycopy[2]);
|
||||
else {
|
||||
rcfile_error(N_("Key name is too short"));
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,15 +409,10 @@ void parse_binding(char *ptr, bool dobind)
|
||||
keycopy[1] = tolower((unsigned char)keycopy[1]);
|
||||
else if (keycopy[0] != '^' && keycopy[0] != 'M' && keycopy[0] != 'F') {
|
||||
rcfile_error(N_("Key name must begin with \"^\", \"M\", or \"F\""));
|
||||
goto free_copy;
|
||||
} else if ((keycopy[0] == 'M' && keycopy[1] != '-') ||
|
||||
(keycopy[0] == '^' && ((keycopy[1] < 'A' || keycopy[1] > 'z') ||
|
||||
keycopy[1] == '[' || keycopy[1] == '`' ||
|
||||
(strlen(keycopy) > 2 && strcmp(keycopy, "^Space") != 0))) ||
|
||||
(strlen(keycopy) > 3 && strcmp(keycopy, "^Space") != 0 &&
|
||||
strcmp(keycopy, "M-Space") != 0)) {
|
||||
goto free_things;
|
||||
} else if (keycode_from_string(keycopy) < 0) {
|
||||
rcfile_error(N_("Key name %s is invalid"), keycopy);
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
|
||||
if (dobind) {
|
||||
@@ -427,7 +421,7 @@ void parse_binding(char *ptr, bool dobind)
|
||||
|
||||
if (funcptr[0] == '\0') {
|
||||
rcfile_error(N_("Must specify a function to bind the key to"));
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,21 +431,21 @@ void parse_binding(char *ptr, bool dobind)
|
||||
if (menuptr[0] == '\0') {
|
||||
/* TRANSLATORS: Do not translate the word "all". */
|
||||
rcfile_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key"));
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
|
||||
if (dobind) {
|
||||
newsc = strtosc(funcptr);
|
||||
if (newsc == NULL) {
|
||||
rcfile_error(N_("Cannot map name \"%s\" to a function"), funcptr);
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
}
|
||||
|
||||
menu = strtomenu(menuptr);
|
||||
if (menu < 1) {
|
||||
rcfile_error(N_("Cannot map name \"%s\" to a menu"), menuptr);
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -485,8 +479,7 @@ void parse_binding(char *ptr, bool dobind)
|
||||
|
||||
if (!menu) {
|
||||
rcfile_error(N_("Function '%s' does not exist in menu '%s'"), funcptr, menuptr);
|
||||
free(newsc);
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
|
||||
newsc->menus = menu;
|
||||
@@ -495,8 +488,7 @@ void parse_binding(char *ptr, bool dobind)
|
||||
/* Do not allow rebinding a frequent escape-sequence starter: Esc [. */
|
||||
if (newsc->meta && newsc->keycode == 91) {
|
||||
rcfile_error(N_("Sorry, keystroke \"%s\" may not be rebound"), newsc->keystr);
|
||||
free(newsc);
|
||||
goto free_copy;
|
||||
goto free_things;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr);
|
||||
@@ -530,7 +522,8 @@ void parse_binding(char *ptr, bool dobind)
|
||||
return;
|
||||
}
|
||||
|
||||
free_copy:
|
||||
free_things:
|
||||
free(newsc);
|
||||
free(keycopy);
|
||||
}
|
||||
|
||||
@@ -1115,6 +1108,8 @@ void parse_rcfile(FILE *rcstream, bool syntax_only)
|
||||
specified_color_combo[TITLE_BAR] = option;
|
||||
else if (strcasecmp(rcopts[i].name, "numbercolor") == 0)
|
||||
specified_color_combo[LINE_NUMBER] = option;
|
||||
else if (strcasecmp(rcopts[i].name, "selectedcolor") == 0)
|
||||
specified_color_combo[SELECTED_TEXT] = option;
|
||||
else if (strcasecmp(rcopts[i].name, "statuscolor") == 0)
|
||||
specified_color_combo[STATUS_BAR] = option;
|
||||
else if (strcasecmp(rcopts[i].name, "keycolor") == 0)
|
||||
|
||||
11
src/search.c
11
src/search.c
@@ -22,11 +22,9 @@
|
||||
#include "proto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#ifdef DEBUG
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
static bool came_full_circle = FALSE;
|
||||
/* Have we reached the starting line again while searching? */
|
||||
@@ -461,7 +459,7 @@ void go_looking(void)
|
||||
statusline(HUSH, "Took: %.2f", (double)(clock() - start) / CLOCKS_PER_SEC);
|
||||
#endif
|
||||
|
||||
edit_redraw(was_current);
|
||||
edit_redraw(was_current, CENTERING);
|
||||
search_replace_abort();
|
||||
}
|
||||
|
||||
@@ -1075,8 +1073,7 @@ void do_find_bracket(void)
|
||||
/* If count is zero, we've found a matching bracket. Update
|
||||
* the screen and get out. */
|
||||
if (count == 0) {
|
||||
focusing = FALSE;
|
||||
edit_redraw(current_save);
|
||||
edit_redraw(current_save, FLOWING);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
233
src/text.c
233
src/text.c
@@ -24,13 +24,11 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifndef NANO_TINY
|
||||
static pid_t pid = -1;
|
||||
@@ -52,7 +50,7 @@ static filestruct *jusbottom = NULL;
|
||||
static int pletion_x = 0;
|
||||
/* The x position in pletion_line of the last found completion. */
|
||||
static completion_word *list_of_completions;
|
||||
/* A linked list of the completions that have been attepmted. */
|
||||
/* A linked list of the completions that have been attempted. */
|
||||
#endif
|
||||
|
||||
#ifndef NANO_TINY
|
||||
@@ -282,162 +280,160 @@ void do_tab(void)
|
||||
* depending on whether --tabstospaces is in effect. */
|
||||
void do_indent(void)
|
||||
{
|
||||
char *line_indent = NULL;
|
||||
/* The text added to each line in order to indent it. */
|
||||
char *line_indent = charalloc(tabsize + 1);
|
||||
/* The whitespace added to each line in order to indent it. */
|
||||
size_t line_indent_len = 0;
|
||||
/* The length of the text added to each line in order to indent
|
||||
* it. */
|
||||
/* The number of bytes added to each line in order to indent it. */
|
||||
filestruct *top, *bot, *f;
|
||||
size_t top_x, bot_x;
|
||||
|
||||
assert(openfile->current != NULL && openfile->current->data != NULL);
|
||||
|
||||
/* If the mark is on, use all lines covered by the mark. */
|
||||
/* Use either all the marked lines or just the current line. */
|
||||
if (openfile->mark_set)
|
||||
mark_order((const filestruct **)&top, &top_x,
|
||||
(const filestruct **)&bot, &bot_x, NULL);
|
||||
/* Otherwise, use the current line. */
|
||||
else {
|
||||
top = openfile->current;
|
||||
bot = top;
|
||||
}
|
||||
|
||||
/* Set up the text we'll be using as indentation. */
|
||||
line_indent = charalloc(tabsize + 1);
|
||||
/* Go through the lines to see if there's a non-empty one. */
|
||||
for (f = top; f != bot->next; f = f->next) {
|
||||
if (f->data[0] != '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
/* If all lines are empty, there is nothing to do. */
|
||||
if (f == bot->next) {
|
||||
free(line_indent);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the indentation to either a bunch of spaces or a single tab. */
|
||||
if (ISSET(TABS_TO_SPACES)) {
|
||||
/* Set the indentation to tabsize spaces. */
|
||||
charset(line_indent, ' ', tabsize);
|
||||
line_indent_len = tabsize;
|
||||
} else {
|
||||
/* Set the indentation to a tab. */
|
||||
line_indent[0] = '\t';
|
||||
line_indent_len = 1;
|
||||
}
|
||||
|
||||
line_indent[line_indent_len] = '\0';
|
||||
|
||||
/* Go through each line of the text. */
|
||||
/* Go through each of the lines, but skip empty ones. */
|
||||
for (f = top; f != bot->next; f = f->next) {
|
||||
size_t line_len = strlen(f->data);
|
||||
size_t indent_len = indent_length(f->data);
|
||||
|
||||
/* Add the characters in line_indent to
|
||||
* the beginning of the non-whitespace text of this line. */
|
||||
if (f->data[0] == '\0')
|
||||
continue;
|
||||
|
||||
/* Add the fabricated indentation to the beginning of the line. */
|
||||
f->data = charealloc(f->data, line_len + line_indent_len + 1);
|
||||
charmove(&f->data[indent_len + line_indent_len],
|
||||
&f->data[indent_len], line_len - indent_len + 1);
|
||||
strncpy(f->data + indent_len, line_indent, line_indent_len);
|
||||
charmove(&f->data[line_indent_len], f->data, line_len + 1);
|
||||
strncpy(f->data, line_indent, line_indent_len);
|
||||
|
||||
openfile->totsize += line_indent_len;
|
||||
|
||||
/* Keep track of the change in the current line. */
|
||||
if (openfile->mark_set && f == openfile->mark_begin &&
|
||||
openfile->mark_begin_x >= indent_len)
|
||||
/* Compensate for the change in the current line. */
|
||||
if (openfile->mark_set && f == openfile->mark_begin)
|
||||
openfile->mark_begin_x += line_indent_len;
|
||||
|
||||
if (f == openfile->current && openfile->current_x >= indent_len) {
|
||||
if (f == openfile->current) {
|
||||
openfile->current_x += line_indent_len;
|
||||
openfile->placewewant = xplustabs();
|
||||
}
|
||||
|
||||
/* If the NO_NEWLINES flag isn't set, and this is the
|
||||
* magicline, add a new magicline. */
|
||||
if (!ISSET(NO_NEWLINES) && f == openfile->filebot)
|
||||
new_magicline();
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
free(line_indent);
|
||||
|
||||
/* Throw away the undo stack, to prevent making mistakes when
|
||||
* the user tries to undo something in the indented text. */
|
||||
discard_until(NULL, openfile);
|
||||
|
||||
/* Mark the file as modified. */
|
||||
set_modified();
|
||||
|
||||
/* Update the screen. */
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
|
||||
/* If the given text starts with a tab's worth of whitespace, return the
|
||||
* number of bytes this whitespace occupies. Otherwise, return zero. */
|
||||
size_t length_of_white(const char *text)
|
||||
{
|
||||
size_t bytes_of_white = 1;
|
||||
|
||||
while (TRUE) {
|
||||
if (*text == '\t')
|
||||
return bytes_of_white;
|
||||
|
||||
if (*text != ' ')
|
||||
return 0;
|
||||
|
||||
if (bytes_of_white == tabsize)
|
||||
return tabsize;
|
||||
|
||||
bytes_of_white++;
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unindent the current line (or the marked lines) by tabsize columns.
|
||||
* The removed indent can be a mixture of spaces plus at most one tab. */
|
||||
void do_unindent(void)
|
||||
{
|
||||
bool indent_changed = FALSE;
|
||||
/* Whether any unindenting was done. */
|
||||
filestruct *top, *bot, *f;
|
||||
size_t top_x, bot_x;
|
||||
|
||||
assert(openfile->current != NULL && openfile->current->data != NULL);
|
||||
|
||||
/* If the mark is on, use all lines covered by the mark. */
|
||||
/* Use either all the marked lines or just the current line. */
|
||||
if (openfile->mark_set)
|
||||
mark_order((const filestruct **)&top, &top_x,
|
||||
(const filestruct **)&bot, &bot_x, NULL);
|
||||
/* Otherwise, use the current line. */
|
||||
else {
|
||||
top = openfile->current;
|
||||
bot = top;
|
||||
}
|
||||
|
||||
/* Go through each line of the text. */
|
||||
/* If any of the lines cannot be unindented and does not consist of
|
||||
* only whitespace, we don't change anything. */
|
||||
for (f = top; f != bot->next; f = f->next) {
|
||||
size_t line_len = strlen(f->data);
|
||||
size_t indent_len = indent_length(f->data);
|
||||
size_t indent_col = strnlenpt(f->data, indent_len);
|
||||
/* The length in columns of the indentation on this line. */
|
||||
|
||||
if (tabsize <= indent_col) {
|
||||
size_t indent_new = actual_x(f->data, indent_col - tabsize);
|
||||
/* The length of the indentation remaining on
|
||||
* this line after we unindent. */
|
||||
size_t indent_shift = indent_len - indent_new;
|
||||
/* The change in the indentation on this line
|
||||
* after we unindent. */
|
||||
|
||||
/* If there's at least tabsize
|
||||
* columns' worth of indentation at the beginning of the
|
||||
* non-whitespace text of this line, remove it. */
|
||||
charmove(&f->data[indent_new], &f->data[indent_len],
|
||||
line_len - indent_shift - indent_new + 1);
|
||||
null_at(&f->data, line_len - indent_shift + 1);
|
||||
openfile->totsize -= indent_shift;
|
||||
|
||||
/* Keep track of the change in the current line. */
|
||||
if (openfile->mark_set && f == openfile->mark_begin &&
|
||||
openfile->mark_begin_x > indent_new) {
|
||||
if (openfile->mark_begin_x <= indent_len)
|
||||
openfile->mark_begin_x = indent_new;
|
||||
else
|
||||
openfile->mark_begin_x -= indent_shift;
|
||||
}
|
||||
|
||||
if (f == openfile->current &&
|
||||
openfile->current_x > indent_new) {
|
||||
if (openfile->current_x <= indent_len)
|
||||
openfile->current_x = indent_new;
|
||||
else
|
||||
openfile->current_x -= indent_shift;
|
||||
openfile->placewewant = xplustabs();
|
||||
}
|
||||
|
||||
/* We've unindented, so the indentation changed. */
|
||||
indent_changed = TRUE;
|
||||
if (length_of_white(f->data) == 0 && !white_string(f->data)) {
|
||||
statusline(HUSH, _("Can unindent only by a full tab size"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (indent_changed) {
|
||||
/* Throw away the undo stack, to prevent making mistakes when
|
||||
* the user tries to undo something in the unindented text. */
|
||||
discard_until(NULL, openfile);
|
||||
/* Go through each of the lines and remove their leading indent. */
|
||||
for (f = top; f != bot->next; f = f->next) {
|
||||
size_t line_len = strlen(f->data);
|
||||
size_t indent_len = length_of_white(f->data);
|
||||
|
||||
/* Mark the file as modified. */
|
||||
set_modified();
|
||||
/* If this line cannot be unindeted, simply skip it. */
|
||||
if (indent_len == 0)
|
||||
continue;
|
||||
|
||||
/* Update the screen. */
|
||||
refresh_needed = TRUE;
|
||||
/* Remove the first tab's worth of whitespace from this line. */
|
||||
charmove(f->data, &f->data[indent_len], line_len - indent_len + 1);
|
||||
null_at(&f->data, line_len - indent_len + 1);
|
||||
openfile->totsize -= indent_len;
|
||||
|
||||
/* Compensate for the change in the current line. */
|
||||
if (openfile->mark_set && f == openfile->mark_begin) {
|
||||
if (openfile->mark_begin_x <= indent_len)
|
||||
openfile->mark_begin_x = 0;
|
||||
else
|
||||
openfile->mark_begin_x -= indent_len;
|
||||
}
|
||||
if (f == openfile->current) {
|
||||
if (openfile->current_x <= indent_len)
|
||||
openfile->current_x = 0;
|
||||
else
|
||||
openfile->current_x -= indent_len;
|
||||
openfile->placewewant = xplustabs();
|
||||
}
|
||||
}
|
||||
|
||||
/* Throw away the undo stack, to prevent making mistakes when
|
||||
* the user tries to undo something in the unindented text. */
|
||||
discard_until(NULL, openfile);
|
||||
|
||||
set_modified();
|
||||
refresh_needed = TRUE;
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
|
||||
@@ -2443,7 +2439,7 @@ void do_justify(bool full_justify)
|
||||
do {
|
||||
#endif
|
||||
statusbar(_("Can now UnJustify!"));
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
curs_set(1);
|
||||
kbinput = do_input(FALSE);
|
||||
#ifndef NANO_TINY
|
||||
@@ -3030,14 +3026,13 @@ void do_spell(void)
|
||||
* termination, and the error string otherwise. */
|
||||
void do_linter(void)
|
||||
{
|
||||
char *read_buff, *read_buff_ptr, *read_buff_word, *ptr;
|
||||
char *read_buff, *read_buff_ptr, *read_buff_word, *ptr, *lintcopy;
|
||||
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;
|
||||
char *lintcopy, *convendptr = NULL;
|
||||
lintstruct *lints = NULL, *tmplint = NULL, *curlint = NULL;
|
||||
|
||||
if (ISSET(RESTRICTED)) {
|
||||
@@ -3128,9 +3123,6 @@ void do_linter(void)
|
||||
read_buff = read_buff_ptr = charalloc(read_buff_size);
|
||||
|
||||
while ((bytesread = read(lint_fd[0], read_buff_ptr, pipe_buff_size)) > 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "text.c:do_linter:%ld bytes (%s)\n", (long)bytesread, read_buff_ptr);
|
||||
#endif
|
||||
read_buff_read += bytesread;
|
||||
read_buff_size += pipe_buff_size;
|
||||
read_buff = read_buff_ptr = charealloc(read_buff, read_buff_size);
|
||||
@@ -3140,10 +3132,6 @@ void do_linter(void)
|
||||
*read_buff_ptr = '\0';
|
||||
close(lint_fd[0]);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "text.c:do_lint:Raw output: %s\n", read_buff);
|
||||
#endif
|
||||
|
||||
/* Process the linter output. */
|
||||
read_buff_word = read_buff_ptr = read_buff;
|
||||
|
||||
@@ -3154,15 +3142,14 @@ void do_linter(void)
|
||||
char *filename = NULL, *linestr = NULL, *maybecol = NULL;
|
||||
char *message = mallocstrcpy(NULL, read_buff_word);
|
||||
|
||||
/* At the moment we're assuming the following formats:
|
||||
/* At the moment we handle the following formats:
|
||||
*
|
||||
* filenameorcategory:line:column:message (e.g. splint)
|
||||
* filenameorcategory:line,column:message (e.g. pylint)
|
||||
* filenameorcategory:line:message (e.g. pyflakes)
|
||||
* filenameorcategory:line,col:message (e.g. pylint)
|
||||
*
|
||||
* This could be turned into some scanf() based parser,
|
||||
* but ugh. */
|
||||
if ((filename = strtok(read_buff_word, ":")) != NULL) {
|
||||
*/
|
||||
if (strstr(message, ": ") != NULL) {
|
||||
filename = strtok(read_buff_word, ":");
|
||||
if ((linestr = strtok(NULL, ":")) != NULL) {
|
||||
if ((maybecol = strtok(NULL, ":")) != NULL) {
|
||||
ssize_t tmplineno = 0, tmpcolno = 0;
|
||||
@@ -3175,18 +3162,16 @@ void do_linter(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
tmpcolno = strtol(maybecol, &convendptr, 10);
|
||||
if (*convendptr != '\0') {
|
||||
/* Previous field might still be
|
||||
* line,col format. */
|
||||
tmpcolno = strtol(maybecol, NULL, 10);
|
||||
/* Check if the middle field is in comma format. */
|
||||
if (tmpcolno <= 0) {
|
||||
strtok(linestr, ",");
|
||||
if ((tmplinecol = strtok(NULL, ",")) != NULL)
|
||||
tmpcolno = strtol(tmplinecol, NULL, 10);
|
||||
else
|
||||
tmpcolno = 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "text.c:do_lint:Successful parse! %ld:%ld:%s\n", (long)tmplineno, (long)tmpcolno, message);
|
||||
#endif
|
||||
/* Nice. We have a lint message we can use. */
|
||||
parsesuccess++;
|
||||
tmplint = curlint;
|
||||
@@ -3313,7 +3298,7 @@ void do_linter(void)
|
||||
}
|
||||
|
||||
/* Place and show the cursor to indicate the affected line. */
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
wnoutrefresh(edit);
|
||||
curs_set(1);
|
||||
|
||||
@@ -3411,7 +3396,7 @@ void do_formatter(void)
|
||||
formatargs[0] = strtok(openfile->syntax->formatter, " ");
|
||||
while ((ptr = strtok(NULL, " ")) != NULL) {
|
||||
arglen++;
|
||||
formatargs = (char **)nrealloc(formatargs, arglen * sizeof(char *));
|
||||
formatargs = (char **)nrealloc(formatargs, arglen * sizeof(char *));
|
||||
formatargs[arglen - 3] = ptr;
|
||||
}
|
||||
formatargs[arglen - 1] = NULL;
|
||||
@@ -3561,7 +3546,7 @@ void do_verbatim_input(void)
|
||||
/* TRANSLATORS: This is displayed when the next keystroke will be
|
||||
* inserted verbatim. */
|
||||
statusbar(_("Verbatim Input"));
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
curs_set(1);
|
||||
|
||||
/* Read in all the verbatim characters. */
|
||||
@@ -3604,7 +3589,7 @@ char *copy_completion(char *check_line, int start)
|
||||
position = next;
|
||||
}
|
||||
|
||||
word = (char *)nmalloc((len_of_word + 1) * sizeof(char));
|
||||
word = charalloc(len_of_word + 1);
|
||||
|
||||
/* Simply copy the word. */
|
||||
while (index < len_of_word)
|
||||
@@ -3669,7 +3654,7 @@ void complete_a_word(void)
|
||||
return;
|
||||
}
|
||||
|
||||
shard = (char *)nmalloc((openfile->current_x - start_of_shard + 1) * sizeof(char));
|
||||
shard = charalloc(openfile->current_x - start_of_shard + 1);
|
||||
|
||||
/* Copy the fragment that has to be searched for. */
|
||||
while (start_of_shard < openfile->current_x)
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_PWD_H
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Return the user's home directory. We use $HOME, and if that fails,
|
||||
* we fall back on the home directory of the effective user ID. */
|
||||
|
||||
124
src/winio.c
124
src/winio.c
@@ -22,15 +22,11 @@
|
||||
#include "proto.h"
|
||||
#include "revision.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef REVISION
|
||||
#define BRANDING REVISION
|
||||
@@ -527,7 +523,15 @@ int parse_kbinput(WINDOW *win)
|
||||
} else if (retval == shiftcontrolend) {
|
||||
shift_held = TRUE;
|
||||
return CONTROL_END;
|
||||
} else if (retval == shiftaltleft) {
|
||||
} else if (retval == altleft)
|
||||
return ALT_LEFT;
|
||||
else if (retval == altright)
|
||||
return ALT_RIGHT;
|
||||
else if (retval == altup)
|
||||
return ALT_UP;
|
||||
else if (retval == altdown)
|
||||
return ALT_DOWN;
|
||||
else if (retval == shiftaltleft) {
|
||||
shift_held = TRUE;
|
||||
return KEY_HOME;
|
||||
} else if (retval == shiftaltright) {
|
||||
@@ -958,6 +962,18 @@ int convert_sequence(const int *seq, size_t seq_len)
|
||||
}
|
||||
break;
|
||||
#ifndef NANO_TINY
|
||||
case '3':
|
||||
switch (seq[4]) {
|
||||
case 'A': /* Esc [ 1 ; 3 A == Alt-Up on xterm. */
|
||||
return ALT_UP;
|
||||
case 'B': /* Esc [ 1 ; 3 B == Alt-Down on xterm. */
|
||||
return ALT_DOWN;
|
||||
case 'C': /* Esc [ 1 ; 3 C == Alt-Right on xterm. */
|
||||
return ALT_RIGHT;
|
||||
case 'D': /* Esc [ 1 ; 3 D == Alt-Left on xterm. */
|
||||
return ALT_LEFT;
|
||||
}
|
||||
break;
|
||||
case '4':
|
||||
/* When the arrow keys are held together with Shift+Meta,
|
||||
* act as if they are Home/End/PgUp/PgDown with Shift. */
|
||||
@@ -1252,7 +1268,7 @@ int parse_escape_sequence(WINDOW *win, int kbinput)
|
||||
suppress_cursorpos = FALSE;
|
||||
lastmessage = HUSH;
|
||||
if (currmenu == MMAIN) {
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
curs_set(1);
|
||||
}
|
||||
}
|
||||
@@ -1655,9 +1671,7 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
|
||||
/* Adjust the index if we hit the last two wider ones. */
|
||||
if ((j > number) && (*mouse_x % i < COLS % i))
|
||||
j -= 2;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Calculated %i as index in shortcut list, currmenu = %x.\n", j, currmenu);
|
||||
#endif
|
||||
|
||||
/* Ignore releases/clicks of the first mouse button beyond
|
||||
* the last shortcut. */
|
||||
if (j > number)
|
||||
@@ -1675,9 +1689,6 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
|
||||
if (j == 0)
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Stopped on func %ld present in menus %x\n", (long)f->scfunc, f->menus);
|
||||
#endif
|
||||
|
||||
/* And put the corresponding key into the keyboard buffer. */
|
||||
if (f != NULL) {
|
||||
@@ -1705,12 +1716,10 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
|
||||
if (in_edit || (in_bottomwin && *mouse_y == 0)) {
|
||||
int i;
|
||||
|
||||
/* One upward roll of the mouse wheel is equivalent to
|
||||
* moving up three lines, and one downward roll of the mouse
|
||||
* wheel is equivalent to moving down three lines. */
|
||||
/* One roll of the mouse wheel should move three lines. */
|
||||
for (i = 0; i < 3; i++)
|
||||
unget_kbinput((mevent.bstate & BUTTON4_PRESSED) ?
|
||||
KEY_PPAGE : KEY_NPAGE, FALSE);
|
||||
KEY_UP : KEY_DOWN, FALSE);
|
||||
|
||||
return 1;
|
||||
} else
|
||||
@@ -1895,7 +1904,9 @@ char *display_string(const char *buf, size_t column, size_t span, bool isdata)
|
||||
} else if (*buf == '\t') {
|
||||
/* Show a tab as a visible character, or as as a space. */
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(WHITESPACE_DISPLAY)) {
|
||||
if (ISSET(WHITESPACE_DISPLAY) && (index > 0 || !isdata ||
|
||||
!ISSET(SOFTWRAP) || column % tabsize == 0 ||
|
||||
column == start_col)) {
|
||||
int i = 0;
|
||||
|
||||
while (i < whitespace_len[0])
|
||||
@@ -2275,7 +2286,7 @@ void onekey(const char *keystroke, const char *desc, int length)
|
||||
|
||||
/* Redetermine current_y from the position of current relative to edittop,
|
||||
* and put the cursor in the edit window at (current_y, "current_x"). */
|
||||
void place_the_cursor(bool forreal)
|
||||
void place_the_cursor(void)
|
||||
{
|
||||
ssize_t row = 0;
|
||||
size_t col, xpt = xplustabs();
|
||||
@@ -2306,8 +2317,7 @@ void place_the_cursor(bool forreal)
|
||||
if (row < editwinrows)
|
||||
wmove(edit, row, margin + col);
|
||||
|
||||
if (forreal)
|
||||
openfile->current_y = row;
|
||||
openfile->current_y = row;
|
||||
}
|
||||
|
||||
/* edit_draw() takes care of the job of actually painting a line into
|
||||
@@ -2340,7 +2350,7 @@ void edit_draw(filestruct *fileptr, const char *converted,
|
||||
if (margin > 0) {
|
||||
wattron(edit, interface_color_pair[LINE_NUMBER]);
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP) && from_x != 0)
|
||||
if (ISSET(SOFTWRAP) && from_col != 0)
|
||||
mvwprintw(edit, row, 0, "%*s", margin - 1, " ");
|
||||
else
|
||||
#endif
|
||||
@@ -2654,9 +2664,9 @@ void edit_draw(filestruct *fileptr, const char *converted,
|
||||
paintlen = actual_x(thetext, end_col - start_col);
|
||||
}
|
||||
|
||||
wattron(edit, hilite_attribute);
|
||||
wattron(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
mvwaddnstr(edit, row, margin + start_col, thetext, paintlen);
|
||||
wattroff(edit, hilite_attribute);
|
||||
wattroff(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
}
|
||||
}
|
||||
#endif /* !NANO_TINY */
|
||||
@@ -2803,10 +2813,6 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Don't move more chunks than the window can hold. */
|
||||
if (nrows > editwinrows - 1)
|
||||
nrows = (editwinrows < 2) ? 1 : editwinrows - 1;
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
/* Recede through the requested number of chunks. */
|
||||
@@ -2993,11 +2999,13 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
|
||||
int char_len = 0;
|
||||
/* Length of current character, in bytes. */
|
||||
|
||||
while (*text != '\0' && column < leftedge)
|
||||
text += parse_mbchar(text, NULL, &column);
|
||||
while (*text != '\0' && column < leftedge) {
|
||||
char_len = parse_mbchar(text, NULL, &column);
|
||||
text += char_len;
|
||||
}
|
||||
|
||||
/* Use a full screen row for text. */
|
||||
goal_column = column + editwincols;
|
||||
/* The intention is to use the entire available width. */
|
||||
goal_column = leftedge + editwincols;
|
||||
|
||||
while (*text != '\0' && column <= goal_column) {
|
||||
/* When breaking at blanks, do it *before* the target column. */
|
||||
@@ -3025,9 +3033,18 @@ size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
|
||||
if (found_blank) {
|
||||
text = text - index + lastblank_index;
|
||||
parse_mbchar(text, NULL, &lastblank_column);
|
||||
|
||||
/* If we've now overshot the screen's edge, then break there. */
|
||||
if (lastblank_column > goal_column)
|
||||
return goal_column;
|
||||
|
||||
return lastblank_column;
|
||||
}
|
||||
|
||||
/* If a tab is split over two chunks, break at the screen's edge. */
|
||||
if (*(text - char_len) == '\t')
|
||||
prev_column = goal_column;
|
||||
|
||||
/* Otherwise, return the column of the last character that doesn't
|
||||
* overshoot the target, since we can't break the text anywhere else. */
|
||||
return (editwincols > 1) ? prev_column : column - 1;
|
||||
@@ -3060,7 +3077,10 @@ size_t get_chunk_and_edge(size_t column, filestruct *line, size_t *leftedge)
|
||||
* relative to the first row (zero-based). */
|
||||
size_t chunk_for(size_t column, filestruct *line)
|
||||
{
|
||||
return get_chunk_and_edge(column, line, NULL);
|
||||
if (ISSET(SOFTWRAP))
|
||||
return get_chunk_and_edge(column, line, NULL);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the leftmost column of the softwrapped chunk of the given line that
|
||||
@@ -3069,6 +3089,9 @@ size_t leftedge_for(size_t column, filestruct *line)
|
||||
{
|
||||
size_t leftedge;
|
||||
|
||||
if (!ISSET(SOFTWRAP))
|
||||
return 0;
|
||||
|
||||
get_chunk_and_edge(column, line, &leftedge);
|
||||
|
||||
return leftedge;
|
||||
@@ -3108,7 +3131,7 @@ size_t actual_last_column(size_t leftedge, size_t column)
|
||||
|
||||
/* If we're not on the last chunk, we're one column past the end of
|
||||
* the row. Shifting back one column might put us in the middle of
|
||||
* a multi-column character, but actual_x() will fix that later. */
|
||||
* a multi-column character, but actual_x() will fix that later. */
|
||||
if (!last_chunk)
|
||||
end_col--;
|
||||
|
||||
@@ -3167,7 +3190,7 @@ bool current_is_offscreen(void)
|
||||
|
||||
/* Update any lines between old_current and current that need to be
|
||||
* updated. Use this if we've moved without changing any text. */
|
||||
void edit_redraw(filestruct *old_current)
|
||||
void edit_redraw(filestruct *old_current, update_type manner)
|
||||
{
|
||||
size_t was_pww = openfile->placewewant;
|
||||
|
||||
@@ -3175,7 +3198,7 @@ void edit_redraw(filestruct *old_current)
|
||||
|
||||
/* If the current line is offscreen, scroll until it's onscreen. */
|
||||
if (current_is_offscreen()) {
|
||||
adjust_viewport((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : FLOWING);
|
||||
adjust_viewport(ISSET(SMOOTH_SCROLL) ? manner : CENTERING);
|
||||
refresh_needed = TRUE;
|
||||
return;
|
||||
}
|
||||
@@ -3220,17 +3243,8 @@ void edit_refresh(void)
|
||||
#endif
|
||||
|
||||
/* If the current line is out of view, get it back on screen. */
|
||||
if (current_is_offscreen()) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "edit-refresh: line = %ld, edittop = %ld and editwinrows = %d\n",
|
||||
(long)openfile->current->lineno, (long)openfile->edittop->lineno, editwinrows);
|
||||
#endif
|
||||
adjust_viewport((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : STATIONARY);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "edit-refresh: now edittop = %ld\n", (long)openfile->edittop->lineno);
|
||||
#endif
|
||||
if (current_is_offscreen())
|
||||
adjust_viewport((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : FLOWING);
|
||||
|
||||
line = openfile->edittop;
|
||||
|
||||
@@ -3245,7 +3259,7 @@ void edit_refresh(void)
|
||||
while (row < editwinrows)
|
||||
blank_row(edit, row++, 0, COLS);
|
||||
|
||||
place_the_cursor(TRUE);
|
||||
place_the_cursor();
|
||||
wnoutrefresh(edit);
|
||||
|
||||
refresh_needed = FALSE;
|
||||
@@ -3275,10 +3289,6 @@ void adjust_viewport(update_type manner)
|
||||
|
||||
/* Move edittop back goal rows, starting at current[current_x]. */
|
||||
go_back_chunks(goal, &openfile->edittop, &openfile->firstcolumn);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "adjust_viewport(): setting edittop to lineno %ld\n", (long)openfile->edittop->lineno);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unconditionally redraw the entire screen. */
|
||||
@@ -3398,7 +3408,7 @@ void spotlight(bool active, size_t from_col, size_t to_col)
|
||||
char *word;
|
||||
size_t word_span, room;
|
||||
|
||||
place_the_cursor(FALSE);
|
||||
place_the_cursor();
|
||||
|
||||
#ifndef NANO_TINY
|
||||
if (ISSET(SOFTWRAP)) {
|
||||
@@ -3425,7 +3435,7 @@ void spotlight(bool active, size_t from_col, size_t to_col)
|
||||
room--;
|
||||
|
||||
if (active)
|
||||
wattron(edit, hilite_attribute);
|
||||
wattron(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
|
||||
waddnstr(edit, word, actual_x(word, room));
|
||||
|
||||
@@ -3433,7 +3443,7 @@ void spotlight(bool active, size_t from_col, size_t to_col)
|
||||
waddch(edit, '$');
|
||||
|
||||
if (active)
|
||||
wattroff(edit, hilite_attribute);
|
||||
wattroff(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
|
||||
free(word);
|
||||
|
||||
@@ -3472,12 +3482,12 @@ void spotlight_softwrapped(bool active, size_t from_col, size_t to_col)
|
||||
break_col - from_col, FALSE);
|
||||
|
||||
if (active)
|
||||
wattron(edit, hilite_attribute);
|
||||
wattron(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
|
||||
waddnstr(edit, word, actual_x(word, break_col));
|
||||
|
||||
if (active)
|
||||
wattroff(edit, hilite_attribute);
|
||||
wattroff(edit, interface_color_pair[SELECTED_TEXT]);
|
||||
|
||||
free(word);
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@ syntax "c" "\.(c(c|pp|xx|\+\+)?|C)$" "\.(h(h|pp|xx)?|H)$" "\.ii?$"
|
||||
magic "(ASCII|UTF-8 Unicode) C(\+\+)? program text"
|
||||
comment "//"
|
||||
|
||||
# Constants.
|
||||
color brightred "\<[A-Z_][0-9A-Z_]+\>"
|
||||
# Labels.
|
||||
color brightmagenta "^[[:space:]]*[A-Z_a-z]+:[[:space:]]*$"
|
||||
|
||||
color green "\<(float|double|bool|char|int|short|long|sizeof|enum|void|auto|static|const|struct|union|typedef|extern|(un)?signed|inline)\>"
|
||||
color green "\<((s?size)|((u_?)?int(8|16|32|64|ptr)))_t\>"
|
||||
color green "\<(class|namespace|template|public|protected|private|typename|this|friend|virtual|override|using|mutable|volatile|register|explicit)\>"
|
||||
|
||||
@@ -5,7 +5,7 @@ magic "HTML document text"
|
||||
comment "<!--|-->"
|
||||
|
||||
# Tags:
|
||||
color cyan start="<[[:alpha:]/!?]" end=">"
|
||||
color cyan "<[[:alpha:]/!?][^>]*>"
|
||||
# Bold, italic, and underlined:
|
||||
color brightmagenta "</?[biu]>"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ icolor brightred "^[[:space:]]*((un)?(bind|set)|include|syntax|header|magic|comm
|
||||
# Keywords
|
||||
icolor brightgreen "^[[:space:]]*(set|unset)[[:space:]]+(allow_insecure_backup|atblanks|autoindent|backup|backwards|boldtext|casesensitive|constantshow|cutfromcursor|fill[[:space:]]+-?[[:digit:]]+|historylog|justifytrim|linenumbers|locking|morespace|mouse|multibuffer|noconvert|nohelp|nopauses|nonewlines|nowrap|positionlog|preserve|quickblank|quiet|rebinddelete|rebindkeypad|regexp|showcursor|smarthome|smooth|softwrap|suspend|tabsize[[:space:]]+[1-9][0-9]*|tabstospaces|tempfile|unix|view|wordbounds)\>"
|
||||
icolor yellow "^[[:space:]]*set[[:space:]]+((function|key|number|status|title)color)[[:space:]]+(bright)?(white|black|red|blue|green|yellow|magenta|cyan)?(,(white|black|red|blue|green|yellow|magenta|cyan))?\>"
|
||||
icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|speller|statuscolor|titlecolor|whitespace|wordchars)[[:space:]]+"
|
||||
icolor brightgreen "^[[:space:]]*set[[:space:]]+(backupdir|brackets|functioncolor|keycolor|matchbrackets|numbercolor|operatingdir|punct|quotestr|selectedcolor|speller|statuscolor|titlecolor|whitespace|wordchars)[[:space:]]+"
|
||||
icolor brightgreen "^[[:space:]]*bind[[:space:]]+((\^([[:alpha:]]|[]0-9\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+[[:alpha:]]+[[:space:]]+(all|main|search|replace(with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
|
||||
icolor brightgreen "^[[:space:]]*unbind[[:space:]]+((\^([[:alpha:]]|[]0-9\^_]|Space)|M-([[:alpha:]]|[]!"#$%&'()*+,./0-9:;<=>?@\^_`{|}~-]|Space))|F([1-9]|1[0-6])|Ins|Del)[[:space:]]+(all|main|search|replace(with)?|gotoline|writeout|insert|ext(ernal)?cmd|help|spell|linter|browser|whereisfile|gotodir)([[:space:]]+#|[[:space:]]*$)"
|
||||
icolor brightgreen "^[[:space:]]*extendsyntax[[:space:]]+[[:alpha:]]+[[:space:]]+(i?color|header|magic|comment|linter|formatter)[[:space:]]+.*$"
|
||||
|
||||
@@ -17,8 +17,8 @@ color brightgreen ""([^"\]|\\.)+""
|
||||
# Comments.
|
||||
color brightred "(^|[[:blank:]])#.*$"
|
||||
# Triple-quoted strings.
|
||||
color brightgreen start="'''[^'),]" end="(^|[^(\])'''"
|
||||
color brightgreen start="\"\"\"[^"),]" end="(^|[^(\])\"\"\""
|
||||
color brightgreen start="'''([^'),]|$)" end="(^|[^(\])'''"
|
||||
color brightgreen start="\"\"\"([^"),]|$)" end="(^|[^(\])\"\"\""
|
||||
|
||||
# Reminders.
|
||||
color ,yellow "(FIXME|TODO|XXX)"
|
||||
|
||||
Reference in New Issue
Block a user