Recently I decided it really was time to do something cool with Pharo again, asked Stef (the one and only Stéphane Ducasse) what was there to do, and soon he suggested several projects I could try. Among them there was one that particularly stood out — code completion. It’s an interesting project to figure out, an even more challenging project to do, and obviously very useful and exciting for the Pharo community.
And so I decided to have a look. I started with learning more about what completion is in general and what are the differences between various types of code completion, looking how it’s done in some other programming environments (for example, Eclipse, IntelliJ IDEA and PyCharm) and so on.
At the moment I am looking at the Pharo implementation of code completion and trying to write some tests and documentation. There isn’t much information regarding how it’s really done here, and so I thought it might be really useful to document some of my observations and discoveries as I go along, to help some people who may decide to look into it in the future.
This article will be rather short and introductory, and yet I still want it to be divided into several distinct parts.
- Definition of code completion.
- Its implementation in Pharo.
- Things to do still.
Autocompletion is a feature with the help of which applications predict the rest of the word a user is typing. For a specific example, think searching for something in your browser address bar or directly in Google, or typing email addresses. In most of these cases, the suggestions will be based on the your recent search history or general habits.
Now, autocompletion that is used for source code editors, or programming environments, is called code completion. When coding, code completion serves not only as a more convenient input method (you don’t have to type up the whole thing yourself), but also as pretty good documentation, as sometimes you might not know what methods a particular class has.
When done right, code completion should only show you methods the most relevant to the class you are using or also the most commonly used in the particular context you are working with. It gives you most probable suggestions on the top of the pop-up list, and so usually you are able to choose the variable or method name you need after just entering a couple of symbols.
Obviously, with a feature as complex as this, there’s always room for improvement, as code editors want to make their code completion as efficient and as helpful as possible.
In Pharo there is ECompletion and OCompletion. Basically, as far as I have been able to figure out, ECompletion is the regular method of code completion that is more or less the same for every system, and OCompletion is something that was built onto the already existing system in order to improve it.
(More on how and why it was done can be read here.)
In short, “OCompletion is a completion tool that uses an optimist completion algorithm together with an implicit invocation interface. As the programmer types the names of identifiers, a short list (up to three candidates) is permanently shown and interactively updated as the programmer types. The suggestions on this list are called “Automatic Suggestions” as they appear without explicit user interaction.”
The implementation of both ECompletion and OCompletion can be found in the NECompletion package, with all the tests for them being in the neighbouring NECompletion-Tests package.
In NECompletion, initially there were three categories: Model, OCompletion and View, which all contain many classes which define the behaviour of completion in general, all functions of OCompletion in particular, and again the way in which the completion is presented in general, respectively. (I say ‘initially’, because now there’s been added a new TypeGuesser category, where Stef and I put classes which it made more sense to have separately).
The main class that puts everything together is NECController, which exists in the NECompletion package and is in the View category. NECController creates the NECContext class and also passes itself and its events to the NECMenuMorph class. NECContext, in its turn, creates the NECModel class whenever it is requested by the ‘model’ method. NECModel stores all the entries to be completed, and all the other classes in the Model category define the behaviour of each of the possible entries (it can be a selector, an instance variable or a global variable, and so on). In TypeGuesser there are only a few classes that guess and store the information on types.
There is still a lot to be done in terms of understanding each of the classes of each of the categories in the NECompletion package, as well as NECompletion-Tests. So far I still haven’t done anything regarding OCompletion, because my main focus right now is ECompletion. But I think I will have to have a look at both, to see the differences of the implementation with my own eyes.
Even though what most classes and methods do is pretty self-explanatory, really understanding how and why they do it in a particular way is pretty challenging. And so is documenting everything. It’s all about debugging, figuring out the dependencies, removing dead code, and writing tests.
As to the actual work that remains to be done in improving code completion — I don’t know how successful I can be with it, but I definitely have in mind a couple of things that could be fixed and improved, and will also greatly appreciate any suggestions, hints, tips, and help from you.
To be continued…