diff options
author | isaacs <i@izs.me> | 2013-07-12 08:56:59 -0700 |
---|---|---|
committer | isaacs <i@izs.me> | 2013-07-12 08:56:59 -0700 |
commit | 9da67fa5198f3c0839904ae05cbfe88c61b3ad09 (patch) | |
tree | 61c03f98b7c2ae549f67c01e1afe6dcbe84847d6 /deps/npm/lib/help-search.js | |
parent | f88b8dad84cd8f37000e55f0b5de7963cbb252cf (diff) | |
download | node-new-9da67fa5198f3c0839904ae05cbfe88c61b3ad09.tar.gz |
npm: Upgrade to 1.3.3
Diffstat (limited to 'deps/npm/lib/help-search.js')
-rw-r--r-- | deps/npm/lib/help-search.js | 343 |
1 files changed, 183 insertions, 160 deletions
diff --git a/deps/npm/lib/help-search.js b/deps/npm/lib/help-search.js index b0b15baca4..590fe270b4 100644 --- a/deps/npm/lib/help-search.js +++ b/deps/npm/lib/help-search.js @@ -8,6 +8,7 @@ var fs = require("graceful-fs") , apiDocsPath = path.join(__dirname, "..", "doc", "api") , log = require("npmlog") , npm = require("./npm.js") + , glob = require("glob") helpSearch.usage = "npm help-search <text>" @@ -17,177 +18,199 @@ function helpSearch (args, silent, cb) { // see if we're actually searching the api docs. var argv = npm.config.get("argv").cooked - , docsPath = cliDocsPath - , cmd = "help" - if (argv.length && argv[0].indexOf("api") !== -1) { - docsPath = apiDocsPath - cmd = "apihelp" - } - fs.readdir(docsPath, function(er, files) { - if (er) { - log.error("helpSearch", "Could not load documentation") + var docPath = path.resolve(__dirname, "..", "doc") + return glob(docPath + "/*/*.md", function (er, files) { + if (er) return cb(er) - } - - var search = args.join(" ") - , results = [] - asyncMap(files, function (file, cb) { - fs.lstat(path.resolve(docsPath, file), function (er, st) { - if (er) return cb(er) - if (!st.isFile()) return cb(null, []) - - fs.readFile(path.resolve(docsPath, file), "utf8", function (er, data) { - if (er) return cb(er) - - var match = false - for (var a = 0, l = args.length; a < l && !match; a ++) { - match = data.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 - } - if (!match) return cb(null, []) - - var lines = data.split(/\n+/) - , context = [] - - // if a line has a search term, then skip it and the next line. - // if the next line has a search term, then skip all 3 - // otherwise, set the line to null. - for (var i = 0, l = lines.length; i < l; i ++) { - var line = lines[i] - , nextLine = lines[i + 1] - , match = false - if (nextLine) { - for (var a = 0, ll = args.length; a < ll && !match; a ++) { - match = nextLine.toLowerCase() - .indexOf(args[a].toLowerCase()) !== -1 - } - if (match) { - // skip over the next line, and the line after it. - i += 2 - continue - } - } - - match = false - for (var a = 0, ll = args.length; a < ll && !match; a ++) { - match = line.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 - } - if (match) { - // skip over the next line - i ++ - continue - } - - lines[i] = null - } - - // now squish any string of nulls into a single null - lines = lines.reduce(function (l, r) { - if (!(r === null && l[l.length-1] === null)) l.push(r) - return l - }, []) - - if (lines[lines.length - 1] === null) lines.pop() - if (lines[0] === null) lines.shift() - - // now see how many args were found at all. - var found = {} - , totalHits = 0 - lines.forEach(function (line) { - args.forEach(function (arg) { - var hit = (line || "").toLowerCase() - .split(arg.toLowerCase()).length - 1 - if (hit > 0) { - found[arg] = (found[arg] || 0) + hit - totalHits += hit - } - }) - }) - - return cb(null, { file: file, lines: lines, found: Object.keys(found) - , hits: found, totalHits: totalHits }) - }) + readFiles(files, function (er, data) { + if (er) + return cb(er) + searchFiles(args, data, function (er, results) { + if (er) + return cb(er) + formatResults(args, results, cb) }) - }, function (er, results) { - if (er) return cb(er) + }) + }) +} - // if only one result, then just show that help section. - if (results.length === 1) { - return npm.commands.help([results[0].file.replace(/\.md$/, "")], cb) +function readFiles (files, cb) { + var res = {} + asyncMap(files, function (file, cb) { + fs.readFile(file, 'utf8', function (er, data) { + res[file] = data + return cb(er) + }) + }, function (er) { + return cb(er, res) + }) +} + +function searchFiles (args, files, cb) { + var results = [] + Object.keys(files).forEach(function (file) { + var data = files[file] + + // skip if no matches at all + for (var a = 0, l = args.length; a < l && !match; a++) { + var match = data.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 + } + if (!match) + return + + var lines = data.split(/\n+/) + var context = [] + + // if a line has a search term, then skip it and the next line. + // if the next line has a search term, then skip all 3 + // otherwise, set the line to null. then remove the nulls. + for (var i = 0, l = lines.length; i < l; i ++) { + var line = lines[i] + , nextLine = lines[i + 1] + , match = false + if (nextLine) { + for (var a = 0, ll = args.length; a < ll && !match; a ++) { + match = nextLine.toLowerCase() + .indexOf(args[a].toLowerCase()) !== -1 + } + if (match) { + // skip over the next line, and the line after it. + i += 2 + continue + } } - if (results.length === 0) { - console.log("No results for " + args.map(JSON.stringify).join(" ")) - return cb() + match = false + for (var a = 0, ll = args.length; a < ll && !match; a ++) { + match = line.toLowerCase().indexOf(args[a].toLowerCase()) !== -1 + } + if (match) { + // skip over the next line + i ++ + continue } - // sort results by number of results found, then by number of hits - // then by number of matching lines - results = results.sort(function (a, b) { - return a.found.length > b.found.length ? -1 - : a.found.length < b.found.length ? 1 - : a.totalHits > b.totalHits ? -1 - : a.totalHits < b.totalHits ? 1 - : a.lines.length > b.lines.length ? -1 - : a.lines.length < b.lines.length ? 1 - : 0 + lines[i] = null + } + + // now squish any string of nulls into a single null + lines = lines.reduce(function (l, r) { + if (!(r === null && l[l.length-1] === null)) l.push(r) + return l + }, []) + + if (lines[lines.length - 1] === null) lines.pop() + if (lines[0] === null) lines.shift() + + // now see how many args were found at all. + var found = {} + , totalHits = 0 + lines.forEach(function (line) { + args.forEach(function (arg) { + var hit = (line || "").toLowerCase() + .split(arg.toLowerCase()).length - 1 + if (hit > 0) { + found[arg] = (found[arg] || 0) + hit + totalHits += hit + } }) + }) - var out = results.map(function (res, i, results) { - var out = "npm " + cmd + " "+res.file.replace(/\.md$/, "") - , r = Object.keys(res.hits).map(function (k) { - return k + ":" + res.hits[k] - }).sort(function (a, b) { - return a > b ? 1 : -1 - }).join(" ") - - out += ((new Array(Math.max(1, 81 - out.length - r.length))) - .join (" ")) + r - - if (!npm.config.get("long")) return out - - var out = "\n\n" + out - + "\n" + (new Array(81)).join("—") + "\n" - + res.lines.map(function (line, i) { - if (line === null || i > 3) return "" - for (var out = line, a = 0, l = args.length; a < l; a ++) { - var finder = out.toLowerCase().split(args[a].toLowerCase()) - , newOut = [] - , p = 0 - finder.forEach(function (f) { - newOut.push( out.substr(p, f.length) - , "\1" - , out.substr(p + f.length, args[a].length) - , "\2" ) - p += f.length + args[a].length - }) - out = newOut.join("") - } - if (npm.color) { - var color = "\033[31;40m" - , reset = "\033[0m" - } else { - var color = "" - , reset = "" - } - out = out.split("\1").join(color) - .split("\2").join(reset) - return out - }).join("\n").trim() - return out - }).join("\n") - - if (results.length && !npm.config.get("long")) { - out = "Top hits for "+(args.map(JSON.stringify).join(" ")) - + "\n" + (new Array(81)).join("—") + "\n" - + out - + "\n" + (new Array(81)).join("—") + "\n" - + "(run with -l or --long to see more context)" - } + var cmd = "npm help " + if (path.basename(path.dirname(file)) === "api") { + cmd = "npm apihelp " + } + cmd += path.basename(file, ".md").replace(/^npm-/, "") + results.push({ file: file + , cmd: cmd + , lines: lines + , found: Object.keys(found) + , hits: found + , totalHits: totalHits + }) + }) - console.log(out.trim()) - cb(null, results) - }) + // if only one result, then just show that help section. + if (results.length === 1) { + return npm.commands.help([results[0].file.replace(/\.md$/, "")], cb) + } + + if (results.length === 0) { + console.log("No results for " + args.map(JSON.stringify).join(" ")) + return cb() + } + // sort results by number of results found, then by number of hits + // then by number of matching lines + results = results.sort(function (a, b) { + return a.found.length > b.found.length ? -1 + : a.found.length < b.found.length ? 1 + : a.totalHits > b.totalHits ? -1 + : a.totalHits < b.totalHits ? 1 + : a.lines.length > b.lines.length ? -1 + : a.lines.length < b.lines.length ? 1 + : 0 }) + + cb(null, results) +} + +function formatResults (args, results, cb) { + var cols = Math.min(process.stdout.columns || Infinity, 80) + 1 + + var out = results.map(function (res, i, results) { + var out = res.cmd + , r = Object.keys(res.hits).map(function (k) { + return k + ":" + res.hits[k] + }).sort(function (a, b) { + return a > b ? 1 : -1 + }).join(" ") + + out += ((new Array(Math.max(1, cols - out.length - r.length))) + .join (" ")) + r + + if (!npm.config.get("long")) return out + + var out = "\n\n" + out + + "\n" + (new Array(cols)).join("—") + "\n" + + res.lines.map(function (line, i) { + if (line === null || i > 3) return "" + for (var out = line, a = 0, l = args.length; a < l; a ++) { + var finder = out.toLowerCase().split(args[a].toLowerCase()) + , newOut = [] + , p = 0 + finder.forEach(function (f) { + newOut.push( out.substr(p, f.length) + , "\1" + , out.substr(p + f.length, args[a].length) + , "\2" ) + p += f.length + args[a].length + }) + out = newOut.join("") + } + if (npm.color) { + var color = "\033[31;40m" + , reset = "\033[0m" + } else { + var color = "" + , reset = "" + } + out = out.split("\1").join(color) + .split("\2").join(reset) + return out + }).join("\n").trim() + return out + }).join("\n") + + if (results.length && !npm.config.get("long")) { + out = "Top hits for "+(args.map(JSON.stringify).join(" ")) + + "\n" + (new Array(cols)).join("—") + "\n" + + out + + "\n" + (new Array(cols)).join("—") + "\n" + + "(run with -l or --long to see more context)" + } + + console.log(out.trim()) + cb(null, results) } |