KanoComputing/terminal-quest

Drop nano source code.

Opened this issue · 7 comments

Hi,

my name is Mike Gabriel and I have just looked at terminal-quest regarding inclusion in Debian. The Debian Edu team has received a request [1] from a Debian user who would like to see the terminal-quest programme included in Debian.

What I stumbled over is the included source code of nano. I see three changes of nano that probably are required for nano to work with terminal quest. However, this change of alien upstream code also blocks the inclusion of terminal-quest in Debian. At least at first glance.

Please provide a terminal-quest source tree that works without the shipped-with nano code. Alternatively, please provide information on how to package this nice project without the bundled nano code.

light+love,
Mike

Hi Mike,

Sorry for not getting back to you earlier but I had to dig through the code to figure out what was going on. Unfortunately there is a lot of thing committed that shouldn't be (aside from the inclusion of the code itself) and in addition the initial adding of the Nano code was committed with some modifications which made it very difficult to figure out what modifications were made in order for their requirement to be removed. After some digging I think that it has boiled down to this diff (formatted as a patch against this nano mirror):

From c427d987f0e527d9dae20c8a529b7eeef928dd42 Mon Sep 17 00:00:00 2001
From: Tom Bettany <tom.bettany@gmail.com>
Date: Mon, 29 Feb 2016 22:05:45 +0000
Subject: [PATCH] Terminal Quest: Add Terminal Quest modifications

Add signals to Nano to integrate with Terminal Quest
---
 src/files.c  | 19 +++++++++++++++++++
 src/nano.c   | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/prompt.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/proto.h  |  1 +
 src/winio.c  |  9 +++++++++
 5 files changed, 148 insertions(+)

diff --git a/src/files.c b/src/files.c
index 8ae3cef..9177d92 100644
--- a/src/files.c
+++ b/src/files.c
@@ -1911,6 +1911,14 @@ bool write_file(const char *name, FILE *f_open, bool tmp, append_type
     if (tempname != NULL)
    free(tempname);

+    char *filename = openfile->filename;
+    char *start_of_nano_prompt = "{\'saved\': True, \'filename\': \'";
+    char nano_prompt[strlen(start_of_nano_prompt) + strlen(filename) + 10];
+    strcpy(nano_prompt, start_of_nano_prompt);
+    strcat(nano_prompt, filename);
+    strcat(nano_prompt, "\'}\n");
+    send_info_to_nano_pipe(nano_prompt);
+
     return retval;
 }

@@ -2120,6 +2128,17 @@ bool do_writeout(bool exiting)

        full_answer = get_full_path(answer);
        full_filename = get_full_path(openfile->filename);
+
+        // Send filename to TQ
+        char nano_info[strlen("{\'filename\': ") + strlen(full_answer) + 1];
+        strcpy(nano_info, "{\'filename\': ");
+        strcat(nano_info, "\'");
+        strcat(nano_info, answer);
+        strcat(nano_info, "\'");
+        strcat(nano_info, "}\n");
+        send_info_to_nano_pipe(nano_info);
+
+
        name_exists = (stat((full_answer == NULL) ? answer :
            full_answer, &st) != -1);
        if (openfile->filename[0] == '\0')
diff --git a/src/nano.c b/src/nano.c
index 9db8460..d42f56d 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -611,6 +611,7 @@ void finish(void)
     thanks_for_all_the_fish();
 #endif

+    send_info_to_nano_pipe("{\'finish\': True}");
     /* Get out. */
     exit(0);
 }
@@ -2011,8 +2012,68 @@ void do_output(char *output, size_t output_len, bool allow_cntrls)
    edit_refresh_needed = FALSE;
     } else
    update_line(openfile->current, openfile->current_x);
+
+    /***********************************************/
+
+    // Send a string of the form:
+    // {contents: {x:1, y:2, text:[line1, line2, line3]}}
+
+    // Initialise the string that stores all the information we send to the pipe
+    char str[500] = "{\'contents\': {\'x\': ";
+
+    // Put the current x position in it.
+    char str2[3];
+    sprintf(str2, "%d", openfile->current_x);
+    strcat(str, str2);
+    strcat(str, ", \'y\': ");
+
+    // Put the current y position.
+    char str3[3];
+    sprintf(str3, "%d", openfile->current_y);
+    strcat(str, str3);
+    strcat(str, ", \'text\': [");
+
+    // Create a deep copy of the top of the filestruct.
+    filestruct *line = copy_filestruct(openfile->fileage);
+    filestruct *current = line;
+    int first_text = 0;
+
+    // Go through the file and get all the text in the file
+    while (current != NULL) {
+
+        if (first_text == 0) first_text += 1;
+        else strcat(str, ", ");
+
+        strcat(str, "\'");
+        strcat(str, current->data);
+        strcat(str, "\'");
+        current = current->next;
+    }
+    strcat(str, "]}}\n");
+
+    // Free the memory allocated.
+    free_filestruct(line);
+    send_info_to_nano_pipe(str);
 }

