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_utils.hh"
|
||||||
|
|
||||||
|
#include "buffer_manager.hh"
|
||||||
#include "event_manager.hh"
|
#include "event_manager.hh"
|
||||||
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
@ -24,6 +25,60 @@ CharCount get_column(const Buffer& buffer,
|
||||||
return col;
|
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* create_fifo_buffer(String name, int fd, bool scroll)
|
||||||
{
|
{
|
||||||
Buffer* buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
|
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_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
|
#endif // buffer_utils_hh_INCLUDED
|
||||||
|
|
135
src/file.cc
135
src/file.cc
|
@ -3,6 +3,7 @@
|
||||||
#include "assert.hh"
|
#include "assert.hh"
|
||||||
#include "buffer.hh"
|
#include "buffer.hh"
|
||||||
#include "buffer_manager.hh"
|
#include "buffer_manager.hh"
|
||||||
|
#include "buffer_utils.hh"
|
||||||
#include "completion.hh"
|
#include "completion.hh"
|
||||||
#include "debug.hh"
|
#include "debug.hh"
|
||||||
#include "unicode.hh"
|
#include "unicode.hh"
|
||||||
|
@ -95,6 +96,21 @@ String compact_path(StringView filename)
|
||||||
return filename.str();
|
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)
|
String read_file(StringView filename)
|
||||||
{
|
{
|
||||||
int fd = open(parse_filename(filename).c_str(), O_RDONLY);
|
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); });
|
auto close_fd = on_scope_end([fd]{ close(fd); });
|
||||||
|
|
||||||
String content;
|
return read_fd(fd);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer* create_buffer_from_file(String filename)
|
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));
|
throw file_access_error(filename, strerror(errno));
|
||||||
}
|
}
|
||||||
|
auto close_fd = on_scope_end([&]{ close(fd); });
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
{
|
|
||||||
close(fd);
|
|
||||||
throw file_access_error(filename, "is a directory");
|
throw file_access_error(filename, "is a directory");
|
||||||
}
|
|
||||||
const char* data = (const char*)mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
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;
|
return create_buffer_from_data({data, data + st.st_size}, filename, Buffer::Flags::File, st.st_mtime);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write(int fd, StringView data, StringView filename)
|
static void write(int fd, StringView data)
|
||||||
{
|
{
|
||||||
const char* ptr = data.data();
|
const char* ptr = data.data();
|
||||||
ssize_t count = (int)data.length();
|
ssize_t count = (int)data.length();
|
||||||
|
@ -206,14 +163,12 @@ static void write(int fd, StringView data, StringView filename)
|
||||||
count -= written;
|
count -= written;
|
||||||
|
|
||||||
if (written == -1)
|
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>();
|
const String& eolformat = buffer.options()["eolformat"].get<String>();
|
||||||
StringView eoldata;
|
StringView eoldata;
|
||||||
if (eolformat == "crlf")
|
if (eolformat == "crlf")
|
||||||
|
@ -221,25 +176,31 @@ void write_buffer_to_file(Buffer& buffer, StringView filename)
|
||||||
else
|
else
|
||||||
eoldata = "\n";
|
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(),
|
// end of lines are written according to eolformat but always
|
||||||
O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
// stored as \n
|
||||||
if (fd == -1)
|
StringView linedata = buffer[i];
|
||||||
throw file_access_error(filename, strerror(errno));
|
write(fd, linedata.substr(0, linedata.length()-1));
|
||||||
auto close_fd = on_scope_end([fd]{ close(fd); });
|
write(fd, eoldata);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
if ((buffer.flags() & Buffer::Flags::File) and
|
||||||
real_path(filename) == real_path(buffer.name()))
|
real_path(filename) == real_path(buffer.name()))
|
||||||
buffer.notify_saved();
|
buffer.notify_saved();
|
||||||
|
|
|
@ -28,9 +28,14 @@ String parse_filename(StringView filename);
|
||||||
String real_path(StringView filename);
|
String real_path(StringView filename);
|
||||||
String compact_path(StringView filename);
|
String compact_path(StringView filename);
|
||||||
|
|
||||||
|
String read_fd(int fd);
|
||||||
String read_file(StringView filename);
|
String read_file(StringView filename);
|
||||||
|
|
||||||
Buffer* create_buffer_from_file(String filename);
|
Buffer* create_buffer_from_file(String filename);
|
||||||
|
|
||||||
void write_buffer_to_file(Buffer& buffer, StringView 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);
|
String find_file(StringView filename, memoryview<String> paths);
|
||||||
|
|
||||||
time_t get_fs_timestamp(StringView filename);
|
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);
|
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();
|
buffer_manager.clear_buffer_trash();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user