Skip to main content

Completion

An editor asks what could go where the cursor is, and the answer arrives while the line is still half written. That is the only state that matters: a suggestion after the code is already complete is a suggestion nobody needed.

Completion is offered on . and on ::, and is triggered by typing either.

After a dot

A value's own members, whether or not the member has been typed yet.

pub type Point {
pub field x: i32;
pub field y: i32;

pub static fn origin() -> Point { return new Point { x: 0, y: 0 }; }

pub fn shifted(dx: i32) -> Point { return new Point { x: self.x + dx, y: self.y }; }
}
WrittenOffered
p.x, y, shifted
self.x, y, shifted
Point::origin

A type on the left is a static access, so only what can be reached that way comes up. self is a value even though it names its own type, so it offers the instance members.

What an interface supplies is offered as well, on every type that implements it and on arrays, which are sequences. Completion asks the compiler what members a type has rather than reading the declaration, so a member nobody wrote on the type still comes up.

WrittenOffered
values. where values is i32[]count, and the seven sequence operators

A union offers its cases through ::, since that is how a case is reached.

pub union Slot {
empty,
filled(i32),
}
WrittenOffered
Slot::empty, filled

A dot with no union named

A pattern and a case written without its union both start with a bare ., and both offer the cases of the union in view.

match slot {
. // empty, filled
}

Where a case is written without its union, the union comes from whatever the value is going into, and completion reads it the same way the compiler does.

pub fn chosen() -> Slot {
return . // empty, filled
}

pub fn held(slot: Slot) -> i32 { return 0; }
WrittenOffered where the union is
return .the function's return type
let s: Slot = .the annotation
s = .the variable being assigned to
held(.the parameter
new Holder { slot: . }the field
new Slot[] { . }the array's element type

Where nothing says which union is wanted, there are no cases to offer and the ordinary list of names in scope comes up instead. let s = . with no annotation is one such place, and so is let n: i32 = ..

note

Where two overloads take different unions, the case name is what picks between them, so held(. offers the cases of whichever union that call could want. Where both could want a case of that name, one of them is offered. Writing the union out says which.

Everywhere else

Anything that is not after a dot offers what is in scope: locals declared above the cursor, the enclosing function's parameters, the enclosing type's members, the file's own declarations, everything the standard library puts in the global namespace, then keywords and the primitive type names.

A local is not offered on the line that declares it, and a local declared below the cursor is not offered at all.