diff --git a/rc/base/lint.kak b/rc/base/lint.kak index b38e3a8d..e02caa16 100644 --- a/rc/base/lint.kak +++ b/rc/base/lint.kak @@ -12,7 +12,7 @@ define-command lint -docstring 'Parse the current buffer with a linter' %{ %sh{ dir=$(mktemp -d "${TMPDIR:-/tmp}"/kak-lint.XXXXXXXX) mkfifo "$dir"/fifo - printf '%s\n' "evaluate-commands -no-hooks write $dir/buf" + printf '%s\n' "evaluate-commands -no-hooks write -sync $dir/buf" printf '%s\n' "evaluate-commands -draft %{ edit! -fifo $dir/fifo -debug *lint-output* diff --git a/rc/base/spell.kak b/rc/base/spell.kak index 793b66f9..cd5a8277 100644 --- a/rc/base/spell.kak +++ b/rc/base/spell.kak @@ -12,7 +12,7 @@ Formats of language supported: try %{ add-highlighter window ranges 'spell_regions' } %sh{ file=$(mktemp -d "${TMPDIR:-/tmp}"/kak-spell.XXXXXXXX)/buffer - printf 'eval -no-hooks write %s\n' "${file}" + printf 'eval -no-hooks write -sync %s\n' "${file}" printf 'set-option buffer spell_tmp_file %s\n' "${file}" } %sh{ diff --git a/rc/core/formatter.kak b/rc/core/formatter.kak index d84318dd..1e4a7f86 100644 --- a/rc/core/formatter.kak +++ b/rc/core/formatter.kak @@ -6,7 +6,7 @@ define-command format -docstring "Format the contents of the current buffer" %{ if [ -n "${kak_opt_formatcmd}" ]; then path_file_tmp=$(mktemp "${TMPDIR:-/tmp}"/kak-formatter-XXXXXX) printf %s\\n " - write \"${path_file_tmp}\" + write -sync \"${path_file_tmp}\" %sh{ readonly path_file_out=\$(mktemp \"${TMPDIR:-/tmp}\"/kak-formatter-XXXXXX) diff --git a/rc/extra/clang.kak b/rc/extra/clang.kak index 6e825266..61a3708a 100644 --- a/rc/extra/clang.kak +++ b/rc/extra/clang.kak @@ -14,7 +14,7 @@ The syntaxic errors detected during parsing are shown when auto-diagnostics are dir=$(mktemp -d "${TMPDIR:-/tmp}"/kak-clang.XXXXXXXX) mkfifo ${dir}/fifo printf %s\\n "set-option buffer clang_tmp_dir ${dir}" - printf %s\\n "evaluate-commands -no-hooks write ${dir}/buf" + printf %s\\n "evaluate-commands -no-hooks write -sync ${dir}/buf" } # end the previous %sh{} so that its output gets interpreted by kakoune # before launching the following as a background task. diff --git a/rc/extra/jedi.kak b/rc/extra/jedi.kak index 95eaa912..c48cb71c 100644 --- a/rc/extra/jedi.kak +++ b/rc/extra/jedi.kak @@ -8,7 +8,7 @@ define-command jedi-complete -docstring "Complete the current selection" %{ dir=$(mktemp -d "${TMPDIR:-/tmp}"/kak-jedi.XXXXXXXX) mkfifo ${dir}/fifo printf %s\\n "set-option buffer jedi_tmp_dir ${dir}" - printf %s\\n "evaluate-commands -no-hooks write ${dir}/buf" + printf %s\\n "evaluate-commands -no-hooks write -sync ${dir}/buf" } %sh{ dir=${kak_opt_jedi_tmp_dir} diff --git a/src/commands.cc b/src/commands.cc index b196f847..dec1edab 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -326,20 +326,25 @@ void write_buffer(const ParametersParser& parser, Context& context, const ShellC and (parser.positional_count() == 0 or real_path(parser[0]) == buffer.name())) throw runtime_error("cannot overwrite the buffer when in readonly mode"); + const bool sync_file = (bool)parser.get_switch("sync"); auto filename = parser.positional_count() == 0 ? buffer.name() : parse_filename(parser[0]); context.hooks().run_hook("BufWritePre", filename, context); - write_buffer_to_file(buffer, filename, force); + write_buffer_to_file(buffer, filename, force, sync_file); context.hooks().run_hook("BufWritePost", filename, context); } const CommandDesc write_cmd = { "write", "w", - "write [filename]: write the current buffer to its file " - "or to [filename] if specified", - single_optional_param, + "write [-sync] [filename]: write the current buffer to its file " + "or to [filename] if specified; the underlying file can be" + "synchronized with the filesystem with the -sync switch", + ParameterDesc{ + { { "sync", { false, "force the synchronization of the file onto the filesystem" } } }, + ParameterDesc::Flags::SwitchesOnlyAtStart, 0, 1 + }, CommandFlags::None, CommandHelper{}, filename_completer, @@ -349,16 +354,20 @@ const CommandDesc write_cmd = { 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, + "write [-sync] [filename]: write the current buffer to its file " + "or to [filename] if specified, even when the file is write protected;" + "the underlying file can be synchronized with the filesystem with the -sync switch", + ParameterDesc{ + { { "sync", { false, "force the synchronization of the file onto the filesystem" } } }, + ParameterDesc::Flags::SwitchesOnlyAtStart, 0, 1 + }, CommandFlags::None, CommandHelper{}, filename_completer, write_buffer, }; -void write_all_buffers(Context& context) +void write_all_buffers(Context& context, bool sync = false) { // Copy buffer list because hooks might be creating/deleting buffers Vector> buffers; @@ -373,7 +382,7 @@ void write_all_buffers(Context& context) and !(buffer->flags() & Buffer::Flags::ReadOnly)) { buffer->run_hook_in_own_context("BufWritePre", buffer->name(), context.name()); - write_buffer_to_file(*buffer, buffer->name()); + write_buffer_to_file(*buffer, buffer->name(), sync); buffer->run_hook_in_own_context("BufWritePost", buffer->name(), context.name()); } } @@ -382,12 +391,18 @@ void write_all_buffers(Context& context) const CommandDesc write_all_cmd = { "write-all", "wa", - "write all buffers that are associated to a file", - no_params, + "write-all [-sync]: write all buffers that are associated to a file;" + "all open files can be synchronized with the filesystem with the -sync switch", + ParameterDesc{ + { { "sync", { false, "force the synchronization of the file onto the filesystem" } } }, + ParameterDesc::Flags::None, 0, 0 + }, CommandFlags::None, CommandHelper{}, CommandCompleter{}, - [](const ParametersParser&, Context& context, const ShellContext&){ write_all_buffers(context); } + [](const ParametersParser& parser, Context& context, const ShellContext&){ + write_all_buffers(context, (bool)parser.get_switch("sync")); + } }; static void ensure_all_buffers_are_saved() @@ -486,9 +501,12 @@ void write_quit(const ParametersParser& parser, Context& context, const CommandDesc write_quit_cmd = { "write-quit", "wq", - "write current buffer and quit current client. An optional integer " - "parameter can set the client exit status", - { {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 }, + "write-quit [-sync] [exit_code]: write current buffer and quit current client. An optional integer parameter can set the client exit status;" + "all open files can be synchronized with the filesystem with the -sync switch", + ParameterDesc{ + { { "sync", { false, "force the synchronization of the file onto the filesystem" } } }, + ParameterDesc::Flags::SwitchesOnlyAtStart, 0, 1 + }, CommandFlags::None, CommandHelper{}, CommandCompleter{}, @@ -510,15 +528,19 @@ const CommandDesc force_write_quit_cmd = { const CommandDesc write_all_quit_cmd = { "write-all-quit", "waq", - "write all buffers associated to a file and quit current client. An " - "optional integer parameter can set the client exit status", - { {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 }, + "write-all-quit [-sync] [exit_code]: write all buffers associated to a file and quit current client." + "An optional integer parameter can set the client exit status;" + "all open files can be synchronized with the filesystem with the -sync switch", + ParameterDesc{ + { { "sync", { false, "force the synchronization of the file onto the filesystem" } } }, + ParameterDesc::Flags::SwitchesOnlyAtStart, 0, 0 + }, CommandFlags::None, CommandHelper{}, CommandCompleter{}, [](const ParametersParser& parser, Context& context, const ShellContext& shell_context) { - write_all_buffers(context); + write_all_buffers(context, (bool)parser.get_switch("sync")); quit(parser, context, shell_context); } }; diff --git a/src/file.cc b/src/file.cc index 8d067d6c..a71bdb55 100644 --- a/src/file.cc +++ b/src/file.cc @@ -257,7 +257,7 @@ void write(int fd, StringView data) } } -void write_buffer_to_fd(Buffer& buffer, int fd) +void write_buffer_to_fd(Buffer& buffer, int fd, bool sync) { auto eolformat = buffer.options()["eolformat"].get(); StringView eoldata; @@ -278,9 +278,12 @@ void write_buffer_to_fd(Buffer& buffer, int fd) write(fd, linedata.substr(0, linedata.length()-1)); write(fd, eoldata); } + + if (sync) + ::fsync(fd); } -void write_buffer_to_file(Buffer& buffer, StringView filename, bool force) +void write_buffer_to_file(Buffer& buffer, StringView filename, bool force, bool sync) { struct stat st; auto zfilename = filename.zstr(); @@ -306,7 +309,7 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, bool force) { auto close_fd = on_scope_end([fd]{ close(fd); }); - write_buffer_to_fd(buffer, fd); + write_buffer_to_fd(buffer, fd, sync); } if ((buffer.flags() & Buffer::Flags::File) and diff --git a/src/file.hh b/src/file.hh index f5a8cf0b..963cbce2 100644 --- a/src/file.hh +++ b/src/file.hh @@ -51,8 +51,8 @@ struct MappedFile struct stat st {}; }; -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_file(Buffer& buffer, StringView filename, bool force = false, bool sync = false); +void write_buffer_to_fd(Buffer& buffer, int fd, bool sync = false); void write_buffer_to_backup_file(Buffer& buffer); String find_file(StringView filename, StringView buf_dir, ConstArrayView paths);