Rethinking Code Editing

One thing frustrated me when I started programming 20 years ago: it’s very difficult to use any kind of software that you didn’t write, but could write yourself. There’s always something wrong, something you would have done slightly differently.

As it turns out, 20 years later, I still have this problem from time to time. This is the reason why this blog has been quiet the past two weeks, I decided to spend my spare time writing code rather than writing prose. I’m not yet happy enough with the result to share it with the world, but I would like to talk a little bit about some of the principles behind it.

As you will have guessed from the title, it’s a code editor.

“Hey, don’t you build a code editor for a living?” No, not anymore. But as the Dutch say “the blood crawls where it cannot go,” I haven’t completely lost interest in code editing. Better yet, taking a bit of a distance allowed me to rethink some things. Anyway, the point here is not to build a competitor to Cloud9 by any means, it’s more of a playground to test some new and old ideas that I have. So far, I’ve been happy with the result.

But let’s take a step back, and start with some observations after 20 years of editing code.

Tabs: Whether you use them in an editor or in a browser, if you’re like me, your open tabs quickly become unwieldy and pretty soon you are unable to find the tab you’re looking for. Why do we use tabs in editors anyway? I believe its sole purpose is to be able to quickly navigate to files you’re working on. However, this convenience results in the inconvenience of having to manage the tabs themselves. Having up to ten tabs open is usually ok, but after that your tabs get so narrow you can no longer read their titles and you have to start deciding which ones to close. Usually what I do is give up on the whole thing and close all of them, and reopen the ones I need as I need them kind of defeating the whole purpose. Conclusion: tabs may not be a great idea for code editing.

File tree: There’s a few things I don’t like about the often present file tree. The first: it takes space. The second, usually you have to operate them with your mouse, or at least, I always end up operating them with my mouse. I don’t like using my mouse, it’s bad for my RSI. Second, navigation is slow. If you have a big projects, with a big directory hierarchy, you end up expanding a lot of tree nodes, and it’s always the wrong nodes that have already been expanded cluttering up your view. So now you end up doing tree management as well as tab management. There’s the use case of doing file management (renaming, copying, moving files around) for the tree, but for navigation between files — for me by far the more common use case — it’s pretty bad. Conclusion: tree (at least as primary file navigation mechanism) gotta go.

File saving: If you’re an iOS (or I suppose Android) user, you may have noticed there’s no “Save” button to be found anywhere. Why? Well, why would you need one? Why does saving a file have to be an explicit command? At Cloud9 we discussed enabling auto saving by default, but decided against it because it was deemed too controversial (you can switch it on in your preferences, though). Personally, I don’t want to deal with having to press Cmd-S all the time. Some people say that they wouldn’t want to auto save, because quite often they making drastic changes to a file that they can then easily revert by closing the file and reopening it, but that seems more like the job of either a version control system, or simply good undo functionality. Conclusion: explicit file saving gotta go.

Split view: I have a 15″ Macbook. If I maximize my editor, I have a lot of white space on the right side. My code doesn’t run much longer than approximately 80 characters. I also have a 27″ external screen. Maximizing my editor there looks insane without split views. Split views are a must have, but when used too heavily can have similar problems as tabs. For instance, in Vim I sometimes go pretty crazy in the number of splits (perhaps 6 or 9 frames). Now you make good use of space, but how do you navigate this mess, which one is active, which file went where? In my experience, vertical splits are useful, but you probably only need about two, or three at most (until I get my 60″ screen). Since the trend in computer screens appears to be for them to become wider rather than higher, horizontal splits are probably less useful (and combining the two always confuses me). Conclusion: split views are must haves, but maybe protect me against myself in using them.

Extensibility: At various times I have found the idea of Emacs very appealing and invested time in learning it. Emacs is the ultimate programmable editor. Using Emacs’ amazing Elisp language, you can change about everything about what Emacs does. You can rebind keys, add completely new features. The power in amazing. But yeah, Elisp… Vim in many ways is similar, it also very extensible, using Vimscript, not exactly as extensible as Emacs, but close. But yeah, it’s this interesting Vimscript language. If you go for Emacs you have to learn Elisp, if you go for Vim you have to learn Vimscript. These days, many developers don’t write Lisp or Vimscript for a living, it would be nicer if the language to extend their editor is something closer to what they know. Javascript for instance. Conclusion: extensibility is a must, but use a sane language.

Open source: I’m by no means a free software fundamentalist. I don’t believe software has to be free by any means. However, I do believe in the practicality of open source software. If you want to make building an editor your full-time job, like the guy who builds Sublime Text, that’s great, go ahead and sell your software. If you’re not interested in that, or want to attract an audience that wants to hack at the editor itself (the core of the thing, not just plugins), then open source is a good model. I believe that open sourcing stuff is a good thing and I like the idea of being able to go in, fix a bug and submit a pull request to the author. Conclusion: open source is good.

Chrome: Many editors today boast a “distraction free” mode. “Remove all the distracting chrome!” That’s great, but when do I want all this distracting chrome? Never. It should always be me and my code, with as little chrome as possible. No panels, no tab bars. Just as clean as functionally possible. If there’s anything visible to me other than the code I’m editing, there’d better be a damn good reason, that is either it gives me a sense of context (what file am I editing? Where am I within this file?) or it’s a temporary UI element that I explicitly asked for (e.g. an open file dialog). Conclusion: reduce chrome to the min.

