nano

nano with my custom patches
git clone git://bsandro.tech/nano
Log | Files | Refs | README | LICENSE

commit 60e2f2baf27c0cc8bf920b87331141e98dd32fef
parent b8c684193e9a958ff28c74e8cc30bbed6ed85fdf
Author: Benno Schulenberg <bensberg@telfort.nl>
Date:   Sat, 10 May 2025 15:51:01 +0200

new feature: save and restore anchors when the first line has an anchor

When an anchor is placed on the first line in a buffer and --positionlog
is active, nano will now save the positions of the anchors when the file
is closed, and will restore the anchors when the file is reopened.

(The positions are stored in the file-positions history file, along
with the cursor position.)

This fulfills https://savannah.gnu.org/bugs/?62269.
Requested-by: Shi Yanling <sylphenix@126.com>
Requested-by: Sébastien Desreux <seb@h-k.fr>

Sponsored-by: Sébastien Desreux <https://doc-solus.fr>

Diffstat:
Msrc/definitions.h | 2++
Msrc/history.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 69 insertions(+), 10 deletions(-)

diff --git a/src/definitions.h b/src/definitions.h @@ -538,6 +538,8 @@ typedef struct poshiststruct { /* The line where the cursor was when we closed the file. */ ssize_t columnnumber; /* The column where the cursor was. */ + char *anchors; + /* The line numbers where anchors were placed, in string form. */ struct poshiststruct *next; /* The next item of position history. */ } poshiststruct; diff --git a/src/history.c b/src/history.c @@ -2,7 +2,7 @@ * history.c -- This file is part of GNU nano. * * * * Copyright (C) 2003-2011, 2013-2025 Free Software Foundation, Inc. * - * Copyright (C) 2016, 2017, 2019 Benno Schulenberg * + * Copyright (C) 2016, 2017, 2019, 2025 Benno Schulenberg * * * * GNU nano is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published * @@ -349,6 +349,47 @@ void save_history(void) free(histname); } +/* Return as a string... the line numbers of the lines with an anchor. */ +char *stringify_anchors(void) +{ + linestruct *line = openfile->filetop; + char *string = NULL; + char number[24]; + + if (!line->has_anchor || asprintf(&string, "%s", "") < 0) + return NULL; + + for (; line != NULL; line = line->next) + if (line->has_anchor) { + sprintf(number, "%li ", line->lineno); + string = free_and_assign(string, concatenate(string, number)); + } + + return string; +} + +/* Set an anchor for each line number in the given string. */ +void restore_anchors(char *string) +{ + linestruct *line = openfile->filetop; + ssize_t number; + char *space; + + while (*string) { + if ((space = strchr(string, ' ')) == NULL) + return; + *space = '\0'; + number = atoi(string); + string = space + 1; + + while (line->lineno < number) + if ((line = line->next) == NULL) + return; + + line->has_anchor = TRUE; + } +} + /* Load the recorded cursor positions for files that were edited. */ void load_poshistory(void) { @@ -365,20 +406,23 @@ void load_poshistory(void) poshiststruct *lastitem = NULL; poshiststruct *newitem; - char *lineptr, *columnptr; - char *stanza = NULL; + char *stanza, *lineptr, *columnptr; + char *phrase = NULL; struct stat fileinfo; size_t dummy = 0; ssize_t count = 0; - ssize_t read; + ssize_t length; /* Read and parse each line, and store the extracted data. */ - while ((read = getline(&stanza, &dummy, histfile)) > 5) { + while ((length = getline(&phrase, &dummy, histfile)) > 1) { + stanza = strchr(phrase, '/'); + length -= (stanza ? stanza - phrase : 0); + /* Decode NULs as embedded newlines. */ - recode_NUL_to_LF(stanza, read); + recode_NUL_to_LF(stanza, length); /* Find the spaces before column number and line number. */ - columnptr = revstrstr(stanza, " ", stanza + read - 3); + columnptr = revstrstr(stanza, " ", stanza + length - 3); if (columnptr == NULL) continue; lineptr = revstrstr(stanza, " ", columnptr - 2); @@ -394,6 +438,7 @@ void load_poshistory(void) newitem->filename = copy_of(stanza); newitem->linenumber = atoi(lineptr); newitem->columnnumber = atoi(columnptr); + newitem->anchors = (phrase == stanza) ? NULL : measured_copy(phrase, stanza - phrase); newitem->next = NULL; /* Add the record to the list. */ @@ -411,6 +456,7 @@ void load_poshistory(void) position_history = position_history->next; free(drop_record->filename); + free(drop_record->anchors); free(drop_record); } } @@ -418,7 +464,7 @@ void load_poshistory(void) if (fclose(histfile) == EOF) jot_error(N_("Error reading %s: %s"), poshistname, strerror(errno)); - free(stanza); + free(phrase); if (stat(poshistname, &fileinfo) == 0) latest_timestamp = fileinfo.st_mtime; @@ -442,7 +488,11 @@ void save_poshistory(void) for (item = position_history; item != NULL; item = item->next) { char *path_and_place; - size_t length; + size_t length = (item->anchors == NULL) ? 0 : strlen(item->anchors); + + /* First write the string of line numbers with anchors, if any. */ + if (length && fwrite(item->anchors, 1, length, histfile) < length) + jot_error(N_("Error writing %s: %s"), poshistname, strerror(errno)); /* Assume 20 decimal positions each for line and column number, * plus two spaces, plus the line feed, plus the null byte. */ @@ -480,6 +530,7 @@ void reload_positions_if_needed(void) for (item = position_history; item != NULL; item = nextone) { nextone = item->next; free(item->filename); + free(item->anchors); free(item); } @@ -511,13 +562,15 @@ void update_poshistory(void) } /* Don't record files that have the default cursor position. */ - if (openfile->current->lineno == 1 && openfile->current_x == 0) { + if (openfile->current->lineno == 1 && openfile->current_x == 0 && + !openfile->filetop->has_anchor) { if (item != NULL) { if (previous == NULL) position_history = item->next; else previous->next = item->next; free(item->filename); + free(item->anchors); free(item); save_poshistory(); } @@ -532,6 +585,7 @@ void update_poshistory(void) if (theone == NULL) { theone = nmalloc(sizeof(poshiststruct)); theone->filename = copy_of(fullpath); + theone->anchors = NULL; if (position_history == NULL) position_history = theone; else @@ -549,6 +603,7 @@ void update_poshistory(void) /* Store the last cursor position. */ theone->linenumber = openfile->current->lineno; theone->columnnumber = xplustabs() + 1; + theone->anchors = free_and_assign(theone->anchors, stringify_anchors()); theone->next = NULL; free(fullpath); @@ -574,6 +629,8 @@ void restore_cursor_position_if_any(void) free(fullpath); + if (item && item->anchors) + restore_anchors(item->anchors); if (item) goto_line_and_column(item->linenumber, item->columnnumber, FALSE, FALSE); }