Scope-aware expanding selection using Alt+Up (like in IntelliJ)


#1

This would be a great feature to add to Atom. By pressing Alt+Up the selection expands gradually with each repeated Alt+Up. IntelliJ users will know what I’m talking about :slight_smile:

For example:

function do(something) {
  var someVar = 'hi there';
  var someVar2 = 'hello';
}

Having the cursor blinking inside the word there and pressing Alt+Up repeatedly would select:

  1. there
  2. hi there
  3. ‘hi there’
  4. var someVar = ‘hi there’;
  5. everything inside the function block, i.e. the two rows declaring the vars
  6. the function block including the { and }
  7. the whole function declaration
  8. … you get the idea

Kind of hard to describe, but download the IntelliJ Community Edition and try it out. It is one of the single best features in IntelliJ, would love to see it in Atom.


Expand selection?
#2

That sounds amazing! I’m sure I’d forget to use it but it sounds great. As a side note, does Sublime have this?


#3

Magnar Sveen wrote a version of this for Emacs, but it had to be specialized for every language. Atom’s selectors should make it much easier to write an expand-selection region by taking advantage of pre-existing grammar definitions.


#4

I’ve also been looking for an editor that has this feature.

Any update on this? Is it something that could be done with packages, or does it need to be handled by the core?


#5

To answer my own question, yes it does (kinda) - ⌘ + ⇧ + Space is ‘expand to scope’. Not sure it works exactly the same, but it’s good enough.

So back to Atom - this feature would be great! My guess is that a package could do this, but it’s probably a lot more involved than you’d think at first glance. At a guess, the scope either side of the current selection (or cursor if no selection) must be detected, then its range must be found and added to the current selection. Sounds relatively simple but there’s almost certainly going to be situations where it doesn’t work right.

And what if you have multiple cursors/selections? Good luck person-who-does-this-who’s-not-me!


#6

What’s involved in a general solution to this is an understanding of the grammar of whatever language is in the active buffer. Basically, the editor would need to have a way to have an abstract syntax tree of the text that the command could successively walk up and translate into buffer coordinates. For example, the AST for the example code might look something like this:

  • function do
    • function keyword
    • function name = do
    • parameter list
      • start paren
      • parameter = something
      • end paren
    • function body
      • start brace
      • assignment statement
        • LHS
          • var keyword
          • variable name = someVar
        • assignment operator
        • RHS
          • string literal
            • open quote
            • literal contents = hi there
              • hi
              • there
            • close quote

etc. So each ⌥⬆︎ would move up one or more steps in the tree to select more and more. I’m not sure that the way that Atom (and, by extension, TextMate) understands grammar is at a deep enough level to create this kind of structure to offer this kind of feature. IntelliJ has an advantage in that it is intended for a specific set of languages rather than all languages.

I should probably write up my rant on why all languages should have a reference lexer and parser that is open source and composable as a service.


#7

While I see where you’re coming from, Sublime (which ‘understands’ languages as much as TM and Atom do but no more (by default) as far as I know) has this functionality, not just IntelliJ. But yes, it’s probably not perfect. As such, I think my previously-stated algorithm, or some cleverer variation on it, is the (naïve) way it probably works. That said, it does appear to the the climbing-the-tree thing, whereas my algorithm wouldn’t necessarily do that, but would instead just expand the current selection outwards a scope at a time, which isn’t quite the same thing.


#8

Ah good point. So if we base it off of scopes and do a best guess …

  1. Get the “most specific” scope at the cursor using Editor.getCursorScopes
  2. Get the extent of the scope by using Editor.bufferRangeForScopeAtCursor and update the selection
  3. On the next ⌥⬆︎ look one character to the left and right of the current and if both sides offer the same scope, expand in both directions. Otherwise pick one.
  4. Rinse. Repeat.

#9

@alexrussell in reply to your side note, there’s a Sublime plugin called expand-region which does a better job at expanding the selection than the included “expand to scope”:


#10

Yup exactly. But yeah, probably far from ideal. Certainly feels like a job for a non-core package either way.

@dlee a-ha, if I’m honest I never knew about this kind of functionality so I’m not aware of its downfalls. I like the idea of it, so I’ll certainly check that package out if the default isn’t good enough.


#11

Here’s a plugin which uses the syntax highlighting scopes to expand selection:

However, it doesn’t work as you’d expect. For example, it doesn’t recognize braces as “containing” the region they wrap.

A generic implementation would need to know which regions in the current file correspond to syntactic elements, rather than just syntax highlighting regions (which are much more primitive).

http://zaach.github.io/jison/docs/ might be a good starting point.


#12

Alternatively, one could implement a selection expander based on some rule like:

  1. scan left for a left delimiter in some predefined set [’"’,"’",’[’,’{’,’<[^<>]+>’, . . .]
  2. scan right for a corresponding right delimiter

Worth noting: vim-mode already supports selecting/changing/etc in and around various delimiters. For example, to replace the text in surrounding quotes:

ci" type some text ESC

Unfortunately, this doesn’t work with Atom’s multiple-cursor support.


#13

Out of frustration for this missing feature, I implemented a package that tries to behave as close as possible to Idea’s expand selection feature. It’s far from being on par with Idea, but I find it usable for my daily needs with Atom. It also supports multiple cursors.

Give it a try.


#14

That looks awesome @mrolla! I will definitely try it out. However, why did you go with Ctrl-Cmd-W as keyboard shortcut, and not Alt-Up?


#15

No particular reason, I used to have it mapped that way when I started using it frequently in Idea and it’s kinda legacy :slight_smile: I guess I should remap it to the default Alt-Up. Opened an issue on github as a reminder, thanks!


#16

@mrolla Your package seems to be the thing i’ve been looking for (I also used it with Ctrl + W in IntelliJ’s IDE) but it’s not compatible with atom v1.12.7… Any plans to update?

Cheers
AJ