summary refs log tree commit diff stats
path: root/lib/wrappers
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2021-02-09 05:25:38 -0800
committerGitHub <noreply@github.com>2021-02-09 14:25:38 +0100
commit630f867bd71336b1227f8772205c0fd004dc9a98 (patch)
tree0b87f1a5e11bec4220a4053c9678b7839fb7205e /lib/wrappers
parent49b64e8dc717dd6db27dabd74b0fe238af5e8208 (diff)
downloadNim-630f867bd71336b1227f8772205c0fd004dc9a98.tar.gz
add linenoise.readLineStatus to get status (eg: ctrl-D or ctrl-C) (#16977)
* add linenoise.readLineStatus to get status (eg: ctrl-D or ctrl-C)

* changelog
Diffstat (limited to 'lib/wrappers')
-rw-r--r--lib/wrappers/linenoise/linenoise.c18
-rw-r--r--lib/wrappers/linenoise/linenoise.h11
-rw-r--r--lib/wrappers/linenoise/linenoise.nim41
3 files changed, 64 insertions, 6 deletions
diff --git a/lib/wrappers/linenoise/linenoise.c b/lib/wrappers/linenoise/linenoise.c
index ae185fece..be792b96b 100644
--- a/lib/wrappers/linenoise/linenoise.c
+++ b/lib/wrappers/linenoise/linenoise.c
@@ -765,7 +765,7 @@ void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
  * when ctrl+d is typed.
  *
  * The function returns the length of the current buffer. */
-static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt)
+static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, const char *prompt, linenoiseData* data)
 {
     struct linenoiseState l;
 
@@ -827,6 +827,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
             return (int)l.len;
         case CTRL_C:     /* ctrl-c */
             errno = EAGAIN;
+            data->status = linenoiseStatus_ctrl_C;
             return -1;
         case BACKSPACE:   /* backspace */
         case 8:     /* ctrl-h */
@@ -839,6 +840,7 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen,
             } else {
                 history_len--;
                 free(history[history_len]);
+                data->status = linenoiseStatus_ctrl_D;
                 return -1;
             }
             break;
@@ -979,7 +981,7 @@ void linenoisePrintKeyCodes(void) {
 
 /* This function calls the line editing function linenoiseEdit() using
  * the STDIN file descriptor set in raw mode. */
-static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
+static int linenoiseRaw(char *buf, size_t buflen, const char *prompt, linenoiseData* data) {
     int count;
 
     if (buflen == 0) {
@@ -988,7 +990,7 @@ static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
     }
 
     if (enableRawMode(STDIN_FILENO) == -1) return -1;
-    count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt);
+    count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, buflen, prompt, data);
     disableRawMode(STDIN_FILENO);
     printf("\n");
     return count;
@@ -1035,7 +1037,7 @@ static char *linenoiseNoTTY(void) {
  * for a blacklist of stupid terminals, and later either calls the line
  * editing function or uses dummy fgets() so that you will be able to type
  * something even in the most desperate of the conditions. */
-char *linenoise(const char *prompt) {
+char *linenoiseExtra(const char *prompt, linenoiseData* data) {
     char buf[LINENOISE_MAX_LINE];
     int count;
 
@@ -1056,12 +1058,18 @@ char *linenoise(const char *prompt) {
         }
         return strdup(buf);
     } else {
-        count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt);
+        count = linenoiseRaw(buf,LINENOISE_MAX_LINE,prompt, data);
         if (count == -1) return NULL;
         return strdup(buf);
     }
 }
 
+char *linenoise(const char *prompt) {
+  linenoiseData data;
+  data.status = linenoiseStatus_ctrl_unknown;
+  return linenoiseExtra(prompt, &data);
+}
+
 /* This is just a wrapper the user may want to call in order to make sure
  * the linenoise returned buffer is freed with the same allocator it was
  * created with. Useful when the main program is using an alternative
diff --git a/lib/wrappers/linenoise/linenoise.h b/lib/wrappers/linenoise/linenoise.h
index ed20232c5..aa86ccb78 100644
--- a/lib/wrappers/linenoise/linenoise.h
+++ b/lib/wrappers/linenoise/linenoise.h
@@ -48,6 +48,16 @@ typedef struct linenoiseCompletions {
   char **cvec;
 } linenoiseCompletions;
 
+typedef enum linenoiseStatus {
+  linenoiseStatus_ctrl_unknown,
+  linenoiseStatus_ctrl_C,
+  linenoiseStatus_ctrl_D
+} linenoiseStatus;
+
+typedef struct linenoiseData {
+  linenoiseStatus status;
+} linenoiseData;
+
 typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
 typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold);
 typedef void(linenoiseFreeHintsCallback)(void *);
@@ -57,6 +67,7 @@ void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *);
 void linenoiseAddCompletion(linenoiseCompletions *, const char *);
 
 char *linenoise(const char *prompt);
+char *linenoiseExtra(const char *prompt, linenoiseData* data);
 void linenoiseFree(void *ptr);
 int linenoiseHistoryAdd(const char *line);
 int linenoiseHistorySetMaxLen(int len);
diff --git a/lib/wrappers/linenoise/linenoise.nim b/lib/wrappers/linenoise/linenoise.nim
index a6260eb12..3bfd74586 100644
--- a/lib/wrappers/linenoise/linenoise.nim
+++ b/lib/wrappers/linenoise/linenoise.nim
@@ -9,7 +9,7 @@
 
 type
   Completions* = object
-    len*: csize
+    len*: csize_t
     cvec*: cstringArray
 
   CompletionCallback* = proc (a2: cstring; a3: ptr Completions) {.cdecl.}
@@ -32,3 +32,42 @@ proc printKeyCodes*() {.importc: "linenoisePrintKeyCodes".}
 
 proc free*(s: cstring) {.importc: "free", header: "<stdlib.h>".}
 
+when defined nimExperimentalLinenoiseExtra:
+  # C interface
+  type linenoiseStatus = enum
+    linenoiseStatus_ctrl_unknown
+    linenoiseStatus_ctrl_C
+    linenoiseStatus_ctrl_D
+
+  type linenoiseData* = object
+    status: linenoiseStatus
+
+  proc linenoiseExtra(prompt: cstring, data: ptr linenoiseData): cstring {.importc.}
+
+  # stable nim interface
+  type Status* = enum
+    lnCtrlUnkown
+    lnCtrlC
+    lnCtrlD
+
+  type ReadLineResult* = object
+    line*: string
+    status*: Status
+
+  proc readLineStatus*(prompt: string, result: var ReadLineResult) =
+    ## line editing API that allows returning the line entered and an indicator
+    ## of which control key was entered, allowing user to distinguish between
+    ## for example ctrl-C vs ctrl-D.
+    runnableExamples("-d:nimExperimentalLinenoiseExtra"):
+      if false:
+        var ret: ReadLineResult
+        while true:
+          readLineStatus("name: ", ret) # ctrl-D will exit, ctrl-C will go to next prompt
+          if ret.line.len > 0: echo ret.line
+          if ret.status == lnCtrlD: break
+        echo "exiting"
+    var data: linenoiseData
+    let buf = linenoiseExtra(prompt, data.addr)
+    result.line = $buf
+    free(buf)
+    result.status = data.status.ord.Status