Friday, October 19, 2012

Commanding Orion's Editor

In a very readable (and pretty) post, Commanding Your Editor, Geoffrey Grosenbach claims that you can learn six simple commands, rather than hundreds, and instantly increase your productivity in your code editor. When I realized that the first two commands in Geoffrey's article weren't implemented by default in Orion, I thought it'd be fun to review the six commands, and how you might do the same kinds of things in Orion.

Orion's editor commands and key bindings are mostly borrowed from Eclipse, and we've not done a great job of exposing them to the end user. We've sometimes assumed people know them already from Eclipse or will figure them out. Given that we are seeing lots of activity on orionhub.org as folks try out Orion for the first time, it's probably a good time to go over some of the editor power commands. Let's start with Geoffrey's favorite six, and then add a few more.

The mighty six?

Delete whole words

The motivation is that if you have a typo, it's easier and faster to retype the whole word than to try to correct the part that's wrong. Orion doesn't specifically implement keystrokes for deleting the current, next, or previous word, but you can use Ctrl+Backspace to delete from your current position to the beginning of the word, or Ctrl+Del to delete from your position to the end. And you can use Ctrl+Left Arrow and Ctrl+Right Arrow to first navigate to the front or end of the word. I have to say that I'm much more likely to have already selected the word some other way (such as using Find) and then I simply type over it. So I haven't missed this command. If you can't live without a command to delete the current word, it sounds like the perfect candidate for an editor command extension (and perhaps I'll show how in my next post).

Add lines

Geoffrey's premise is that it's a lot faster to add a line above or below from anywhere in the line, rather than cursoring to the end of a line and hitting return. I must admit that the extra keystroke to cursor to beginning or end of a line hasn't bothered me. Once again, you'd need to write an editor command extension to get this exact functionality, but it'd be simple enough. Our current commands have evolved as committers add the ones that they miss the most.

In-file search

Now we're talking. Orion has a pretty advanced in-file search. Use Ctrl+F to open a prompt and type in the word you are looking for. You'll see the matches light up in the editor. You can move to the next match using Enter or Ctrl+K and the previous match using Shift+Enter or Ctrl+Shift+K. (You can also use the next and previous buttons in the prompt.) A number of options are available to you from the prompt menu to fine tune your search, including regular expressions.

Once you've found the word you are looking for, hit Escape to return focus to the editor, where you can type over that pesky incorrect word.

If you prefer not to move your eyes away from the editor cursor, Orion also provides an Incremental search mode (sometimes called live search in other editors) that doesn't open a prompt. To use incremental search, you use Ctrl+J to start live search. Your focus remains in the editor, but your typing applies to the search rather than the editor content. The editor status area in the toolbar will show you that you are in this mode. The editor will position you to the match (or give you a message in the toolbar if there's no match).

You can use Ctrl+J to move to the next match. Pressing Escape ends the mode.

Of course, since Orion is part of a larger development environment, you can also perform searches across multiple files and do global replacements. That's another topic completely, and is described pretty well in the Orion user doc.

Fuzzy file search

You can open other files in the editor using the Find File Named command, Ctrl+Shift+F. The popup will look for matching file names, in addition to initially offering you the files you've marked as favorites. You can use wildcards to find the file. (We could do better here, highlighting the part of the pattern that matches.)

If you are looking for path name matching, it's not currently supported from the file search. However, because the Orion editor is in a browser, you can find previously edited files by path name using the browser bar. You are of course at the mercy of your browser. Firefox does a pretty good job with this kind of path matching.

Automatic indentation

Orion's automatic indentation is pretty simple. It simply preserves the indent of the previous line. We don't (yet) recognize language specific blocks and indent. We do support automatic code formatting through plugins such as jsbeautifier.

Completion

Like Eclipse, you can invoke code completion using Ctrl+Space. Code completion has come a long way in Orion, thanks largely to the Esprima parsing engine and an Esprima-based plugin committed by our VMWare colleagues. Esprima-based content assist is now installed by default in Orion 1.0, so your code completions for JavaScript code are type-inferenced. Non-inferred proposals are also suggested (at the bottom of the list).

More mightiness

What else should you know? First and foremost, you should know that you can find a complete list of keybindings and commands in the Orion editor by pressing Alt+Shift+? (or Ctrl+Shift+? on Mac OS X).

Maximizing space

By default, the Orion editor opens with an outliner that lets you traverse your code by function. You can use Ctrl+O to hide the outliner. It's a toggle key, so you can use the same key binding to get the outliner back. You can also use Ctrl+Shift+M to "maximize" the editor, hiding the Orion banner and footer. This key is also a toggle. The end result is just the editor and its toolbar.

Navigating to errors

The Orion editor shows annotations in a ruler on the right of the source file. Most folks know you can click on these annotations, or hover on them, to find out about errors and warnings in your file. Power users know that you can quickly move between annotations using Ctrl+. to move forward, or Ctrl+, to move backward. This works great for correcting errors that our built-in jslint validator finds.

Toggle line comment

You can use Ctrl+/ to comment or uncomment a line of code. This works great when you are working with tracing logs or other debug code that you often toggle on and off.

Moving lines around

You can use Alt+Up Arrow and Alt+Down Arrow to move the current line up and down. If you have more than one line of text selected, you can use these commands to move multiple lines up and down without precisely selecting the whole lines. Adding the Ctrl key to use Ctrl+Alt+Up Arrow and Ctrl+Alt+Down Arrow will copy the line(s) around.

