Box selection


Slow start, eh? I haven’t written a post in here since I started this blog, as I’ve been a bit, uh, distracted by other work-like things. One of those things was implementing box selection in the new editor.

Quick side note: coming up in the near future, I’ll write a bit about two extensions I put up on the extension gallery for the beta: GoToDef (ctrl+click does go to definition) and ItalicComments.

First off, here’s a video that Brittany put together on the new box selection stuff that we’ve (Brittany as a PM, Luke as QA extrodinaire, and Ameen on some of the box selection UI stuff) been working on and recently checked in:

<a href="http://video.msn.com/?mkt=en-US&#038;playlist=videoByUuids:uuids:3e57917d-1b92-4188-b898-25a1d64a408e&#038;showPlaylist=true" target="_new" title="Box Selection and Multi-Line Editing Demo">Video: Box Selection and Multi-Line Editing Demo</a>

You can jump on over to the article on the VS Editor blog to read the full announcement-y version. I wanted to share a bit about getting it written, though.

Though it’s not necessarily a technically complicated feature, it’s one of those things that ends up touching a good deal of the codebase (effectively everything that wants to know about what text is currently selected). Though I could have “hidden” box selection, in a sense, by forcing people who wanted to know about selection mode to go looking for it, I decided for the slightly more onerous path of making people who ask about the selection deal with it, at least to some degree.

It’s a somewhat irksome decision to make; an early prototype of the box selection feature went the opposite route, leaving the API alone as much as possible. While it simplified some of the cases (like asking for the selected span while the selection was in stream mode), it meant that things would fail in odd ways in box selection mode, since it was a piece of the API that wasn’t necessarily obvious. It would be kinda like having some type called Gizmo, with a property on it called GizmoText, and another property called JustKiddingcommaHereIsTheRealText. Not quite that bad, though 🙂

The scarier one is that you could have written code against the old API that didn’t change at the semantic level of the programming language (there was still a property, called SelectionSpan, that returned a SnapshotSpan), but the but the behavior at the semantic of the editor had changed, especially relative to other consumers that were doing “the right thing” with the new API.

I’m all about trying to make as few changes for consumers as possible, but if the consumer really does need to know about the change, you’re doing them a disservice by allowing the same code to compile and run before and after the change, but with different behavior.

So, the new model is a bit more complicated than the original, though it lends itself to decently simple usage (using Linq or just iterating over the collection with foreach).

A selection has a collection of SelectedSpans or VirtualSelectedSpans (yeah, I changed the tense; I don’t really have a great reason for why, besides that it sounds slightly better to me and would hopefully be a bit more obvious of a change than just adding an “s” to the old property name and making the ensuing build breaks slightly harder to figure out). The Virtual version takes into account virtual space, which is frustrating enough to deal with that it probably deserves its own blog post 🙂

In most cases, you can treat box selection and stream (regular) selection the same by writing code like:

string selectionText = string.Join(newLine, textView.Selection.SelectedSpans.Select(s => s.GetText()))

A box selection on the clipboard is just an endline-separated string; when we read it back in for a paste, we look out for a special clipboard data object (that VS has used for awhile), and take that to mean “split this string back into separate lines and insert them a line at a time.

Multi-line insertion

One of the new (at least to VS) things about the implementation is multi-line insertion mode. If you make an “empty” box selection (or make a non-empty box selection and then delete it), you can type, backspace, and delete as if you had a gigantic cursor – whatever you type gets inserted on each line, backspace deletes a character on each line, and delete behaves similarly. It may not be a feature people will use all the time, but it’s one of those nice things that makes you slightly happier a couple of minutes a week. As a recently filed bug report said, it’ll keep you from cursing me for 5 minutes each week.

So, what would you use it for? Here are a few things (most of them are covered in the video):

  • Appending something to the front of field names (depending on the file I’m in, the language it’s written in, and who wrote it: “_”, “m_”, things like that).
  • Adding “private” or “internal” in front of a set of fields.
  • Adding “//” at the beginning of a couple of lines.
  • Given a set of variable names that you’ve box selected, copied, and pasted, you could add various pieces of code around it, like “Console.WriteLine(” and “);”.
  • Since a box selection can now be entirely in virtual space, you can add a comment block past the end of a line by creating an empty box in virtual space and typing “//”
  • Whatever else you write in the comments 🙂

An interesting side-effect of being able to create box selections entirely in virtual space is that alt+click (even before you drag) sets the cursor in virtual space. Originally, I thought this felt kinda buggy, and spent a bit of time thinking about how to work around it, until I realized the use for it.

I hate lining up arguments to method calls. Seriously hate. At some point, maybe the languages in VS will make TAB be nice and emacs-y and line up arguments; until that day, I spend a couple of seconds like this:

TAB, TAB, TAB, oh, crap, too far, backspace, backspace, NO, missed it again, space, space, space, space, space, space…

Now, I’m not usually big on the mouse, being a vim guy at heart, but here’s one case where I can bow to the mouse:

var foo = some.Property.MethodCall(firstLongParameterName,
                                   **alt+click here**

Yeah, sign me up.

Anyways, comments welcome.

Comments (4)

  1. Jon says:

    Noah, thanks for posting about this. I’m the  author of ViEmu, the vi/vim emulator for Visual Studio, and I’m finding this kind of posts very valuable while I get started porting ViEmu and Codekana to VS 2010. Mainly because the very scarce documentation available! Please keep them coming.

    Word doesn’t expose all its selection model via it’s extensibility API ("object model"), and it’s a pain: you can click around to get an arbitrary multi-span selection, but an add-in can’t do that programatically. For this reason, ViEmu for Word & Outlook can’t support column selections. This is just to confirm that you made the right decision when fully exposing the underlying selection in the new VS — trying to hide stuff seems to save some effort in the beginning, but it ends up being much more costly in the long term.

    Congrats on the new IDE and best wishes towards RTM.

  2. Pleasant surprise from Microsoft

  3. Sascha says:

    Hey Noah,

    I stumbled over your blog through the italics comment plugin for VS2010 on the Visual Studio Gallery. You said in comments there you would post the source code for that soon.

    I’d definitely be interested in that since I had this cool idea for an enhancement to how comments are being displayed, and I was admittedly blown away by the new WPF visualization of comments in VS2010. Looks like you guys took some of the ideas straight from my brain 🙂

    However, I had some other ideas and would love to implement it right away, but need some help to get started. Anything you could publish would help! THANKS!

  4. noahric says:

    @Sascha:

    Still working on it, unfortunately 🙁  You can always post your questions here, or ping me on twitter (@noahsmark) or by email (my alias is noahric @ ms).

    -Noah