Selecting contiguous buffer range with a scope selector


#1

I’m trying to build a package where I select a contiguous text-block under the cursor based on the scope descriptor (basically a block that has a given syntax highlight scope) - specifically a block of latex maths within a pandoc-flavor markdown file.

I’ve been trying to use editor.bufferRangeForScopeAtCursor(".markup.math.block.pfm") however I only get the range on the current row - it does not automatically select the whole block that is scoped by “.markup.math.block.pfm”. Does anyone know how to make this happen?


#2

Files are tokenized line-by-line in Atom. I don’t think you’ll be able to coerce the existing API to do what you want. So I’d write a chunk of code that:

  1. Gets the buffer range for the scope at the cursor on the current row
  2. If the same scope exists at the last character on the previous row, repeat on the line previous
  3. If the same scope exists at the first character on the next row, repeat on the line next
  4. Coalesce all the ranges into one range

#3

Ok that will probably be the quickest in the short term, but how does the syntax highlighter do it’s thing then? Presumably at some point it has to understand multi-line blocks so that scopes can be applied - surely it should be possible to tap into that system at some point?


#4

The grammar passes the ending state from one line to the next. See:


#5

Ah right, thanks. Actually that might still be useful later - I could try hacking a grammar that generates marker ranges for the blocks of interests as it goes through the document. Will start with your method though, probably easier for now, cheers.


#6

I have this same need, my lib annotates Ruby files (https://atom.io/packages/seeing-is-believing), and it would be nice for it to work on a codeblock inside of Markdown. However, there does not appear to be a way to select the Ruby code from the codeblock.

Example, consider this markdown:

This is markdown

```ruby
'this is Ruby'
a = 1 # <-- place the cursor here
a + a
```

And this is markdown again

Then I want to get the text from 'this is Ruby' through a + a. I also looked at the Markdown source code and found a few useful things, but the OP already pointed them out, and I had the same issue (that the selector only selects the line, not the block).

I’m sure there’s a way to do this, but I looked around for a while and don’t see it, but how do I select the text that matches a scope? eg given that editor.getCursorScope().toString() returns ".source.gfm .markup.code.ruby.gfm .source.embedded.ruby .constant.numeric.ruby", how do I select all the text under .source.gfm, which I’d expect to be the entire file, or under .markup.code.ruby which might be the text I’m interested in.


#7

So you can use editor.bufferRangeForScopeAtCursor('.source.ruby') to get the range of a scope if you have a cursor inside it. You can then select that range. For embedded code, you may need to scan through each row in the document (place a cursor at (0,0), (0,1), (0,2), and so forth and check until you find the scope).


#8

Didn’t work for me, I tried on the example provided, with the cursor where the comment says to put it:

> atom.workspace.getActiveTextEditor().bufferRangeForScopeAtCursor('.source.ruby').toString()
"[(4, 0) - (4, 34)]"

#9

That works just fine, it just tells us that the scope range only covers a single line and you’ll have to go through each line to find out where the embedded code is.


#10

That means it can’t be composed. A dev can work with the entire document or the current line, but not the current chunk of code. I can’t think of any reason for it to be this way, so it’s probably incidental complexity from some optimization around syntax highlighting.


#11

If you have a set of lines that are consecutive, you can figure out the chunk of code. In this case, the code chunk will not end in the middle of a line, so you don’t even have to remember the columns. You just have to check for rows that are next to one another.