about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-09T10·00+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-09T10·00+0200
commite133e91410d9486e022a1bc0372b822152b6654e (patch)
treef1593b76a7389a3e153a70b74ebcd4948488cb29
parent8e765b8876ff67879a6bd1a067bad526b14a4045 (diff)
Support tab-completion on attribute sets
Example:

$ nix-repl '<nixos>'

> config.services.xserver.desktop<TAB>

comletes to

> config.services.xserver.desktopManager

You also get suggestions if there are multiple matches:

> config.services.xserver.desktopManager.kde4
config.services.xserver.desktopManager.kde4.enable
config.services.xserver.desktopManager.kde4.phononBackends
-rw-r--r--nix-repl.cc39
1 files changed, 34 insertions, 5 deletions
diff --git a/nix-repl.cc b/nix-repl.cc
index f7eb6ab5c0d7..9c22abbfacf6 100644
--- a/nix-repl.cc
+++ b/nix-repl.cc
@@ -183,11 +183,40 @@ void NixRepl::completePrefix(string prefix)
 {
     completions.clear();
 
-    StringSet::iterator i = varNames.lower_bound(prefix);
-    while (i != varNames.end()) {
-        if (string(*i, 0, prefix.size()) != prefix) break;
-        completions.insert(*i);
-        i++;
+    size_t dot = prefix.rfind('.');
+
+    if (dot == string::npos) {
+        /* This is a variable name; look it up in the current scope. */
+        StringSet::iterator i = varNames.lower_bound(prefix);
+        while (i != varNames.end()) {
+            if (string(*i, 0, prefix.size()) != prefix) break;
+            completions.insert(*i);
+            i++;
+        }
+    } else {
+        try {
+            /* This is an expression that should evaluate to an
+               attribute set.  Evaluate it to get the names of the
+               attributes. */
+            string expr(prefix, 0, dot);
+            string prefix2 = string(prefix, dot + 1);
+
+            Expr * e = parseString(expr);
+            Value v;
+            e->eval(state, *env, v);
+            state.forceAttrs(v);
+
+            foreach (Bindings::iterator, i, *v.attrs) {
+                string name = i->name;
+                if (string(name, 0, prefix2.size()) != prefix2) continue;
+                completions.insert(expr + "." + name);
+            }
+
+        } catch (ParseError & e) {
+            // Quietly ignore parse errors.
+        }catch (EvalError & e) {
+            // Quietly ignore evaluation errors.
+        }
     }
 }