From 86ed911968b3ae60b7098df4b0d4feebc91d3ef5 Mon Sep 17 00:00:00 2001 From: faissaloo Date: Tue, 11 Oct 2016 14:28:22 +0100 Subject: [PATCH] Added line numbering --- configure.ac | 8 ++++++ doc/man/nano.1 | 3 ++ doc/man/nanorc.5 | 3 ++ src/global.c | 12 ++++++++ src/move.c | 7 +++-- src/nano.c | 11 ++++++++ src/nano.h | 3 +- src/proto.h | 5 ++++ src/rcfile.c | 3 ++ src/utils.c | 42 +++++++++++++++++++++++++--- src/winio.c | 85 +++++++++++++++++++++++++++++++++----------------------- 11 files changed, 140 insertions(+), 42 deletions(-) diff --git a/configure.ac b/configure.ac index e024a1e..62f3de0 100644 --- a/configure.ac +++ b/configure.ac @@ -125,6 +125,14 @@ 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$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 029b68b..596ec86 100644 --- a/src/global.c +++ b/src/global.c @@ -45,6 +45,13 @@ 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 last_drawn_line = 0; + /* The line number of the last drawn line. */ +int last_line_y; + /* The y coordinate of the last drawn line. */ + message_type lastmessage = HUSH; /* Messages of type HUSH should not overwrite type MILD nor ALERT. */ @@ -1160,6 +1167,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", do_toggle_void, NO_HELP); add_to_sclist(MMAIN, "M-C", do_toggle_void, CONST_UPDATE); add_to_sclist(MMAIN, "M-O", do_toggle_void, MORE_SPACE); @@ -1343,6 +1353,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 7fe82b9..b1a6119 100644 --- a/src/move.c +++ b/src/move.c @@ -475,13 +475,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) / (COLS - margin) - + xplustabs() / (COLS -margin) + + strlenpt(openfile->current->next->data) / (COLS - margin) + 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) / (COLS - margin); if (amount > 0) topline = topline->next; if (amount < enough) { diff --git a/src/nano.c b/src/nano.c index a542073..f15d772 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1414,6 +1414,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; @@ -1990,6 +1993,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 @@ -2269,6 +2275,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); 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 553418b..11c9eb1 100644 --- a/src/proto.h +++ b/src/proto.h @@ -38,6 +38,10 @@ extern bool shift_held; extern bool focusing; +extern int margin; +extern int last_drawn_line; +extern int last_line_y; + extern message_type lastmessage; extern int controlleft; @@ -677,6 +681,7 @@ void do_verbatim_input(void); /* All functions in utils.c. */ void get_homedir(void); +int intlen(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 2a12d38..d496bdf 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..e979e31 100644 --- a/src/utils.c +++ b/src/utils.c @@ -51,6 +51,40 @@ void get_homedir(void) homedir = mallocstrcpy(NULL, homenv); } } +/* Return the number of digits that the given integer n takes up. */ +int intlen(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; + } + } +} /* 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 @@ -430,12 +464,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 < COLS - margin - 1) return 0; - else if (COLS > 8) - return column - 7 - (column - 7) % (COLS - 8); + else if (COLS - margin > 8) + return column - 7 - (column - 7) % (COLS - margin - 8); else - return column - (COLS - 2); + return column - (COLS - margin - 2); } /* Return the placewewant associated with current_x, i.e. the zero-based diff --git a/src/winio.c b/src/winio.c index eccf41c..2744aff 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; @@ -2220,13 +2220,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) / (COLS - margin) + 1; line = line->next; } - openfile->current_y += xpt / COLS; + openfile->current_y += xpt / (COLS - margin); if (openfile->current_y < editwinrows) - wmove(edit, openfile->current_y, xpt % COLS); + wmove(edit, openfile->current_y, xpt % (COLS - margin) + margin); } else #endif { @@ -2234,7 +2234,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); } } @@ -2253,7 +2253,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 + COLS - margin - 1) + 1; /* The position in fileptr->data of the first character that is * completely off the window to the right. * @@ -2262,11 +2262,26 @@ void edit_draw(filestruct *fileptr, const char *converted, int #endif assert(openfile != NULL && fileptr != NULL && converted != NULL); - assert(strlenpt(converted) <= COLS); + assert(strlenpt(converted) <= COLS - margin); + +#ifdef ENABLE_LINENUMBERS + if (ISSET(LINE_NUMBERS)) { + /* If the line numbers now require more room, schedule a refresh. */ + if (intlen(openfile->filebot->lineno) + 1 != margin) { + margin = intlen(openfile->filebot->lineno) + 1; + refresh_needed = TRUE; + } + /* Show the line number only for the non-softwrapped parts. */ + if (!(last_drawn_line == fileptr->lineno && last_line_y < line)) + mvwprintw(edit, line, margin - (intlen(fileptr->lineno) + 1), + "%i", fileptr->lineno); + } else + margin = 0; +#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 @@ -2344,7 +2359,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; @@ -2361,7 +2376,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); @@ -2370,7 +2385,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. */ @@ -2466,7 +2481,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) @@ -2512,9 +2527,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 < COLS - margin); - mvwaddnstr(edit, line, x_start, + mvwaddnstr(edit, line, x_start + margin, converted + index, paintlen); if (paintlen > 0) { fileptr->multidata[varnish->id] = CSTARTENDHERE; @@ -2541,10 +2556,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 < COLS - margin); /* 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); @@ -2622,11 +2637,13 @@ 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 */ + last_drawn_line = fileptr->lineno; + last_line_y = line; } /* Just update one line in the edit buffer. This is basically a wrapper @@ -2650,7 +2667,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) / (COLS - margin)) + 1; } else #endif line = fileptr->lineno - openfile->edittop->lineno; @@ -2674,11 +2691,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, COLS - margin, TRUE); #else - converted = display_string(fileptr->data, page_start, COLS, !ISSET(SOFTWRAP)); + converted = display_string(fileptr->data, page_start, COLS - margin, !ISSET(SOFTWRAP)); #ifdef DEBUG - if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2) + if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - margin - 2) fprintf(stderr, "update_line(): converted(1) line = %s\n", converted); #endif #endif /* !NANO_TINY */ @@ -2691,13 +2708,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 + COLS - margin) 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 += COLS - margin; index <= full_length && line < editwinrows - 1; index += COLS - margin) { line++; #ifdef DEBUG fprintf(stderr, "update_line(): softwrap code, moving to %d index %lu\n", line, (unsigned long)index); @@ -2706,9 +2723,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, COLS - margin, !ISSET(SOFTWRAP)); #ifdef DEBUG - if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - 2) + if (ISSET(SOFTWRAP) && strlen(converted) >= COLS - margin - 2) fprintf(stderr, "update_line(): converted(2) line = %s\n", converted); #endif @@ -2749,7 +2766,7 @@ void compute_maxrows(void) maxrows = 0; for (n = 0; n < editwinrows && foo; n++) { maxrows++; - n += strlenpt(foo->data) / COLS; + n += strlenpt(foo->data) / (COLS - margin); foo = foo->next; } @@ -2794,7 +2811,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) / (COLS - margin); i -= len; if (len > 0) refresh_needed = TRUE; @@ -2875,7 +2892,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) >= COLS - margin) || #endif openfile->current->lineno < openfile->edittop->lineno) { edit_update((focusing || !ISSET(SMOOTH_SCROLL)) ? CENTERING : FLOWING); @@ -2974,7 +2991,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) / (COLS - margin); #endif } } else { @@ -2992,7 +3009,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) / (COLS - margin); if (goal < 0) openfile->edittop = openfile->edittop->next; } @@ -3114,7 +3131,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 = COLS - margin + get_page_start(xplustabs()) - xplustabs(); assert(room > 0); @@ -3254,7 +3271,7 @@ void do_credits(void) } else what = credits[crpos]; - start_x = COLS / 2 - strlenpt(what) / 2 - 1; + start_x = (COLS - margin) / 2 - strlenpt(what) / 2 - 1; mvwaddstr(edit, editwinrows - 1 - (editwinrows % 2), start_x, what); } -- 2.7.4