diff options
| author | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-11-18 22:41:52 +0100 | 
|---|---|---|
| committer | Raymaekers Luca <raymaekers.luca@gmail.com> | 2024-11-18 22:42:42 +0100 | 
| commit | ce8790254a32ebc77a39ebd80dd1ee0f0a8be3cb (patch) | |
| tree | aca67f175bd770d64f7d67a0dd7245929708370a | |
| parent | 0d635bc20467b3d789091f14affe8c499c74d2ea (diff) | |
Added pasting clipboard on ctrl-y
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | archived.md | 2 | ||||
| -rw-r--r-- | chatty.c | 110 | ||||
| -rw-r--r-- | ui.c | 2 | 
4 files changed, 103 insertions, 13 deletions
| @@ -12,7 +12,6 @@ The idea is the following:  - [ ] bug: when connecting two clients of the same account  - [ ] bug: wrapping does not work and displays nothing if there is no screen space  - [ ] bug: reconnect does not work when server does not know id -- [ ] markup for messages  - [ ] convert tabs to spaces  ## server @@ -43,6 +42,7 @@ The idea is the following:  - `Ctrl+C` | `Ctrl+D`: quits  - `Ctrl+U`: Erase input line  - `Ctrl+W`: Erase word behind cursor +- `Ctrl+Y`: Paste clipboard into input field  ## Resources I used for building this  - source code I looked at: diff --git a/archived.md b/archived.md index 7895224..afebf8b 100644 --- a/archived.md +++ b/archived.md @@ -11,6 +11,8 @@  - [x] bug: when reconnecting nrecv != -1  - [x] bug: when disconnecting  - [x] use error type success to say that authentication succeeded +- [x] markup for messages +- [x] clipboard shortcut  ## Server  - [x] import clients @@ -1,16 +1,13 @@  #define TB_IMPL  #include "termbox2.h" -#include "chatty.h" -#include "protocol.h" -#include "ui.c" -  #include <arpa/inet.h>  #include <assert.h>  #include <locale.h>  #include <poll.h>  #include <pthread.h>  #include <sys/socket.h> +#include <sys/wait.h>  #define TIMEOUT_POLL 60 * 1000  // time to reconnect in seconds @@ -23,6 +20,12 @@  // enable logging  #define LOGGING +#define DEBUG + +#include "chatty.h" +#include "protocol.h" +#include "ui.c" +  enum { FDS_BI = 0, // for one-way communication with the server (eg. TextMessage)         FDS_UNI,      // For two-way communication with the server (eg. IDMessage)         FDS_TTY, @@ -36,6 +39,11 @@ typedef struct {  #define USER_FMT "[%s](%lu)"  #define USER_ARG(client) client.Author, client.ID +typedef struct {  +    s32 NumRead; +    u32 Error; +} command_output; +  // User used by chatty  global_variable User user = {0};  // Address of chatty server @@ -51,11 +59,11 @@ fillstr(u32* Str, u32 ch, u32 Len)  // Centered popup displaying message in the appropriate cololrs  void -popup(u32 fg, u32 bg, char* text) +popup(u32 fg, u32 bg, u8* text)  { -    u32 len = strlen(text); +    u32 len = strlen((char*)text);      assert(len > 0); -    tb_print(global.width / 2 - len / 2, global.height / 2, fg, bg, text); +    tb_print(global.width / 2 - len / 2, global.height / 2, fg, bg, (char*)text);  }  // Returns client in clientsArena matching id @@ -213,6 +221,56 @@ thread_reconnect(void* fds_ptr)      return 0;  } +command_output +run_command_get_output(char *Command, char *Argv[], u8 *OutputBuffer, int Len) +{ +    command_output Result = {0}; + +    int CommandPipe[2]; +    int Error = pipe(CommandPipe); +    assert(Error != -1); + +    int Pid = fork(); +    assert(Pid != -1); + +    // Run command in child +    if (!Pid) +    { +        dup2(CommandPipe[1], STDOUT_FILENO); //redirect stdout to Pipe +        close(CommandPipe[0]); +        close(CommandPipe[1]); + +        int fd = open("/dev/null", O_WRONLY); +        dup2(fd, STDERR_FILENO); + +        execvp(Command, Argv); +    } + +    // Wait for child +    int statval; +    waitpid(Pid, &statval, 0); + +    if(WIFEXITED(statval)) +    { +        int ExitCode = WEXITSTATUS(statval); +        if (ExitCode) +        { +            Result.Error = ExitCode; +        } +    } +    else +    { +        Result.Error = 1; +        return Result; +    } + +    close(CommandPipe[1]); + +    Result.NumRead = read(CommandPipe[0], OutputBuffer, Len); +    assert(Result.NumRead != -1); + +    return Result; +}  // home screen, the first screen the user sees  // it displays a prompt with the user input of input_len wide characters  // and the received messages from msgsArena @@ -250,7 +308,7 @@ screen_home(Arena* ScratchArena,      //  03:24:33 [TlasT]     │ I am fine      //  03:24:33 [Fin]       │ I am too      { -        u32 VerticalBarOffset = TIMESTAMP_LEN + AUTHOR_LEN + 2; +        s32 VerticalBarOffset = TIMESTAMP_LEN + AUTHOR_LEN + 2;          u32 FreeHeight = global.height - box_height;          if (FreeHeight <= 0) @@ -333,7 +391,7 @@ screen_home(Arena* ScratchArena,                  tb_printf(TIMESTAMP_LEN, MessageY, fg, 0, "[%s]", client->Author);                  // Only display when there is enough space -                if (global.width >  VerticalBarOffset + 2) +                if (global.width > VerticalBarOffset + 2)                  {                      raw_result RawText = markdown_to_raw(ScratchArena, (u32*)&message->text, message->len);                      markdown_formatoptions MDFormat = preprocess_markdown(ScratchArena, @@ -460,7 +518,7 @@ screen_home(Arena* ScratchArena,          if (fds[FDS_UNI].fd == -1 || fds[FDS_BI].fd == -1)          {              // show error popup -            popup(TB_RED, TB_BLACK, "Server disconnected."); +            popup(TB_RED, TB_BLACK, (u8*)"Server disconnected.");          }      }  } @@ -670,7 +728,39 @@ main(int argc, char** argv)                  kill(pid, SIGSTOP);                  tb_init();              } break; +            case TB_KEY_CTRL_Y: // Paste clipboard contents to input +            { +                u32 OutputBufferLen = INPUT_LIMIT - InputLen; +                if (OutputBufferLen <= 0) break; +                u8 OutputBuffer[OutputBufferLen]; + +                char *PathName = "xclip"; +                char *Argv[] = {PathName, "-o", "-sel", "c", 0}; + +                command_output Output = run_command_get_output(PathName, Argv, OutputBuffer, OutputBufferLen - 1); +                if (Output.Error) break; + +                // Remove trailing whitespace +                int BufferIndex = Output.NumRead - 1; +                while (BufferIndex > 0 && +                        (OutputBuffer[BufferIndex] == '\n' || +                         OutputBuffer[BufferIndex] == '\t')) +                { +                    OutputBuffer[BufferIndex] = 0; +                    BufferIndex--; +                } + +                // Append to output +                for (s32 BufferIndex = 0; BufferIndex < Output.NumRead; BufferIndex++) +                { +                    // convert u8 to u32 +                    u32 ch = OutputBuffer[BufferIndex]; +                    Input[InputLen] = ch; +                    InputLen++; +                } + +            } break;              case TB_KEY_CTRL_D:              case TB_KEY_CTRL_C:                  quit = 1; @@ -1,5 +1,3 @@ -#define DEBUG -  // Format option at a position in raw text, used when iterating to know when to toggle a color  // option.  typedef struct { | 
