ACE.js: In-Browser Code Editing Finally Solved You may have seen them around -- "in-browser code editors" are text editors that run on the web in your browser, supporting editing, syntax highlighting, indentation, and other features familiar from a desktop editor/IDE like Emacs, Eclipse, or TextMate. Compared to desktop editors, the in-browser knock-offs I've seen leave me quite dissatisfied. I can deal with the lack of power-user features, but just in terms of basic usability, these web-based editors are sputtering at the starting line. On the whole, they feel unresponsive on small files, they slow to a crawl on large files, and they tend to have unaddressed quirks, artifacts, and differences from native appearance and behavior. Anyway, that's enough negativity; I have a lot of respect for the authors and their hard work, and in writing ACE I'm standing on their shoulders. But I was curious to see if I could take AppJet's editor to the next level and approach the speed and robustness of a desktop editor. After a few months of work, I'm proud to declare success. Here's a walk-through of ACE.js, our new in-browser code editor. ACE.js is a self-contained, cross-browser JavaScript file that allows a web page to embed scrolling panes of editable code. Typing text is snappy and there are no visual artifacts or clutter. Syntax-highlighting happens live, as you type. Amazingly, operations scale up well with document size. You can paste in 1,000 lines of text, or more, and after a second or two of thought, the editor is fully responsive again. While you keep typing, it unobtrusively finishes syntax-highlighting the whole buffer in a matter of seconds. Local edits to the text are just as fast on long documents as on short ones. Changes that require large-scale re-highlighting, like opening or closing a multi-line comment, affect the text in view almost instantaneously, and then ACE.js quitely goes to work on the rest of the document over the next few seconds without holding you up. ACE.js supports advanced features like Emacs-style unlimited undo, flashing matching parentheses as you type them or move across them, and basic auto-indentation. Full functionality is supported across Internet Explorer 6+, Firefox 2+, Safari 3+, and Camino 1.5+. I've emphasized "scalability" a lot so far, by which I mean efficiency and responsiveness in the face of large documents, because that's the aspect of ACE that so clearly sets it apart. But that's only one of three "axes" that the ultimate editor needs to excel on. The second is what I'll call "nativity", meaning how close the editor comes to the gold standard of the desktop editor experience. This includes responsiveness (some in-browser editors have sluggish typing even on small documents), but also things like undo, copy/paste, selection, arrow-keys, shift-arrow-keys, different input methods and devices, and so on. The third axis is "flexibility". How easy is it to add features? To support more languages for the incremental highlighting, different undo models, different indentation schemes, macros that expand as you type, auto-complete, go-to-line by number, and whatever else you can imagine. Why am I lecturing you on these theoretical principles? Well, there's an interesting insight that explains a lot about the existing crop of editors, and it isn't one you'd hit upon without spending a lot of time in the trenches (yes, specifically the trenches of writing an in-browser code editor). Based on the hodge-podge of facilities that browsers happen to make available, you basically end up with the following slogan: "scalability, nativity, flexibility, pick any two". Based on this, we can classify editors into three types, which I'll describe briefly from the point of view of someone writing an editor (like me); if you're not familiar with browser scripting, hopefully this won't be too hard to get through. Type I editors sacrifice scalability. The typical implementation is a text-area to handle the typing, covered by a block of colored text to handle the display. You (the person making the editor) get a boost in nativity at the start, because you inherit the browser's text handling, all the stuff I mentioned above, like undo and copy/paste. The degree of flexibility is also good, because you can style the colored text independently of the editing in the textarea, and you can manipulate the textarea easily, such as by assigning a new content string. Unfortunately, this scales quite badly with document size. The good Type I editors are slick and responsive, but pretty limited in how large files can get. Type II editors sacrifice nativity. This is the kind of editor where you manually manipulate document (DOM) nodes as the user types. You have to re-implement the desktop's native editing behavior from scratch, first putting in support for typing and selecting text (both by mouse and keyboard), and hopefully eventually supporting undo and copy/paste with other programs (through some elaborate hack). This type is attractive because it offers unlimited flexibility, and theoretical scalability. In practice, you end up with mostly flexibility, because getting the nativity right is such a huge task, and scalability takes a back seat to general responsiveness. Type II editors are fancy but feel slow and quirky. Type III editors, as you've probably guessed by now, are the category ACE falls into, and are the ones that sacrifice flexibility, the third axis, though in fact they make you work for all three axes. The crazy idea here, which seems to have originated with Dutch programmer Marijn Haverbeke, is to take advantage of a browser feature called "design mode" (or "content editable"), a mode which allows the user to directly edit an HTML document. This feature has quietly been added to all major browsers over time. In fact, it's what GMail uses to let users compose rich-text e-mail. The advantages of basing an editor on a design-mode buffer are that such a buffer has a full DOM (document model), which allows arbitrary styling and swapping of parts of the document, and that native editing operations (selection, copy/paste) are mapped by the browser onto operations on the DOM. What's the downside of a Type III editor? It's a nightmare to implement! GMail skirts the issue by only using hard-coded browser commands like "make the selection bold" or "insert unordered list". What happens if you stray from this set of basic commands, and access that alluring DOM directly, without careful preparation? Disaster! Building a robust, extensible editor on top of design mode is kind of like landing a man safely on the moon, where you design the spacecraft, the mission control computer, and the pressurized suit. You're constantly trying to insulate yourself from a hostile environment. More specifically, any change your editor makes to the design mode DOM causes the browser to instantly lose track of the selection range or insertion point if any, the undo history, and basically any other useful editing state. (This can be worked around with a lot of selection manipulation, though IE in particular lacks even a way to access the current selection relative to the DOM.) A simple edit like the user pressing the "enter" key to start a new line may cause the browser to insert a line break tag (BR), or split a block element into two, whatever it wishes. Pasted text is converted into HTML, through a somewhat arbitrary process, and inserted into the document. In fact, the DOM is constantly being modified by the browser in response to user actions (like typing), and you have to peek at it and efficiently make sense of it, determine what's changed, incorporate it into your representation, make any of your own changes (e.g. indent a line), modify the DOM to display your changes to the user, and have it all look like nothing special happened. A more Draconian policy for dealing with the browser, like trapping all mouse and key events, would just leave you with a Type II editor. The key is to treat the DOM as a hugely complicated I/O device between you and the browser, and carefully make rules to constrain it. You also deal with the fact that design mode's "native" behavior is HTML-oriented, not text-oriented, and the fact that it tends to have a lot of quirks and bugs. You don't get scalability for free, either, you need some clever data structures. For example, determining the absolute line number of the blinking insertion point is an order-of-document-size operation without the aid of efficient data structures that can be maintained as the document changes. The plus side is that once you've systematically beat design mode into submission, you can have an unmatched degree of scalability and nativity. From there, it's just a matter of keeping your layers of abstraction scalable, and being aware of "nativity"-style constraints (like responsiveness and events), and you can build up to flexibility, the crown jewel. The reward is how easy it is to add new editor features! Speaking of which, here is a list of current ACE features. Some of them are small and just required recognizing their benefit, while others are more significant. Some features, like "Emacs-style undo" and "highlight matching parentheses", are significant despite having been implemented in a couple hours each, and are signs of what's to come in the future of ACE. General - Numbered lines - Correct vert/horiz scroll-bar behavior - Handles large documents (thousands of lines, but see "quirks") Browser support - Internet Explorer 6+, Firefox 2+, Safari 3+, Camino 1.5+ - Text size scales with page when changed by user Syntax highlighting - Correct JavaScript syntax (including regular expression subtleties) - Extensible for other programming languages - Incremental rehighlighting with minimal recalculation for each edit - Highlight live as you type - Moves highlighting task to background if not finished right away Editing - Emacs-style unlimited undo - Native copy/paste, within editor and with other programs - Highlight matching (or mis-matched) parentheses, brackets, and braces - Basic auto-indentation - Multi-stroke international characters on Mac Interface - Import/export text string - Toggle editor between ACE and textarea - Resize, focus, register key event handlers - Multiple ACE editors allowed per page - Packaged in one JavaScript file - Can be created inside an iframe, any domain, any nesting Future - Super-extensible - More languages? - Smarter auto-indentation? - Indent/unindent selection? - Auto-complete? - Macros? - User extensibility, a la Emacs?? Bugs/Quirks - Firefox 2/3: Document height and width are limited to 32767 pixels (about 2,045 lines of text at default text size) due to Firefox bug, not scheduled for resolution for FF3 launch ====== >> TO ADD: - link to demo - what to {say,ask} about {interest, use, licensing, source}? ACE.js: In-Browser Code Editing Finally Solved You may have seen them around -- "in-browser code editors" are text editors that run over the web in a browser, supporting editing, syntax highlighting, indentation, and other features familiar from a desktop editor/IDE like Emacs, Eclipse, or TextMate. Compared to desktop editors, the in-browser knock-offs that I've seen leave me very dissatisfied. I can deal without the power-user features, but just in terms of basic usability, these web-based editors are sputtering at the starting line. On the whole, they feel unresponsive on small files, they slow to a crawl on large files, and they tend to have unaddressed quirks, artifacts, and differences from native appearance and behavior. Anyway, that's enough negativity; I have a lot of respect for the authors and their hard work, and in writing ACE I'm standing on their shoulders. But you see, I tend to approach projects like this with super-high standards, dangerously so even. Luckily, after months of work here at AppJet, there's a happy ending. [[="I tend to approach projects with super-high standards" is a bit awkward - sounds like tooting your own horn too much for my taste=]] Here's a walk-through of ACE.js, our new in-browser code editor. It's [[="it" the walkthrough? or "it" the browser?=]] written in self-contained, cross-browser JavaScript that can be dropped into any web page. It looks and feels a lot like a "native" editor, meaning typing is fast and there are no artifacts or clutter. It does syntax-highlighting live, as you type. Amazingly, it scales up with document size. You can paste in 1,000 lines of text, or more, and after a second or two of thought, the editor is fully responsive again. While you keep typing, it unobtrusively finishes syntax-highlighting the whole buffer in a matter of seconds. Local edits to the text are just as fast on long documents as on short ones. Changes that require large-scale re-highlighting, like opening or closing a multi-line comment, affect the text in view almost instantaneously, and then ACE quitely goes to work on the rest of the document over the next few seconds without holding you up. Advanced features include Emacs-style unlimited undo, flashing matching parentheses as you type them or move across them, and basic auto-indentation. Full functionality is supported on Internet Explorer 6+, Firefox 2+, Safari 3+, and Camino 1.5+. I've emphasized "scalability" a lot so far, by which I mean efficiency and responsiveness in the face of large documents, because that's the aspect of ACE that so clearly sets it apart. But that's only one of three "axes" that the ultimate editor needs to excel on. The second is what I'll call "nativity", meaning how close the editor comes to the gold standard of the desktop editor experience. This includes responsiveness (some in-browser editors have sluggish typing even on small documents), but also things like undo, copy/paste, selection, arrow-keys, shift-arrow-keys, different input methods and devices, and so on. The third axis is "flexibility". How easy is it to add features? To support more languages for the incremental highlighting, different undo models, different indentation schemes, macros that expand as you type, auto-complete, go-to-line by number, and whatever else you can imagine. Why am I lecturing you on these theoretical principles? Well, there's an interesting insight that explains a lot about the existing crop of editors, and it isn't one you'd hit upon without spending a lot of time in the trenches (yes, specifically the trenches of writing an in-browser code editor). Based on the hodge-podge of facilities that browsers happen to make available, you basically end up with the following slogan: "scalability, nativity, flexibility, pick any two". Based on this, we can classify editors into three types, which I'll describe briefly from the point of view of someone writing an editor (like me); if you're not familiar with browser scripting, hopefully this won't be too hard to get through. [[= I'm not a huge fan of "type I-II-III" nomenclature. It's totally opaque. And in this case, they don't even form a continuum, except for type III being better than I and II. =]] Type I editors sacrifice scalability. The typical implementation is a text-area to handle the typing, covered by a block of colored text to handle the display. You (the person making the editor) get a boost in nativity at the start, because you inherit the browser's text handling, all the stuff I mentioned above, like undo and copy/paste. The degree of flexibility is also good, because you can style the colored text independently of the editing in the textarea, and you can manipulate the textarea easily, such as by assigning a new content string. Unfortunately, this scales quite badly with document size. The good Type I editors are slick and responsive, but pretty limited in how large files can get. Type II editors sacrifice nativity. This is the kind of editor where you manually manipulate document (DOM) nodes as the user types. You have to re-implement the desktop's native editing behavior from scratch, first putting in support for typing and selecting text (both by mouse and keyboard), and hopefully eventually supporting undo and copy/paste with other programs (through some elaborate hack). This type is attractive because it offers unlimited flexibility, and theoretical scalability. In practice, you end up with mostly flexibility, because getting the nativity right is such a huge task, and scalability takes a back seat to general responsiveness. Type II editors are fancy but feel slow and quirky. Type III editors, as you've probably guessed by now, are the category ACE falls into, and are the ones that sacrifice flexibility, the third axis, though in fact they make you work for all three axes. The crazy idea here, which seems to have originated with Dutch programmer Marijn Haverbeke, is to take advantage of a browser feature called "design mode" (or "content editable"), a mode which allows the user to directly edit an HTML document. This feature has quietly been added to all major browsers over time. In fact, it's what GMail uses to let users compose rich-text e-mail. The advantages of basing an editor on a design-mode buffer are that such a buffer has a full DOM (document model), which allows arbitrary styling and swapping of parts of the document, and that native editing operations (selection, copy/paste) are mapped by the browser onto operations on the DOM. [[= It's not clear how Type III editors sacrifice flexibility =]] What's the downside of a Type III editor? It's a nightmare to implement! GMail skirts the issue by only using hard-coded browser commands like "make the selection bold" or "insert unordered list". What happens if you stray from this set of basic commands, and access that alluring DOM directly, without careful preparation? Disaster! Building a robust, extensible editor on top of design mode is kind of like landing a man safely on the moon, where you design the spacecraft, the mission control computer, and the pressurized suit. You're constantly trying to insulate yourself from a hostile environment. More specifically, any change your editor makes to the design mode DOM causes the browser to instantly lose track of the selection range or insertion point if any, the undo history, and basically any other useful editing state. (This can be worked around with a lot of selection manipulation, though IE in particular lacks even a way to access the current selection relative to the DOM.) A simple edit like the user pressing the "enter" key to start a new line may cause the browser to insert a line break tag (BR), or split a block element into two, whatever it wishes. Pasted text is converted into HTML, through a somewhat arbitrary process, and inserted into the document. In fact, the DOM is constantly being modified by the browser in response to user actions (like typing), and you have to peek at it and efficiently make sense of it, determine what's changed, incorporate it into your representation, make any of your own changes (e.g. indent a line), modify the DOM to display your changes to the user, and have it all look like nothing special happened. A more Draconian policy for dealing with the browser, like trapping all mouse and key events, would just leave you with a Type II editor. The key is to treat the DOM as a hugely complicated I/O device between you and the browser, and carefully make rules to constrain it. [[= Genius analgy, IMO. :) =]] You also deal with the fact that design mode's "native" behavior is HTML-oriented, not text-oriented, and the fact that it tends to have a lot of quirks and bugs. You don't get scalability for free, either, you need some clever data structures. For example, determining the absolute line number of the blinking insertion point is an order-of-document-size operation without the aid of efficient data structures that can be maintained as the document changes. The plus side is that once you've systematically beat design mode into submission, you can have an unmatched degree of scalability and nativity. From there, it's just a matter of keeping your layers of abstraction scalable, and being aware of "nativity"-style constraints (like responsiveness and events), and you can build up to flexibility, the crown jewel. The reward is how easy it is to add new editor features! [[= I'm kind of confused here. You said ACE is a type III editor, sacrificing flexibility, but now you say that ACE *has* flexibility. Huh? =]] Speaking of which, here is a list of current ACE features. Some of them are small and just required recognizing their benefit, while others are more significant. [[= awkward sentence =]] Some features, like "Emacs-style undo" and "highlight matching parentheses", are significant despite having been implemented in a couple hours each, and are signs of what's to come in the future of ACE.