new feature: the ability to show line numbers before the text

It can be activated with --linenumbers on the command line or with
'set linenumbers' in a nanorc file, and it can be toggled with M-#.

Signed-off-by: Faissal Bensefia <faissaloo@gmail.com>
Signed-off-by: Benno Schulenberg <bensberg@justemail.net>
master
Faissal Bensefia 2016-10-20 09:44:29 +01:00 committed by Benno Schulenberg
parent 55878efe5d
commit de95ca68f7
11 changed files with 172 additions and 42 deletions

View File

@ -125,6 +125,19 @@ fi
AC_ARG_ENABLE(libmagic,
AS_HELP_STRING([--disable-libmagic], [Disable detection of file types via libmagic]))
AC_ARG_ENABLE(linenumbers,
AS_HELP_STRING([--disable-linenumbers], [Disable line numbering]))
if test "x$enable_tiny" = xyes; then
if test "x$enable_linenumbers" != xyes; then
enable_linenumbers=no
fi
fi
if test "x$disable_linenumbers" != xyes; then
if test "x$enable_linenumbers" != xno; then
AC_DEFINE(ENABLE_LINENUMBERS, 1, [Define this to enable line numbering.])
fi
fi
AC_ARG_ENABLE(mouse,
AS_HELP_STRING([--disable-mouse], [Disable mouse support (and -m flag)]))
if test "x$enable_mouse" = xno; then

View File

@ -183,6 +183,9 @@ editing source code.
Make the 'Cut Text' command (normally ^K) cut from the current cursor
position to the end of the line, instead of cutting the entire line.
.TP
.BR \-l ", " \-\-linenumbers
Display line numbers to the left of the text area.
.TP
.BR \-m ", " \-\-mouse
Enable mouse support, if available for your system. When enabled, mouse
clicks can be used to place the cursor, set the mark (with a double

View File

@ -116,6 +116,9 @@ Specify the color combination to use for the shortcut key combos
in the two help lines at the bottom of the screen.
See \fBset titlecolor\fR for more details.
.TP
.B set linenumbers
Display line numbers to the left of the text area.
.TP
.B set locking
Enable vim-style lock-files for when editing files.
.TP

View File

@ -45,6 +45,17 @@ bool shift_held;
bool focusing = TRUE;
/* Whether an update of the edit window should center the cursor. */
int margin = 0;
/* The amount of space reserved at the left for line numbers. */
int editwincols = -1;
/* The number of usable columns in the edit window: COLS - margin. */
#ifdef ENABLE_LINENUMBERS
int last_drawn_line = 0;
/* The line number of the last drawn line. */
int last_line_y;
/* The y coordinate of the last drawn line. */
#endif
message_type lastmessage = HUSH;
/* Messages of type HUSH should not overwrite type MILD nor ALERT. */
@ -1154,6 +1165,9 @@ void shortcut_init(void)
add_to_sclist(MMAIN, "M-O", 0, do_toggle_void, MORE_SPACE);
add_to_sclist(MMAIN, "M-S", 0, do_toggle_void, SMOOTH_SCROLL);
add_to_sclist(MMAIN, "M-$", 0, do_toggle_void, SOFTWRAP);
#ifdef ENABLE_LINENUMBERS
add_to_sclist(MMAIN, "M-#", 0, do_toggle_void, LINE_NUMBERS);
#endif
add_to_sclist(MMAIN, "M-P", 0, do_toggle_void, WHITESPACE_DISPLAY);
#ifndef DISABLE_COLOR
add_to_sclist(MMAIN, "M-Y", 0, do_toggle_void, NO_COLOR_SYNTAX);
@ -1332,6 +1346,8 @@ const char *flagtostr(int flag)
return N_("No conversion from DOS/Mac format");
case SUSPEND:
return N_("Suspension");
case LINE_NUMBERS:
return N_("Line numbering");
default:
return "?????";
}

View File

