src: Implement a write!
command
This commit allows "forced" writes to a write-protected file, by attempting to temporarily grant the current user write permissions on it. After the buffer has been written, the previous permissions are restored if the file existed, or set to 0644 otherwise.
This commit is contained in:
parent
30e6387071
commit
51ab59cd36
|
@ -676,8 +676,10 @@ command `q!` has to be used).
|
||||||
* `e[dit][!] <filename> [<line> [<column>]]`: open buffer on file, go to given
|
* `e[dit][!] <filename> [<line> [<column>]]`: open buffer on file, go to given
|
||||||
line and column. If file is already opened, just switch to this file.
|
line and column. If file is already opened, just switch to this file.
|
||||||
use edit! to force reloading.
|
use edit! to force reloading.
|
||||||
* `w[rite] [<filename>]`: write buffer to <filename> or use it's name if
|
* `w[rite][!] [<filename>]`: write buffer to <filename> or use it's name if
|
||||||
filename is not given.
|
filename is not given. If the file is write-protected, its
|
||||||
|
permissions are temporarily changed to allow saving the buffer and
|
||||||
|
restored afterwards when the write! command is used.
|
||||||
* `w[rite]a[ll]`: write all buffers that are associated to a file.
|
* `w[rite]a[ll]`: write all buffers that are associated to a file.
|
||||||
* `q[uit][!]`: exit Kakoune, use quit! to force quitting even if there is some
|
* `q[uit][!]`: exit Kakoune, use quit! to force quitting even if there is some
|
||||||
unsaved buffers remaining.
|
unsaved buffers remaining.
|
||||||
|
|
|
@ -24,8 +24,11 @@ command *q!* has to be used).
|
||||||
open buffer on file, go to given line and column. If file is already
|
open buffer on file, go to given line and column. If file is already
|
||||||
opened, just switch to this file. Use edit! to force reloading
|
opened, just switch to this file. Use edit! to force reloading
|
||||||
|
|
||||||
*w[rite]* [<filename>]::
|
*w[rite][!]* [<filename>]::
|
||||||
write buffer to <filename> or use it's name if filename is not given
|
write buffer to <filename> or use it's name if filename is not
|
||||||
|
given. If the file is write-protected, its permissions are temporarily
|
||||||
|
changed to allow saving the buffer and restored afterwards when
|
||||||
|
the write! command is used.
|
||||||
|
|
||||||
*w[rite]a[ll]*::
|
*w[rite]a[ll]*::
|
||||||
write all buffers that are associated to a file
|
write all buffers that are associated to a file
|
||||||
|
|
|
@ -309,6 +309,7 @@ const CommandDesc force_edit_cmd = {
|
||||||
edit<true>
|
edit<true>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<bool force = false>
|
||||||
void write_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
|
void write_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
Buffer& buffer = context.buffer();
|
Buffer& buffer = context.buffer();
|
||||||
|
@ -326,7 +327,7 @@ void write_buffer(const ParametersParser& parser, Context& context, const ShellC
|
||||||
buffer.name() : parse_filename(parser[0]);
|
buffer.name() : parse_filename(parser[0]);
|
||||||
|
|
||||||
context.hooks().run_hook("BufWritePre", filename, context);
|
context.hooks().run_hook("BufWritePre", filename, context);
|
||||||
write_buffer_to_file(buffer, filename);
|
write_buffer_to_file(buffer, filename, force);
|
||||||
context.hooks().run_hook("BufWritePost", filename, context);
|
context.hooks().run_hook("BufWritePost", filename, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +343,18 @@ const CommandDesc write_cmd = {
|
||||||
write_buffer,
|
write_buffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CommandDesc force_write_cmd = {
|
||||||
|
"write!",
|
||||||
|
"w!",
|
||||||
|
"write [filename]: write the current buffer to its file "
|
||||||
|
"or to [filename] if specified, even when the file is write protected",
|
||||||
|
single_optional_param,
|
||||||
|
CommandFlags::None,
|
||||||
|
CommandHelper{},
|
||||||
|
filename_completer,
|
||||||
|
write_buffer<true>,
|
||||||
|
};
|
||||||
|
|
||||||
void write_all_buffers(Context& context)
|
void write_all_buffers(Context& context)
|
||||||
{
|
{
|
||||||
// Copy buffer list because hooks might be creating/deleting buffers
|
// Copy buffer list because hooks might be creating/deleting buffers
|
||||||
|
@ -2102,6 +2115,7 @@ void register_commands()
|
||||||
register_command(edit_cmd);
|
register_command(edit_cmd);
|
||||||
register_command(force_edit_cmd);
|
register_command(force_edit_cmd);
|
||||||
register_command(write_cmd);
|
register_command(write_cmd);
|
||||||
|
register_command(force_write_cmd);
|
||||||
register_command(write_all_cmd);
|
register_command(write_all_cmd);
|
||||||
register_command(write_all_quit_cmd);
|
register_command(write_all_quit_cmd);
|
||||||
register_command(kill_cmd);
|
register_command(kill_cmd);
|
||||||
|
|
22
src/file.cc
22
src/file.cc
|
@ -278,9 +278,27 @@ void write_buffer_to_fd(Buffer& buffer, int fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_buffer_to_file(Buffer& buffer, StringView filename)
|
void write_buffer_to_file(Buffer& buffer, StringView filename, bool force)
|
||||||
{
|
{
|
||||||
int fd = open(filename.zstr(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
struct stat st;
|
||||||
|
auto zfilename = filename.zstr();
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
if (::stat(zfilename, &st) == 0)
|
||||||
|
{
|
||||||
|
if (::chmod(zfilename, st.st_mode | S_IWUSR) < 0)
|
||||||
|
throw runtime_error("couldn't change file permissions");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
force = false;
|
||||||
|
}
|
||||||
|
auto restore_mode = on_scope_end([&]{
|
||||||
|
if (force and ::chmod(zfilename, st.st_mode) < 0)
|
||||||
|
throw runtime_error("couldn't restore file permissions");
|
||||||
|
});
|
||||||
|
|
||||||
|
int fd = open(zfilename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
throw file_access_error(filename, strerror(errno));
|
throw file_access_error(filename, strerror(errno));
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct MappedFile
|
||||||
struct stat st {};
|
struct stat st {};
|
||||||
};
|
};
|
||||||
|
|
||||||
void write_buffer_to_file(Buffer& buffer, StringView filename);
|
void write_buffer_to_file(Buffer& buffer, StringView filename, bool force = false);
|
||||||
void write_buffer_to_fd(Buffer& buffer, int fd);
|
void write_buffer_to_fd(Buffer& buffer, int fd);
|
||||||
void write_buffer_to_backup_file(Buffer& buffer);
|
void write_buffer_to_backup_file(Buffer& buffer);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user