• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Syntax Coloring...
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Syntax Coloring...


  • Subject: Re: Syntax Coloring...
  • From: Charles Jolley <email@hidden>
  • Date: Mon, 10 Jun 2002 12:06:21 -0500

Hi Josh:

First, let me state that the project I have been working on has required that I have very tight control over the entire text system, so my solution might plumb the depths of the network of text objects more than necessary. If so, I would invite anyone else to make that know. With that warning, here are my thoughts:

1. I would make changes directly to the textStorage attributes, NOT using text view. This way you know exactly what is happening. I can almost gaurantee the text view method is doing more than you would like it to. Even better, use the temporary attributes of the NSLayoutManager to handle your syntax coloring. It is intended exactly for this purpose.

2. Remember that attributes do not have to be used for display only. You could use this to keep some state information about your evaluated syntax. For example, you might have an attribute that tells you how many nest level's deep you are or another one that tells you what type of syntax a particular range of characters is part of.

3. With this type of system in place, you could use the syntax coloring state for the character preceding the start of your edited range and then commence evaluating the text from there until at least the end of the edited range. I would continue from there, however, until your evaluated state starts to match the marked state. This would address a situation where someone deletes the beginning of a comment marker.

4. When you are finished with everything, then use the NSLayoutManager invalidateCharacterRange: with the entire range you evaluated.

I'm sure there are many gotcha's here that I have just glossed over...but then again that's why your the developer! ;-)

Searching text, even if it is 5000 characters or so, is not expensive at all compared to the cost of invalidating all the attributes and forcing a redisplay. You most costly operations are likely to be evaluating the text to determine the syntax and invalidating the display. The best way to address these problem spots will be to mark the text so you can pick up at any character and start checking the syntax without having to build much state information and having fine grained control over when display takes place. I have used this exact technique for similar applications and it works very well.

Hope that helps,
-Charles

On Monday, June 10, 2002, at 11:27 AM, Josh Ferguson wrote:

Charles,

I really appreciate your input on this. I do make use of the textDidChange delegate for some other things in my program. The reason I'm using textView:shouldChangeTextInRange:replacementString (whew that's a mouthful) is because it already has a NSRange that I can use. Is using the -editedRange method any more efficient? I suppose it would be if it meant I only needed to use textDidChange:. As far as not using an incremental approach, the main problem is speed here. I don't know if I'm doing something wrong, but to get the coloring to work properly, I first have to reset everything to black, then run through and recolor everything. Just setting a large set of text (we'll say somewhere around 5,000 lines of code) to black causes a noticeable delay (I use [textView setTextColor:forRange:], should I not be using this?). When you do this every time a key is pressed, then it gets REALLY slow as you get towards the bottom of the document. I'm always going to have a dynamic dictionary of "tokens" (like int, float, etc.), and rather than searching through the text for each of these tokens, I would think it would be much faster to determine the last word that was typed, then search the dictionary of tokens for that word. The exact problems I run into right now are:

If you have a line with only a "//" comment, then delete the entire line and begin typing again, then line will retain the comment coloring. This is why I reset everything to being black before running through my coloring again. I'm sure there's a more efficient way of doing this, but it wouldn't be a concern if I use a smaller section of text.

If you have a multiple line comment using "/**/", then you have to search through a larger block of text to find the location of the "/*" and "*/". This is why I'm doing the incremental approach. If I didn't have to color "/**/", it wouldn't even be a problem! ARGH!

After thinking it a bit more, I think I agree that finding the text range in the scroll view is not going to be the answer here. I just haven't decided what right answer is going to be. I prefer a simple, black and white, algorithmic approach, and I don't think I'm going to get that here =(.

-----Original Message-----
From: Charles Jolley [mailto:email@hidden]
Sent: Monday, June 10, 2002 11:09 AM
To: Josh Ferguson
Cc: email@hidden
Subject: Re: Syntax Coloring...


Josh:

If you are using a network of text view objects, let me suggest a couple
of different changes to your approach you might want to consider:

1. Consider using the textDidChange: delegate method and finding the
edited range using textStorage's -editedRange method. This may be a bad
way of doing it though, I would invite anyone else with some thoughts to
chime in.

2. Rather than try to develop an incremental approach based on text
entered, etc. it is probably simpler just to search the text for the
markers and set the relevant text coloring attributes or temporary
attributes. (You are using text color attributes to do this coloring,
right?) Given how complicated an incremental approach is likely to get,
this simpler approach may still just as fast. Even if it isn't, my
experience has been that the difference in speed will not be great
enough to justify the extra effort.

3. Marking large sections of text with a new color attribute is not a
very expensive operation. The text system in Cocoa is very efficient.
Don't worry about changing color attributes in large sections of text.
Cocoa will at most redisplay only the visible portion.

4. Rather than worrying about the visible range of text, let the layout
manager do that for you. See the -invalidateDisplayForCharacterRange:
method (or something like that). Again, this is very efficient.
Anything you write yourself will basically do the same thing this method
will do.

That being said, here is what you would have to do to find the smallest
range of characters to completely include the visible portion of your
text view:

1. Find the visible portion of your text view(s). (see NSView's
visibleRect method).

2. Convert that rect to the text container rect (probably the same
thing. see NSTextView's textContainerOrigin method)

3. Use NSLayoutManager's -glyphRangeForBoundingRect:inTextContainer:
(see also the "withoutAdditionalLayout" variety)

4. convert the glyphRange to the characterRange. (see NSLayoutManagers
characterRangeForGlyphRange:actualGlyphRange: method.)

Well, that's all I know. Hope it helps a little bit.

-Charles

On Monday, June 10, 2002, at 10:28 AM, Josh Ferguson wrote:

Ok, this is probably a pretty basic question, but I've searched through
the docs and haven't found an answer. I'm creating a basic text editor
that supports syntax coloring (I know, novel idea...). In an effort to
keep it running speedy (which is the reason I created it in the first
place), I'm trying to keep the range of text that gets colored to a
minimum. My problem is with "/**/" comments, as that's the only item
that I'm coloring that will span multiple lines (otherwise I would just
color one line at a time).

When the user types any input, I get the location for that input, then
search backwards from that location for the nearest "/*", then just run
my syntax coloring method from there. I then do a forward search for
the first "*/" to determine where to end my coloring. This obviously
isn't foolproof, as this doesn't take into consideration the fact that
the text they're editing may not be a comment at all, and if the code
has very few "/**/" comments, then the range being colored is going to
be unnecessarily large. I determine what's being changed by using the
textView:shouldChangeTextInRange:replacementString delegate method. If
the user is deleting text, is there any way to check what character the
user has deleted (that way I could just check to see if the user
delete "/" and save myself a big headache)? If not, how do you get the
range of text that's being displayed in the Scroll View (that way, I
could just make sure that this text is always up to date).

I'm sorry if this seems stupid, I'm just kind of working from the
ground up here, and I'm getting to the point where I think I need a
fresh perspective. Feel free to criticize.

Josh Ferguson
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

  • Follow-Ups:
    • Re: Syntax Coloring...
      • From: Douglas Davidson <email@hidden>
  • Prev by Date: Re: How do you change the Application Icon in Interface Builder?
  • Next by Date: Re: copyPath and FilePackages
  • Previous by thread: Re: Syntax Coloring...
  • Next by thread: Re: Syntax Coloring...
  • Index(es):
    • Date
    • Thread