>From f2a96f0dc48309a1d5828ed80c018276c25bcd17 Mon Sep 17 00:00:00 2001 From: faissaloo Date: Wed, 19 Oct 2016 18:46:14 +0100 Subject: [PATCH] Added line numbering Signed-off-by: faissaloo --- configure.ac | 13 ++++++++ doc/man/nano.1 | 3 ++ doc/man/nanorc.5 | 3 ++ src/global.c | 16 ++++++++++ src/move.c | 9 +++--- src/nano.c | 20 ++++++++++++ src/nano.h | 3 +- src/proto.h | 8 +++++ src/rcfile.c | 3 ++ src/utils.c | 45 ++++++++++++++++++++++++--- src/winio.c | 92 ++++++++++++++++++++++++++++++++++++-------------------- 11 files changed, 173 insertions(+), 42 deletions(-) diff --git a/configure.ac b/configure.ac index e024a1e..ed486b2 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/doc/man/nano.1 b/doc/man/nano.1 index b63f73c..247a497 100644 --- a/doc/man/nano.1 +++ b/doc/man/nano.1 @@ -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 diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index 053c9fe..6fec53a 100644 --- a/doc/man/nanorc.5 +++ b/doc/man/nanorc.5 @@ -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 diff --git a/src/global.c b/src/global.c index 402575f..0f4c136 100644 --- a/src/global.c +++ b/src/global.c @@ -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. */ @@ -1149,6 +1160,9 @@ void shortcut_init(void) #ifndef NANO_TINY /* Group of "Appearance" toggles. */ + #ifdef ENABLE_LINENUMBERS + add_to_sclist(MMAIN, "M-#", do_toggle_void, LINE_NUMBERS); + #endif add_to_sclist(MMAIN, "M-X", 0, do_toggle_void, NO_HELP); add_to_sclist(MMAIN, "M-C", 0, do_toggle_void, CONST_UPDATE); add_to_sclist(MMAIN, "M-O", 0, do_toggle_void, MORE_SPACE); @@ -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 "?????"; } diff --git a/src/move.c b/src/move.c index afce2a4..b13b9be 100644 --- a/src/move.c +++ b/src/move.c @@ -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) { diff --git a/src/nano.c b/src/nano.c index 6cd68da..f16f9aa 100644 --- a/src/nano.c +++ b/src/nano.c @@ -962,6 +962,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 +1011,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 +1346,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 @@ -1414,6 +1421,9 @@ void do_toggle(int flag) #ifndef DISABLE_COLOR case NO_COLOR_SYNTAX: #endif +#ifdef ENABLE_LINENUMBERS + case LINE_NUMBERS: +#endif case SOFTWRAP: edit_refresh(); break; @@ -1992,6 +2002,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 @@ -2271,6 +2284,11 @@ int main(int argc, char **argv) SET(SOFTWRAP); break; #endif +#ifdef ENABLE_LINENUMBERS + case 'l': + SET(LINE_NUMBERS); + break; +#endif case 'h': usage(); exit(0); @@ -2542,6 +2560,8 @@ int main(int argc, char **argv) * dimensions. */ window_init(); + editwincols = COLS - margin; + /* Set up the signal handlers. */ signal_init(); diff --git a/src/nano.h b/src/nano.h index 474e8c2..4e1e35f 100644 --- a/src/nano.h +++ b/src/nano.h @@ -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. */ diff --git a/src/proto.h b/src/proto.h index b4087e9..1f3f804 100644 --- a/src/proto.h +++ b/src/proto.h @@ -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); diff --git a/src/rcfile.c b/src/rcfile.c index 541c71a..72a5880 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -35,6 +35,9 @@ static const rcoption rcopts[] = { {"boldtext", BOLD_TEXT}, +#ifdef ENABLE_LINENUMBERS + {"linenumbers", LINE_NUMBERS}, +#endif #ifndef DISABLE_JUSTIFY {"brackets", 0}, #endif diff --git a/src/utils.c b/src/utils.c index 54b3859..72dae0a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -52,6 +52,43 @@ 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 < 100) { + if (n < 10) + return 1; + else + return 2; + } else { + if (n < 1000) + 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 if (n < 1000000000) + return 9; + else + return 10; + } + } +} +#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 +467,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 diff --git a/src/winio.c b/src/winio.c index a1f6c0c..d2d6e16 100644 --- a/src/winio.c +++ b/src/winio.c @@ -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); -- 2.7.4