about summary refs log tree commit diff
path: root/nix-repl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'nix-repl.cc')
-rw-r--r--nix-repl.cc38
1 files changed, 27 insertions, 11 deletions
diff --git a/nix-repl.cc b/nix-repl.cc
index cdf6a79e9206..f4850271dc6a 100644
--- a/nix-repl.cc
+++ b/nix-repl.cc
@@ -41,7 +41,7 @@ struct NixRepl
     NixRepl(const Strings & searchPath);
     void mainLoop(const Strings & files);
     void completePrefix(string prefix);
-    bool getLine(string & line);
+    bool getLine(string & input, const char * prompt);
     bool processLine(string line);
     void loadFile(const Path & path);
     void initEnv();
@@ -94,21 +94,35 @@ void NixRepl::mainLoop(const Strings & files)
     using_history();
     read_history(0);
 
+    string input;
+
     while (true) {
-        string line;
-        if (!getLine(line)) {
+        // When continuing input from previous lines, don't print a prompt, just align to the same
+        // number of chars as the prompt.
+        const char * prompt = input.empty() ? "nix-repl> " : "          ";
+        if (!getLine(input, prompt)) {
             std::cout << std::endl;
             break;
         }
 
         try {
-            if (!processLine(removeWhitespace(line))) return;
+            if (!processLine(input)) return;
+        } catch (ParseError & e) {
+            if (e.msg().find("unexpected $end") != std::string::npos) {
+                // For parse errors on incomplete input, we continue waiting for the next line of
+                // input without clearing the input so far.
+                continue;
+            } else {
+                printMsg(lvlError, "error: " + e.msg());
+            }
         } catch (Error & e) {
             printMsg(lvlError, "error: " + e.msg());
         } catch (Interrupted & e) {
             printMsg(lvlError, "error: " + e.msg());
         }
 
+        // We handled the current input fully, so we should clear it and read brand new input.
+        input.clear();
         std::cout << std::endl;
     }
 }
@@ -147,7 +161,7 @@ char * completerThunk(const char * s, int state)
 }
 
 
-bool NixRepl::getLine(string & line)
+bool NixRepl::getLine(string & input, const char * prompt)
 {
     struct sigaction act, old;
     act.sa_handler = sigintHandler;
@@ -156,15 +170,17 @@ bool NixRepl::getLine(string & line)
     if (sigaction(SIGINT, &act, &old))
         throw SysError("installing handler for SIGINT");
 
-    if (sigsetjmp(sigintJmpBuf, 1))
-        line = "";
-    else {
+    if (sigsetjmp(sigintJmpBuf, 1)) {
+        input.clear();
+    } else {
         curRepl = this;
         rl_completion_entry_function = completerThunk;
 
-        char * s = readline("nix-repl> ");
+        char * s = readline(prompt);
         if (!s) return false;
-        line = chomp(string(s));
+        string line = chomp(string(s));
+        input.append(removeWhitespace(line));
+        input.push_back('\n');
         free(s);
         if (line != "") {
             add_history(line.c_str());
@@ -268,7 +284,7 @@ bool NixRepl::processLine(string line)
     string command, arg;
 
     if (line[0] == ':') {
-        size_t p = line.find(' ');
+        size_t p = line.find_first_of(" \n\r\t");
         command = string(line, 0, p);
         if (p != string::npos) arg = removeWhitespace(string(line, p));
     } else {