Merge remote-tracking branch 'lenormf/command-force-write'

This commit is contained in:
Maxime Coste 2017-04-20 16:25:24 +01:00
commit ab3a255d58
5 changed files with 45 additions and 8 deletions

View File

@ -676,8 +676,10 @@ command `q!` has to be used).
* `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.
use edit! to force reloading.
* `w[rite] [<filename>]`: write buffer to <filename> or use it's name if
filename is not given.
* `w[rite][!] [<filename>]`: 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]`: write all buffers that are associated to a file.
* `q[uit][!]`: exit Kakoune, use quit! to force quitting even if there is some
unsaved buffers remaining.

View File

@ -24,8 +24,11 @@ command *q!* has to be used).
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
*w[rite]* [<filename>]::
write buffer to <filename> or use it's name if filename is not given
*w[rite][!]* [<filename>]::
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]*::
write all buffers that are associated to a file

View File

@ -309,6 +309,7 @@ const CommandDesc force_edit_cmd = {
edit<true>
};
template<bool force = false>
void write_buffer(const ParametersParser& parser, Context& context, const ShellContext&)
{
Buffer& buffer = context.buffer();
@ -326,7 +327,7 @@ void write_buffer(const ParametersParser& parser, Context& context, const ShellC
buffer.name() : parse_filename(parser[0]);
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);
}
@ -342,6 +343,18 @@ const CommandDesc write_cmd = {
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)
{
// Copy buffer list because hooks might be creating/deleting buffers
@ -2102,6 +2115,7 @@ void register_commands()
register_command(edit_cmd);
register_command(force_edit_cmd);
register_command(write_cmd);
register_command(force_write_cmd);
register_command(write_all_cmd);
register_command(write_all_quit_cmd);
register_command(kill_cmd);

View File

@ -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)
throw file_access_error(filename, strerror(errno));

View File

@ -49,7 +49,7 @@ struct MappedFile
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_backup_file(Buffer& buffer);