TokenTokenMaker and hex in assembly

Post a reply

Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :arrow: :| :mrgreen: :geek: :ugeek:
BBCode is ON
[img] is ON
[flash] is OFF
[url] is ON
Smilies are ON
Topic review
   

Expand view Topic review: TokenTokenMaker and hex in assembly

Re: TokenTokenMaker and hex in assembly

Post by robert » Tue Mar 27, 2012 3:22 am

Yes, looks like you're right. See the implementation of RTextArea#find(). It's using SearchEngine.find() to find all locations of the selected word; that method moves the caret to select the next match, so markAll() does one last setCaretPosition() after marking everything to move the caret back to its original position. And each caret change resets the timer.

Maybe as a workaround, in your callback, disable the support's listener before calling markAll() and re-add it afterwards? I admit that's quite a terrible hack, but I think it should work. The ultimate solution would likely be to move markAll() into SearchEngine and have it not move the caret around.

Re: TokenTokenMaker and hex in assembly

Post by Vicne » Sun Mar 18, 2012 10:10 am

Vicne wrote:I guess there is something else in my code refreshing the view regularly that interferes with the setCaretPosition() in markAll()... I'm having a look.

OK. Doesn't look like it's linked to my other code in the end.
I think we have a loop effect: we manually move the caret to a given place, the updateCaret() listener method is called and restarts the timer. After it fires, it calls markAll(), which calls setCaretPosition(), which fires a state change... ant the updateCaret() listener is called again.
So we have a neverending update at the rate of one call every <delay> :-(

I admit I don't see a way to solve this apart from rewriting markAll()...

What's your feeling ?

Kind regards,

Vicne

Re: TokenTokenMaker and hex in assembly

Post by Vicne » Sun Mar 18, 2012 9:42 am

I believe the darker yellow colored region is the default "mark all" color. I think the problem here is twofold. First, you still have the default mark occurrences functionality enabled, which you don't want to do since you're providing your own substitute functionality with MarkAllOccurrencesSupport. Not really a problem, but something to note.

Oh, yes, indeed, I had forgotten green was not the default for highlights. Sorry.
I disabled the default highlighting and i now only get the new one.
The second problem is a bug in the code snippet I provided earlier.
Note the bug was that the second parameter to JTextComponent.getText(int start, int len) is the length of the string to get, not the end offset.

I see. No problem.
By the way, the end-start+1 is correct, but there is a "Caret c = textArea.getCaret();" missing at the beginning of course. Not a big deal.

Hope this helps!

Definitely. I'm getting close (errr, I should say you are getting close ;-))
But there's still a glitch :-(

The highlights work, but every time the timer fires (every second), it brings back the "caret" line in the view. In other words, if you have a 200 lines text shown in a 100-line view (so only half of it is visible) and line 1 is currently highlighted, if you try to scroll down to see the second half of the text, the text will jump back to the start, which is really annoying :-(

I think this is due to markAll() fiddling with setCaretPosition() to search for occurrences, causing "state changed" events to be fired on the caret, which in turn cause the line highlighter to be brought in view.

Does it make sense ? Is there a simple way to avoid this ? Having a one-shot delay at each caret position change instead of a repeating timer maybe ?

Edit : now wait, it doesn't repeat. I guess there is something else in my code refreshing the view regularly that interferes with the setCaretPosition() in markAll()... I'm having a look.

Kind regards,

Vicne

Re: TokenTokenMaker and hex in assembly

Post by robert » Sat Mar 17, 2012 11:22 pm

Don't worry about asking lots of questions. It's good to know that folks are using the library other than just me!

I believe the darker yellow colored region is the default "mark all" color. I think the problem here is twofold. First, you still have the default mark occurrences functionality enabled, which you don't want to do since you're providing your own substitute functionality with MarkAllOccurrencesSupport. Not really a problem, but something to note.

The second problem is a bug in the code snippet I provided earlier. I think your actionPerformed() method should be:

Code: Select all
public void actionPerformed(ActionEvent e) {

    textArea.clearMarkAllHighlights();
    if (c.getDot()!=c.getMark()) {
       return;
    }

    try {
       int start = Utilities.getWordStart(textArea, c.getDot());
       int end = Utilities.getWordEnd(textArea, c.getDot());
       String word = textArea.getText(start, end-start+1); // May need to be just (end-start), not sure
       textArea.markAll(word, false, true, false);
    } catch (BadLocationException ble) {
       ble.printStackTrace();
    }

}


Note the bug was that the second parameter to JTextComponent.getText(int start, int len) is the length of the string to get, not the end offset. Sorry about that. This was causing a "mark all" highlight of longer and longer length, depending on how far down in the document you placed the caret.

You'll also probably want to call setMarkAllHighlightColor() and set it to what you're currently using for your mark occurrences color to keep your color scheme as you'd expect.

Hope this helps!

Re: TokenTokenMaker and hex in assembly

Post by Vicne » Sat Mar 17, 2012 9:52 pm

robert wrote:Rather than subclassing MarkOccurrencesSupport (I see now that you need access to the private field "p"), you could make a copy of it and name it MarkAllOccurrencesSupport, and change just the actionPerformed() method.

That's exactly what I had done.

Then, rather than modifying RSyntaxTextArea so its MarkOccurrencesSupport is your copy, simply install yours from the outside:
Code: Select all
MarkAllOccurrencesSupport support = new MarkAllOccurrencesSupport();
support.install(textArea);



Oh, yes. That way ! I was looking for a method on the area to add the support, not the other way round. Excellent.

OK. That's done.

Now, the behaviour is quite strange : not only do I have the highlights matching the term I clicked on (green), but I also have weird blocks highlighted in orange when I set the focus on some words :
Image

(Please note the light yellow line is the one which has the caret on, while the blue highlight is set to indicate which line the debugger is on)

Is that a known side effect ?

Sorry if I'm asking too many questions. Don't hesitate to tell me if it's the case.

Best regards,

Vicne

Re: TokenTokenMaker and hex in assembly

Post by robert » Thu Mar 15, 2012 10:40 pm

Rather than subclassing MarkOccurrencesSupport (I see now that you need access to the private field "p"), you could make a copy of it and name it MarkAllOccurrencesSupport, and change just the actionPerformed() method. Alternatively you could change the source of your local copy of MarkOccurrencesSupport so that either p is protected, or you can add a protected getPainter() method so your subclass can access the field.

Then, rather than modifying RSyntaxTextArea so its MarkOccurrencesSupport is your copy, simply install yours from the outside:

Code: Select all
MarkAllOccurrencesSupport support = new MarkAllOccurrencesSupport();
support.install(textArea);


This is all RSTA really does anyway when you call setMarkOccurrences(true) (besides firing a property so anybody who wants to get notified about it does get notified).

Re: TokenTokenMaker and hex in assembly

Post by Vicne » Tue Mar 13, 2012 9:28 pm

robert wrote:It sounds like what you really want is "mark all" perhaps?

Yes, that would do it. Sometimes, a value is loaded in a register that will be used in a jump. So in this case, clicking on the operand and highlighting the matching address would make sense. Assembly is very - very - loosely typed ;-)

You'd basically want to clone the org.fife.ui.rsyntaxtextarea.MarkOccurrencesSupport class, since it handles imposing a delay with no caret changes before changing the highlights. You'd just change the actionPerformed() method to be something like this: (...)
Does that sound like it'll fit your needs?

Yes, exactly.
I cloned it that way (named it MarkAllOccurrencesSupport) and made it extend MarkOccurrencesSupport, but I missed a "setMarkOccurrencesSupport(MarkOccurrencesSupport);" method on RSyntaxTextArea.
Had to subclass RSyntaxTextArea to add such a method but MarkOccurrencesSupport is private so I couldn't set it from a subclass.
I ended up copying all occurrence-related methods from RSyntaxTextArea and it builds...
... but it crashes on init because as MarkAllOccurrencesSupport extend MarkOccurrencesSupport, the super constructor gets called (still don't understand why as I don't call super() explicitely) and crashes because it calls in turn :

p = new MarkOccurrencesHighlightPainter(); // This line addresses the private "p" of the superclass
setColor(color); // This line calls the overridden method that works on a separate "p" instance which is not yet initialized, so it crashes with a NPE.

:-(

Well, I could start hacking the original RSyntaxTextArea classes, but I'd rather be able to simply update the version in the future and subclassing seemed cleaner to me. Have to think about it more...

Thanks again for your insightful help.

Vicne

Re: TokenTokenMaker and hex in assembly

Post by robert » Tue Mar 13, 2012 12:41 am

Yes, it's done on a per-type basis. In reality, marking occurrences is usually semantics-based; that is, clicking on a variable named "foo" will only mark occurrences of "foo" that are actually that variable's name. RSTA is just cheating and highlighting all identifiers (or tokens of the same type) as the "foo" you click on.

It sounds like what you really want is "mark all" perhaps? It would be a little legwork, but you could implement this yourself with a CaretListener and these methods (on RTextArea):

Code: Select all
int markAll(String toMark, boolean matchCase, boolean wholeWord, boolean regex);
void clearMarkAllHighlights();
void setMarkAllHighlightColor(Color color);


You'd basically want to clone the org.fife.ui.rsyntaxtextarea.MarkOccurrencesSupport class, since it handles imposing a delay with no caret changes before changing the highlights. You'd just change the actionPerformed() method to be something like this:

Code: Select all
public void actionPerformed(ActionEvent e) {

   textArea.clearMarkAllHighlights();
   if (c.getDot()!=c.getMark()) {
      return;
   }

   try {
      int start = Utilities.getWordStart(textArea, c.getDot());
      int end = Utilities.getWordEnd(textArea, c.getEnd());
      String word = textArea.getText(start, end); // May need to be end+1, not sure
      textArea.markAll(word, false, true, false);
   } catch (BadLocationException ble) {
      ble.printStackTrace();
   }

}


Does that sound like it'll fit your needs?

Re: TokenTokenMaker and hex in assembly

Post by Vicne » Mon Mar 12, 2012 9:49 pm

Hi, Robert,

Thanks for your help and sorry for the delay.
Overriding AbstractTokenMaker.getMarkOccurrencesOfTokenType(int) worked indeed, but it doesn't highlight tokens cross-type. In other words, if one clicks on an expression in a comment, that expression doesn't get highlighted when it's used as an argument. Not a big deal, but I'd rather have highlights not be limited to one type.

Thanks again,

Vicne

Re: TokenTokenMaker and hex in assembly

Post by robert » Thu Mar 01, 2012 1:19 am

You'll need to override the AbstractTokenMaker.getMarkOccurrencesOfTokenType(int) method to return true for all token types you want "marked." There's no direct support for it in TokenMakerMaker but you should be able to edit the generated .flex or .java file with your override. Yet another thing to add to TokenMakerMaker!

Top

cron