summaryrefslogtreecommitdiff
path: root/appl/lib/complete.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2007-01-15 21:04:26 +0000
committerCharles.Forsyth <devnull@localhost>2007-01-15 21:04:26 +0000
commit8911721efbf3b3721376e2baa30bae002c2975c2 (patch)
treeaa059ffa39c2c4f1cd5ed2e137dcb9b079de2717 /appl/lib/complete.b
parent0e96539ff7cff23233d3f0a64bb285b385a3a1f4 (diff)
20070115
Diffstat (limited to 'appl/lib/complete.b')
-rw-r--r--appl/lib/complete.b93
1 files changed, 93 insertions, 0 deletions
diff --git a/appl/lib/complete.b b/appl/lib/complete.b
new file mode 100644
index 00000000..1a2e7713
--- /dev/null
+++ b/appl/lib/complete.b
@@ -0,0 +1,93 @@
+implement Complete;
+
+# Limbo translation by caerwyn of libcomplete on Plan 9
+# Subject to the Lucent Public License 1.02
+
+include "sys.m";
+ sys: Sys;
+
+include "string.m";
+ str: String;
+
+include "complete.m";
+
+include "readdir.m";
+ readdir: Readdir;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ str = load String String->PATH;
+ readdir = load Readdir Readdir->PATH;
+}
+
+
+longestprefixlength(a, b: string, n: int): int
+{
+ for(i := 0; i < n; i++)
+ if(a[i] != b[i])
+ break;
+ return i;
+}
+
+complete(dir, s: string): (ref Completion, string)
+{
+ if(str->splitl(s, "/").t1 != nil)
+ return (nil, "slash character in name argument to complete()");
+
+ (da, n) := readdir->init(dir, Readdir->COMPACT);
+ if(n < 0)
+ return (nil, sys->sprint("%r"));
+ if(n == 0)
+ return (nil, nil);
+
+ readdir = nil;
+
+ c := ref Completion(0, 0, nil, 0, nil);
+
+ name := array[n] of string;
+ mode := array[n] of int;
+ length := len s;
+ nfile := 0;
+ minlen := 1000000;
+ for(i := 0; i < n; i++)
+ if(str->prefix(s,da[i].name)){
+ name[nfile] = da[i].name;
+ mode[nfile] = da[i].mode;
+ if(minlen > len da[i].name)
+ minlen = len da[i].name;
+ nfile++;
+ }
+
+ if(nfile > 0){
+ # report interesting results
+ # trim length back to longest common initial string
+ for(i = 1; i < nfile; i++)
+ minlen = longestprefixlength(name[0], name[i], minlen);
+
+ c.complete = (nfile == 1);
+ c.advance = c.complete || (minlen > length);
+ c.str = name[0][length:minlen];
+ if(c.complete){
+ if(mode[0]&Sys->DMDIR)
+ c.str[minlen++ - length] = '/';
+ else
+ c.str[minlen++ - length] = ' ';
+ }
+ c.nmatch = nfile;
+ }else{
+ # no match: return all names
+ for(i = 0; i < n; i++){
+ name[i] = da[i].name;
+ mode[i] = da[i].mode;
+ }
+ nfile = n;
+ c.nmatch = 0;
+ }
+ c.filename = name;
+ for(i = 0; i < nfile; i++)
+ if(mode[i] & Sys->DMDIR)
+ c.filename[i] += "/";
+
+ return (c, nil);
+}