2016-08-19
My current Go autocompletion setup in GNU Emacs
A while back I wrote about getting gocode
based autocompletion
working in GNU Emacs, and then about
things about the autocompletion that I was unsatisfied with. After a certain amount of struggling I
actually wound up with a Go autocompletion setup that I'm happy
with, and I've now realized that I never wrote it up, and there
is one change that wound up quite important for me.
GNU Emacs has at least two auto-completion systems, auto-complete and company-mode. In my original approach I followed gocode's recommendation and used auto-complete. I have now switched to company-mode and I like this much better, in large part because I've been able to do much more customization of how it behaves than I managed with auto-complete.
My first set of customizations are more or less gocode's recommended ones. I enable on company-mode only in Go code, and I copied many of the possible improvements it lists:
(setq company-tooltip-limit 15) (setq company-idle-delay .15) (setq company-echo-delay 0) (setq company-begin-commands '(self-insert-command))
This still left my general issues with autocompletion, so I got out a big hammer and started changing company-mode's key bindings so that they didn't steal keys from me in a way that irritated me.
; complete selections with Control-Return, not ; normal Return. (define-key company-active-map (kbd "RET") nil) (define-key company-active-map (kbd "<return>") nil) (define-key company-active-map (kbd "C-<return>") 'company-complete-selection) ; Use C-Up/Down to move through the selection list (define-key company-active-map (kbd "<down>") nil) (define-key company-active-map (kbd "<up>") nil) (define-key company-active-map (kbd "C-<down>") 'company-select-next-or-abort) (define-key company-active-map (kbd "C-<up>") 'company-select-previous-or-abort)
The result of these bindings is that company-mode is relatively inoffensive. In practice, often it's enough that it tells me what's available and I wind up just typing out the function or variable name myself. But at least some of the time I'll wind up using C-return once I've typed enough to make the name unambiguous. This means that I'm not making much use of its power, but at least it's inoffensive and helpful.
(Actively looking at company-mode in the process of writing this entry has suggested a number of things I should remember about it, like that TAB will complete as much as possible, up to and including everything.)
Overall my experience with company-mode in Go has been pleasant. It doesn't seem to hurt and it's non-distracting enough and potentially helpful enough that I keep it around. It's even reached the point where I'm a bit annoying when it doesn't offer suggestions for various reasons, such as that I haven't yet run goimports to actually add an import for the new package that I'm using and that I want names from.
(This is a kind of chicken and egg situation. I need to write something that uses the package before goimports will auto-add it for me, but I need it added before company-mode will start conveniently completing names so that I can use the package. The real answer turns out to be that I should remember the go-mode C-c C-a binding to add an import by hand.)
One of the things that I have wound up quite liking about company-mode is simply that I can modify it like this. Possibly auto-complete can be modified in this way too, but it was easy enough for me to work out how to do it to company-mode even as a semi-outsider to GNU Emacs mode hacking.
(I have some additional bindings I consider experimental, which I've decided not to mention any specifics about. That it's easy enough to bind things that I do have experimental bindings is nice.)
Localhost is (sometimes) a network
Everyone knows localhost
, 127.0.0.1, the IP(v4) address of every
machine's loopback network. If you're talking to 127.0.0.1, you're
talking to yourself (machine-wise). Many of us (although not all)
know that localhost is not just a single IP address; instead, all
of 127.*.*.* (aka 127/8) is reserved as the loopback network.
ifconfig
will tell you about this on most machines:
lo0: flags=[...] inet 127.0.0.1 netmask ff000000
You don't see that many 0's in a netmask all that often.
One of the tricks that you can play here is to give your loopback network more 127.* IP aliases. Why would you want that? Well, suppose that you have two things that both want to run localhost web servers. With 127.* IP aliases, one can be http://127.0.0.1/ and the other can be http://127.0.0.2/, and both can be happy. Localhost IP aliases can also be a convenient way to invent additional source addresses for testing. Need to connect to something on the same machine from ten different source IPs? Just add 127.0.100.1 through 127.0.100.10, then have your software rotate among them as the source addresses. It's all still loopback traffic, so all of the usual guarantees apply; it just has some different IPs involved.
Sometimes, though, we mean that loopback is a network in a more literal way. Specifically, on Linux:
bash $ ping 127.0.$(($RANDOM % 256)).$(($RANDOM % 256)) PING 127.0.251.170 (127.0.251.170) 56(84) bytes of data. 64 bytes from 127.0.251.170: icmp_seq=1 ttl=64 time=0.055 ms [...]
On at least FreeBSD, OpenBSD, and OmniOS, this will fail in various ways. On Linux, it works. Through black magic, you don't have to add additional 127.* IP aliases in order to use those addresses; although not explicitly declared anywhere as existing, they are just there, all 16,777,215 or so of them. The various localhost IPs are all distinct from each other as usual, so a service listening on some port on 127.0.0.1 can't be reached at that port on 127.0.0.2. You just don't have to explicitly create 127.0.0.2 before you can start using it, either to have a service listen on it or to have a connection use that as its source address.
(And anything that listens generically can be reached on any 127.* address. You can ssh to these random localhost IPs, for example.)
PS: Before I tested it as part of writing this entry, I thought that the Linux behavior was how all Unixes worked. I was a bit surprised to find otherwise, partly because it makes the Linux behavior (much) more odd. It is kind of convenient, though.