+/*
+ * TODO: change the return value so that depending on if it's successful,
+ * it returns 0 or 1.
+ */
+void send_info_to_nano_pipe(char *text) {
+    // Initialise the pipe.
+    int fd;
+    char *myfifo = "/tmp/linux-story-nano-pipe";
+    mkfifo(myfifo, 0666);
+    fd = open(myfifo, O_WRONLY);
+
+    // Send the info to the pipe
+    write(fd, text, strlen(text));
+    close(fd);
+}
+
+/****************************************************/
+
 int main(int argc, char **argv)
 {
     int optchr;
diff --git a/src/prompt.c b/src/prompt.c
index 38e8930..06cf24d 100644
--- a/src/prompt.c
+++ b/src/prompt.c
@@ -1162,8 +1162,13 @@ int do_prompt(bool allow_tabs,
     bool list = FALSE;
 #endif

+    char *nano_prompt = "{\'prompt\': ";
+    char *editable = "\'editable\': ";
+    char nano_info[strlen(nano_prompt) + strlen(editable) + strlen(msg) + strlen(curranswer) + 30];
+
     /* prompt has been freed and set to NULL unless the user resized
      * while at the statusbar prompt. */
+
     if (prompt != NULL)
    free(prompt);

@@ -1173,6 +1178,23 @@ int do_prompt(bool allow_tabs,

     va_start(ap, msg);
     vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap);
+
+    /* Nano prompt section */
+    strcpy(nano_info, nano_prompt);
+    strcat(nano_info, "\'");
+    strcat(nano_info, prompt);
+    strcat(nano_info, "\', ");
+
+    /* Editable section */
+    strcat(nano_info, editable);
+    strcat(nano_info, "\'");
+    strcat(nano_info, curranswer);
+    strcat(nano_info, "\'");
+
+    strcat(nano_info, "}");
+    send_info_to_nano_pipe(nano_info);
+
+
     va_end(ap);
     null_at(&prompt, actual_x(prompt, COLS - 4));

@@ -1206,6 +1228,18 @@ int do_prompt(bool allow_tabs,
     else if (s && s->scfunc == DO_ENTER)
    retval = (*answer == '\0') ? -2 : 0;

+    char answer[25];
+    if (retval == -1) strcpy(answer, "\'aborted enter\'");
+    else if (retval == -2) strcpy(answer, "\'blank string\'");
+    else if (retval == 0) strcpy(answer, "\'valid shortcut\'");
+
+    char *response = "{\'response\': ";
+    char nano_info_2[strlen(response) + strlen(answer) + 15];
+    strcpy(nano_info_2, response);
+    strcat(nano_info_2, answer);
+    strcat(nano_info_2, "}\n");
+    send_info_to_nano_pipe(nano_info_2);
+
     blank_statusbar();
     wnoutrefresh(bottomwin);

@@ -1240,6 +1274,15 @@ void do_prompt_abort(void)
  * TRUE when passed in), and -1 for Cancel. */
 int do_yesno_prompt(bool all, const char *msg)
 {
+    // Send the info shown on the status bar
+    char nano_msg[strlen(msg) + strlen("{\'prompt\': ") + 10];
+    strcpy(nano_msg, "{\'prompt\': ");
+    strcat(nano_msg, "\'");
+    strcat(nano_msg, msg);
+    strcat(nano_msg, "\'");
+    strcat(nano_msg, "}\n");
+    send_info_to_nano_pipe(nano_msg);
+
     int ok = -2, width = 16;
     const char *yesstr;        /* String of Yes characters accepted. */
     const char *nostr;     /* Same for No. */
@@ -1359,5 +1402,20 @@ int do_yesno_prompt(bool all, const char *msg)
     } while (ok == -2);

     currmenu = oldmenu;
+
+    // Send the info shown on the status bar
+    char str_ok[10];
+
+    if (ok == 1) strcpy(str_ok, "\'yes\'");
+    else if (ok == 0) strcpy(str_ok, "\'no\'");
+    else if (ok == 2) strcpy(str_ok, "\'all\'");
+    else if (ok == -1) strcpy(str_ok, "\'cancel\'");
+
+    char nano_msg_2[strlen(str_ok) + strlen("{\'response\': ") + 5];
+    strcpy(nano_msg_2, "{\'response\': ");
+    strcat(nano_msg_2, str_ok);
+    strcat(nano_msg_2, "}\n");
+    send_info_to_nano_pipe(nano_msg_2);
+
     return ok;
 }
diff --git a/src/proto.h b/src/proto.h
index 6ba0845..e1268da 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -476,6 +476,7 @@ int do_input(bool *meta_key, bool *func_key, bool *have_shortcut, bool
 #ifndef DISABLE_MOUSE
 int do_mouse(void);
 #endif
+void send_info_to_nano_pipe(char *text);
 void do_output(char *output, size_t output_len, bool allow_cntrls);

 /* All functions in prompt.c. */
diff --git a/src/winio.c b/src/winio.c
index 918c049..b8832ac 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -2266,6 +2266,15 @@ void set_modified(void)
  * constant cursor position display is on. */
 void statusbar(const char *msg, ...)
 {
+    // Send the info shown on the status bar
+    char nano_msg[strlen(msg) + strlen("{\'statusbar\': ") + 20];
+    strcpy(nano_msg, "{\'statusbar\': ");
+    strcat(nano_msg, "\'");
+    strcat(nano_msg, msg);
+    strcat(nano_msg, "\'");
+    strcat(nano_msg, "}\n");
+    send_info_to_nano_pipe(nano_msg);
+
     va_list ap;
     char *bar, *foo;
     size_t start_x, foo_len;
-- 
2.7.0

Now that we have this, I can do some work towards removing this requirement.

I'll let you know how I get on.

Hi Tom,

On Mo 29 Feb 2016 23:24:20 CET, Tom wrote:

Hi Mike,

Sorry for not getting back to you earlier but I had to dig through
the code to figure out what was going on. Unfortunately there is a
lot of thing committed that shouldn't be (aside from the inclusion
of the code itself) and in addition the initial adding of the Nano
code was committed with some modifications which made it very
difficult to figure out what modifications were made in order for
their requirement to be removed. After some digging I think that it
has boiled down to this diff (formatted as a patch against this
nano mirror):

[...]

Now that we have this, I can do some work towards removing this requirement.

I'll let you know how I get on.

Great. Thanks for looking into this. Looking forward to seeing this
issue solved.

Mike

DAS-NETZWERKTEAM
mike gabriel, herweg 7, 24357 fleckeby
fon: +49 (1520) 1976 148

GnuPG Key ID 0x25771B31
mail: mike.gabriel@das-netzwerkteam.de, http://das-netzwerkteam.de

freeBusy:
https://mail.das-netzwerkteam.de/mailxchange/kronolith/fb.php?u=m.gabriel%40das-netzwerkteam.de

Looks like the changes were made to allow terminal-quest to supervise nano, so it can be used as editor inside of the game.

I am not sure how this could be solved. One possibility is to remove the levels (called "challenges" in Terminal-Quest) to make the game playable. Another is to find a different method of supervising nano that works with the existing nano binaries.

@bernhardreiter maybe file a patch against nano upstream that enables the above mentioned code additions via a cmdline option? Then one could use upstream nano, launch it as a subprocess from within terminal-quest (using that new cmdline option) and the feature would be available without shipping nano as bundled copy of code.

@sunweaver I did not suggest this, because if I would be a nano maintainer (which I am not), I would require that a new functionality suggested for addition comes with a compelling use case. I'm not sure that piping the output a second time in a special format in a fifo is a use case that an editor it should support. Also the code would have to be more generalised. I believe it is unlikely that nano would accept this.

My suggestion is:

  1. document how to remove the nano challenge and keep the game experience good. Then Debian packaging of the first version can go ahead. (There are other technical problems to solve.)
  2. Then see if using a wrapper around the original nano can be made which serves the terminal-quest part of the interface. As the nano output on the terminal will (most likely) already have the output that terminal-quests needs, just in a different format.

Another option could be asking the nano Debian maintainers to add another bin:pkg, called nano-src (containing the full source code in a deb as a tarball). Then you can extract what's needed from that tarball, patch it accordingly and thus you still use the most recent nano code on every rebuild. Not as good as directly using the nano binaries, but close to it.

@bernhardreiter I also like your approach.