summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2025-02-19 20:58:49 +1100
committerMaxime Coste <mawww@kakoune.org>2025-02-19 21:25:39 +1100
commiteb7d34333b0698e8e1a8af4f2be908ab08cb2089 (patch)
tree4b53ba24111ce88901669c3e7651b5ec4edb4f87 /src
parent9eda509282ebc881207c2d8278085cb53835641c (diff)
Cleanup file.cc/hh dependencies
file.cc/hh should not know about Context, Buffer, etc... It should be a pretty low level set of helper functions. Move buffer related functions to buffer_utils and extract busy indicators to callers.
Diffstat (limited to 'src')
-rw-r--r--src/buffer.hh2
-rw-r--r--src/buffer_manager.cc2
-rw-r--r--src/buffer_utils.cc90
-rw-r--r--src/buffer_utils.hh14
-rw-r--r--src/commands.cc20
-rw-r--r--src/file.cc127
-rw-r--r--src/file.hh32
-rw-r--r--src/main.cc5
8 files changed, 154 insertions, 138 deletions
diff --git a/src/buffer.hh b/src/buffer.hh
index 50423502..cd895c17 100644
--- a/src/buffer.hh
+++ b/src/buffer.hh
@@ -50,8 +50,6 @@ constexpr auto enum_desc(Meta::Type<ByteOrderMark>)
class Buffer;
-constexpr timespec InvalidTime = { -1, -1 };
-
// A BufferIterator permits to iterate over the characters of a buffer
class BufferIterator
{
diff --git a/src/buffer_manager.cc b/src/buffer_manager.cc
index 8d2820b2..c7d8f0aa 100644
--- a/src/buffer_manager.cc
+++ b/src/buffer_manager.cc
@@ -4,7 +4,7 @@
#include "buffer.hh"
#include "client_manager.hh"
#include "exception.hh"
-#include "file.hh"
+#include "buffer_utils.hh"
#include "ranges.hh"
#include "string.hh"
#include "regex.hh"
diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc
index a4fb639b..a2d2e709 100644
--- a/src/buffer_utils.cc
+++ b/src/buffer_utils.cc
@@ -166,6 +166,96 @@ void reload_file_buffer(Buffer& buffer)
buffer.flags() &= ~Buffer::Flags::New;
}
+void write_buffer_to_fd(Buffer& buffer, int fd)
+{
+ auto eolformat = buffer.options()["eolformat"].get<EolFormat>();
+ StringView eoldata;
+ if (eolformat == EolFormat::Crlf)
+ eoldata = "\r\n";
+ else
+ eoldata = "\n";
+
+
+ BufferedWriter<false> writer{fd};
+ if (buffer.options()["BOM"].get<ByteOrderMark>() == ByteOrderMark::Utf8)
+ writer.write("\xEF\xBB\xBF");
+
+ for (LineCount i = 0; i < buffer.line_count(); ++i)
+ {
+ // end of lines are written according to eolformat but always
+ // stored as \n
+ StringView linedata = buffer[i];
+ writer.write(linedata.substr(0, linedata.length()-1));
+ writer.write(eoldata);
+ }
+}
+
+void write_buffer_to_file(Buffer& buffer, StringView filename,
+ WriteMethod method, WriteFlags flags)
+{
+ auto zfilename = filename.zstr();
+ struct stat st;
+
+ bool replace = method == WriteMethod::Replace;
+ bool force = flags & WriteFlags::Force;
+
+ if ((replace or force) and (::stat(zfilename, &st) != 0 or
+ (st.st_mode & S_IFMT) != S_IFREG))
+ {
+ force = false;
+ replace = false;
+ }
+
+ if (force and ::chmod(zfilename, st.st_mode | S_IWUSR) < 0)
+ throw runtime_error(format("unable to change file permissions: {}", strerror(errno)));
+
+ char temp_filename[PATH_MAX];
+ const int fd = replace ? open_temp_file(filename, temp_filename)
+ : create_file(zfilename);
+ if (fd == -1)
+ {
+ auto saved_errno = errno;
+ if (force)
+ ::chmod(zfilename, st.st_mode);
+ throw file_access_error(filename, strerror(saved_errno));
+ }
+
+ {
+ auto close_fd = on_scope_end([fd]{ close(fd); });
+ write_buffer_to_fd(buffer, fd);
+ if (flags & WriteFlags::Sync)
+ ::fsync(fd);
+ }
+
+ if (replace and geteuid() == 0 and ::chown(temp_filename, st.st_uid, st.st_gid) < 0)
+ throw runtime_error(format("unable to set replacement file ownership: {}", strerror(errno)));
+ if (replace and ::chmod(temp_filename, st.st_mode) < 0)
+ throw runtime_error(format("unable to set replacement file permissions: {}", strerror(errno)));
+ if (force and not replace and ::chmod(zfilename, st.st_mode) < 0)
+ throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
+
+ if (replace and rename(temp_filename, zfilename) != 0)
+ {
+ if (force)
+ ::chmod(zfilename, st.st_mode);
+ throw runtime_error("replacing file failed");
+ }
+
+ if ((buffer.flags() & Buffer::Flags::File) and
+ real_path(filename) == real_path(buffer.name()))
+ buffer.notify_saved(get_fs_status(real_path(filename)));
+}
+
+void write_buffer_to_backup_file(Buffer& buffer)
+{
+ const int fd = open_temp_file(buffer.name());
+ if (fd >= 0)
+ {
+ write_buffer_to_fd(buffer, fd);
+ close(fd);
+ }
+}
+
Buffer* create_fifo_buffer(String name, int fd, Buffer::Flags flags, AutoScroll scroll)
{
static ValueId fifo_watcher_id = get_free_value_id();
diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh
index bc0dab68..96e89743 100644
--- a/src/buffer_utils.hh
+++ b/src/buffer_utils.hh
@@ -81,6 +81,20 @@ Buffer* open_or_create_file_buffer(StringView filename,
Buffer::Flags flags = Buffer::Flags::None);
void reload_file_buffer(Buffer& buffer);
+enum class WriteFlags
+{
+ None = 0,
+ Force = 0b01,
+ Sync = 0b10
+};
+constexpr bool with_bit_ops(Meta::Type<WriteFlags>) { return true; }
+
+void write_buffer_to_file(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);
+
+
void write_to_debug_buffer(StringView str);
Vector<String> history_as_strings(const Vector<Buffer::HistoryNode>& history);
diff --git a/src/commands.cc b/src/commands.cc
index 0f892004..ddc94c3b 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -618,7 +618,11 @@ 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(context, buffer, effective_filename, method, flags);
+ BusyIndicator busy_indicator{context, [&](std::chrono::seconds elapsed) {
+ return DisplayLine{format("waiting while writing buffer '{}' ({}s)", buffer.name(), elapsed.count()),
+ context.faces()["Information"]};
+ }};
+ write_buffer_to_file(buffer, effective_filename, method, flags);
context.hooks().run_hook(Hook::BufWritePost, effective_filename, context);
}
@@ -673,7 +677,11 @@ 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(context, *buffer, buffer->name(), method, flags);
+ BusyIndicator busy_indicator{context, [&](std::chrono::seconds elapsed) {
+ return DisplayLine{format("waiting while writing buffer ({}s)", elapsed.count()),
+ context.faces()["Information"]};
+ }};
+ write_buffer_to_file(*buffer, buffer->name(), method, flags);
buffer->run_hook_in_own_context(Hook::BufWritePost, buffer->name(), context.name());
}
}
@@ -1555,7 +1563,13 @@ const CommandDesc echo_cmd = {
message.push_back('\n');
if (auto filename = parser.get_switch("to-file"))
- write_to_file(context, *filename, message);
+ {
+ BusyIndicator busy_indicator{context, [&](std::chrono::seconds elapsed) {
+ return DisplayLine{format("waiting while writing to '{}' ({}s)", *filename, elapsed.count()),
+ context.faces()["Information"]};
+ }};
+ write_to_file(*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 2fbf2e78..b434e9dc 100644
--- a/src/file.cc
+++ b/src/file.cc
@@ -1,14 +1,15 @@
#include "file.hh"
#include "assert.hh"
-#include "buffer.hh"
-#include "client.hh"
-#include "exception.hh"
#include "flags.hh"
#include "event_manager.hh"
#include "ranked_match.hh"
#include "regex.hh"
#include "string.hh"
+#include "string_utils.hh"
+#include "format.hh"
+#include "ranges.hh"
+#include "hash_map.hh"
#include <limits>
#include <cerrno>
@@ -40,16 +41,12 @@
namespace Kakoune
{
-struct file_access_error : runtime_error
-{
-public:
- file_access_error(StringView filename,
- StringView error_desc)
- : runtime_error(format("{}: {}", filename, error_desc)) {}
+file_access_error::file_access_error(StringView filename,
+ StringView error_desc)
+ : runtime_error(format("{}: {}", filename, error_desc)) {}
- file_access_error(int fd, StringView error_desc)
- : runtime_error(format("fd {}: {}", fd, error_desc)) {}
-};
+file_access_error::file_access_error(int fd, StringView error_desc)
+ : runtime_error(format("fd {}: {}", fd, error_desc)) {}
String parse_filename(StringView filename, StringView buf_dir)
{
@@ -272,64 +269,36 @@ void write(int fd, StringView data)
else if (errno == EAGAIN and not atomic and EventManager::has_instance())
EventManager::instance().handle_next_events(EventMode::Urgent, nullptr, std::chrono::nanoseconds{});
else
- throw file_access_error(format("fd: {}", fd), strerror(errno));
+ throw file_access_error(fd, strerror(errno));
}
}
template void write<true>(int fd, StringView data);
template void write<false>(int fd, StringView data);
-static int create_file(const Context& context, const char* filename)
+int create_file(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, nanoseconds{1'000'000});
+ EventManager::instance().handle_next_events(EventMode::Urgent, nullptr,
+ std::chrono::nanoseconds{1'000'000});
else
return -1;
}
return fd;
}
-void write_to_file(const Context& context, StringView filename, StringView data)
+void write_to_file(StringView filename, StringView data)
{
- int fd = create_file(context, filename.zstr());
+ int fd = create_file(filename.zstr());
if (fd == -1)
throw file_access_error(filename, strerror(errno));
auto close_fd = on_scope_end([fd]{ close(fd); });
write(fd, data);
}
-void write_buffer_to_fd(Buffer& buffer, int fd)
-{
- auto eolformat = buffer.options()["eolformat"].get<EolFormat>();
- StringView eoldata;
- if (eolformat == EolFormat::Crlf)
- eoldata = "\r\n";
- else
- eoldata = "\n";
-
-
- BufferedWriter<false> writer{fd};
- if (buffer.options()["BOM"].get<ByteOrderMark>() == ByteOrderMark::Utf8)
- writer.write("\xEF\xBB\xBF");
-
- for (LineCount i = 0; i < buffer.line_count(); ++i)
- {
- // end of lines are written according to eolformat but always
- // stored as \n
- StringView linedata = buffer[i];
- writer.write(linedata.substr(0, linedata.length()-1));
- writer.write(eoldata);
- }
-}
-
int open_temp_file(StringView filename, char (&buffer)[PATH_MAX])
{
String path = real_path(filename);
@@ -349,72 +318,6 @@ int open_temp_file(StringView filename)
return open_temp_file(filename, buffer);
}
-void write_buffer_to_file(const Context& context, Buffer& buffer, StringView filename,
- WriteMethod method, WriteFlags flags)
-{
- auto zfilename = filename.zstr();
- struct stat st;
-
- bool replace = method == WriteMethod::Replace;
- bool force = flags & WriteFlags::Force;
-
- if ((replace or force) and (::stat(zfilename, &st) != 0 or
- (st.st_mode & S_IFMT) != S_IFREG))
- {
- force = false;
- replace = false;
- }
-
- if (force and ::chmod(zfilename, st.st_mode | S_IWUSR) < 0)
- throw runtime_error(format("unable to change file permissions: {}", strerror(errno)));
-
- char temp_filename[PATH_MAX];
- const int fd = replace ? open_temp_file(filename, temp_filename)
- : create_file(context, zfilename);
- if (fd == -1)
- {
- auto saved_errno = errno;
- if (force)
- ::chmod(zfilename, st.st_mode);
- throw file_access_error(filename, strerror(saved_errno));
- }
-
- {
- auto close_fd = on_scope_end([fd]{ close(fd); });
- write_buffer_to_fd(buffer, fd);
- if (flags & WriteFlags::Sync)
- ::fsync(fd);
- }
-
- if (replace and geteuid() == 0 and ::chown(temp_filename, st.st_uid, st.st_gid) < 0)
- throw runtime_error(format("unable to set replacement file ownership: {}", strerror(errno)));
- if (replace and ::chmod(temp_filename, st.st_mode) < 0)
- throw runtime_error(format("unable to set replacement file permissions: {}", strerror(errno)));
- if (force and not replace and ::chmod(zfilename, st.st_mode) < 0)
- throw runtime_error(format("unable to restore file permissions: {}", strerror(errno)));
-
- if (replace and rename(temp_filename, zfilename) != 0)
- {
- if (force)
- ::chmod(zfilename, st.st_mode);
- throw runtime_error("replacing file failed");
- }
-
- if ((buffer.flags() & Buffer::Flags::File) and
- real_path(filename) == real_path(buffer.name()))
- buffer.notify_saved(get_fs_status(real_path(filename)));
-}
-
-void write_buffer_to_backup_file(Buffer& buffer)
-{
- const int fd = open_temp_file(buffer.name());
- if (fd >= 0)
- {
- write_buffer_to_fd(buffer, fd);
- close(fd);
- }
-}
-
String find_file(StringView filename, StringView buf_dir, ConstArrayView<String> paths)
{
struct stat buf;
diff --git a/src/file.hh b/src/file.hh
index a0b55e56..3d0d8603 100644
--- a/src/file.hh
+++ b/src/file.hh
@@ -1,12 +1,13 @@
#ifndef file_hh_INCLUDED
#define file_hh_INCLUDED
+#include "array.hh"
#include "array_view.hh"
#include "enum.hh"
+#include "exception.hh"
#include "meta.hh"
#include "string.hh"
#include "units.hh"
-#include "array.hh"
#include "vector.hh"
#include <sys/types.h>
@@ -16,10 +17,16 @@
namespace Kakoune
{
-class Buffer;
class String;
class Regex;
+struct file_access_error : runtime_error
+{
+ file_access_error(StringView filename, StringView error_desc);
+ file_access_error(int fd, StringView error_desc);
+};
+
+
using CandidateList = Vector<String, MemoryDomain::Completion>;
// parse ~/ and %/ in filename and returns the translated filename
@@ -42,8 +49,10 @@ 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);
-class Context;
-void write_to_file(const Context&, StringView filename, StringView data);
+void write_to_file(StringView filename, StringView data);
+int create_file(const char* filename);
+int open_temp_file(StringView filename);
+int open_temp_file(StringView filename, char (&buffer)[PATH_MAX]);
struct MappedFile
{
@@ -69,19 +78,6 @@ constexpr auto enum_desc(Meta::Type<WriteMethod>)
});
}
-enum class WriteFlags
-{
- None = 0,
- Force = 0b01,
- Sync = 0b10
-};
-constexpr bool with_bit_ops(Meta::Type<WriteFlags>) { return true; }
-
-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);
-
String find_file(StringView filename, StringView buf_dir, ConstArrayView<String> paths);
bool file_exists(StringView filename);
bool regular_file_exists(StringView filename);
@@ -90,6 +86,8 @@ Vector<String> list_files(StringView directory);
void make_directory(StringView dir, mode_t mode);
+constexpr timespec InvalidTime = { -1, -1 };
+
struct FsStatus
{
timespec timestamp;
diff --git a/src/main.cc b/src/main.cc
index ac9af4ca..0d70bd6a 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1007,15 +1007,14 @@ 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(empty_context, *buffer, buffer->name() + suffix_backup,
+ write_buffer_to_file(*buffer, buffer->name() + suffix_backup,
WriteMethod::Overwrite, WriteFlags::None);
apply_to_buffer(*buffer);
- write_buffer_to_file(empty_context, *buffer, buffer->name(),
+ write_buffer_to_file(*buffer, buffer->name(),
WriteMethod::Overwrite, WriteFlags::None);
buffer_manager.delete_buffer(*buffer);
}