Using the Samsung Chromebook for remote and local development with Emacs

3 November 2014

With the death of my Macbook’s battery, I decided to find a new portable computer, rather than pay a bunch for a several year old “new” battery. I settled on Samsung’s Chromebook. It is a lot of computer (and battery life) for one of the lowest price-points on the market. It is, however, the first general purpose computer I have used that has an ARM processor. While this is limiting in some ways, it was not a deal-breaker.

This post will be a somewhat disjointed dump of things that I’ve done in order to be comfortable working with the Chromebook.

Linux in Chrome OS

While Chrome OS does feature a shell (Ctrl-Alt-T opens a terminal, then type shell), it is pretty limited. Some people will be totally fine SSHing into another computer and working from there, but I wanted to have the ability to compile things locally. To get a functional development environment local to the Chromebook there are two options: Install an OS on a separate partition (dual booting, or replacing Chrome OS entirely), or installing Linux on top of Chrome OS. Both require developer mode to be enabled. Since I didn’t want to lose the hardware specific enhancements present in Chrome OS (such as power management – which apparently Linux does not handle well on this machine – and a browser with Flash – which isn’t otherwise available on ARM), I chose the latter.

Crouton is the best supported way of running another OS on top of Chrome. It’s quite impressive how easy it is to use!

Crouton will let you start a new X session with a chroot. This works quite well with some caveats:

Terminals

Despite getting Crouton set up running X, I decided that given the limited RAM, it wasn’t too desirable to be running two browsers at the same time: One in Chrome OS and the other in the chroot. Instead, I realized that much can be done through a chrooted terminal in Chrome OS and the host-x11 command, and living in the Chrome OS X session, taking advantage of the native Chrome browser.

Chrome OS’s terminal, hterm, is perfectly capable provided you install Secure Shell which updates the hterm that comes with Chrome OS. You can learn more about it in its FAQ. It can be configured via Chrome’s extensions page.

Crosh Window is handy if you like the feel of a dedicated terminal that is a separate window from Chrome. Crosh does not tabs, though, and even if it did, chrooting multiple times would be a pain. A terminal multiplexer like tmux is therefore recommended.

Despite being comfortable in my Linux chroot, I realized that many operations would still be simpler if done on my primary computer. While SSH was the tool I initially reached for, I soon discovered Mosh which has some notable advantages over SSH on systems that may not have a persistent network connection (and also has a Chrome App). While Mosh turned out to be awesome, I ended up abandoning it because it lacked a killer feature: The ability for programs running in it to copy to through to the Chrome OS clipboard.

File syncing

It’s nice to have an easy way of synchronizing files (such as dotfiles). I’ve so far found Unison to be very nice to work with. It was the second synchronizer that I tried after Pulse a.k.a Syncthing. Despite the inherently difficult setup for Pulse, my initial impressions were quite good. Running into some snags syncing some git repositories (possibly due to halting syncs partway through) ruined my good faith, though. Recovering from these failed syncs proved to be nearly impossible save for deleting and re-adding the folders from both Pulse setups, which is a slow process. Unison proved easier to set up, is much faster, and safer, albeit not geared towards quite the same use-case and not as automatic.

Emacs

Since I do most of my stuff in Emacs, making sure it worked smoothly both locally and remotely was important. I had decided to work in terminal Emacs, so that I could easily work out of Chrome OS and from my remote computer. This required a bit of tweaking to be used with hterm, as well as some more basic things that I hadn’t been doing before, but are plenty well documented (such as using the – indispensable for remote connections – Emacs daemon and setting the TERM environment variable to xterm-256color or screen-256color to unlock a larger colour pallet).

Escape sequences for hterm

Since terminal Emacs does not have direct access to the keys that are being pressed, it relies on the escape sequences beings sent by the terminal that represent modified key presses. Not all terminals send the same escape sequences, and I ended up needing to define a few for hterm. Emacs has excellent support for mapping escape sequences, which I am thankful for!

(defun fix-terminal-keys ()
  (interactive)
  (define-key input-decode-map "\e[5~" [(meta up)])
  (define-key input-decode-map "\e[6~" [(meta down)])
  (define-key input-decode-map "\e\e[OD" [(meta left)])
  (define-key input-decode-map "\e\e[OC" [(meta right)])
  (define-key input-decode-map "\e[A" [(ctrl up)])
  (define-key input-decode-map "\e[B" [(ctrl down)])
  (define-key input-decode-map "\e[C" [(ctrl right)])
  (define-key input-decode-map "\e[D" [(ctrl left)])
  (define-key input-decode-map "\e[1~" [(meta ctrl up)])
  (define-key input-decode-map "\e[4~" [(meta ctrl down)])
  (define-key input-decode-map "\e\e[D" [(meta ctrl left)])
  (define-key input-decode-map "\e[3~" (kbd "M-DEL")))

(advice-add 'terminal-init-xterm :after #'fix-terminal-keys)

There are likely more combinations that Emacs interprets incorrectly, but these are the ones that I’ve run into. In general, when faced with this problem, the escape codes can be found by executing (open-dribble-file "/tmp/key-presses”), then opening that file, typing the key combination in question, and looking at what gets added to the file. (open-dribble-file nil) will end Emacs’ connection with the dribble file.

Copying

While hterm can copy out of and into the system clipboard, one thing that got old fast was highlighting regions of text with the mouse in order to copy them out of Emacs. These chunks of text often spanned across multiple windows, thus adding junk characters I’d have to edit out after pasting. Using tmux’s copying mode made things more palatable – things copied in tmux end up being added to the system clipboard (as tmux sends the escape codes that xterm and hterm expect for copied text). I still wanted to figure out a way to copy text directly out of Emacs, so I did!

osc52.el, provided by Chrome OS, was an excellent starting point. It is not able to copy out of tmux, however, nor does it support multi-byte characters. My enhanced version adds just that, and also integrates into Emacs a bit better. For this to work with tmux for selections of more than fifty-odd characters, a development version of tmux is required (which depends on automake, ncurses, and libevent).