vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit db9e8215d83444f763739bda1341e8e520498fe5
parent 3d0fbb8b0bda5a09b09c80a9f9719b886e9a9ec0
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Wed, 14 Dec 2016 13:37:47 +0100

vis: add new :set savemethod auto|atomic|inplace option

Specifies how the current file should be saved, `atomic` which uses
rename(2) to atomically replace the file, `inplace` which truncates the
file and then rewrites it or `auto` which tries the former before falling
back to the latter. The rename method fails for symlinks, hardlinks,
in case of insufficient directory permissions or when either the file
owner, group, POSIX ACL or SELinux labels can not be restored.

The option defaults to `auto`.

Diffstat:
Mman/vis.1 | 13+++++++++++++
Msam.c | 11+++++++++--
Mvis-cmds.c | 15+++++++++++++++
Mvis-core.h | 1+
4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/man/vis.1 b/man/vis.1 @@ -1111,6 +1111,19 @@ Whether to display replacement symbol instead of tabs. Whether to display replacement symbol instead of newlines. .It Cm show-spaces Bq off Whether to display replacement symbol instead of blank cells. +.It Cm savemethod Bq auto +How the current file should be saved, +.Sy atomic +which uses +.Xr rename 2 +to atomically replace the file, +.Sy inplace +which truncates the file and then rewrites it or +.Sy auto +which tries the former before falling back to the latter. The rename +method fails for symlinks, hardlinks, in case of insufficient directory +permissions or when either the file owner, group, POSIX ACL or SELinux +labels can not be restored. .El . .Sh CONFIGURATION diff --git a/sam.c b/sam.c @@ -294,6 +294,7 @@ enum { OPTION_CURSOR_LINE, OPTION_COLOR_COLUMN, OPTION_HORIZON, + OPTION_SAVE_METHOD, }; static const OptionDef options[] = { @@ -372,6 +373,11 @@ static const OptionDef options[] = { OPTION_TYPE_NUMBER, OPTION_FLAG_WINDOW, "Number of bytes to consider for syntax highlighting", }, + [OPTION_SAVE_METHOD] = { + { "savemethod" }, + OPTION_TYPE_STRING, OPTION_FLAG_WINDOW, + "Save method to use for current file 'auto', 'atomic' or 'inplace'", + }, }; bool sam_init(Vis *vis) { @@ -1349,9 +1355,10 @@ static bool cmd_write(Vis *vis, Win *win, Command *cmd, const char *argv[], Curs return false; } - TextSave *ctx = text_save_begin(text, *name, TEXT_SAVE_AUTO); + TextSave *ctx = text_save_begin(text, *name, file->save_method); if (!ctx) { - vis_info_show(vis, "Can't write `%s': %s", *name, strerror(errno)); + const char *msg = errno ? strerror(errno) : "try changing `:set savemethod`"; + vis_info_show(vis, "Can't write `%s': %s", *name, msg); return false; } diff --git a/vis-cmds.c b/vis-cmds.c @@ -248,6 +248,21 @@ static bool cmd_set(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor case OPTION_HORIZON: win->horizon = arg.i; break; + case OPTION_SAVE_METHOD: + if (strcmp("auto", arg.s) == 0) { + win->file->save_method = TEXT_SAVE_AUTO; + } else if (strcmp("atomic", arg.s) == 0) { + win->file->save_method = TEXT_SAVE_ATOMIC; + } else if (strcmp("inplace", arg.s) == 0) { + win->file->save_method = TEXT_SAVE_INPLACE; + } else { + vis_info_show(vis, "Invalid save method `%s', expected " + "'auto', 'atomic' or 'inplace'", arg.s); + return false; + } + break; + default: + return false; } return true; diff --git a/vis-core.h b/vis-core.h @@ -116,6 +116,7 @@ struct File { /* shared state among windows displaying the same file */ struct stat stat; /* filesystem information when loaded/saved, used to detect changes outside the editor */ int refcount; /* how many windows are displaying this file? (always >= 1) */ Mark marks[VIS_MARK_INVALID]; /* marks which are shared across windows */ + enum TextSaveMethod save_method; /* whether the file is saved using rename(2) or overwritten */ File *next, *prev; };