Zed: a Status Update

A few weeks ago I [shared some thoughts on code editing](https://zef.me/5672/rethinking-code-editing). I described my spare
time project to build an editor that’s a bit different and that would suit my
needs. After a few weeks of on-and-off development I switched to the editor for
most of my work. That means not just writing code, but also writing articles and
notes — stuff that I used to do in WordPress and [Notational Velocity](http://notational.net/) before.
The working title for the project has been _Zed_, which is not very original, but it seems to stick and [nobody seemed to have better ideas](https://twitter.com/zef/status/315495268126691328). So for now, Zed it is.

A few new observations and nuggets of the current status of the project.

**Keyboard** 
Any editor that wants me to touch my mouse (or my case: trackpad)
has failed. The whole thing should be keyboard operable. Interesting side effect
is that this rules out the good old menu bar as a desirable UI element, at least
on Mac where you can only use the menu bar with the mouse, as far as I know.

So, the question is how to execute editor commands that don’t have a keyboard
shortcut, or that you don’t know the keyboard shortcut of. My first intuition
was: a Javascript REPL. If you use this editor, you can write code: just enter
whatever you’re interested as a Javascript command. However, I came back from
this idea when I watched [a few tutorial videos about
Sublime](http://net.tutsplus.com/articles/news/perfect-workflow-in-sublime-text-free-course/).
Now, I’m not a Sublime user myself. I have it installed, but I never really used
it. However, as it turns out it reuses the “Jump to file” UI idea that I first
encountered in Textmate:

src=”https://zef.me/wp-content/uploads/2013/03/textmate_intelligent_file.jpg” class=”aligncenter size-full”/>

It reuses it in what it calls the “Command Pallette”:

This is clearly a _much_ better idea, so I reused the fuzzy finder panel I
already built for opening files and now it can be used to quickly find commands
as well.

**Tree** 
So, I changed my stance a little bit on the tree. I still think it’s
pretty bad for navigating a project. However, using an editor without a tree has
showed me that for _exploring_ a project you’re not familiar with, it’s actually
pretty essential. So, I added a simple tree. Not as a persistent panel to the
left, but instead as a pop-over panel that you can open with a keyboard shortcut
and that hides again once you selected a file. Generally I’m thinking if using a
tree isn’t useful for exploring any kind of hierarchical fuzzy search view that
the user isn’t familiar with, e.g. it would also make sense for the
Sublime-style command palette. I have to explore this a bit further.

**Projects**: I’ve added the concept of projects. When you press Command-Shift-Z anywhere in Chrome, the Zed project picker shows up ordered by most recently used:

As everything in Zed, this window is 100% keyboard operable. You type in part of the name, and press return to open it in a new window. You create a new project by typing in a name that does not yet exist
and pressing return, it will then ask for the project’s URL and login credentials.

By default Zed comes with two projects: “Manual” and “Settings”. Both of those just use Zed to edit and navigate.

**Settings** 
I’ve done a lot of thinking about settings. How do you represent
settings, and how do you change them. My first go was simply giving the user a
big JSON file with all default settings filled in. For this purpose I created a
separate in-editor settings file system, which stores its files using Chrome’s sync
storage so that it will automatically be synced between all your devices. I put
watchers on the settings file, which would reload settings whenever changes were
made to the file. The result worked quite well. You could change the `theme`
setting to something else and within a few seconds you would see the colors
of all your editor windows (on all your devices) change. The one drawback is
managing this file as new settings become available. You may want to change
defaults, add new settings and those would have to magically appear in the
user’s settings file. Instead, I changed this to have a built-in
`/settings.default.json` file which you cannot modify and a second
`/settings.user.json` in which you can override the settings you’d like to
override. Some settings will also be available as an editor command and will
automatically add or update the entry in the user’s settings file.

This is what it looks like when you open both files in a split view:

In the future I’d like to add another layer at the project level. You’d be able
to create a settings file in your projects, and those settings would then
override your editor-wide settings, which in turn override the defaults settings.

**Code Complete** 
There’s only some much time you can spend in an editor before you start begging for some sort of code completion. Currently I’ve implemented three kinds of code completion in Zed:

* Word-based completion for the current file
* [Snippets](http://screencast.com/t/AYCwS0ZKE)
* CTags

[CTags](http://en.wikipedia.org/wiki/Ctags) are an ancient format for keeping an index of symbols within a project. The format is surprisingly dumb. In the days of C, with no object-oriented programming or namespaces it was probably perfect, in today’s language landscape it’s still useful, but cannot be used
as a basis of very intelligent code completion or “jump to defintion” like functionality. However,
it’s very easy to implement parsers that extract ctags from source files and to use those files. So, I
added ctags support to Zed. It can keep ctags up-to-date as you edit the file (if a `ctags` tool is defined for the language), or use `tags` files produced by tools like [exuberant ctags](http://ctags.sourceforge.net/). After using it for a while I wouldn’t want to go back, it’s pretty useful in the absence of “real” intelligent code completion.

**Extensibility** 
As I mentioned in [my previous
post](https://zef.me/5712/the-chrome-route) a Chrome Packaged App in some ways is
more constrained than a regular web app. It is not allowed to load JavaScript
from arbitrary servers, for instance, or to use `eval`. The reason is to prevent
malicious scripts to get access to the chrome APIs, which allow you to do _more_
than a regular web app allows you to do. There’s one way around that, and that’s
sandboxing. You can sandbox pages, or use the special “ tag and load
any page in there. You can communicate with this page via `postMessage`, similar
to how you work with WebWorkers.

Still, as I don’t want to sandbox the entire editor, this stops me from allowing
a user to simply specify a list of his favorite extensions located someplace on
the web, and to run that code alongside the rest of the app. So, I started to think about different extension scenarios.

Thus far I’ve been working to support extension at the level of language modes.

Just like settings, a language mode is a JSON file on the settings filesystem (under `/mode/`)
with a `default` and a `user` version. Here’s what a shortened version of `/mode/javascript.default.json` looks like:

{
 “name”: “JavaScript”,
 “highlighter”: “ace/mode/javascript”,
 “extensions”: [“js”],
 
 “tool:beautify”: {
 “scriptUrl”: “plugin/beautify/javascript.js”
 },
 
 “tool:ctags”: {
 “scriptUrl”: “plugin/ctags/javascript.js”
 },
 
 “tool:remotebeautify”: {
 “url”: “http://webfs-js.herokuapp.com/beautify/js”,
 “method”: “PUT”
 },
 
 “tool:check”: {
 “scriptUrl”: “plugin/check/javascript.js”,
 “options”: {
 “undef”: true,
 “unused”: true,
 “es5”: true,
 “esnext”: true,
 “devel”: true,
 “browser”: true,
 “node”: true,
 “laxcomma”: true,
 “laxbreak”: true,
 “lastsemic”: true,
 “onevar”: false,
 “passfail”: false,
 “maxerr”: 100,
 “expr”: true,
 “multistr”: true,
 “globalstrict”: true
 }
 },
 
 “snippet:log”: “console.log({0})”,
 “snippet:def”: “define(function(require, exports, module) {nt{0}n});”, “snippet:foreach”: “for(var {0:i} = 0; {0:i} < {1:array}.length; {0:i}++) {ntvar {2:item} = {1:array}[{0:i}];nt{3}n}”
 }

The `name` should be self explanatory. The `highlighter` is a tricky one, for
now Zed won’t offer real extensibility at this level, but only support any of the
current [ACE](http://ace.ajax.org) highlighters. If you want to add one, contribute it to ACE and make
more people happy.

The `tool:*` settings are used to implement various useful editor features:

* `check`: check this piece of code and give me back an array of errors and
 warnings (to be marked in the editor’s gutter). There’s currently implementations for JavasScript (based on JSHint), CSS (based on CSSLint) and JSON.
* `beautify`: reformat this piece of code.
* `preview`: render this piece of code into HTML for previewing (think:
 markdown, Coffeescript Javascript preview).
* `ctags`: analyze this piece of code and give me back a list of symbols (for
 navigation and completion)

In a tool object, you can specify either:

* a `scriptUrl`, which can be a local path, or a remote URL of a [require.js](http://requirejs.org)
 module that exports a single function that implements the tool in question and
 returns the result.
* a `url` in conjunction with some additional options (like the
 `tool:remotebeautify` example). In this scenario the code that is operated on is submitted to the web service at this URL.

In addition, snippets for completion can be specified with [multiple insertion
points](http://screencast.com/t/AYCwS0ZKE).

**Release** 
I think Zed is nearing the point where other people can start playing with it. This requires some additional work and especially documentation. I hope to have something to test for early adopters next week, we’ll see.