[comp.sys.mac] tabs in textedit

radford@calgary.UUCP (Radford Neal) (07/29/87)

In article <8587@ut-sally.UUCP>, brian@ut-sally.UUCP (Brian H. Powell) writes:
> 
>      I've been working on adding tabs to my TextEdit-based editor...

>      First, I looked at all the scary code in the November 1986 MacTutor...
> ...Fortunately, my editor was simpler than his general case...
>
>  [ various stuff... ]
>
>  [ As part of a procedure for measuring text length: ]
>
> 	Else you'll have to back up and find the most recent CR.  (Don't
> 	   forget you may be on the first line, so you want to stop when you
> 	   get to the beginning of the text.  I had the current TEHandle
> 	   as a global, so this wasn't hard.)

I don't know what the ultimate purpose of all this is, but if it's part
of a serious program, it seems rather chancy. Where does it say that
TextEdit won't copy some text to a temporary area and call the text
measurement routine for that? Searching backwards for the beginning of
the line certainly won't work then. I don't know why Apple might make
a change of this sort, but it's certainly not impossible.

As I recall, the MacTutor stuff had some dicey stuff too, but did rely
only on features that were at least mentioned in IM.

Life would be much easier if Apple had put in tab support to start with.

   Radford Neal

brian@ut-sally.UUCP (Brian H. Powell) (07/30/87)

In article <1041@vaxb.calgary.UUCP>, radford@calgary.UUCP (Radford Neal) writes:
> I don't know what the ultimate purpose of all this is, but if it's part
> of a serious program, it seems rather chancy. Where does it say that
> TextEdit won't copy some text to a temporary area and call the text
> measurement routine for that? Searching backwards for the beginning of
> the line certainly won't work then. I don't know why Apple might make
> a change of this sort, but it's certainly not impossible.
     I thought of this, too, so I checked when I first started to make sure
they didn't.  I seriously doubt TE would ever not work on the text in-place.
(after all, when they call StdTxMeas, it's almost always in relation to a
lineStart.  It doesn't make much sense, if you've got all those lineStarts
pointing to the right place, to copy text out to measure it.  Of course, there
may be a good reason five years from now.  Oh well, my program won't run on
that machine.)
     To do anything this deep, you're going to run into cases where IM doesn't
