From ef84b6c3fc5930b856e12c145fcd30dad7d886d2 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 10 Nov 2016 09:02:13 -0500 Subject: [PATCH] Added preliminary support for copy paste --- Makefile | 5 +-- inc/edit.h | 23 +++++++++++++ libedit/buf.c | 40 ++++++++++++++++++++++ libedit/clip.c | 20 +++++++++++ libedit/exec.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++ libedit/keyboard.c | 18 ++++++++-- libedit/utils.c | 13 +++++++ 7 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 libedit/clip.c create mode 100644 libedit/exec.c diff --git a/Makefile b/Makefile index 7ee3306..f9a3e95 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,3 @@ - INCS = -Iinc/ LIBEDIT_OBJS = \ @@ -8,7 +7,9 @@ LIBEDIT_OBJS = \ libedit/mouse.o \ libedit/screen.o \ libedit/utf8.o \ - libedit/utils.o + libedit/utils.o \ + libedit/exec.o \ + libedit/clip.o LIBX_OBJS = \ libx/x11.o diff --git a/inc/edit.h b/inc/edit.h index 80d4693..c294c47 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -11,6 +11,7 @@ uint32_t getmillis(void); bool risword(Rune r); bool risblank(Rune r); char* stringdup(const char* str); +char* fdgets(int fd); /* Buffer management functions *****************************************************************************/ @@ -69,6 +70,8 @@ unsigned buf_byrune(Buf* buf, unsigned pos, int count); unsigned buf_byline(Buf* buf, unsigned pos, int count); unsigned buf_getcol(Buf* buf, unsigned pos); unsigned buf_setcol(Buf* buf, unsigned pos, unsigned col); +char* buf_getstr(Buf* buf, unsigned beg, unsigned end); +unsigned buf_putstr(Buf* buf, unsigned beg, unsigned end, char* str); /* Charset Handling *****************************************************************************/ @@ -134,6 +137,26 @@ void screen_clearrow(unsigned row); unsigned screen_setcell(unsigned row, unsigned col, uint32_t attr, Rune r); UGlyph* screen_getglyph(unsigned row, unsigned col, unsigned* scrwidth); +/* Command Executions + *****************************************************************************/ +typedef struct { + int pid; + int in; + int out; + int err; +} Process; + +int execute(char** cmd, Process* proc); +void detach(Process* proc); +void terminate(Process* proc, int sig); +char* cmdread(char** cmd); +void cmdwrite(char** cmd, char* text); + +/* Clipboard Access + *****************************************************************************/ +void clipcopy(char* text); +char* clippaste(void); + /* Color Scheme Handling *****************************************************************************/ /* color indexes for the colorscheme */ diff --git a/libedit/buf.c b/libedit/buf.c index 8f017a7..8382d56 100644 --- a/libedit/buf.c +++ b/libedit/buf.c @@ -348,3 +348,43 @@ unsigned buf_setcol(Buf* buf, unsigned pos, unsigned col) { } return curr; } + +char* buf_getstr(Buf* buf, unsigned beg, unsigned end) { + char utf[UTF_MAX] = {0}; + size_t len = 0; + char* str = NULL; + for (; beg <= end; beg++) { + Rune rune = buf_get(buf, beg); + if (rune == RUNE_CRLF) { + str = realloc(str, len + 2); + str[len + 1] = '\r'; + str[len + 2] = '\n'; + len += 2; + } else { + size_t n = utf8encode(utf, rune); + str = realloc(str, len + n); + memcpy(str+len, utf, n); + len += n; + } + } + str = realloc(str, len+1); + if (str) str[len] = '\0'; + return str; +} + +unsigned buf_putstr(Buf* buf, unsigned beg, unsigned end, char* str) { + bool locked = buf_locked(buf); + buf_setlocked(buf, false); + /* delete the selected text first */ + for (unsigned i = beg; ((end-beg) > 1) && (i <= end); i++) + buf_del(buf, beg); + /* insert the text */ + while (*str) { + Rune rune = 0; + size_t length = 0; + while (!utf8decode(&rune, &length, *str++)); + buf_ins(buf, beg++, rune); + } + buf_setlocked(buf, locked); + return beg; +} diff --git a/libedit/clip.c b/libedit/clip.c new file mode 100644 index 0000000..f1b0644 --- /dev/null +++ b/libedit/clip.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#ifdef __MACH__ +char* CopyCmd[] = { "pbcopy", NULL }; +char* PasteCmd[] = { "pbpaste", NULL }; +#else +char* CopyCmd[] = { "xsel", "-bi", NULL }; +char* PasteCmd[] = { "xsel", "-bo", NULL }; +#endif + +void clipcopy(char* text) { + cmdwrite(CopyCmd, text); +} + +char* clippaste(void) { + return cmdread(PasteCmd); +} diff --git a/libedit/exec.c b/libedit/exec.c new file mode 100644 index 0000000..e90bfda --- /dev/null +++ b/libedit/exec.c @@ -0,0 +1,85 @@ +#include +#include +#include + +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +int execute(char** cmd, Process* proc) { + int inpipe[2], outpipe[2], errpipe[2]; + /* create the pipes */ + if ((pipe(inpipe) < 0) || (pipe(outpipe) < 0) || (pipe(errpipe) < 0)) + return -1; + /* create the process */ + proc->pid = fork(); + if (proc->pid < 0) { + /* signal that we failed to fork */ + proc->in = -1; + proc->out = -1; + proc->err = -1; + } else if (0 == proc->pid) { + /* redirect child process's io to the pipes */ + if ((dup2(inpipe[PIPE_READ], STDIN_FILENO) < 0) || + (dup2(outpipe[PIPE_WRITE], STDOUT_FILENO) < 0) || + (dup2(errpipe[PIPE_WRITE], STDERR_FILENO) < 0)) { + perror("failed to pipe"); + exit(1); + } + /* execute the process */ + close(inpipe[PIPE_WRITE]); + close(outpipe[PIPE_READ]); + close(errpipe[PIPE_READ]); + exit(execvp(cmd[0], cmd)); + } else { + close(inpipe[PIPE_READ]); + close(outpipe[PIPE_WRITE]); + close(errpipe[PIPE_WRITE]); + proc->in = inpipe[PIPE_WRITE]; + proc->out = outpipe[PIPE_READ]; + proc->err = errpipe[PIPE_READ]; + } + return proc->pid; +} + +void detach(Process* proc) { + close(proc->in); + close(proc->out); + close(proc->err); +} + +void terminate(Process* proc, int sig) { + detach(proc); + kill(proc->pid, sig); +} + +char* cmdread(char** cmd) { + Process proc; + if (execute(cmd, &proc) < 0) { + perror("failed to execute"); + return NULL; + } + char* str = fdgets(proc.out); + detach(&proc); + waitpid(proc.pid, NULL, 0); + return str; +} + +void cmdwrite(char** cmd, char* text) { + Process proc; + if (execute(cmd, &proc) < 0) { + perror("failed to execute"); + return; + } + if (write(proc.in, text, strlen(text)) < 0) { + perror("failed to write"); + return; + } + detach(&proc); + waitpid(proc.pid, NULL, 0); +} diff --git a/libedit/keyboard.c b/libedit/keyboard.c index c05df34..d530e32 100644 --- a/libedit/keyboard.c +++ b/libedit/keyboard.c @@ -127,6 +127,20 @@ static void redo(void) { /*****************************************************************************/ +static void yank_selection(void) { + char* str = buf_getstr(&Buffer, SelBeg, SelEnd); + clipcopy(str); + free(str); +} + +static void paste_after(void) { + char* str = clippaste(); + buf_putstr(&Buffer, SelBeg, SelEnd, str); + free(str); +} + +/*****************************************************************************/ + typedef struct { Rune key; void (*action)(void); @@ -181,9 +195,9 @@ static KeyBinding_T Normal[] = { { KEY_DELETE, dot_delete }, /* Copy/Paste */ - //{ 'y', yank_selection }, + { 'y', yank_selection }, + { 'p', paste_after }, //{ 'Y', yank_line }, - //{ 'p', paste_after }, //{ 'P', paste_before }, /* context sensitive language */ diff --git a/libedit/utils.c b/libedit/utils.c index bfe5ca6..4aae69f 100644 --- a/libedit/utils.c +++ b/libedit/utils.c @@ -73,3 +73,16 @@ char* stringdup(const char* s) { strcpy(ns,s); return ns; } + +char* fdgets(int fd) { + char buf[256]; + size_t len = 0, nread = 0; + char* str = NULL; + while ((nread = read(fd, buf, 256)) > 0) { + str = realloc(str, len + nread + 1); + memcpy(str+len, buf, nread); + len += nread; + } + if (str) str[len] = '\0'; + return str; +} -- 2.52.0