Emboldened by my previous success and with a better idea as to how SublimeClang fetches code completions internally, I set about trying to make the Emacs plugin a reality once more. I initially figured that I would write it entirely in C++, with Emacs communicating with the server using sockets or something like that. However, I soon realized that most of the code I wrote would be more or less identical to how SublimeClang works. In addition to that, I had no idea how I would go about caching results, while SublimeClang already had a working solution that seemed to perform admirably.
Hence, in the interest of getting the thing done as soon as possible, I decided to revisit SublimeClang’s code, starting with the C++ part. I didn’t really sit down and completely understand all of it, but I gave it a once-over to get a basic idea of what it does (except the caching part, I still have no idea how that works). It exposes a bunch of classes, all of which are instantiated in Python with ctypes, and Python calls the member functions of those objects for stuff like parsing a file, creating a translation unit, getting code completions etc. An object of the C++ class named Cache
is created Python-side and stored in a list/dict (I forget which). Most of this happens in translationunitcache.py.
Armed with this knowledge, I immediately saw how I had botched things the first time around in my hurry to create an Emacs plugin as soon as possible. Instead of keeping most of the plugin’s functionality intact, I had set about breaking it by sprinkling lisp calls all over the place, a problem that I retroactively tried to fix by moving all the lisp calls to a few functions in the internals.common
module, but that turned out to be too little too late.
This time around, I set about with the task of first separating the plugin out into a module that could be imported and run on its own. To this end, I created a new module, sublime.py, in which I created classes like View
and Region
that are provided by Sublime Text 2 to its plugins, and mimiced their functionality. Once I was done with this, porting the rest of the plugin proved to be an almost trivial task, and I had a functional version up and running in a matter of two days or so.
Anyway, without further ado, that python module can be accessed here: https://github.com/ameyp/py-clang-util. It currently supports finding all possible code completions at a particular location in a file, given the file’s path, the position, and a list of flags needed for clang to be able to compile that file. It also supports jumping to a symbol’s declaration or definition (referred to as definition and implementation respectively, as those terms are used in the original plugin), although the implementation part is slightly flaky and hence might have a few bugs (for example, I haven’t looked into how the plugin does Extensive Search
for the implementation)
Sample code is present in test.py, along with extensively-documented examples in the README.md itself. Enjoy.
(next post will be about my progress with using this module with Emacs)