diff --git a/pd/nw/dialog_search.html b/pd/nw/dialog_search.html
index b35e73e1bfb69f515402072ad717a35b49b4f901..28c9bf4703603103de52ceaf335baa38dde11e1d 100644
--- a/pd/nw/dialog_search.html
+++ b/pd/nw/dialog_search.html
@@ -11,12 +11,14 @@
 var pdgui = require("./pdgui.js");
 var fs = require("fs");
 var path = require("path");
+var dive = require("./dive.js"); // small module to recursively search dirs
 var l = pdgui.get_local_string;
 
 var index = elasticlunr();
 index.addField("title");
 index.addField("keywords");
 index.addField("description");
+//index.addField("body");
 index.addField("path");
 index.setRef("id");
 var doc_id = 0;
@@ -47,6 +49,10 @@ function add_doc_to_index(filename, data) {
             .match(/#X text [0-9]+ [0-9]+ DESCRIPTION ([\s\S]*?);/);
         keywords = keywords && keywords.length > 1 ? keywords[1].trim() : null;
         desc = desc && desc.length > 1 ? desc[1].trim() : null;
+        if (desc) {
+            // format Pd's "comma atoms" as normal commas
+            desc = desc.replace(" \\,", ",");
+        }
     if (title.slice(-5) === "-help") {
         title = title.slice(0, -5);
     }
@@ -55,46 +61,39 @@ function add_doc_to_index(filename, data) {
         "title": title,
         "keywords": keywords,
         "description": desc,
+        //"body": big_line,
         "path": filename
     });
     
 }
 
-function read_file(filename, len, i) {
-    fs.readFile(filename, { encoding: "utf8", flag: "r" },
-        function(err, data) {
-            if (!err) {
-                add_doc_to_index(filename, data);
-            } else {
-                pdgui.post("err: " + err);
-            }
-        if (i === (len - 1)) {
-            // Probably about finished...
-            document.getElementById("results").textContent = "";
-            document.getElementById("search_text").disabled = false;
-        } 
-    });
+function read_file(err, filename, stat) {
+    if (!err) {
+        if (filename.slice(-3) === ".pd") {
+            fs.readFile(filename, { encoding: "utf8", flag: "r" },
+                function(read_err, data) {
+                    if (!read_err) {
+                        add_doc_to_index(filename, data);
+                    } else {
+                        pdgui.post("err: " + read_err);
+                    }
+                }
+            );
+        }
+    } else {
+        pdgui.post("err: " + err);
+    }
 }
 
+function finish_build() {
+    document.getElementById("search_text").disabled = false;
+    document.getElementById("results").innerHTML = "";
+}
 
 function build_index() {
-    var doc_path = path.join(pdgui.get_gui_dir(), "doc", "5.reference");
+    var doc_path = path.join(pdgui.get_gui_dir(), "doc");
     pdgui.post("doc path is " + doc_path);
-    fs.readdir(doc_path, function(err, files) {
-        var i, j = 0,
-            len = files.length,
-            filename;
-        if (!err) {
-            for (i = 0; i < len; i++) {
-                if (files[i].slice(-3) === ".pd") {
-                    filename = path.join(doc_path, files[i]);
-                    read_file(filename, len, j++);
-                } else {
-                    j++;
-                }
-            }
-        } else { pdgui.post("err: " + err); }
-    });
+    dive(doc_path, read_file, finish_build);
 }
 
 function console_unwrap_tag(console_elem, tag_name) {
diff --git a/pd/nw/dive.js b/pd/nw/dive.js
new file mode 100644
index 0000000000000000000000000000000000000000..802beb4cf924d720f3994be3e629b24218bd5db0
--- /dev/null
+++ b/pd/nw/dive.js
@@ -0,0 +1,110 @@
+var fs = require('fs');
+var path = require('path');
+
+// default options
+var defaultOpt = {
+  all: false,
+  recursive: true,
+  files: true,
+  directories: false,
+  ignore: false
+};
+
+function defaults(defaults, obj) {
+  for (var prop in defaults)
+    if (defaults.hasOwnProperty(prop))
+      if (!obj.hasOwnProperty(prop))
+        obj[prop] = defaults[prop];
+  return obj;
+}
+
+// general function
+module.exports = function(dir, opt, action, complete) {
+
+  // check args
+  if (typeof opt === 'function') {
+    if (typeof action === 'undefined')
+      complete = function () {};
+    else
+      complete = action;
+
+    action = opt;
+    opt = { };
+  } else if (typeof complete === 'undefined')
+    complete = function () {};
+
+  // Assert that dir is a string
+  if (typeof dir !== 'string')
+    dir = process.cwd();
+
+  opt = defaults(defaultOpt, opt);
+
+  // Check if user wants to ignore dir/file
+  // If they do, create function that can test if file matches
+  var ignore = null;
+  if (opt.ignore instanceof RegExp) {
+    ignore = function(file) { return file.match(opt.ignore); }
+  } else if (typeof opt.ignore === 'string' && opt.ignore.trim()) {
+    ignore = function(file) { return file.indexOf(opt.ignore) !== -1; }
+  }
+
+  function dive(dir) {
+    // Read the directory
+    todo++;
+    fs.readdir(dir, function(err, list) {
+      todo--;
+      // Return the error if something went wrong
+      if (err) {
+        action(err, dir);
+      } else {
+        // For every file in the list
+        list.forEach(function(file) {
+          if (ignore && ignore(file))
+            return;
+
+          if (opt.all || file[0] !== '.') {
+            // Full path of that file
+            var fullPath = path.resolve(dir, file);
+            // Get the file's stats
+            todo++;
+            fs.lstat(fullPath, function(err, stat) {
+              todo--;
+              if (err) {
+                action(err, fullPath);
+              } else {
+                if (stat) {
+                  // If the file is a directory
+                  if (stat.isDirectory()) {
+                    // Call action if enabled for directories
+                    if (opt.directories)
+                      action(null, fullPath, stat);
+
+                    // Dive into the directory
+                    if (opt.recursive)
+                      dive(fullPath);
+
+                  } else {
+                    // Call action if enabled for files
+                    if (opt.files)
+                      action(null, fullPath, stat);
+                  }
+                }
+              }
+              if (!todo)
+                complete();
+            });
+          }
+
+        });
+
+      }
+      //empty directories, or with just hidden files
+      if (!todo)
+        complete();
+    });
+  }
+
+  var todo = 0;
+  dive(path.resolve(dir));
+};
+