diff options
| author | Johannes Altmanninger <aclopte@gmail.com> | 2024-11-24 10:19:32 +0100 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2024-12-09 22:23:35 +1100 |
| commit | 7105584538f84d1c244809601fd3e573e8d6080c (patch) | |
| tree | ca1e38b5fb7fd6862fb917212af817e3328f1412 /src | |
| parent | 816a8c35a8cfa0cc8b7f9d80dd3c0e721ba3c273 (diff) | |
Print elapsed time when blocked on opening file for writing
Extract the logic for "waiting for shell to finish" and reuse it for
potentially blocking calls to open() that use the O_WRONLY flags.
Diffstat (limited to 'src')
| -rw-r--r-- | src/client.cc | 32 | ||||
| -rw-r--r-- | src/client.hh | 14 | ||||
| -rw-r--r-- | src/commands.cc | 6 | ||||
| -rw-r--r-- | src/file.cc | 18 | ||||
| -rw-r--r-- | src/file.hh | 5 | ||||
| -rw-r--r-- | src/main.cc | 5 | ||||
| -rw-r--r-- | src/shell_manager.cc | 30 |
7 files changed, 73 insertions, 37 deletions
diff --git a/src/client.cc b/src/client.cc index 611216a7..2fa8e8fb 100644 --- a/src/client.cc +++ b/src/client.cc @@ -1,5 +1,6 @@ #include "client.hh" +#include "clock.hh" #include "context.hh" #include "buffer_utils.hh" #include "debug.hh" @@ -509,4 +510,35 @@ void Client::clear_pending() m_pending_clear = PendingClear::None; } +constexpr std::chrono::seconds wait_timeout{1}; + +BusyIndicator::BusyIndicator(const Context& context, + std::function<DisplayLine(std::chrono::seconds)> status_message, + TimePoint wait_time) + : m_context(context), + m_timer{wait_time + wait_timeout, + [this, status_message = std::move(status_message), wait_time](Timer& timer) { + if (not m_context.has_client()) + return; + using namespace std::chrono; + const auto now = Clock::now(); + timer.set_next_date(now + wait_timeout); + + auto& client = m_context.client(); + if (not m_previous_status) + m_previous_status = client.current_status(); + + client.print_status(status_message(duration_cast<seconds>(now - wait_time))); + client.redraw_ifn(); + }, EventMode::Urgent} {} + +BusyIndicator::~BusyIndicator() +{ + if (m_previous_status and std::uncaught_exceptions() == 0) // restore the status line + { + m_context.print_status(std::move(*m_previous_status)); + m_context.client().redraw_ifn(); + } +} + } diff --git a/src/client.hh b/src/client.hh index 05b091ae..43584c42 100644 --- a/src/client.hh +++ b/src/client.hh @@ -2,6 +2,7 @@ #define client_hh_INCLUDED #include "array.hh" +#include "clock.hh" #include "display_buffer.hh" #include "env_vars.hh" #include "input_handler.hh" @@ -165,6 +166,19 @@ constexpr auto enum_desc(Meta::Type<Autoreload>) }); } +class BusyIndicator +{ +public: + BusyIndicator(const Context& context, + std::function<DisplayLine(std::chrono::seconds)> status_message, + TimePoint wait_time = Clock::now()); + ~BusyIndicator(); +private: + const Context& m_context; + Timer m_timer; + Optional<DisplayLine> m_previous_status; +}; + } #endif // client_hh_INCLUDED diff --git a/src/commands.cc b/src/commands.cc index 90f7a23e..0f892004 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -618,7 +618,7 @@ void do_write_buffer(Context& context, Optional<String> filename, WriteFlags fla auto method = write_method.value_or_compute([&] { return context.options()["writemethod"].get<WriteMethod>(); }); context.hooks().run_hook(Hook::BufWritePre, effective_filename, context); - write_buffer_to_file(buffer, effective_filename, method, flags); + write_buffer_to_file(context, buffer, effective_filename, method, flags); context.hooks().run_hook(Hook::BufWritePost, effective_filename, context); } @@ -673,7 +673,7 @@ void write_all_buffers(const Context& context, bool sync = false, Optional<Write auto method = write_method.value_or_compute([&] { return context.options()["writemethod"].get<WriteMethod>(); }); auto flags = sync ? WriteFlags::Sync : WriteFlags::None; buffer->run_hook_in_own_context(Hook::BufWritePre, buffer->name(), context.name()); - write_buffer_to_file(*buffer, buffer->name(), method, flags); + write_buffer_to_file(context, *buffer, buffer->name(), method, flags); buffer->run_hook_in_own_context(Hook::BufWritePost, buffer->name(), context.name()); } } @@ -1555,7 +1555,7 @@ const CommandDesc echo_cmd = { message.push_back('\n'); if (auto filename = parser.get_switch("to-file")) - write_to_file(*filename, message); + write_to_file(context, *filename, message); else if (auto command = parser.get_switch("to-shell-script")) ShellManager::instance().eval(*command, context, message, ShellManager::Flags::None, shell_context); else if (parser.get_switch("debug")) diff --git a/src/file.cc b/src/file.cc index 64c9321a..2fbf2e78 100644 --- a/src/file.cc +++ b/src/file.cc @@ -2,6 +2,7 @@ #include "assert.hh" #include "buffer.hh" +#include "client.hh" #include "exception.hh" #include "flags.hh" #include "event_manager.hh" @@ -277,23 +278,28 @@ void write(int fd, StringView data) template void write<true>(int fd, StringView data); template void write<false>(int fd, StringView data); -static int create_file(const char* filename) +static int create_file(const Context& context, const char* filename) { int fd; const int flags = O_CREAT | O_WRONLY | O_TRUNC | (EventManager::has_instance() ? O_NONBLOCK : 0); + using namespace std::chrono; + BusyIndicator busy_indicator{context, [&](seconds elapsed) { + return DisplayLine{format("waiting to open file ({}s)", elapsed.count()), + context.faces()["Information"]}; + }}; while ((fd = open(filename, flags, 0644)) == -1) { if (errno == ENXIO and EventManager::has_instance()) // trying to open a FIFO with no readers yet - EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{1'000'000}); + EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, nanoseconds{1'000'000}); else return -1; } return fd; } -void write_to_file(StringView filename, StringView data) +void write_to_file(const Context& context, StringView filename, StringView data) { - int fd = create_file(filename.zstr()); + int fd = create_file(context, filename.zstr()); if (fd == -1) throw file_access_error(filename, strerror(errno)); auto close_fd = on_scope_end([fd]{ close(fd); }); @@ -343,7 +349,7 @@ int open_temp_file(StringView filename) return open_temp_file(filename, buffer); } -void write_buffer_to_file(Buffer& buffer, StringView filename, +void write_buffer_to_file(const Context& context, Buffer& buffer, StringView filename, WriteMethod method, WriteFlags flags) { auto zfilename = filename.zstr(); @@ -364,7 +370,7 @@ void write_buffer_to_file(Buffer& buffer, StringView filename, char temp_filename[PATH_MAX]; const int fd = replace ? open_temp_file(filename, temp_filename) - : create_file(zfilename); + : create_file(context, zfilename); if (fd == -1) { auto saved_errno = errno; diff --git a/src/file.hh b/src/file.hh index ead88c43..a0b55e56 100644 --- a/src/file.hh +++ b/src/file.hh @@ -42,7 +42,8 @@ String read_fd(int fd, bool text = false); String read_file(StringView filename, bool text = false); template<bool force_blocking = false> void write(int fd, StringView data); -void write_to_file(StringView filename, StringView data); +class Context; +void write_to_file(const Context&, StringView filename, StringView data); struct MappedFile { @@ -76,7 +77,7 @@ enum class WriteFlags }; constexpr bool with_bit_ops(Meta::Type<WriteFlags>) { return true; } -void write_buffer_to_file(Buffer& buffer, StringView filename, +void write_buffer_to_file(const Context& context, Buffer& buffer, StringView filename, WriteMethod method, WriteFlags flags); void write_buffer_to_fd(Buffer& buffer, int fd); void write_buffer_to_backup_file(Buffer& buffer); diff --git a/src/main.cc b/src/main.cc index e360a6d8..48368ab6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1007,14 +1007,15 @@ int run_filter(StringView keystr, ConstArrayView<StringView> files, bool quiet, } }; + Context empty_context{Context::EmptyContextFlag{}}; for (auto& file : files) { Buffer* buffer = open_file_buffer(file, Buffer::Flags::NoHooks); if (not suffix_backup.empty()) - write_buffer_to_file(*buffer, buffer->name() + suffix_backup, + write_buffer_to_file(empty_context, *buffer, buffer->name() + suffix_backup, WriteMethod::Overwrite, WriteFlags::None); apply_to_buffer(*buffer); - write_buffer_to_file(*buffer, buffer->name(), + write_buffer_to_file(empty_context, *buffer, buffer->name(), WriteMethod::Overwrite, WriteFlags::None); buffer_manager.delete_buffer(*buffer); } diff --git a/src/shell_manager.cc b/src/shell_manager.cc index 6b656191..0baf77c8 100644 --- a/src/shell_manager.cc +++ b/src/shell_manager.cc @@ -14,6 +14,7 @@ #include "regex.hh" #include <array> +#include <chrono> #include <cstring> #include <sys/types.h> #include <sys/wait.h> @@ -316,24 +317,11 @@ std::pair<String, int> ShellManager::eval( bool failed = false; using namespace std::chrono; - static constexpr seconds wait_timeout{1}; - Optional<DisplayLine> previous_status; - Timer wait_timer{wait_time + wait_timeout, [&](Timer& timer) { - if (not context.has_client()) - return; - - const auto now = Clock::now(); - timer.set_next_date(now + wait_timeout); - auto& client = context.client(); - if (not previous_status) - previous_status = client.current_status(); - - client.print_status({format("waiting for shell command to finish{} ({}s)", - terminated ? " (shell terminated)" : "", - duration_cast<seconds>(now - wait_time).count()), - context.faces()[failed ? "Error" : "Information"]}); - client.redraw_ifn(); - }, EventMode::Urgent}; + BusyIndicator busy_indicator{context, [&](seconds elapsed) { + return DisplayLine{format("waiting for shell command to finish{} ({}s)", + terminated ? " (shell terminated)" : "", elapsed.count()), + context.faces()[failed ? "Error" : "Information"]}; + }}; bool cancelling = false; while (not terminated or shell.in or @@ -373,12 +361,6 @@ std::pair<String, int> ShellManager::eval( if (cancelling) throw cancel{}; - if (previous_status) // restore the status line - { - context.print_status(std::move(*previous_status)); - context.client().redraw_ifn(); - } - return { std::move(stdout_contents), WIFEXITED(status) ? WEXITSTATUS(status) : -1 }; } |