Deleting a line

You can use Ctrl+D to delete the current line. If you have more than one line of text selected, you can delete them all without precisely selecting the whole lines.

Goto line

You can use Ctrl+L to go to a particular line by line number. This is especially useful when you see an error in the browser debugger and you want to quickly go to the offending line in Orion.

Going forward

We certainly hope to do a better job of exposing all the powerful commands that the Orion editor provides. And we hope to see the community continue to add commands using our extension mechanisms. If you have your own ideas about "can't live without" editing commands, please consider writing an Orion plugin that contributes some of these! In a future post I'll show how simple that is. Some of our most powerful features started out as a plugin hosted at somebody else's site, and then became so widely adopted that they've been contributed back into the Orion base platform.

Thanks to Geoffrey Grosenbach for sparking the conversation (and for not naming his post something like "Six Brilliant Editor Commands You Must Know"). Thanks also to colleague Mark MacDonald for suggesting some of the Orion commands to mention (he is much more the power user than me!)

Thursday, October 4, 2012

More CSS, less JS: Orion Page Layout

We're in the "end game" of the Orion 1.0 release, and I realize that one of my bigger efforts won't surface in any of our end-user oriented New and Noteworthy lists. This summer, I revamped our JS-based approach for page layout and instead use mostly CSS for our layout and animation. Why didn't we do this in the first place? Here's a story about that.

Viewports and layout

Our very first Orion page was our editor. Given that a user might be editing a huge file, and working with only a small part of it, the editor does not render the entire document. It adds elements to the DOM as needed. The browser page can't do the scrolling since it doesn't know about the editor viewport. That meant we needed to pin the page footer to the bottom of the editor page, giving the editor the chunk of real estate between the header and footer.

We found that dijit's BorderContainer managed exactly this kind of layout and happily delegated the positioning work to this widget. This approach was adopted for the rest of our Orion pages. It didn't immediately occur to me that the editor layout was really a special case, until I started watching sites like github move to skinnier headers (and the requisite fatter footers). As footers became fatter (taller?), the fact that our footers were unnecessarily pinned to the page bottom really started to bother me. Shouldn't we be able to have a bottom area under a split main panel, but not have to pin it to the bottom?

The pain of a hybrid approach

That wasn't the only thing bugging me. Most of our UI implementation does not use dijit widgets. We have many of our own UI components, such as the editor, navigator, and compare view. We rely on dijit for things like menus, dropdowns and dialogs. It turns out that using dijit layout mechanisms to manage both dijit and non-dijit components is a pain. The dijit layouts very nicely handle the ripple associated with widget size changes and layout. But if your component is not a dijit widget, you end up with code that has to walk up the DOM looking for dijit layout managers to inform about what you've just done in the DOM. This just felt...errr....wrong. Note I'm not saying dijit layout is bad, just that a hybrid approach is bad. We needed to either embrace the dijit widget and layout model with all our components, or stop using dijit layout. The first idea wasn't viable because folks who consume our editor don't want to bring in a library they don't already use. And doesn't the rest of the world just use CSS?

Leaner layout

After looking at a few different grid systems and site templates, the first thing to decide was whether we were trying to build a generic grid and layout system or just solve our own problems. Orion plugins are either contributing behavior to our pages or linking to their own. Since it doesn't matter to us how you accomplish your layout, our solution needn't be too general or generic (a departure from our Eclipse thinking!)

Page regions

A quick tour of our pages showed that we have (at most) four regions to contend with. The header, the footer, an optional side panel, and main panel. The CSS classes use this terminology throughout. The model is one of a "side panel" defaulting to 1/3 width on the left and a "main panel" taking the rest of the room. A page always has a fixed header but may have a fluid footer (at the bottom of content) or a fixed footer on the bottom of the page. Part of the exercise in establishing this model was separating out the layout classes from the other styling, moving all of our layout related css to its own layout file.

Splitters

A missing piece was the splitter. By keeping the splitter very particular to Orion's model of a vertical split between side and main panel, this was only a couple hundred lines of JS, including reasonable documentation. Splitter classes in the CSS control the default positioning and animation effects. The splitter is the only JS code managing any of our main page layout.

CSS Transitions

We previously relied on dojo's animation features to animate the effect of the side panel opening and closing. Now we've adopted simple CSS transitions for animating this effect. The downside is that you won't see the animation at play in older browsers like IE9, but the upside is that the animation is smoother, faster, and less buggy.

Some details

If you read the CSS, you'll see it's mostly about the concepts I've described here. A few more details are involved.

Toolbars

Classes dealing with the toolbar ensure that the toolbar maintains a fixed vertical position and that message bars and input bars appear in the right place underneath the toolbar, letting the rest of the main panel scroll.

dijitManagesLayout

We have some CSS classes for pages to use if they are still using dijit layout widgets inside their implementation. At that point, it's up the page to deal with any "hybrid" problems when dijit is managing non-dijit widgets. We just need to know when dijit layout is taking over.

Fluid footers

So where are those fluid footers? Since our footer is still pretty skinny, there wasn't a crying a need to revisit the footer content and pinning behavior for 1.0. Even so, I'm very happy with the result of this effort. We got rid of a lot of code, the animations are smoother, the DOM is simpler to debug, and our CSS is better organized.