@ -367,7 +367,7 @@ void do_next_word_void(void)
void ensure_line_is_visible(void)
{
#ifndef NANO_TINY
if (ISSET(SOFTWRAP) && strlenpt(openfile->current->data) / COLS +
if (ISSET(SOFTWRAP) && strlenpt(openfile->current->data) / editwincols +
openfile->current_y >= editwinrows) {
edit_update(ISSET(SMOOTH_SCROLL) ? FLOWING : CENTERING);
refresh_needed = TRUE;
@ -492,13 +492,14 @@ void do_down(bool scroll_only)
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
/* Compute the number of lines to scroll. */
amount = strlenpt(openfile->current->data) / COLS - xplustabs() / COLS +
strlenpt(openfile->current->next->data) / COLS +
amount = strlenpt(openfile->current->data) / editwincols -
xplustabs() / editwincols +
strlenpt(openfile->current->next->data) / editwincols +
openfile->current_y - editwinrows + 2;
topline = openfile->edittop;
/* Reduce the amount when there are overlong lines at the top. */
for (enough = 1; enough < amount; enough++) {
amount -= strlenpt(topline->data) / COLS;
amount -= strlenpt(topline->data) / editwincols;
if (amount > 0)
topline = topline->next;
if (amount < enough) {

View File

@ -884,6 +884,9 @@ void usage(void)
print_opt("-i", "--autoindent", N_("Automatically indent new lines"));
print_opt("-k", "--cut", N_("Cut from cursor to end of line"));
#endif
#ifdef ENABLE_LINENUMBERS
print_opt("-l", "--linenumbers", N_("Show line numbers in front of the text"));
#endif
#ifndef DISABLE_MOUSE
print_opt("-m", "--mouse", N_("Enable the use of the mouse"));
#endif
@ -962,6 +965,9 @@ void version(void)
#ifdef HAVE_LIBMAGIC
printf(" --enable-libmagic");
#endif
#ifdef ENABLE_LINENUMBERS
printf(" --enable-linenumbers");
#endif
#ifndef DISABLE_MOUSE
printf(" --enable-mouse");
#endif
@ -1008,6 +1014,9 @@ void version(void)
#ifndef HAVE_LIBMAGIC
printf(" --disable-libmagic");
#endif
#ifndef ENABLE_LINENUMBERS
printf(" --disable-linenumbers");
#endif
#ifdef DISABLE_MOUSE
printf(" --disable-mouse");
#endif
@ -1340,6 +1349,7 @@ void regenerate_screen(void)
COLS = win.ws_col;
LINES = win.ws_row;
#endif
editwincols = COLS - margin;
#ifdef USE_SLANG
/* Slang curses emulation brain damage, part 1: If we just do what
@ -1413,6 +1423,9 @@ void do_toggle(int flag)
break;
#ifndef DISABLE_COLOR
case NO_COLOR_SYNTAX:
#endif
#ifdef ENABLE_LINENUMBERS
case LINE_NUMBERS:
#endif
case SOFTWRAP:
edit_refresh();
@ -1992,6 +2005,9 @@ int main(int argc, char **argv)
{"constantshow", 0, NULL, 'c'},
{"rebinddelete", 0, NULL, 'd'},
{"help", 0, NULL, 'h'},
#ifdef ENABLE_LINENUMBERS
{"linenumbers", 0, NULL, 'l'},
#endif
#ifndef DISABLE_MOUSE
{"mouse", 0, NULL, 'm'},
#endif
@ -2270,6 +2286,11 @@ int main(int argc, char **argv)
case '$':
SET(SOFTWRAP);
break;
#endif
#ifdef ENABLE_LINENUMBERS
case 'l':
SET(LINE_NUMBERS);
break;
#endif
case 'h':
usage();
@ -2542,6 +2563,8 @@ int main(int argc, char **argv)
* dimensions. */
window_init();
editwincols = COLS - margin;
/* Set up the signal handlers. */
signal_init();

View File

@ -536,7 +536,8 @@ enum
NOREAD_MODE,
MAKE_IT_UNIX,
JUSTIFY_TRIM,
SHOW_CURSOR
SHOW_CURSOR,
LINE_NUMBERS
};
/* Flags for the menus in which a given function should be present. */

View File

@ -38,6 +38,13 @@ extern bool shift_held;
extern bool focusing;
extern int margin;
extern int editwincols;
#ifdef ENABLE_LINENUMBERS
extern int last_drawn_line;
extern int last_line_y;
#endif
extern message_type lastmessage;
extern int controlleft;
@ -675,6 +682,7 @@ void do_verbatim_input(void);
/* All functions in utils.c. */
void get_homedir(void);
int digits(int n);
bool parse_num(const char *str, ssize_t *val);
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column);
void align(char **str);

View File

@ -35,6 +35,9 @@
static const rcoption rcopts[] = {
{"boldtext", BOLD_TEXT},
#ifdef ENABLE_LINENUMBERS
{"linenumbers", LINE_NUMBERS},
#endif
#ifndef DISABLE_JUSTIFY
{"brackets", 0},
#endif

View File

@ -52,6 +52,39 @@ void get_homedir(void)
}
}
#ifdef ENABLE_LINENUMBERS
/* Return the number of digits that the given integer n takes up. */
int digits(int n)
{
if (n < 100000) {
if (n < 1000) {
if (n < 100)
return 2;
else
return 3;
} else {
if (n < 10000)
return 4;
else
return 5;
}
} else {
if (n < 10000000) {
if (n < 1000000)
return 6;
else
return 7;
}
else {
if (n < 100000000)
return 8;
else
return 9;
}
}
}
#endif
/* Read a ssize_t from str, and store it in *val (if val is not NULL).
* On error, we return FALSE and don't change *val. Otherwise, we
* return TRUE. */
@ -430,12 +463,12 @@ char *free_and_assign(char *dest, char *src)
* get_page_start(column) < COLS). */
size_t get_page_start(size_t column)
{
if (column == 0 || column < COLS - 1)
if (column == 0 || column < editwincols - 1)
return 0;
else if (COLS > 8)
return column - 7 - (column - 7) % (COLS - 8);
else if (editwincols > 8)
return column - 7 - (column - 7) % (editwincols - 8);
else
return column - (COLS - 2);
return column - (editwincols - 2);
}
/* Return the placewewant associated with current_x, i.e. the zero-based

View File

@ -1534,7 +1534,7 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
return -1;
/* Save the screen coordinates where the mouse event took place. */
*mouse_x = mevent.x;
*mouse_x = mevent.x - margin;
*mouse_y = mevent.y;
in_bottomwin = wenclose(bottomwin, *mouse_y, *mouse_x);
@ -1564,7 +1564,7 @@ int get_mouseinput(int *mouse_x, int *mouse_y, bool allow_shortcuts)
if (*mouse_y == 0) {
/* Restore the untranslated mouse event coordinates, so
* that they're relative to the entire screen again. */
*mouse_x = mevent.x;
*mouse_x = mevent.x - margin;
*mouse_y = mevent.y;
return 0;
@ -2224,13 +2224,13 @@ void reset_cursor(void)
openfile->current_y = 0;
while (line != NULL && line != openfile->current) {
openfile->current_y += strlenpt(line->data) / COLS + 1;
openfile->current_y += strlenpt(line->data) / editwincols + 1;
line = line->next;
}
openfile->current_y += xpt / COLS;
openfile->current_y += xpt / editwincols;
if (openfile->current_y < editwinrows)
wmove(edit, openfile->current_y, xpt % COLS);
wmove(edit, openfile->current_y, xpt % editwincols + margin);
} else
#endif
{
@ -2238,7 +2238,7 @@ void reset_cursor(void)
openfile->edittop->lineno;
if (openfile->current_y < editwinrows)
wmove(edit, openfile->current_y, xpt - get_page_start(xpt));
wmove(edit, openfile->current_y, xpt - get_page_start(xpt) + margin);
}
}
@ -2257,7 +2257,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
size_t startpos = actual_x(fileptr->data, start);
/* The position in fileptr->data of the leftmost character
* that displays at least partially on the window. */
size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1;
size_t endpos = actual_x(fileptr->data, start + editwincols - 1) + 1;
/* The position in fileptr->data of the first character that is
* completely off the window to the right.
*
@ -2266,11 +2266,33 @@ void edit_draw(filestruct *fileptr, const char *converted, int
#endif
assert(openfile != NULL && fileptr != NULL && converted != NULL);
assert(strlenpt(converted) <= COLS);
assert(strlenpt(converted) <= editwincols);
#ifdef ENABLE_LINENUMBERS
if (ISSET(LINE_NUMBERS)) {
/* If the line numbers now require more room, schedule a refresh. */
if (digits(openfile->filebot->lineno) + 1 != margin) {
margin = digits(openfile->filebot->lineno) + 1;
editwincols = COLS - margin;
refresh_needed = TRUE;
}
/* Show the line number only for the non-softwrapped parts. */
wattron(edit, hilite_attribute);
if (last_drawn_line != fileptr->lineno || last_line_y >= line)
mvwprintw(edit, line, 0, "%*i", margin - 1, fileptr->lineno);
else
mvwprintw(edit, line, 0, "%*s", margin - 1, " ");
wattroff(edit, hilite_attribute);
} else {
margin = 0;
editwincols = COLS;
}
#endif
/* First simply paint the line -- then we'll add colors or the
* marking highlight on just the pieces that need it. */
mvwaddstr(edit, line, 0, converted);
mvwaddstr(edit, line, margin, converted);
#ifdef USING_OLD_NCURSES
/* Tell ncurses to really redraw the line without trying to optimize
@ -2348,7 +2370,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
assert(0 <= x_start && 0 <= paintlen);
mvwaddnstr(edit, line, x_start, converted +
mvwaddnstr(edit, line, x_start + margin, converted +
index, paintlen);
}
k = startmatch.rm_eo;
@ -2365,7 +2387,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
if (fileptr->multidata[varnish->id] == CNONE)
goto tail_of_loop;
else if (fileptr->multidata[varnish->id] == CWHOLELINE) {
mvwaddnstr(edit, line, 0, converted, -1);
mvwaddnstr(edit, line, margin, converted, -1);
goto tail_of_loop;
} else if (fileptr->multidata[varnish->id] == CBEGINBEFORE) {
regexec(varnish->end, fileptr->data, 1, &endmatch, 0);
@ -2374,7 +2396,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
goto tail_of_loop;
paintlen = actual_x(converted, strnlenpt(fileptr->data,
endmatch.rm_eo) - start);
mvwaddnstr(edit, line, 0, converted, paintlen);
mvwaddnstr(edit, line, margin, converted, paintlen);
goto tail_of_loop;
} if (fileptr->multidata[varnish->id] == -1)
/* Assume this until proven otherwise below. */
@ -2470,7 +2492,7 @@ void edit_draw(filestruct *fileptr, const char *converted, int
fprintf(stderr, " Marking for id %i line %i as CBEGINBEFORE\n", varnish->id, line);
#endif
}
mvwaddnstr(edit, line, 0, converted, paintlen);
mvwaddnstr(edit, line, margin, converted, paintlen);
/* If the whole line has been painted, don't bother looking
* for any more starts. */
if (paintlen < 0)
@ -2516,9 +2538,9 @@ void edit_draw(filestruct *fileptr, const char *converted, int
strnlenpt(fileptr->data,
endmatch.rm_eo) - start - x_start);
assert(0 <= x_start && x_start < COLS);
assert(0 <= x_start && x_start < editwincols);
mvwaddnstr(edit, line, x_start,
mvwaddnstr(edit, line, x_start + margin,
converted + index, paintlen);
if (paintlen > 0) {
fileptr->multidata[varnish->id] = CSTARTENDHERE;
@ -2545,10 +2567,10 @@ void edit_draw(filestruct *fileptr, const char *converted, int
if (end_line == NULL)
break;
assert(0 <= x_start && x_start < COLS);
assert(0 <= x_start && x_start < editwincols);
/* Paint the rest of the line. */
mvwaddnstr(edit, line, x_start, converted + index, -1);
mvwaddnstr(edit, line, x_start + margin, converted + index, -1);
fileptr->multidata[varnish->id] = CENDAFTER;
#ifdef DEBUG
fprintf(stderr, " Marking for id %i line %i as CENDAFTER\n", varnish->id, line);
@ -2626,11 +2648,15 @@ void edit_draw(filestruct *fileptr, const char *converted, int
paintlen = actual_x(converted + index, paintlen);
wattron(edit, hilite_attribute);
mvwaddnstr(edit, line, x_start, converted + index, paintlen);
mvwaddnstr(edit, line, x_start + margin, converted + index, paintlen);
wattroff(edit, hilite_attribute);
}
}
#endif /* !NANO_TINY */
#ifdef ENABLE_LINENUMBERS
last_drawn_line = fileptr->lineno;
last_line_y = line;
#endif
}
/* Just update one line in the edit buffer. This is basically a wrapper
@ -2654,7 +2680,7 @@ int update_line(filestruct *fileptr, size_t index)
filestruct *tmp;
for (tmp = openfile->edittop; tmp && tmp != fileptr; tmp = tmp->next)
line += (strlenpt(tmp->data) / COLS) + 1;
line += (strlenpt(tmp->data) / editwincols) + 1;
} else
#endif
line = fileptr->lineno - openfile->edittop->lineno;
@ -2678,11 +2704,11 @@ int update_line(filestruct *fileptr, size_t index)
/* Expand the line, replacing tabs with spaces, and control
* characters with their displayed forms. */
#ifdef NANO_TINY
converted = display_string(fileptr->data, page_start, COLS, TRUE);
converted = display_string(fileptr->data, page_start, editwincols, TRUE);
#else
converted = display_string(fileptr->data, page_start, COLS, !ISSET(SOFTWRAP));
converted = display_string(fileptr->data, page_start, editwincols, !ISSET(SOFTWRAP));
#ifdef DEBUG
if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2)
if (ISSET(SOFTWRAP) && strlen(converted) >= editwincols - 2)
fprintf(stderr, "update_line(): converted(1) line = %s\n", converted);
#endif
#endif /* !NANO_TINY */
@ -2695,13 +2721,13 @@ int update_line(filestruct *fileptr, size_t index)
if (!ISSET(SOFTWRAP)) {
#endif
if (page_start > 0)
mvwaddch(edit, line, 0, '$');
if (strlenpt(fileptr->data) > page_start + COLS)
mvwaddch(edit, line, margin, '$');
if (strlenpt(fileptr->data) > page_start + editwincols)
mvwaddch(edit, line, COLS - 1, '$');
#ifndef NANO_TINY
} else {
size_t full_length = strlenpt(fileptr->data);
for (index += COLS; index <= full_length && line < editwinrows - 1; index += COLS) {
for (index += editwincols; index <= full_length && line < editwinrows - 1; index += editwincols) {
line++;
#ifdef DEBUG
fprintf(stderr, "update_line(): softwrap code, moving to %d index %lu\n", line, (unsigned long)index);
@ -2710,9 +2736,9 @@ int update_line(filestruct *fileptr, size_t index)
/* Expand the line, replacing tabs with spaces, and control
* characters with their displayed forms. */
converted = display_string(fileptr->data, index, COLS, !ISSET(SOFTWRAP));
converted = display_string(fileptr->data, index, editwincols, !ISSET(SOFTWRAP));
#ifdef DEBUG
if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2)
if (ISSET(SOFTWRAP) && strlen(converted) >= editwincols - 2)
fprintf(stderr, "update_line(): converted(2) line = %s\n", converted);
#endif
@ -2753,7 +2779,7 @@ void compute_maxrows(void)
maxrows = 0;
for (n = 0; n < editwinrows && foo; n++) {
maxrows++;
n += strlenpt(foo->data) / COLS;
n += strlenpt(foo->data) / editwincols;
foo = foo->next;
}
@ -2798,7 +2824,7 @@ void edit_scroll(scroll_dir direction, ssize_t nlines)
#ifndef NANO_TINY
/* Don't over-scroll on long lines. */
if (ISSET(SOFTWRAP) && direction == UPWARD) {
ssize_t len = strlenpt(openfile->edittop->data) / COLS;
ssize_t len = strlenpt(openfile->edittop->data) / editwincols;
i -= len;
if (len > 0)
refresh_needed = TRUE;
@ -2879,7 +2905,7 @@ void edit_redraw(filestruct *old_current)
if (openfile->current->lineno >= openfile->edittop->lineno + maxrows ||
#ifndef NANO_TINY
(openfile->current->lineno == openfile->edittop->lineno + maxrows - 1 &&
ISSET(SOFTWRAP) && strlenpt(openfile->current->data) >= COLS) ||
ISSET(SOFTWRAP) && strlenpt(openfile->current->data) >= editwincols) ||
#endif
openfile->current->lineno < openfile->edittop->lineno) {
edit_update((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : FLOWING);
@ -2978,7 +3004,7 @@ void edit_update(update_type manner)
goal = editwinrows - 1;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP))
goal -= strlenpt(openfile->current->data) / COLS ;
goal -= strlenpt(openfile->current->data) / editwincols;
#endif
}
} else {
@ -2996,7 +3022,7 @@ void edit_update(update_type manner)
goal --;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
goal -= strlenpt(openfile->edittop->data) / COLS;
goal -= strlenpt(openfile->edittop->data) / editwincols;
if (goal < 0)
openfile->edittop = openfile->edittop->next;
}
@ -3118,7 +3144,7 @@ void spotlight(bool active, const char *word)
size_t word_len = strlenpt(word), room;
/* Compute the number of columns that are available for the word. */
room = COLS + get_page_start(xplustabs()) - xplustabs();
room = editwincols + get_page_start(xplustabs()) - xplustabs();
assert(room > 0);