Add support for reading from stdin/writing to stdout in filter mode
Note that kakoune still needs to read the whole buffer first, only once stdin is closed can it execute the keys.
This commit is contained in:
parent
eff32aa1a1
commit
8d4531d419
|
@ -1,5 +1,6 @@
|
|||
#include "buffer_utils.hh"
|
||||
|
||||
#include "buffer_manager.hh"
|
||||
#include "event_manager.hh"
|
||||
|
||||
#include <sys/select.h>
|
||||
|
@ -24,6 +25,60 @@ CharCount get_column(const Buffer& buffer,
|
|||
return col;
|
||||
}
|
||||
|
||||
Buffer* create_buffer_from_data(StringView data, StringView name,
|
||||
Buffer::Flags flags, time_t fs_timestamp)
|
||||
{
|
||||
bool bom = false, crlf = false;
|
||||
|
||||
const char* pos = data.begin();
|
||||
if (data.length() >= 3 and
|
||||
data[0] == '\xEF' and data[1] == '\xBB' and data[2] == '\xBF')
|
||||
{
|
||||
bom = true;
|
||||
pos = data.begin() + 3;
|
||||
}
|
||||
|
||||
std::vector<String> lines;
|
||||
while (pos < data.end())
|
||||
{
|
||||
const char* line_end = pos;
|
||||
while (line_end < data.end() and *line_end != '\r' and *line_end != '\n')
|
||||
++line_end;
|
||||
|
||||
// this should happen only when opening a file which has no
|
||||
// end of line as last character.
|
||||
if (line_end == data.end())
|
||||
{
|
||||
lines.emplace_back(pos, line_end);
|
||||
lines.back() += '\n';
|
||||
break;
|
||||
}
|
||||
|
||||
lines.emplace_back(pos, line_end + 1);
|
||||
lines.back().back() = '\n';
|
||||
|
||||
if (line_end+1 != data.end() and *line_end == '\r' and *(line_end+1) == '\n')
|
||||
{
|
||||
crlf = true;
|
||||
pos = line_end + 2;
|
||||
}
|
||||
else
|
||||
pos = line_end + 1;
|
||||
}
|
||||
|
||||
Buffer* buffer = BufferManager::instance().get_buffer_ifp(name);
|
||||
if (buffer)
|
||||
buffer->reload(std::move(lines), fs_timestamp);
|
||||
else
|
||||
buffer = new Buffer{name, flags, std::move(lines), fs_timestamp};
|
||||
|
||||
OptionManager& options = buffer->options();
|
||||
options.get_local_option("eolformat").set<String>(crlf ? "crlf" : "lf");
|
||||
options.get_local_option("BOM").set<String>(bom ? "utf-8" : "no");
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Buffer* create_fifo_buffer(String name, int fd, bool scroll)
|
||||
{
|
||||
Buffer* buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
|
||||
|
|
|
@ -29,6 +29,10 @@ CharCount get_column(const Buffer& buffer,
|
|||
|
||||
Buffer* create_fifo_buffer(String name, int fd, bool scroll = false);
|
||||
|
||||
Buffer* create_buffer_from_data(StringView data, StringView name,
|
||||
Buffer::Flags flags,
|
||||
time_t fs_timestamp = InvalidTime);
|
||||
|
||||
}
|
||||
|
||||
#endif // buffer_utils_hh_INCLUDED
|
||||
|
|
135
src/file.cc
135
src/file.cc
|
@ -3,6 +3,7 @@
|
|||
#include "assert.hh"
|
||||
#include "buffer.hh"
|
||||
#include "buffer_manager.hh"
|
||||
#include "buffer_utils.hh"
|
||||
#include "completion.hh"
|
||||
#include "debug.hh"
|
||||
#include "unicode.hh"
|
||||
|
@ -95,6 +96,21 @@ String compact_path(StringView filename)
|
|||
return filename.str();
|
||||
}
|
||||
|
||||
String read_fd(int fd)
|
||||
{
|
||||
String content;
|
||||
char buf[256];
|
||||
while (true)
|
||||
{
|
||||
ssize_t size = read(fd, buf, 256);
|
||||
if (size == -1 or size == 0)
|
||||
break;
|
||||
|
||||
content += String(buf, buf + size);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
String read_file(StringView filename)
|
||||
{
|
||||
int fd = open(parse_filename(filename).c_str(), O_RDONLY);
|
||||
|
@ -107,17 +123,7 @@ String read_file(StringView filename)
|
|||
}
|
||||
auto close_fd = on_scope_end([fd]{ close(fd); });
|
||||
|
||||
String content;
|
||||
char buf[256];
|
||||
while (true)
|
||||
{
|
||||
ssize_t size = read(fd, buf, 256);
|
||||
if (size == -1 or size == 0)
|
||||
break;
|
||||
|
||||
content += String(buf, buf + size);
|
||||
}
|
||||
return content;
|
||||
return read_fd(fd);
|
||||
}
|
||||
|
||||
Buffer* create_buffer_from_file(String filename)
|
||||
|
@ -132,69 +138,20 @@ Buffer* create_buffer_from_file(String filename)
|
|||
|
||||
throw file_access_error(filename, strerror(errno));
|
||||
}
|
||||
auto close_fd = on_scope_end([&]{ close(fd); });
|
||||
|
||||
struct stat st;
|
||||
fstat(fd, &st);
|
||||
if (S_ISDIR(st.st_mode))
|
||||
{
|
||||
close(fd);
|
||||
throw file_access_error(filename, "is a directory");
|
||||
}
|
||||
|
||||
const char* data = (const char*)mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
auto cleanup = on_scope_end([&]{ munmap((void*)data, st.st_size); close(fd); });
|
||||
auto unmap = on_scope_end([&]{ munmap((void*)data, st.st_size); });
|
||||
|
||||
const char* pos = data;
|
||||
bool crlf = false;
|
||||
bool bom = false;
|
||||
if (st.st_size >= 3 and
|
||||
data[0] == '\xEF' and data[1] == '\xBB' and data[2] == '\xBF')
|
||||
{
|
||||
bom = true;
|
||||
pos = data + 3;
|
||||
}
|
||||
|
||||
std::vector<String> lines;
|
||||
const char* end = data + st.st_size;
|
||||
while (pos < end)
|
||||
{
|
||||
const char* line_end = pos;
|
||||
while (line_end < end and *line_end != '\r' and *line_end != '\n')
|
||||
++line_end;
|
||||
|
||||
// this should happen only when opening a file which has no
|
||||
// end of line as last character.
|
||||
if (line_end == end)
|
||||
{
|
||||
lines.emplace_back(pos, line_end);
|
||||
lines.back() += '\n';
|
||||
break;
|
||||
}
|
||||
|
||||
lines.emplace_back(pos, line_end + 1);
|
||||
lines.back().back() = '\n';
|
||||
|
||||
if (line_end+1 != end and *line_end == '\r' and *(line_end+1) == '\n')
|
||||
{
|
||||
crlf = true;
|
||||
pos = line_end + 2;
|
||||
}
|
||||
else
|
||||
pos = line_end + 1;
|
||||
}
|
||||
Buffer* buffer = BufferManager::instance().get_buffer_ifp(filename);
|
||||
if (buffer)
|
||||
buffer->reload(std::move(lines), st.st_mtime);
|
||||
else
|
||||
buffer = new Buffer{filename, Buffer::Flags::File,
|
||||
std::move(lines), st.st_mtime};
|
||||
|
||||
OptionManager& options = buffer->options();
|
||||
options.get_local_option("eolformat").set<String>(crlf ? "crlf" : "lf");
|
||||
options.get_local_option("BOM").set<String>(bom ? "utf-8" : "no");
|
||||
|
||||
return buffer;
|
||||
return create_buffer_from_data({data, data + st.st_size}, filename, Buffer::Flags::File, st.st_mtime);
|
||||
}
|
||||
|
||||
static void write(int fd, StringView data, StringView filename)
|
||||
static void write(int fd, StringView data)
|
||||
{
|
||||
const char* ptr = data.data();
|
||||
ssize_t count = (int)data.length();
|
||||
|
@ -206,14 +163,12 @@ static void write(int fd, StringView data, StringView filename)
|
|||
count -= written;
|
||||
|
||||
if (written == -1)
|
||||
throw file_access_error(filename, strerror(errno));
|
||||
throw file_access_error("fd: " + to_string(fd), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void write_buffer_to_file(Buffer& buffer, StringView filename)
|
||||
void write_buffer_to_fd(Buffer& buffer, int fd)
|
||||
{
|
||||
buffer.run_hook_in_own_context("BufWritePre", buffer.name());
|
||||
|
||||
const String& eolformat = buffer.options()["eolformat"].get<String>();
|
||||
StringView eoldata;
|
||||
if (eolformat == "crlf")
|
||||
|
@ -221,25 +176,31 @@ void write_buffer_to_file(Buffer& buffer, StringView filename)
|
|||
else
|
||||
eoldata = "\n";
|
||||
|
||||
if (buffer.options()["BOM"].get<String>() == "utf-8")
|
||||
::write(fd, "\xEF\xBB\xBF", 3);
|
||||
|
||||
for (LineCount i = 0; i < buffer.line_count(); ++i)
|
||||
{
|
||||
int fd = open(parse_filename(filename).c_str(),
|
||||
O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
||||
if (fd == -1)
|
||||
throw file_access_error(filename, strerror(errno));
|
||||
auto close_fd = on_scope_end([fd]{ close(fd); });
|
||||
|
||||
if (buffer.options()["BOM"].get<String>() == "utf-8")
|
||||
::write(fd, "\xEF\xBB\xBF", 3);
|
||||
|
||||
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];
|
||||
write(fd, linedata.substr(0, linedata.length()-1), filename);
|
||||
write(fd, eoldata, filename);
|
||||
}
|
||||
// end of lines are written according to eolformat but always
|
||||
// stored as \n
|
||||
StringView linedata = buffer[i];
|
||||
write(fd, linedata.substr(0, linedata.length()-1));
|
||||
write(fd, eoldata);
|
||||
}
|
||||
}
|
||||
|
||||
void write_buffer_to_file(Buffer& buffer, StringView filename)
|
||||
{
|
||||
buffer.run_hook_in_own_context("BufWritePre", buffer.name());
|
||||
|
||||
int fd = open(parse_filename(filename).c_str(),
|
||||
O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
||||
if (fd == -1)
|
||||
throw file_access_error(filename, strerror(errno));
|
||||
auto close_fd = on_scope_end([fd]{ close(fd); });
|
||||
|
||||
write_buffer_to_fd(buffer, fd);
|
||||
|
||||
if ((buffer.flags() & Buffer::Flags::File) and
|
||||
real_path(filename) == real_path(buffer.name()))
|
||||
buffer.notify_saved();
|
||||
|
|
|
@ -28,9 +28,14 @@ String parse_filename(StringView filename);
|
|||
String real_path(StringView filename);
|
||||
String compact_path(StringView filename);
|
||||
|
||||
String read_fd(int fd);
|
||||
String read_file(StringView filename);
|
||||
|
||||
Buffer* create_buffer_from_file(String filename);
|
||||
|
||||
void write_buffer_to_file(Buffer& buffer, StringView filename);
|
||||
void write_buffer_to_fd(Buffer& buffer, int fd);
|
||||
|
||||
String find_file(StringView filename, memoryview<String> paths);
|
||||
|
||||
time_t get_fs_timestamp(StringView filename);
|
||||
|
|
13
src/main.cc
13
src/main.cc
|
@ -411,6 +411,19 @@ int run_filter(StringView keystr, memoryview<StringView> files)
|
|||
|
||||
buffer_manager.delete_buffer(*buffer);
|
||||
}
|
||||
if (not isatty(0))
|
||||
{
|
||||
Buffer* buffer = create_buffer_from_data(read_fd(0), "*stdin*", Buffer::Flags::None);
|
||||
InputHandler input_handler{{ *buffer, Selection{} }};
|
||||
|
||||
for (auto& key : keys)
|
||||
input_handler.handle_key(key);
|
||||
|
||||
write_buffer_to_fd(*buffer, 1);
|
||||
|
||||
buffer_manager.delete_buffer(*buffer);
|
||||
}
|
||||
|
||||
buffer_manager.clear_buffer_trash();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user