浏览代码

Add filepath completion for `cat`, `cd` and `ls`

Also try restricting the site to 840px, because 1200px is too large.
Maybe smaller than 960px is better for what this page contains.
Weiyi Lou 10 年之前
父节点
当前提交
cf56984792
共有 2 个文件被更改,包括 43 次插入19 次删除
  1. 4 1
      css/style.css
  2. 39 18
      js/pgsh.js

+ 4 - 1
css/style.css

@@ -1,4 +1,4 @@
-/* pgs-cli styles */
+/* pgs-cli stylesheet */
 * {
   color: #DDD;
   font-family: 'Courier New', Courier, Monospace;
@@ -37,3 +37,6 @@ div.console-inner { overflow-y: auto; }
   ::-webkit-scrollbar-track { background: rgba(0, 0, 0, 0.1); }
   ::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.5); }
 }
+
+/* Keep to 840px. 1200px is too wide. */
+.container{ max-width: 840px }

+ 39 - 18
js/pgsh.js

@@ -21,7 +21,7 @@ function pgsh(ev) {
   ev.on('mount', function() {
     document.getElementById(ev.id).onkeydown = function(e) {
       var code = e.keyCode || e.which
-      // Tab
+      // Tab for file path completion
       if (code == 9) {
         var input = ev.tags['command-line'].command.value.trim().split(' ')
         var command = input.shift()
@@ -29,7 +29,7 @@ function pgsh(ev) {
           var args = input.join(' ').trim()
           var isFile = (command == 'cat') ? true : false;
           var path = completePath(args, isFile)
-          if (path) { ev.trigger('cmd_set', cmd + ' ' + path) }
+          if (path) { ev.trigger('cmd_set', command + ' ' + path) }
         }
         e.preventDefault()
       }
@@ -137,7 +137,7 @@ function pgsh(ev) {
       }
       show('\n' + content + '\n\n')
     } else {
-      show("cd: " + arg + ": no such file")
+      show("cat: " + arg + ": no such file")
     }
   }
   this.cd = function(args) {
@@ -198,18 +198,14 @@ function pgsh(ev) {
     var path = resolveAbsPath(folder)
     if (pathExists(path)) {
       var contents = getContents(path)
-      var items = []
-      for (var item in contents) {
-        items.push(item)
-      }
-      items.sort()
       var dstat = 'drwxr-xr-x <span style="color:#268bd2">'
       var fstat = '-rw-r--r-- '
-      items.forEach(function(item, key, items) {
+      var items = []
+      for (var item in contents) {
         var prefix = (typeof contents[item] === 'string') ? fstat : dstat
         var suffix = (typeof contents[item] === 'string') ? '' : '</span>'
-        items[key] = prefix + item + suffix
-      })
+        items.push(prefix + item + suffix)
+      }
       items.unshift(dstat + '..</span>')
       items.unshift('total ' + items.length)
       show(items.join('\n'))
@@ -260,7 +256,7 @@ function pgsh(ev) {
     }
   }
   this.version = function(args) {
-    show('Parsley Gardens Shell (pgsh) 1.1.0 Built with ' +
+    show('Parsley Gardens Shell (pgsh) 1.1.0\nBuilt with: ' +
          '<a target="_blank" href="http://riotjs.com">Riot</a> ' +
          '<a target="_blank" href="https://skeleton-framework.github.io">Skeleton</a> ' +
          '<a target="_blank" href="https://highlightjs.org">highlight.js</a>')
@@ -313,15 +309,40 @@ function pgsh(ev) {
     parts.forEach(function(part) {
       if (part) { tree = tree[part] }
     })
+    // Sort JS object. TODO not a great way.
+    if (typeof tree === 'object') {
+      var keys = []
+      for (key in tree) {
+        keys.push(key)
+      }
+      keys.sort()
+      var temp = {}
+      keys.forEach(function(key) {
+        temp[key] = tree[key]
+      })
+      tree = temp
+    }
     return tree
   }
 
-  var completePath = function(path, isFile) {
-    // check if we are doing partial name completion
-      // ending slash means completing first content
-      // not ending slash means word completion - cut off bit for completion
-    // first get right directory with absolute path
-    console.log('completing')
+  var completePath = function(input, isFile) {
+    // Extract file fragment and get actual path.
+    var slash = input.lastIndexOf('/') + 1
+    var frag = input.substring(slash)
+    var base = input.substring(0, slash)
+    var path = resolveAbsPath(base)
+    // Complete fragments
+    if (pathExists(path)) {
+      var contents = getContents(path)
+      var found = ''
+      for (var name in contents) {
+        if (!isFile && typeof contents[name] === 'string') { continue }
+        if (!frag) { found = name; break }
+        if (name.indexOf(frag) == 0) { found = name }
+      }
+      var end = typeof contents[found] === 'object' ? '/' : ''
+      return base + found + end
+    }
     return ''
   }
 }