summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-03-21 06:22:42 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-03-21 06:22:42 -0700
commit7e2f1500f34098be4a0cc0b2130cffb3a729793b (patch)
tree18e9a0b5e4136d8379f583fdd2069748f6648ac8
parentc2dec325d87de8be8917e7b52f118f4664a9e13a (diff)
downloadtxr-7e2f1500f34098be4a0cc0b2130cffb3a729793b.tar.gz
txr-7e2f1500f34098be4a0cc0b2130cffb3a729793b.tar.bz2
txr-7e2f1500f34098be4a0cc0b2130cffb3a729793b.zip
listener: completion sensitive for slots and methods.
When completing .prefix[TAB], .(prefix[TAB] or .[prefix[TAB], restrict identifiers to the appropriate namespace. The former will report only symbols from the relevant package which are struct slots; the latter further restricts it to those which are static slots defined as functions. * lib.c (symbol_visible): Static function becomes extern. * lib.h (symbol_visible): Declared. * parser.c (find_matching_syms): par parameter is renamed kind and can hold additional values 'S' (slots) and 'M' (methods). New get_slot_syms function is used to fetch the slots, as necessary, instead of the visible syms, if the kind is 'S' or 'M'. The same loop as before (with the minor change of recognizing 'S' and 'M' also) performs the prefix matching. (provide_completions): Recognize . .( and .[ prefix, calculating the kind argument of find_matching_syms in a new way. * struct.c (get_slot_syms): New function. * struct.h (get_slot_syms): Declared. * txr.1: Add some notes about this under the description of completion. The full rules are not given though; let the user discover.
-rw-r--r--lib.c5
-rw-r--r--lib.h1
-rw-r--r--parser.c27
-rw-r--r--struct.c38
-rw-r--r--struct.h1
-rw-r--r--txr.114
6 files changed, 74 insertions, 12 deletions
diff --git a/lib.c b/lib.c
index 5d2724fe..e578b308 100644
--- a/lib.c
+++ b/lib.c
@@ -5053,7 +5053,10 @@ val unuse_package(val unuse_list, val package_in)
return unuse_package_list;
}
-static val symbol_visible(val package, val sym)
+/* symbol_visible assumes the perspective that package
+ * is the current package!
+ */
+val symbol_visible(val package, val sym)
{
val name = symbol_name(sym);
type_check (package, PKG);
diff --git a/lib.h b/lib.h
index 87b23465..4d359f60 100644
--- a/lib.h
+++ b/lib.h
@@ -800,6 +800,7 @@ val use_sym(val use_list, val package);
val unuse_sym(val symbol, val package);
val use_package(val use_list, val package);
val unuse_package(val unuse_list, val package);
+val symbol_visible(val package, val sym);
val find_symbol(val str, val package);
val intern(val str, val package);
val unintern(val sym, val package);
diff --git a/parser.c b/parser.c
index 11249945..20e5a094 100644
--- a/parser.c
+++ b/parser.c
@@ -686,18 +686,20 @@ static val get_visible_syms(val package, int is_cur)
static void find_matching_syms(lino_completions_t *cpl,
val package, val prefix,
- val line_prefix, char par,
+ val line_prefix, char kind,
val force_qualify)
{
- int is_cur = package == cur_package;
+ val is_cur = tnil(package == cur_package);
val qualify = tnil(force_qualify || !is_cur);
val pkg_name = if2(qualify,
if3(package == keyword_package && !force_qualify,
lit(""),
package_name(package)));
- val syms;
+ val syms = ((kind == 'S' || kind == 'M')
+ ? hash_keys((get_slot_syms(package, is_cur, tnil(kind == 'M'))))
+ : get_visible_syms(package, is_cur != nil));
- for (syms = get_visible_syms(package, is_cur); syms; syms = cdr(syms)) {
+ for ( ; syms; syms = cdr(syms)) {
val sym = car(syms);
val name = symbol_name(sym);
val found = if3(cpl->substring,
@@ -707,7 +709,7 @@ static void find_matching_syms(lino_completions_t *cpl,
if (found) {
val comple;
- switch (par) {
+ switch (kind) {
case '(':
if (!fboundp(sym) && !mboundp(sym) && !special_operator_p(sym))
continue;
@@ -716,6 +718,9 @@ static void find_matching_syms(lino_completions_t *cpl,
if (!boundp(sym) && !lookup_fun(nil, sym))
continue;
break;
+ case 'M':
+ case 'S':
+ break;
default:
break;
}
@@ -812,13 +817,19 @@ static void provide_completions(const char *data,
char prev = (end > data) ? end[-1] : 0;
char pprev = (end > data + 1) ? end[-2] : 0;
int quote = (pprev == '^' || pprev == '\'' || pprev == '#');
- int meth = (pprev == '.');
int ppar = (pprev == '(');
int dwim = (prev == '[');
- char par = (!pprev || (!quote && !meth && !ppar) || dwim) ? prev : 0;
+ int par = (prev == '(');
+ int slot = (prev == '.');
+ int meth = (pprev == '.') && (dwim || par);
+ char kind = (slot
+ ? 'S'
+ : (meth
+ ? 'M'
+ : (!pprev || (!quote && !ppar) || dwim) ? prev : 0));
find_matching_syms(cpl, or2(package, cur_package),
- sym_pfx, line_pfx, par, if2(package, null(keyword)));
+ sym_pfx, line_pfx, kind, if2(package, null(keyword)));
}
}
}
diff --git a/struct.c b/struct.c
index 84977da6..57870980 100644
--- a/struct.c
+++ b/struct.c
@@ -1507,6 +1507,44 @@ val method_name(val fun)
return nil;
}
+val get_slot_syms(val package, val is_current, val method_only)
+{
+ val result_hash = make_hash(nil, nil, nil);
+ val sth_iter = hash_begin(struct_type_hash);
+ val sth_cell;
+
+ while ((sth_cell = hash_next(sth_iter))) {
+ val stype = cdr(sth_cell);
+ val sl_iter;
+ struct struct_type *st = coerce(struct struct_type *, stype->co.handle);
+
+ for (sl_iter = st->slots; sl_iter; sl_iter = cdr(sl_iter)) {
+ val slot = car(sl_iter);
+
+ if (gethash(result_hash, slot))
+ continue;
+
+ if (!is_current && symbol_package(slot) != package)
+ continue;
+
+ if (!symbol_visible(package, slot))
+ continue;
+
+ if (method_only) {
+ loc ptr = lookup_static_slot(st, slot);
+ if (nullocp(ptr))
+ continue;
+ if (!functionp(deref(ptr)))
+ continue;
+ }
+
+ sethash(result_hash, slot, t);
+ }
+ }
+
+ return result_hash;
+}
+
static_def(struct cobj_ops struct_type_ops =
cobj_ops_init(eq, struct_type_print, struct_type_destroy,
struct_type_mark, cobj_hash_op))
diff --git a/struct.h b/struct.h
index d7f30f0d..10f87f72 100644
--- a/struct.h
+++ b/struct.h
@@ -63,4 +63,5 @@ val super_method(val strct, val slotsym);
val uslot(val slot);
val umethod(val slot, struct args *);
val method_name(val fun);
+val get_slot_syms(val package, val is_current, val method_only);
void struct_init(void);
diff --git a/txr.1 b/txr.1
index 22ced1b2..9c7cdf34 100644
--- a/txr.1
+++ b/txr.1
@@ -52097,11 +52097,19 @@ sequence Ctrl-X Tab.
When completion is invoked with Tab or Ctrl-X Tab, the listener looks at a few
of the trailing characters to the left of the cursor position to determine the
applicable list of completions. Completions are determined from among the \*(TL symbols which have
-global variable, function, macro and symbolic macro bindings. Symbols which
-have operator binding are also taken into consideration. If a
+global variable, function, macro and symbolic macro bindings, as well
+as the static and instance slots of structures. Symbols which
+have operator bindings are also taken into consideration. If a
package-qualified symbol is completed, then completion is restricted to that
package. Keyword symbol completion is restricted to the contents of the keyword
-package.
+package. The namespaces which are searched for symbols are restricted according
+to preceding character syntax. For instance if the characters
+.code ".("
+or
+.code ".["
+immediately precede the prefix, then only those symbols are considered
+which are methods: that is, each is the static slot of at least one structure,
+in which that static slots holds a function.
The difference between Tab and Ctrl-X Tab is that Tab completion looks only for
prefix matches among the eligible identifiers. Thus it is a pure completion in