How to highlight line ( or region ) from package?


#1

I would like to add/remove highlight for line (or text region) from my code.

I’m able to do this by modifying editorView.lineElementForScreenRow(lineNo) ( add ‘my-highlight’ class for example ), but because line elements are rebuilt at scroll this change is temporary.

Can someone point me how to do it properly? How normal selection is implemented? It looks like it’s some kind of absolutely positioned overlay but I can’t find it in the tree.

I’ve seen highlight-line package but I want to have custom style for arbitrary line number, not only selected line and torn on/off this programmatically

Cheers,
Andrey


#2

Selection is implemented by drawing absolute regions in the underlayer div. As for your question, you should register to the screen-lines-changed event on the EditorView to get notified when lines on screen are redrawn and then decorates the lines with you class.


#3

Thanks! I was going to use editor:display-updated event based on what I saw in https://github.com/atom/bookmarks/blob/master/lib/bookmarks.coffee#L11


#4

I could be wrong, but it sounds a lot like you’re describing Markers:

Reprents a buffer annotation that remains logically stationary even as the buffer changes. This is used to represent cursors, folds, snippet targets, misspelled words, and anything else that needs to track a logical location in the buffer over time.


#5

Just trying to find out how to best solve a similar issue and have browsed the Marker documentation.

Unfortunately I’m very new to the atom api and then I lack a lot of other infos as well. In practice: what is the best way to highlight something in atom? Should I associate some class using lineElementForScreenRow or should I go with markers? If Markers is the “correct way”, the documentation does not give any clue about what ‘properties’ are and how to use them.

Any help would be great. Code sample would be even better :smile:

In case adding a class to the line element is the way to go, where I find some documentation that describes how I do that, where I should put the corresponding css file, and how do I tell atom to use that css (if necessary)?

Thanks in advance for all the help.


#6

Well, it depends on whether you want to call attention to entire lines or whether you want to call attention to certain sections of code that may or may not span across line boundaries.

The Atom Lint package is a good example of how to use Markers:

You may want to look at the code for that package for examples.

As far as decorating whole lines, you may want to look at the new Gutter API that @benogle created:

Hope that helps!


#7

This is about to get a whoooole lot easier. With the new react editor, there is a new ‘decoration’ API that can decorate marker regions.

For background, a Marker is the data representation of a chunk of the buffer. There is nothing visual inherently associated with a Marker. Markers move with the text, and can grow and shrink, but they are just models that emit events.

A ‘Decoration’ is a way to render a Marker visually. They will follow the marker around and render efficiently so you dont have to think about it.

This is how you use it:

marker = editor.markBufferRange([[5, 0], [5, 10]], invalidate: 'inside')
editor.addDecorationForMarker(marker, type: 'gutter', class: 'my-sweet-class')

This will allow you to add classes to gutter lines (type: ‘gutter’), add classes to code lines (type: ‘line’), or highlight your marker’s ranges in the buffer (type: ‘highlight’; these look like selections, but with your styling).

It’s still in flux, but should be solid really soon. Some of it isnt out yet (highlight types).

The builtin git-diff, and bookmarks use this right now for the react editor:
https://github.com/atom/git-diff/blob/master/lib/react-git-diff-view.coffee#L110


#8

Great! I’m writing debugger package, so I need a way to highlight breakpoint marker, current line and current expression. I was going to write a bunch of code very similar to what linter have but it seems that it’s much easier now - everything you mentioned solves exactly what I need


#9

@benogle great news here. I’ve just studied a bit the linter code as @leedohm suggested and if I’m not wrong I would need to instantiate a new View subclass, use markers to keep track of where the text is, react to update events in order to move the view with the text, make conversions from text positions to pixel positions and so on. It looked like a lot of work to do for something as simple as highlighting a piece of text. What is worse is that it would have been all code duplicating what several other packages already do. The decoration API seems to solve the problem brilliantly.

At the time I’m writing (v. 103) the addDecorationForMarker method is not defined on editor objects (this is what I understand from a brief interaction with the atom console). Do you think that the new API will be part of v. 104?


#10

Hi, I’ve done some research and I think I came up with a solution which requires as little code as possible. The decoration API described above would greatly simplify it, but in the meanwhile I thought that the following could be useful to share:

{ View } = require 'atom'

module.exports =
class HighlightView extends View

  @content: ->
    @div ""

  initialize: (editorView, range)->
    @editorView = editorView

    start = editorView.pixelPositionForScreenPosition( range.start )
    end = editorView.pixelPositionForScreenPosition( range.end )
    { lineHeight } = editorView
    this.css {
      position: "absolute",
      top: start.top,
      left: start.left,
      width: end.left - start.left,
      height: lineHeight,
      border: "1px solid",
      "background-color": "blue",
      opacity: 0.3
      }

    @editorView.underlayer.append(this)
    # you can remove the highlight by calling this.remove()

I got most of the background info by browsing the linter package (as suggested by @leedohm) . I feared I would need to update the view position during scrolling, etc. However, by appending the view to the underlayer this was not necessary and the result is not as complex as I thought initially.

For the beginners (like myself), to get the editorView you can call atom.workspace.getEditorViews().

By the way, I could not find a way to get the “active” editor view. Any hint?


#11

The decoration api is only available on the react editor (and should be available in 0.103). Go into settings and enable the “Use React Editor” option. We’re pushing to get the react editor out the door as the default editor. It should be the default very soon.


#12

Also, I wouldnt put much effort into doing it without the new decoration API. There are a lot of considerations (see find and replace MarkerViews!) and it’s hard to get right.


#13

can’t see any reference to addDecorationForMarker anywhere in atom code installed ( mac, 0.103 ), I grepped whole “/Applications/Atom.app/Contents/” folder


#14

@benogle I tried in ubuntu / 0.104 and I can see class is added to gutter what I do

editor.addDecorationForMarker(marker3, {type: 'gutter', class: 'my-sweet-class'})

‘my-sweet-class’ is added to gutter line in elements panel and my style applied to it
But nothing seems to happen when I use ‘line’ and ‘highlight’ style. ( expected: elements added to overlay / selection with ‘my-seet-class’, visible on screen ( gray background / red borders in my case, I can see it in gutter and it’s a global css rule, not gutter specific )


#15

I’m not great with the release numbers, as I dont manage the releases. Both line and highlight decorations should be out now in 106. There is an issue with line decorations where they dont span the whole width of the editor, though. You can fix that with a .react.editor .lines .line {width: 100%;} in your user.less for now.


#16

Thanks! gutter and line works great as expected but ‘highlight’ region is always single line on top of the editor. Atom 0.106 / osx


#17

My guess is that you are styling .my-highlight-class. But with highlights, you’ll need to style the .my-highlight-class .region. Selections and find and replace result highlights now use decorations and are a good example.

.editor .my-highlight-class .region {
  border: 1px solid red;
}

#18

That worked! Thank you!


#19

Glad to hear. I cant wait to get this out there with proper info around it. Let us know what you make with it!


#20

everyone reading this topic - fyi since 0.110.0 api has changed

Editor::addDecorationForMarker is now Editor::decorateMarker and it now returns a Decoration object
Editor::removeDecorationForMarker is now Decoration::destroy
Added Decoration::update to modify the decoration