I would think that primitive symbol completion (similar to Alice Pascal) was already available on the Lisp Machine a bit earlier.
See for example the command 'List Completions' in the CADR sources of 1980:
https://common-lisp.net/svn/mit-cadr/tags/system-46/nzwei/co...
"Give a menu of possible completions for string so far"
and
'Completion Apropos'
"Do apropos within the completions of what has been typed"
The editor of a Symbolics Lisp Machine would already sectionize a buffer and would know what is defined there. It also kept track what was changed in various buffers, what compilation errors were related to which definitions, etc.
Basic completion would work over symbols in a buffer or what is available in packages in the running Lisp.
Note that the Symbolics had a COMPLETE key on the keyboard and in a Lisp editor buffer it would run COM-COMPLETE-DEFINITION-NAME 'Attempt to complete the definition-name of the symbol under point'-
Mid 80s Symbolics introduced the Presentation System, which recorded all I/O (including graphics) and recorded which objects were displayed as what type.
Thus when one interacted with the machine, it knew what were classes, methods, functions, etc. and it could also reconstruct it from the textual display. If one would for example use an editor command which needed a class, then when typing, completion and searching was limited to classes and only classes on screen would be mouse sensitive. Also if one would right-click on an object, there would be only the commands for that class or presentation type in the popup menu. Similar for all kinds of dialog menus. The system knows which types are acceptable and knew which objects could be reused, or which to search.
This is not really 'completion', but puts the classes (or the presentation types) directly into the user interface - based on the dynamic classes and presentation types of the objects displayed.
A lot of interaction in Dynamic Windows goes through listeners and command loops, which understand input contexts and accceptable presentation types. The main listener does that, but also all other applications had such a command loop. When you interact in a REPL with Dynamic Windows, completion wasn't really that necessary, since the UI had access to the actual objects (and not just a textual representation).
From a UI standpoint I as a developer would write typed functions (aka commands) which then would be invoked via gestures (keystrokes, commands, mouse gestures, ...). Developing an application always then would involve writing presentation types and presentation methods for classes (and other things), which could then also be used in a listener/repl in a programming sessions. Let's say we wanted to implement a calendar, then one would implement presentation types for days, weeks, months, years, persons, rooms, events, tags, etc., provide visual and textual representations for them. Then while programming, we could play around with those objects in the listener. It would know which commands are applicable for the things on the screen - no completion necessary. Still if a person/event/room/tag/... would be requested, it could complete or search through the known persons/events/rooms/tag/....
Much of the UI was developed with Flavors and later with CLOS
, such that there were lots of classes, lots of messages/generic functions/methods, ... Naturally this worked only over the things loaded into the current Lisp world. Code or other objects on disk was not available for this kind of interaction - though some stuff worked also with pre-computed tag tables. But to know about classes, methods, presentation types and presentations, they usually had to be present in the running world (which could be saved and restarted later).