Add support for running Kakoune with redirected stdin
Will read to a *stdin* fifo buffer
This commit is contained in:
parent
f683946681
commit
479c067a40
|
@ -1,5 +1,7 @@
|
||||||
#include "buffer_utils.hh"
|
#include "buffer_utils.hh"
|
||||||
|
|
||||||
|
#include "event_manager.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -20,4 +22,37 @@ CharCount get_column(const Buffer& buffer,
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Buffer* create_fifo_buffer(String name, int fd)
|
||||||
|
{
|
||||||
|
Buffer* buffer = new Buffer(std::move(name), Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
|
||||||
|
|
||||||
|
auto watcher = new FDWatcher(fd, [buffer](FDWatcher& watcher) {
|
||||||
|
constexpr size_t buffer_size = 1024 * 16;
|
||||||
|
char data[buffer_size];
|
||||||
|
ssize_t count = read(watcher.fd(), data, buffer_size);
|
||||||
|
buffer->insert(buffer->end()-1, count > 0 ? String(data, data+count)
|
||||||
|
: "*** kak: fifo closed ***\n");
|
||||||
|
if (count <= 0)
|
||||||
|
{
|
||||||
|
kak_assert(buffer->flags() & Buffer::Flags::Fifo);
|
||||||
|
buffer->flags() &= ~Buffer::Flags::Fifo;
|
||||||
|
buffer->flags() &= ~Buffer::Flags::NoUndo;
|
||||||
|
close(watcher.fd());
|
||||||
|
delete &watcher;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buffer->hooks().add_hook("BufClose", "",
|
||||||
|
[buffer, watcher](const String&, const Context&) {
|
||||||
|
// Check if fifo is still alive, else watcher is already dead
|
||||||
|
if (buffer->flags() & Buffer::Flags::Fifo)
|
||||||
|
{
|
||||||
|
close(watcher->fd());
|
||||||
|
delete watcher;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ inline void avoid_eol(const Buffer& buffer, Selection& sel)
|
||||||
CharCount get_column(const Buffer& buffer,
|
CharCount get_column(const Buffer& buffer,
|
||||||
CharCount tabstop, BufferCoord coord);
|
CharCount tabstop, BufferCoord coord);
|
||||||
|
|
||||||
|
Buffer* create_fifo_buffer(String name, int fd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // buffer_utils_hh_INCLUDED
|
#endif // buffer_utils_hh_INCLUDED
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "buffer.hh"
|
#include "buffer.hh"
|
||||||
#include "buffer_manager.hh"
|
#include "buffer_manager.hh"
|
||||||
|
#include "buffer_utils.hh"
|
||||||
#include "client.hh"
|
#include "client.hh"
|
||||||
#include "client_manager.hh"
|
#include "client_manager.hh"
|
||||||
#include "color_registry.hh"
|
#include "color_registry.hh"
|
||||||
|
@ -45,7 +46,7 @@ Buffer* open_or_create(const String& filename, Context& context)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer* open_fifo(const String& name , const String& filename, Context& context)
|
Buffer* open_fifo(const String& name , const String& filename)
|
||||||
{
|
{
|
||||||
int fd = open(parse_filename(filename).c_str(), O_RDONLY);
|
int fd = open(parse_filename(filename).c_str(), O_RDONLY);
|
||||||
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
fcntl(fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
@ -54,35 +55,7 @@ Buffer* open_fifo(const String& name , const String& filename, Context& context)
|
||||||
|
|
||||||
BufferManager::instance().delete_buffer_if_exists(name);
|
BufferManager::instance().delete_buffer_if_exists(name);
|
||||||
|
|
||||||
Buffer* buffer = new Buffer(name, Buffer::Flags::Fifo | Buffer::Flags::NoUndo);
|
return create_fifo_buffer(std::move(name), fd);
|
||||||
|
|
||||||
auto watcher = new FDWatcher(fd, [buffer](FDWatcher& watcher) {
|
|
||||||
constexpr size_t buffer_size = 1024 * 16;
|
|
||||||
char data[buffer_size];
|
|
||||||
ssize_t count = read(watcher.fd(), data, buffer_size);
|
|
||||||
buffer->insert(buffer->end()-1, count > 0 ? String(data, data+count)
|
|
||||||
: "*** kak: fifo closed ***\n");
|
|
||||||
if (count <= 0)
|
|
||||||
{
|
|
||||||
kak_assert(buffer->flags() & Buffer::Flags::Fifo);
|
|
||||||
buffer->flags() &= ~Buffer::Flags::Fifo;
|
|
||||||
buffer->flags() &= ~Buffer::Flags::NoUndo;
|
|
||||||
close(watcher.fd());
|
|
||||||
delete &watcher;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buffer->hooks().add_hook("BufClose", "",
|
|
||||||
[buffer, watcher](const String&, const Context&) {
|
|
||||||
// Check if fifo is still alive, else watcher is already dead
|
|
||||||
if (buffer->flags() & Buffer::Flags::Fifo)
|
|
||||||
{
|
|
||||||
close(watcher->fd());
|
|
||||||
delete watcher;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PerArgumentCommandCompleter filename_completer({
|
const PerArgumentCommandCompleter filename_completer({
|
||||||
|
@ -138,7 +111,7 @@ void edit(const ParametersParser& parser, Context& context)
|
||||||
buffer = new Buffer(name, Buffer::Flags::None);
|
buffer = new Buffer(name, Buffer::Flags::None);
|
||||||
}
|
}
|
||||||
else if (parser.has_option("fifo"))
|
else if (parser.has_option("fifo"))
|
||||||
buffer = open_fifo(name, parser.option_value("fifo"), context);
|
buffer = open_fifo(name, parser.option_value("fifo"));
|
||||||
else
|
else
|
||||||
buffer = open_or_create(name, context);
|
buffer = open_or_create(name, context);
|
||||||
}
|
}
|
||||||
|
|
17
src/main.cc
17
src/main.cc
|
@ -30,6 +30,10 @@
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
using namespace Kakoune;
|
using namespace Kakoune;
|
||||||
|
|
||||||
void run_unit_tests();
|
void run_unit_tests();
|
||||||
|
@ -192,6 +196,19 @@ void create_local_client(const String& init_command)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (not isatty(1))
|
||||||
|
throw runtime_error("stdout is not a tty");
|
||||||
|
|
||||||
|
if (not isatty(0))
|
||||||
|
{
|
||||||
|
// move stdin to another fd, and restore tty as stdin
|
||||||
|
int fd = dup(0);
|
||||||
|
int tty = open("/dev/tty", O_RDONLY);
|
||||||
|
dup2(tty, 0);
|
||||||
|
close(tty);
|
||||||
|
create_fifo_buffer("*stdin*", fd);
|
||||||
|
}
|
||||||
|
|
||||||
UserInterface* ui = new LocalNCursesUI{};
|
UserInterface* ui = new LocalNCursesUI{};
|
||||||
static Client* client = ClientManager::instance().create_client(
|
static Client* client = ClientManager::instance().create_client(
|
||||||
std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
|
std::unique_ptr<UserInterface>{ui}, get_env_vars(), init_command);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user