Editor state: Another thing I observed using iOS applications: preserving UI state between application launches is very convenient. No longer do you need recreate your entire setup (open tabs, split views) between application restarts. All of that should just be persistent. We did this pretty well in Cloud9, that’s the way to go. Conclusion: near perfection UI state preservation is a must.

Remote file editing: Although all the points above this one are nice, I made them up as I worked on this project. The trigger to hack on my own editor is that I spend a lot of my time these days editing files in a virtual machine, i.e. not locally. The current version of LogicBlox runs only on 64-bit Linux, and I’m a Mac user. So, I have a VMWare Fusion VM with Linux running, with all my stuff there. I’ve wasted many hours in setting up shared folders with my Mac, using SSHFS and Fuse to share a file system, but each had its own set of problem. Eventually I broke down and switched to doing a lot of my editing inside the VM, which is highly confusing, because of course Linux keybindings are different than on the Mac. Not great. What I need is first-class support for editing files “remotely”. I realize this is not important to everybody, but hey, deal with it, this editor’s primary audience (for now) is me. Conclusion: gotta have remote file editing support.

So, what did I come up with?

Here’s a screenshot of the current state of affairs:

Some of you may instantly recognize the editor. Indeed, I have no intension in reinventing the wheel, so I’m reusing the excellent ACE editor. It’s the editor component I know best, both as a user and from a technical perspective.

Also, yes, this is a web app, built using web technologies. I’m still unsure if it should remain living in a web browser or if I should wrap it in something like node-webkit. I’m not sure. As you can see, there’s very little chrome. No menus, no button bars, only the editor and a little editor bar at the bottom which tells you which file is visible there and what’s the current line and column offset (for context). That’s it.

Navigation So how do you navigate between files? Just press Cmd-E (or Ctrl-E on non-Mac keyboards) to open up the goto UI:

This UI is heavily inspired by the Textmate Cmd-T command, of course:

However, it’s also inspired by my favorite note taking program Notational Velocity, which has a location bar that can be used both for search, but if no note’s title matches, pressing enter actually creates a new note and allows you to instantly edit it. I really like this UX concept, so I have it in my editor.

As a result the goto UI currently serves three purposes:

  1. Search for any file in your project (using a cleaned up version of this fuzzy finder implementation) and instantly navigate to it.
  2. Navigate to recently opened files, replacing the typical use case of tabs. Recently openend files will have a higher ranking score so will always appear at the top ordered by last use, so typing jumps between this and the previously opened file, typing one character is probably enough to select a recent file you want to edit.
  3. Create new files, by typing in a path that does not exist.

Editor state All editor components save their state using the state module. For instance:

  • Splits save how many splits there are and which files are loaded in which split
  • Session manager saves for recently opened files:
    • Cursor location and selection
    • Scroll state
    • Undo and redo stack
    • Last use (last time it was opened)

As a result, restarting the editor brings you back in exactly the same editor state, you can even undo changes you made in the last launch. As you switch between the different files, you’ll always end up with the edition session in the same state you left it.

Back-end As I mentioned, I often have to edit files “remotely”. At Cloud9, to support this, we built VFS which is a nice, but non-trivial piece of machinery that abstracts the filesystem and can expose both a local file system, as well as an FTP file system, as well as exposing a file system via SSH. It’s very powerful, but relies on node.js. I decided to opt for something much simpler, which is a simple RESTful interface that only really requires you to implement three RESTful APIs:

  • PUT on any path saves the body of the request to this path, for later retrieval via GET. If the content-type is text/directory an empty directory has to be created instead of a regular file.
  • GET gives back the content of the file, or in case of a directory, a JSON representation of all files in this directory.
  • POST is a general purpose RPC-like mechanism, currently it only requires a “filelist” command, which sends back a list of all files in the directory that was POSTed to, one file per line (basically the output of running the find command).

I have a simple implementation of this in PHP (yay, PHP!), which amounts to about 140 lines of code and should be easy to reimplement in whatever other language. To edit files on any server, all you’d have to do is upload one version of this script there and run it to serve the API on a certain port, point the editor to it and off you go.

Extensibility The whole thing is implemented in Javascript. I took inspiration from Cloud9 in pretty thoroughly separating the code base into separate pluggable modules. There’s a configured list of plugins that are loaded by default, you can easily add to it or remove things from it to add or disable features. Adding your own plugin is as simple as implementing a require.jsJavascript module that exposes a hook and init method.

Overall experience I’ve been using the editor for the past week almost exclusively for all my code editing and I like it a lot. I tweak a lot along the way, and I still hit Cmd-S from time, but overall I’m pretty happy with the current state. While a directory structure is inherent to any programming project today, this editor allows you to think about it more conceptually: you’re editing bits and pieces of your code in a namespace, you can select pieces in this namespace and add pieces to this namespace. Yes, of course, these translate to just directories and files, but you no longer have to worry about creating directories and files, because that’s all abstracted away and happens automatically on demand.

Anyway, this is what I work on occasionally in my spare time. It’s still a small project, amounting to about 2200 lines of my own code. As I said, it’s not ready to be used by people other than me, but if you want to, you can probably find the code (although I doubt you can get it to run).

More as this project matures.