assure you of certain behavior.  (Or in the case of StdTxMeas, at least, they
don't tell you of certain behavior.)  Sure we're living on the edge, but I
think this is a safe solution to the tab problem.  There are several other
ways to do it, and I considered many of them.  Some are safer, but at the
expense of hundreds of lines of code at least, and many have a high
performance overhead.  (my opinion, of course.)  In short, you've got to take
chances when you program on the Mac.  By following IM and the TechNotes to the
letter, you will improve your odds, but if you need to go beyond what IM and
the TN's talk about, you shouldn't just stop programming.  You need to move
with at least as much care as when you were following IM.

> As I recall, the MacTutor stuff had some dicey stuff too, but did rely
> only on features that were at least mentioned in IM.
     Actually, they used some undocumented low-memory globals to call
undocumented TE support routines.  My stuff is UL-approved compared to that.
I relied on two instances of undocumented behavior:
	* that the text I'd measure and draw was not a copy, but that I was
	  looking at part of the whole text.
	* that TE would already have the fontinfo before I'd have to measure
	  a line that consisted only of tabs.  I think this is safe because
	  TE has to show the insertion point before I can enter the tabs.
	  This implies that TE already knows the fontinfo.  This is the reason
	  why StdTxMeas gets called early with byteCount==0 and textAddr==0,
	  by the way.  Even if this changes, you can take out one line of code
	  and my stuff will start working again.  (It's a performance issue.)
There may be others, but I can't think of any right off the top of my head
like this.

     You are right to challenge my work.  Tabs, like marriages, are not
something to be entered into lightly.  Let these comments serve as warning to
those who intend to use my algorithm.

Brian

jww@sdcsvax.UCSD.EDU (Joel West) (07/31/87)

Don't forget, if you're doing software for commercial release,
you must be very careful when backing up.  Seems some folks
can't write their language using only 256 characters, so
Apple has accomodated them (even gave 'em a manager,
though I dunno where 'Script' came from) by allowing two-character
characters.  I don't have the stuff in front of me, but it seems
like parsing backwards ain't such a hot idea for these circumstances.
-- 
	Joel West,  (c/o UCSD)
	Palomar Software, Inc., P.O. Box 2635, Vista, CA  92083
	{ucbvax,ihnp4}!sdcsvax!jww 	jww@sdcsvax.ucsd.edu

brian@ut-sally.UUCP (Brian H. Powell) (08/06/87)

     Enclosed please find everything you need to implement tabs in a TextEdit
window.  The language is C, the dialect LightSpeed, but I don't think you'll
have to change anything for the other compilers.
     This stuff is intended for TextEdit editors that don't wrap lines.  (That
way, I don't have to wrap tabs.)  I set crOnly to -1 and just to be sure, I
use a destRect.right == 32767.  If you want to wrap tabs, I suggest you see
the MacTutor article in Vol. 2, No.11, November, 1986 titled "Extending
TextEdit for TABS" by Bradley Nedrud.  Thanks to Bart Geraci for giving me
this issue of MacTutor.

     Caveats:
	* I don't guarantee this code will do anything.
	* I don't guarantee this code will work with an SE or a II; I haven't
	  tried it, yet.  It should work, though.
	* I don't guarantee this code will work with all future ROMs.  It
	  probably will, though.

	* Don't call CharWidth to measure a tab; it won't work.

     In particular, my code depends on two things:
	* That when tabTxMeas and tabText are called, they get pointers into
the actual TextEdit text.  This is so they can poke around in neighboring text
to find out where the beginning of the line is.  If TextEdit ever decides to
measure text by copying it into a buffer, then measuring it, these routines
will return funny values.
	* That TextEdit will never use the values returned by numer, denom and
info after tabTxMeas has been called to measure a line consisting only of
tabs.  Currently, TextEdit sets up its variables (such as
te_handle^^.lineHeight) during TENew by calling GetFontInfo, which calls
tabTxMeas with byteCount == textAddr == 0.  If tabTxMeas is ever called to
measure a line consisting only of tabs, it figures out the width of the text
on its own and never calls StdTxMeas.  Therefore, numer, denom and info aren't
touched.  This isn't hard to change if you feel uncomfortable with it.  I'd
suggest initially calling StdTxMeas with count == 0.  Then if tabTxMeas' input
parameter byteCount was also zero, tabTxMeas can return zero safely, else do
all the work.  (Maybe I'll change this in my program, too.)

Brian H. Powell
		UUCP:	{ihnp4,seismo,ctvax}!ut-sally!brian
		ARPA:	brian@sally.UTEXAS.EDU

   _Work_					 _Not Work_
  Department of Computer Sciences		P.O. Box 5899
  Taylor Hall 2.124				Austin, TX 78763-5899
  The University of Texas at Austin		(512) 346-0835
  Austin, TX 78712-1188
  (512) 471-9536


/*
	by Brian H. Powell		brian@sally.UTEXAS.EDU
					brian@ut-sally.UUCP

	Copyright (c) 1987
	This code may be freely distributed and used, provided my name and the
	  copyright notice appear (at least in source comments, as above.)
	(i.e., if you're going to sell your program, then write it yourself,
	  don't get me to do it for you.)

	Thanks to MacTutor, November, 1986, for the ideas, but not for the
	  code.

   tab.c -- My routines to replace the low-level quickdraw routines for
   	    measuring and drawing text.  They are used to implement tabs.
   	    The routines tabTxMeas and tabText should be installed in a
   	    QDProcs record pointed to by the grafProcs field of the
   	    window's grafPort.

      These general-purpose routines are designed to work only if the
   TextEdit record for the associated grafPort has an infinite right
   margin.  (i.e., lines wrap only at carriage returns.)  Also, there
   must be an infinite number of tabs possible:  These routines don't
   try to handle the case where tabs cause a wrap to the next line.
*/

#include <MacTypes.h>
#include <Quickdraw.h>
#include <TextEdit.h>

#define NULL	0

pascal int tabTxMeas(byteCount, textAddr, numer, denom, info)
int byteCount;
Ptr textAddr;
Point *numer, *denom;
FontInfo *info;
{
   extern TEHandle current_textedit_hdl;
	/* A global handle to the TextEdit record for this window.
	   Normally, current_textedit_hdl is the handle for the front
	   window, but for update events (before calls to TEUpdate), we
	   change current_textedit_hdl to the TERecord for the window
	   being updated.  (And we change it back when we're through.
	   See the code for update events.)  */

   register int total_result,		/* the total length of the
   					   text.  */
   		current_line_length,	/* the length from the beginning
   					   of the line up to traverse_ptr.
   					   It's used to know how far to
   					   skip to the next tab stop.  */
   		result;		/* a variable to hold intermediate
   				   results.  */

   register char *start_ptr,	      /* pointers that work their way */
   		 *traverse_ptr,	      /*  through the text looking for
   		 			  tabs.  Start_ptr and traverse_ptr
   		 			  bound the current range of text
   		 			  to be measured.  */

   		 *text_limit,		/* a pointer to the end of the
   		 			   text to be measured.  */
   		 *start_limit,		/* a pointer to the beginning of
   		 			   the TextEdit text.  This is
   		 			   obtained from the TEHandle.  */

		 *last_cr;		/* a pointer to the last carriage
		 			   return encountered.  (or to the
		 			   last character we measured,
		 			   whichever is later.)  */


   if (byteCount == 0)	/* even though we know the answer to this is
   			   zero, we still want StdTxMeas to
   			   compute numer, denom and info for us.  */
      return(StdTxMeas(byteCount, textAddr, numer, denom, info));

   total_result = 0;
   last_cr = NULL;	/* we haven't found a CR yet.  */
   start_ptr = traverse_ptr = textAddr;
   text_limit = traverse_ptr + byteCount;
   start_limit = *((*current_textedit_hdl)->hText);
	/* In case you're wondering, we can dereference this handle
	   without locking it:  it should already be locked by TE,
	   since StdTxMeas gets a pointer to part of the text.  */

   while (traverse_ptr < text_limit) {

	/* search for a tab, keeping track of the CR's we see.  */
      while ((traverse_ptr < text_limit) && (*traverse_ptr != '\t'))
         if (*traverse_ptr++ == '\r') {
            last_cr = traverse_ptr;
            current_line_length = 0;
         }

	/* If we made it to the end of the text without finding a tab,
	   just call the StdTxMeas to measure the text.  */
      if (traverse_ptr >= text_limit)
         total_result += StdTxMeas(traverse_ptr - start_ptr, start_ptr,
            			   numer, denom, info);

      else { /* we found a tab.  */
         if (last_cr == NULL) {
	/* If we haven't noticed a CR yet, back up and find it.  In this
	   case, current_line_length doesn't have a defined value, so we
	   need to measure from the beginning of the current line up to
	   the beginning of the text to be measured.  */
            while ((*(start_ptr - 1) != '\r') &&
               	   (start_ptr > start_limit))
               start_ptr--;

            if (start_ptr < textAddr) {

	/* If we had to back up at all, recurse and find the length from
	   the beginning of the line to the start of the text to be
	   measured.  It will never recurse more than one level.  */
               current_line_length = tabTxMeas(textAddr - start_ptr,
                  			       start_ptr, numer, denom,
                  			       info);
               start_ptr = textAddr;	/* reset start_ptr.  */
            } else
	/* If we didn't have to back up, that means we were called starting
	   from the beginning of the line.  So we can set the current line
	   length to zero.  */
               current_line_length = 0;

         } else { /* last_cr had a meaningful value, so measure from the
         	     beginning of the text to the beginning of the current
         	     line and add to our running total.  For speed, don't
         	     call StdTxMeas unless the range is non-empty.  */
            if (last_cr > start_ptr)
               total_result += StdTxMeas(last_cr - start_ptr, start_ptr,
               				 numer, denom, info);
            start_ptr = last_cr;
         }

	/* Now measure from the beginning of the line to the tab.  For
	   speed, don't call StdTxMeas unless the range is non-empty.
	   Add the result to both the total length and the current line
	   length.  */
         if (traverse_ptr > start_ptr) {
            total_result += result = StdTxMeas(traverse_ptr - start_ptr,
         				       start_ptr, numer, denom,
         				       info);
            current_line_length += result;
         }

	/* To avoid measuring parts of the text twice, set last_cr to the
	   current location (just past the tab).  */
         last_cr = start_ptr = ++traverse_ptr;	/* skip the tab */

	/* Now that we know the current line length, we can figure out
	   where the next tabstop is.  compute_tab_length returns the
	   length of the tab in pixels.  */
         total_result += result = compute_tab_length(current_line_length);
         current_line_length += result;
      } /* else */
   } /* while */
   return(total_result);
}

pascal void tabText(byteCount, textBuf, numer, denom)
int byteCount;
Ptr textBuf;
Point numer, denom;
{
   FontInfo info;		/* This is ignored, but since we call
   				   tabTxMeas, we need to pass a pointer to
   				   one of these records.  */

   register char *traverse_ptr,	/* Pointers that move through the text */
   		 *start_ptr,	/*  looking for tabs.  */
   		 *text_limit,	/* A Pointer to the end of the text to
   		 		   draw.  */
   		 *line_start,	/* A Pointer to the beginning of the
   		 		   line.  */
		 *start_limit;	/* A Pointer to the beginning of the
		 		   TextEdit text.  */

   extern TEHandle current_textedit_hdl;	/* A global handle to the
   						   TextEdit record for this
   						   window.  */

/* This routine relies on the fact that it never has to draw a carriage
   return.  TextEdit calls this procedure for each line. (or sometimes only
   part of a line.)  */

   line_start = NULL;
   /* search for first tab. */
   traverse_ptr = start_ptr = textBuf;
   text_limit = textBuf + byteCount;
   while (traverse_ptr < text_limit) {
      while ((traverse_ptr < text_limit) && (*traverse_ptr != '\t'))
         traverse_ptr++;

    /* Call StdText for what we've found so far.  */
      StdText(traverse_ptr - start_ptr, start_ptr, numer, denom);

    /* If there's still some text left, we must have found a tab.  */
      if (traverse_ptr < text_limit) {	/* we found a tab */

    /* If this is the first tab we've found, we need to go back and find
       the beginning of the line so we can figure out how big the tab is
       supposed to be.  */
         if (line_start == NULL) {
            line_start = textBuf;
            start_limit = *((*current_textedit_hdl)->hText);
            while ((*(line_start - 1) != '\r') &&
            	   (line_start > start_limit))
               line_start--;
         }
     /* Now measure the text from the beginning of the line to the tab and
        call compute_tab_length.  Feed this to Move(dh,dv) to move the pen
        that many pixels to the right.  */
         Move(compute_tab_length(tabTxMeas(traverse_ptr - line_start, 
         			line_start, &numer, &denom, &info)), 0);
      }
      start_ptr = ++traverse_ptr;    /* skip the tab and continue drawing.  */
   }
}

int compute_tab_length(current_line_length)
int current_line_length;
/* This routine could be a whole lot more complicated.  I only support one
   tab_size.  It would not be too difficult to have an array of tabstops
   associated with each window.  This routine could search for the next
   larger tabstop and return the difference between it and the
   current_line_length.  */
{
   extern int tab_size;		/* A global that contains the size in pixels
   				   of the tab stops.  */

   return(tab_size - current_line_length % tab_size);
}

			------- end of tab.c -------

     In case you're wondering, here's how to set up the QDProcs:

   Do this once at initialization time.  Since it allocates a non-relocatable
block, you probably want this to be in the main segment.  (Or else, make it a
handle, MoveHHi, lock it and dereference it.)

void setup_globals()
{
   extern QDProcsPtr myQDProcs;		/* It's a global variable. */
   extern pascal void tabText();
   extern pascal int tabTxMeas();

   myQDProcs = (QDProcsPtr)NewPtr(sizeof(QDProcs));
   SetStdProcs(myQDProcs);
   myQDProcs->textProc = tabText;	/* You may have to cast these, */
   myQDProcs->txMeasProc = tabTxMeas;	/* depending on your development
					   environment. */
}


   If you just have one size tab like I did, somewhere you need to set up
tab_size.  I felt more confident doing this before setting up myQDProcs in the
current grafPort.  I made it a global that never changes.  (I only use one
font and size.)  It may be better to make it a global that changes depending
on the font of the window being brought up.  I'll let you decide.
   If you have an array of tabs, such as was described in MacTutor, you should
rewrite compute_tab_length and you'll never need tab_size.

   extern int tab_size;

   tab_size = CHARS_PER_TAB * CharWidth('0');	/* For me, CHARS_PER_TAB is
						   constant 8, but it's not
						   hard to bring up a dialog
						   to let the user specify. */


   Then, for each window:

void setup_te_port(new_window)
WindowPtr new_window;
{
   extern QDProcsPtr myQDProcs;

   (*new_window).grafProcs = myQDProcs;
}
			----- -----
     It's been real.

Brian

     "You know, I used to think people rewrote TextEdit to get tabs, multiple
fonts and styles and the like.  Now I realize they do it to get error
checking." -- Brian H. Powell, August, 1987.

brian@ut-sally.UUCP (Brian H. Powell) (08/13/87)

     I noticed that my code was pretty slow drawing a line with several tabs
in it, so I made a simple optimization that makes it quite a bit faster.
tabTxMeas still isn't as fast as I want it.  If I optimize that much, I'll
post the changes to it, also.
     This change keeps tabText from calling tabTxMeas more than once.  It used
to call it to measure from the beginning of the line up to every tab.  I don't
know why I didn't do this in the first place.
     Insert this fragment into the proper place in tabText.  You should be
able to figure it out.  I put plus signs in front of the new code.  (I hope I
got all the plus signs right.)
     I pasted this in here, and our ethernet was running slow, so some char-
acters were lost.  I think I put them all back right, but no guarantees.

pascal void tabText(byteCount, textBuf, numer, denom)
...
+	register int line_length, line_dh;

...
     /* If this is the first tab we've found, we need to go back and find
        the beginning of the line so we can figure out how big the tab is
        supposed to be.  */
         if (line_start == NULL) {
            line_start = textBuf;
            start_limit = *((*current_textedit_hdl)->hText);
            while ((*(line_start - 1) != '\r') &&
            	   (line_start > start_limit))
               line_start--;
+           line_length = tabTxMeas(traverse_ptr - line_start, line_start,
+           			    &numer, &denom, &info);
+        } else
+           /* just add in the length of the text we just drew.  */
+	    line_length += StdTxMeas(traverse_ptr - start_ptr, start_ptr,
+	    			     &numer, &denom, &info);
+
+     /* find the length of the tab.  */
+     line_length += line_dh = compute_tab_length(line_length);
+
+     /* Call Move(dh,dv) to move the pen line_dh pixels to the right.  */
+        Move(line_dh, 0);
      }
...

Brian H. Powell
		UUCP:	{ihnp4,seismo,ctvax}!ut-sally!brian
		ARPA:	brian@sally.UTEXAS.EDU

   _Work_					 _Not Work_
  Department of Computer Sciences		P.O. Box 5899
  Taylor Hall 2.124				Austin, TX 78763-5899
  The University of Texas at Austin		(512) 346-0835
  Austin, TX 78712-1188
  (512) 471-9536

mjbo@mist.cs.orst.edu (Mark Borgerson) (01/12/88)

I have modified a textedit-based programming editor to
support tabs  using the Quickdraw StdText and StdTxtMeas
routines.  My patches to these routines treat tabs as
variable width characters using a simplified version 
of the routines given in a MacTutor article from about
a year ago.  My routines work well on the Mac Plus
and SE with system 3.2, 4.1 and 4.2. They also work
on the Mac II  ---but only if the Mac II is in 2-color
mode.  IF I switch to other modes, text is not properly
displayed as input is  entered.   However, if the screen
is invalidated and redrawn all is ok. 
Anyone have any ideas?   What is different about 
the quickdraw routines when in other than 2-color
mode?   IM Vol five does not mention anything about
stdText or stdTxtMeas acting  differently in 
multi-bit modes?

I also saw  something on the net to the effect that
modifying textedit  to support tabs was verboten. 
There is nothing to this effect in the latest 
compatibility guidelines.  Am I doomed to failure
or what?

Mark Borgerson
Dept. Computer Science
Oregon State University

Disclaimers are for opinions.  The material above is factual.

brian@ut-sally.UUCP (Brian H. Powell) (01/13/88)

In article <1860@orstcs.CS.ORST.EDU>, mjbo@mist.cs.orst.edu (Mark Borgerson) writes:
> I also saw  something on the net to the effect that
> modifying textedit  to support tabs was verboten. 
> There is nothing to this effect in the latest 
> compatibility guidelines.  Am I doomed to failure
> or what?

     I was the person who posted some information to the net about adding tabs
to TextEdit a few months ago.  At the time I was working on it, I sent mail to
Apple asking them to clarify some of the issues involved with TextEdit.  I got
a letter from Cameron Birse, which said, in part,

	It wasn't entirely clear to me what exactly you meant with your
	StdText and StdTxMeas calls, but I can say that things not only can
	change in future ROMs, but probably will.  For example, the new
	TextEdit routines allow for styled text (i.e., bold, italic, etc.),
	which obviously complicates measuring text.  The point is, the only
	things you can depend on being supported in future revisions of ROMs
	are things that are clearly documented in Inside Macintosh Volumes
	1-5.

     Let me say that first of all, the MacTutor article included some very
questionable code which I'm sure has failed on SEs and IIs.  When I wrote code
to support tabs, I made some restrictions (in particular, I don't allow
word-wrapping) that let me throw out much of the "dangerous" code from the
MacTutor article.  Also, I didn't use the "new" TextEdit; I'm using the "old"
TextEdit that only supports one typeface.
     I also had to make some assumptions.  Here is what I said in the original
article I posted:
			     ********************
     In particular, my code depends on two things:
	* That when tabTxMeas and tabText are called, they get pointers into
the actual TextEdit text.  This is so they can poke around in neighboring text
to find out where the beginning of the line is.  If TextEdit ever decides to
measure text by copying it into a buffer, then measuring it, these routines
will return funny values.
	* That TextEdit will never use the values returned by numer, denom and
info after tabTxMeas has been called to measure a line consisting only of
tabs.  Currently, TextEdit sets up its variables (such as
te_handle^^.lineHeight) during TENew by calling GetFontInfo, which calls
tabTxMeas with byteCount == textAddr == 0.  If tabTxMeas is ever called to
measure a line consisting only of tabs, it figures out the width of the text
on its own and never calls StdTxMeas.  Therefore, numer, denom and info aren't
touched.  This isn't hard to change if you feel uncomfortable with it.  I'd
suggest initially calling StdTxMeas with count == 0.  Then if tabTxMeas' input
parameter byteCount was also zero, tabTxMeas can return zero safely, else do
all the work.  (Maybe I'll change this in my program, too.)
			     ********************

     As I said at the time, it would be pretty stupid if Apple were to change
TextEdit to invalidate my above assumptions.  It would imply that they were
throwing away a lot of useful information in their TERecord and recomputing it
each time.
     If you did anything similar to what I did, then I suggest two things:
	Don't call CharWidth.  (It's obvious why not if you think about it.)
	Check to make sure that my first assumption holds on calls to the
	 bottlenecks.  That's the most likely place for something to mess up.

     I'll try my code on a Mac II tomorrow or Thursday and let you know if it
works.  If you'd like, I could send you my original posting when I worked on
it.

Brian H. Powell
		UUCP:	...!uunet!ut-sally!brian
		ARPA:	brian@sally.UTEXAS.EDU

		P.O. Box 5899
		Austin, TX 78763-5899
		(512) 346-0835

brian@im4u.UUCP (Brian H. Powell) (01/15/88)

     I tried using my tabs code on a Mac II.  (By "tabs code", I mean the code
that I wrote which adds tabs to TextEdit.)  I tried running the program in
2-bit, 4-bit and 16-bit mode (gray; I didn't try it on a color Mac II), and in
all cases, it worked fine.  It worked for both the initial typing, and for
window updates.
     If anybody's interested, I can send them my original posting on the
matter.  (It included some code.)

Brian H. Powell
		UUCP:	...!uunet!ut-sally!brian
		ARPA:	brian@sally.UTEXAS.EDU

		P.O. Box 5899
		Austin, TX 78763-5899
		(512) 346-0835

tomc@mntgfx.mentor.com (Tom Carstensen) (01/15/88)

As far as I'm concerned, TextEdit is worthless 
because of it's 32K limit, non-handling of tabs,
and the implementation is so slow.  I originally
added by on StdMeas and StdTxt routines to support
tabs, but by doing this, selecting text was
EXTREMELY sluggish and annoying.  (Try typing 
in a line of 200 characters or so WITH tabs, and then
selecting that line - moving the mouse back and forth - UGH!).

I bagged TextEdit, and wrote my own which is overall,
much faster.  It's being incorperated into an Editor
I'm developing, which will be finished soon.

Since I rewrote TextEdit, I was able to support such things
as rectangular selection (which I find most useful) and
Hiding (folding in ) of text.

:------------------------------------------------------------:
: Tom Carstensen              Usenet: tomc@mntgfx.MENTOR.COM :
: Mentor Graphics             GEnie:  XPC23637               :
:                                                            :
:     . . . and this shall be Max Headroom's finest hour.    :
:                                       - Max Headroom       :
:------------------------------------------------------------:

brian@ut-sally.UUCP (Brian H. Powell) (01/16/88)

In a recent article, tomc@mntgfx.mentor.com (Tom Carstensen) writes:
> As far as I'm concerned, TextEdit is worthless 
> because of it's 32K limit, non-handling of tabs,
> and the implementation is so slow.

     But you left out the worst part:  it doesn't do _any_ error checking.  In
particular, it loves to run out of memory and not tell you about it.  If I
were going to write a new TextEdit, I would do so to get error checking, not
tabs, the 32K limit or anything else.
     (Of course, if you rewrite TextEdit, it's also easier to implement the
arrow keys according to the user interface guidelines.  (In particular,
modifier keys with arrow keys.)  It's not that hard to implement the
guidelines with TE, but the solution is not at all intuitive.  See a posting I
made a few months ago about arrow keys.)
     (Of course, it may not be a good idea to implement the user interface
guidelines; Apple's response to my work was along the lines of, "How dare you
confuse the user by implementing the User Interface Guidelines and doing
something different than what TextEdit does?"  I guess Apple was feeling
especially schizophrenic that day.)

> I originally
> added by on StdMeas and StdTxt routines to support
> tabs, but by doing this, selecting text was
> EXTREMELY sluggish and annoying.  (Try typing 
> in a line of 200 characters or so WITH tabs, and then
> selecting that line - moving the mouse back and forth - UGH!).
     Mine isn't terribly slow.  It's certainly slower than "normal", but it's
not intolerable.  I even wrote mine in C.

     It's great that you took the effort to rewrite TextEdit.  When I was
working on this stuff, I certainly considered it, but I didn't need a powerful
editor, so I just put up with TE.

Brian