/**************************************************************************
/**************************************************************************
           File:  'tse_tip1.txt  Tuesday -  November 9, 1993

       Started 5-13-93 for small bits of info and/or source code.
                TSE (The SemWare Editor, a.k.a. TESSIE)

/**************************************************************************
/**************************************************************************
===========================================================================
                  Date: 05-11-93  From: EBERHART ADAM

                 Unmarking text with the mouse button:
---------------------------------------------------------------------------

I just tried this (changed mLeftBtn from tse.s):

/**************************************************************************

proc mLeftBtn()
    if not MouseMarking(_INCLUSIVE_) and not ProcessHotSpot()
        MainMenu()
    elseif not iscursorinblock()
        UnMarkBlock()
    endif
end

/**************************************************************************
                        Thursday - May 13, 1993
/**************************************************************************

TSE change to *.key to have CTRL-Y move cursor position to BegLine.

  Change  <Ctrl y>   DelLine()

  to      <Ctrl y>   DelLine() BegLine()

  then recompile.

  While having two commands on the same will currently work, it is not
  guaranteed to always be implemented. So instead of the double command
  define a procedure in 'tse.s'

    proc  YankLine()
        DelLine()        and then define the key:  <Ctrl y>  YankLine()
        BegLine()
    end

/**************************************************************************

===========================================================================
                    Date: 05-13-93  From: RAY ASBURY
                     Subj: WordRight/Left TSE Macro
---------------------------------------------------------------------------
If you've noticed that WordLeft() and WordRight() stop on the beginning
and the end of lines, and don't like this behavior, here's a simple
replacement for these commands which skips over the beginning and the
ending of lines:

    CONSTANT kPREVIOUS_WORD = FALSE,        kNEXT_WORD = TRUE

    INTEGER PROC mGotoWord1(INTEGER whichOne)
        IF (whichOne ==kNEXT_WORD)
            Return(WordRight())
        ENDIF
        Return(WordLeft())
    END mGoToWord1

    INTEGER PROC mGotoWord2(INTEGER whichOne)
        WHILE ( (mGotoWord1(whichOne)) AND (NOT IsWord()) )
            whichOne = whichOne
        ENDWHILE
        IF (IsWord())
            Return(TRUE)
        ENDIF
        Return(FALSE)
    END mGotoWord2

    PROC mGotoWord(INTEGER whichOne)
        PushPosition()
        IF (mGotoWord1(whichOne))
            IF (NOT IsWord())
                IF (NOT mGotoWord2(whichOne))
                    PopPosition()
                    Return()
                ENDIF
            ENDIF
        ELSE
            PopPosition()
            Return()
        ENDIF
        KillPosition()
    END mGotoWord

To use this, simply add this to your TSE.S file and replace direct calls
of WordLeft() with mGotoWord(kPREVIOUS_WORD) and of WordRight() with
mGotoWord(kNEXT_WORD).

Currently, if a word is not found, the cursor won't move.  If, however,
you would prefer that it go to either the beginning of the file, or the
end (depending on the direction you are searching), use this version of
mGotoWord():

    PROC mGotoWord(INTEGER whichOne)
        IF (mGotoWord1(whichOne))
            IF (NOT IsWord())
                mGotoWord2(whichOne)
            ENDIF
        ENDIF
    END mGotoWord

I hope you find this useful,

"Buddy" E. Ray Asbury, Jr.
Team TSE
/**************************************************************************

===========================================================================
                   Date: 05-13-93  From: KYLE WATKINS

      Subj: TSRGEP problem that hit line# is shifted down one line
    Reference:  Next item also has a solution for a TSRGREP problem
---------------------------------------------------------------------------

-> markline()                <----  CHANGE TO CHARACTER OR COLUMN
-> GotoBufferId(oid)
-> BegLine()
-> if linenumbers
->      InsertText(Format(linenumber:lndigits) +  ' 
->
-> endif
-> copyblock()               <---- Then the copy block will be on same
                                   line instead of below (or above)


->But what is happening is the text associated with the hit line# is
->shifted down one line.

Hi David,
   If you change to a block other than LineBlock, then CopyBlock will
   use the same line.                                      ----  Kyle

/**************************************************************************

===========================================================================
                   Date: 05-13-93  From: DAVID MARCUS
                         Subj: TSGREP Solution
---------------------------------------------------------------------------

I have determined the problem and solution causing your TSGREP hit list
to be so erratic; it is the setting for your InsertLineBlocksAbove
configuration option. You can either set it to ON or TRUE, or make
these three small changes to TSGREP:

1. Add this line as the first line under the
   global INTEGER declarations [line ~82]:

     ILBA,                              // holds InsertLineAbove value

2. Add this line as the first line in
   proc MAIN() [line ~260]:

     ILBA = Set(InsertLineBlocksAbove, ON)

3. In proc end_processing(), add this line as the first line under
          /*
               Reset editor
          */

   [line ~723]:

          Set(InsertLineBlocksAbove, ILBA)


*** Please let me know if this does not work. ***
/**************************************************************************

===========================================================================
                   Date: 05-13-93  From: KYLE WATKINS
                Subj: Remove blank lines in a text file
---------------------------------------------------------------------------

   The following will delete all blank lines in a file, even if the line
contains just tab and space characters.

proc DelBlankLine()
    pushposition()    //save your position
    begfile()         //remove this if you want to start at the
                      //current pos. and replace it with begline()

    while LFind("[\d009\d032]*$","X")  //Find "Beginning of line followed
                                        //by 0 or more tabs or spaces
                                        //followed by EOL". Use of LFind
                                        //instead of Find so that the display
                                        //does not update with each find.

        message(currline()," of ",numlines()) //just for information in case
                                              //it's a large file
        delline()
    endwhile
    message("DONE!")                          //So you know it's done when
                                              //no blank lines are in file

    popposition()     //return to your original position
end

/**************************************************************************

===========================================================================
                  Date: 05-14-93  From: SAMMY MITCHELL
---------------------------------------------------------------------------
>   I am trying to use a command macro I had for QEdit that would allow
>  me to abandon a file and restart the edit with the last saved copy.  I
>  seem to want a variable into which I can place the CURRENT FILE NAME,
>  but I don't see this.

How about this:

// quit the current file (even if changed) and reload it from disk
proc ReloadCurrentFile()                // version 1
    string fn[65] = CurrFilename()      // save the name

    AbandonFile()                       // quit the file
    EditFile(fn)                        // and reload it
end

Or, if you prefer:

// quit the current file (allow saving first) and reload it from disk
proc ReloadCurrentFile()                // version 2, safer
    string fn[65] = CurrFilename()      // save the name

    if isChanged()                      // if changed allow saving
        case YesNo("Save Changes?")
            when 0, 3   return()
            when 1      if not SaveFile()
                            return ()
                        endif
        endcase
    endif
    AbandonFile()
    EditFile(fn)
end

And finally, a version that is more like QEdits "NewFile", which will
allow you to optionally reload the current file, or just load another
file after quitting the current file:

// quit the current file (allow saving first) and load another
proc NewFile()
    string fn[65] = CurrFilename()      // save the name

    if isChanged()                      // if changed allow saving
        case YesNo("Save Changes?")
            when 0, 3   return()
            when 1      if not SaveFile()
                            return ()
                        endif
        endcase
    endif
    AbandonFile()
    AddHistoryStr(fn, _EDIT_HISTORY_)
    EditFile()
end

/**************************************************************************

===========================================================================
                   Date: 05-09-93  From: KYLE WATKINS
                       Subj: MOUSE SELECTED TEXT
---------------------------------------------------------------------------
-> editors, when you click again on the screen the highlighted text
-> doesn't go away. This is very annoying. With TSE you must click and
-> then drag some to get the previous selected text to disapear. With

  You can issue unmarkblock() to get rid of the marked block (our
default <ALT U>) instead of trying to remark a block to get rid of the
first block. When you "click and drag" the mouse, you are actually using
the markchar() command to mark a character block.  If you would rather
the marked block be unmarked each time you press the left mouse button
whenever you are in an "editing portion" of the screen, you can make the
following adjustments to the mLeftBtn() procedure that is near the
bottom of the tse.s file (or within the ".s" file you used to configure
the editor):

proc mLeftBtn()
    if mousehotspot() == _mouse_marking_    // add this line
        unmarkblock()                       // add this line
    endif                                   // add this line
    if not ProcessHotSpot()
       MainMenu()
    endif
end

This will unmark any block if you press the left mouse button and you
are within the editing window.  If you are outside the editing
window, the block will remain marked.  If you want to unmark the block
no matter where the mouse cursor is, modify the mLeftBtn() procedure to
begin with unmarkblock() instead of the three lines I show.

  When you use the mouse with QEdit by first loading qm.com, mouse
movements are translated to the appropriate cursor commands depending on
the direction of mouse movement and are placed in the keyboard buffer.
That is why the movement of the mouse caused the cursor to move.  One
drawback to this is that the cursor will move whenever the mouse is
moved, which means if you bump the mouse, your cursor moves.

   If you want to do this in TSE, it should be possible with a macro
if you take all of the window borders into account.

Kyle Watkins (SemWare Technical Support)

/**************************************************************************

===========================================================================
                   Date: 05-15-93  From: BOB CAMPBELL
                    Subj: Re: TSE not finding macro
---------------------------------------------------------------------------

 > Here's how I got around this problem.  In your
 > TSE.S file's WhenLoaded(), add the following

 >     AddHistoryStr(Query(MacPath), _ExecMacro_History_)
 >     AddHistoryStr("", _ExecMacro_History_)

Thanks Ray. It took me a while to figure out how to use your routine but
I've got it installed now and it's even better than what I was asking for!

/**************************************************************************

===========================================================================
                   Date: 05-17-93  From: KYLE WATKINS
                          Subj: BLOCK TABBING
---------------------------------------------------------------------------
Question:  In Qedit, I can highlight a block of text, move it, and then
           if the indent happens to be further in that it was
           originally, I can place the cursor at the beginning of a line
           of text and hit tab, and the whole block is tabbed over.

Hi John,

   If you are using the tse.s file, there is a macro called
mShiftBlock().  This macro is used with the default <shift f7>,
<shift f8>, and <ctrl f7> key assignments. Modify your tab keys to be:

for <Shift Tab> use:

iif(isCursorInBlock(),mShiftBlock(-Query(TabWidth)),TabLeft())

for <Tab> use:

iif(isCursorInBlock(),mShiftBlock(Query(TabWidth)),TabRight())

  If your cursor is not in a marked block, you will get the normal
tableft() and tabright(), otherwise the block will be shifted by the
current tab width.

Kyle Watkins (STS)
/**************************************************************************

===========================================================================
                    Date: 05-17-93  From: RAY ASBURY
                          Subj: TSE macro help
---------------------------------------------------------------------------

<User blushing>

Spend some time just playing around with regular expressions - the power
of them is incredible.  Although they've been around a long time, I'd
never used them until I started alpha testing TSE.  I could hardly get
along without them now.

BTW - here's three searches that I use a lot and are extremely handy:

        Find("^$", "X") - finds blank lines
        Find("^.@", "X") - finds all lines
        Find("^.#", "X") - finds all non-blank lines

I've put these into the find & replace histories so that I can simply
Up() to them.  If you want to do the same thing, just add something like
the following to your TSE.S's WhenLoaded() macro:

    AddHistoryStr("^{.@}", _Find_History_)
    AddHistoryStr("^{.#}", _Find_History_)
    AddHistoryStr("", _Find_History_)

<<< BOB CAMPBELL >>>Ŀ
I also discovered (quite by accident) while working with the search function
that the search strings are saved to a buffer for recall by using the       
CursorUp and CursorDown keys.                                               
>>> RAY ASBURY <<<

These are called "histories".  A lot of the dialog prompt boxes within
TSE have them.  Check out pages 24-5 in the User's Guide.  Did you know
that you can mark text, and then use the Copy() command <Alt C> to paste
the marked text into most dialog boxes?

<<< BOB CAMPBELL >>>Ŀ
I'm sure you know about this feature but I wanted to mention it and your
search string above because it offered a valuable example for learning. 
>>> RAY ASBURY <<<

<User REALLY BLUSHING>

My humility demands that I let you know it took a couple of hours to
come up with that macro.  Although putting the search string together
wasn't bad, how to handle some of the other stuff wasn't easily
apparent.

Thanks for the compliments,  but I suspect you'll be teaching me things
before too long.

"Buddy" E. Ray Asbury, Jr.
Team TSE
/**************************************************************************

===========================================================================
                  Date: 05-18-93  fFrom: KYLE WATKINS
                       Subj:  Regular Expressions
---------------------------------------------------------------------------
-> What does the stuff inside the quotes ("^[\d009\d032]*$") mean and is
-> there a place I can find this information in the manual?

Hi Paul,
   Pages 75-82 in the "User's Guide" explains the use of Regular
expressions (the "X" for the Find options means to use regular
eXpressions).

   The ^ means to anchor the search to the beginning of the line.

   The [\d009\d032] denotes the set of the tab character (ASCII decimal
   9) and the space character (ASCII decimal 32).

   The * means zero or more occurences of the preceding character. In
   this case the preceding character is a "set" of characters (the tab
   and the space) that are valid candidates for satisfying the
   condition.

   The $ means the end of the line.

Kyle Watkins (SemWare Technical Support)
/**************************************************************************

===========================================================================
                   Date: 05-18-93  From: KYLE WATKINS
                             Subj: KILLFILE
---------------------------------------------------------------------------

Try the following and see if it is what you want:


proc mKillFile()

//get currentfilename less ext and add .bak as ext.


string filename[65]=SplitPath(CurrFilename(),_DRIVE_|_PATH_|_NAME_)+".bak"

EraseDiskFile(filename)  //erase the currentfile with .bak ext from disk

    killfile()               //erase currentfile from disk
    abandonfile()            //abandon the current file

    updatedisplay(_statusline_refresh_) //clears "erase disk file" message

    editfile("-a- *.*")          // give a pickdir of *.* in the current dir
end

<alt greydel> mKillFile()

Kyle Watkins (STS)

/**************************************************************************

===========================================================================
                Date: 05-18-93  From: RICHARD BLACKBURN
                    Subj: TSE Macro To Run KBD Macr
---------------------------------------------------------------------------

Richard, have you had a chance to develop a TSE macro to load and run
keyboard macros from the command line yet?


Yes, I wanted to test it for a while, before posting it :)  You will need
to add the following to your WhenLoaded() in your TSE.S file:

    string  cmdline[128]    = Query(DosCmdLine),
            temp[128]       = cmdline,
            macrofile[62]   = ''
    integer s1 = 0,
            s2 = 0

    Upper(temp)
    s1 = Pos('-U', temp)
    if s1 == 1 or temp[s1 - 1] == ' '
        macrofile = SubStr(cmdline, s1 + 2, sizeof(macrofile))
        s2 = Pos(' ', macrofile)
        if s2
            macrofile = SubStr(macrofile, 1, s2)
        endif
        LoadKeyMacro(macrofile)
        cmdline = iif(s1 == 1, '', SubStr(cmdline, 1, s1)) + iif(s2 == 0, '', SubStr(cmdline, s1 + 2 + s2, sizeof(cmdline)))
        Set(DosCmdLine, cmdline)
    endif

Once you have added this, be sure to burn it in using SC.EXE.  I picked
-U[KbdMacroName] as the command line switch.  You can change it to whatever
you prefer by chnaging the Pos('-U', temp) to look for the character you
want to use.

Richard Blackburn (SemWare Technical Support)

/**************************************************************************

===========================================================================
                   Date: 05-18-93  From: ALAN DAWSON
                          Subj: DRAGGING TEXT
---------------------------------------------------------------------------
In the spirit of macros sharing:

I'm not a mouse kinda guy, but dragging text is sure one of the neat
things about rodents and GUIs. Here are a couple of keyboard-tied
macros for TSE to let you drag text up and down a file until you
reach the point you want to "drop" it. I don't have any doubt the
macros can be improved, either. They're quick and dirty and work
great for me.

I have these tied to my Ctrl-ArrrowUp and Ctrl-ArrowDown keys. What
they do is this:

If a block is marked, drag it in the direction of the pressed key.
If a block is NOT marked, mark the current line and drag that.

Put the following keys in your TSE.KEY file, compile the macros and put
them in the \tse\mac file, and burn a new copy of E.EXE

<Ctrl CursorDown>     ExecMacro ("linedown")
<Ctrl CursorUp>       ExecMacro ("lineup")

    ----------- lineup.s starts ---------
proc Main ()
   If IsBlockMarked () <1
          MarkLine ()
   Else
          MoveBlock ()
          GotoBlockBegin ()
          BegLine ()
          UP ()
   EndIf
End
    ----------- linedown.s starts ---------
proc Main ()
   If IsBlockMarked () <1
        BegLine ()
        MarkChar ()
        Down ()
        MarkChar ()
        Down ()
  Else
       MoveBlock ()
       GotoBlockEnd ()
       BegLine ()
       Down ()
   EndIf
End

/**************************************************************************

===========================================================================
                   Date: 05-21-93  From: ALAN KELLEY
                        Subj: CUT with _NO_FILL_
---------------------------------------------------------------------------

I have a suggestion for an additional function you might consider if you
ever update it.  I use a Cut with _NO_FILL_ a lot when working on menus
or columnar data (or whenever I don't want anything else to move from
where it's at after a block cut).  It's what I would call the compliment
to the Paste(_OVERWRITE_) command.  In fact I've changed my key def's
around a bit (see below) so my cut_with_no_fill_macro could be assigned
to <Ctrl Grey-> to compliment <Ctrl Grey*>.

<Grey*>                 Paste()
<Grey->                 Cut()
<Grey+>                 Copy()
<Alt Grey->             Cut(_APPEND_)
<Alt Grey+>             Copy(_APPEND_)
<Ctrl Grey*>            Paste(_OVERWRITE_)
<Ctrl Grey->            myCutNoFill()

I'm not much of a programmer, but to give you an idea of what I'm
talking about, here is the macro I came up with.  It seems to work with
any kind of block you throw at it.

proc myCutNoFill()

  PushBlock()
  Copy()
  PopBlock()
  FillBlock(" ")
  GotoBlockBegin()
  UnMarkBlock()

end

/**************************************************************************

===========================================================================
                   Date: 05-19-93  From: DAVID WALKER
                      Subj: Intercepting key input
---------------------------------------------------------------------------
 ͸
 It would help to see the macro as it stands, but what I think you
 are looking for is this looping construct (it's fresh in my mind
 'cause SemWare just told me how <g>):
 
 KeyDef Name()
     <Escape>
     <Enter>
 End
 
 PROC you_are_working_on()
 
     Stuff you are working on....
 
     Enable(Name)
     Process()
     Disable(Name)
 
     More stuff
 
 END
 ;

You're right, Mel.  That's exactly what I was looking for.  Here's my
own version, from the current incarnation of my "copy block from this
window to the other window" macro:

/*
    CpyBlk.S
    Macro to mark a block, then copy it to the next window (at the end).
    Assumes two windows open on the screen [next version should check
     for that].
*/

keydef wMarkSet
    <Escape>    EndProcess()
    <Enter>     EndProcess()
end

integer proc wMark()    // get keys until <Enter> or <Esc> pressed
                        // return TRUE if <Enter> was pressed,
                        // FALSE if <Esc> was pressed
    Message("Mark block to copy, then <Enter>")
    Enable(wMarkSet)
    Process()           // accept everything until EndProcess() executed
    Disable(wMarkSet)
    return(Query(key) == <Enter>)   // 'key' returns the last key pressed
end

proc wCopyBlock()
    MarkStream()        // start marking, then switch to Process()
    if wMark()          // if <Enter> was pressed,
        Copy()          // copy the marked block to the clipboard
        NextWindow()    // Switch to the 'other' window
        Paste()         // Paste the block from the clipboard
        UpdateDisplay() // Make sure the pasted block is visible
        Endfile()       // Move to the end of the file
        NextWindow()    // Back to where we started
    else
        UnMarkBlock()   // if <Escape> was pressed, never mind
    endif
end

<Alt z> wCopyBlock()

/**************************************************************************

===========================================================================
                   Date: 05-22-93  From: DAVID MARCUS
                     Subj: mGetClipboardBlockType()
---------------------------------------------------------------------------
/**************************************************************************
     GET_CLIPBOARD_BLOCK_TYPE

     Determines the type of block that was copied to the current
     clipboard. Returns same integer values as isBLockMarked()
     -- see TSE doc for details.

     D. Marcus -- 5-21-93
/**************************************************************************
integer proc                  get_clipboard_block_type()
     integer tid,                            // temp buffer
          blocktype
     PushPosition()
     PushBlock()
     tid=CreateTempBuffer()
     Paste()
     blocktype = IsBlockMarked()
     AbandonFile(tid)
     PopBlock()
     PopPosition()
     return(blocktype)
end

/**************************************************************************

==========================================================================
                  Date: 05-24-93  From: SAMMY MITCHELL
    Subj: TSE CONFIGURATIONS - switching between two configurations
---------------------------------------------------------------------------

>  I  would  really like to know how to use two different configurations in
>  TSE.  I currently have TSE set with no wordwrap or autoindent, just what
>  I  want  when  I'm  writing  batch files.  But when I write mail, I like
>  those things on.  Is there anyway I can have my standard setting on most
>  of  the time, but when I'm editing mail use my other settings?

If you have specific file extensions that can identify each of these
conditions, then it is fairly easy to do what you ask.  In the
'OnChangingFiles' macro in TSE.S, it contains a case statement based on
the current extension.  Say your mail stuff has an filename-extension of
'ml'. Changing the code to the following should give you what you want:

from:

    language = FALSE
    cmode = FALSE
    case CurrExt()
        when ".s",".asm",".pas",".inc",".prg"
            language = TRUE
        when ".c",".h",".cpp",".hpp"
            language = TRUE
            cmode = TRUE
    endcase

to:
    // assumes mail filename-extension is ".ml"
    Set(WordWrap, off)
    Set(AutoIndent, off)
    language = FALSE
    cmode = FALSE
    case CurrExt()
        when ".s",".asm",".pas",".inc",".prg"
            language = TRUE
        when ".c",".h",".cpp",".hpp"
            language = TRUE
            cmode = TRUE
        when ".ml"
            Set(WordWrap, on)
            Set(AutoIndent, on)
    endcase

This will force WordWrap and AutoIndent off, everytime you change files,
except if the file has an extension of '.ml', in which case these
settings will be turned on.


===========================================================================
                    Date: 05-25-93  From: MEL HULSE
                 Subj: RepeatCommand deleting too much
---------------------------------------------------------------------------

1. If a string search fails, how do I get a repeated macro to abort. I
   use the repeat for 1000 times, but there are only 500 occurances in
   the file.  It will keep deleting at the line where it fails, so I
   lose 500 too many lines.

#INCLUDE this with a keybinding in TSE.S, compile

    ("sc -b \ui\tse")

...and use as the last command in your keyboard macro, run the
macro then use RepeatCmd as in QEdit.

PROC  FindOut()
    If RepeatFind()
        Right()
    Else
        PurgeKeyMacro()
    EndIf
END


<key>                   FindOut()

If you want to use your keyboard macro again, be sure and save it
as the above deletes the loaded copy in order to stop it.

/**************************************************************************

===========================================================================
                    Date: 05-25-93  From: MEL HULSE
                         Subj: WhenLoaded Usage
---------------------------------------------------------------------------

 o
 (Incidentally, why do you refer to them as WhenLoaded
 macros?  They're not by chance tied into the WhenLoaded statement
 in TSE.S (and ALWAYS LOADED AND ACTIVE when the editor starts) are
 they?)
 o

That's it.  Here's the relevant code:

Proc WhenLoaded()
    integer cid = GetBufferId()             /* ppp */

    LoadMacro("c:\SE\macros\utility1")
    LoadMacro("c:\SE\macros\utility2")
    LoadMacro("c:\SE\macros\utility3")

    Set(MacPath, "c:\se\macros\")           // Default Path
    SetGlobalStr("Ruler", "4")

    Set(MouseRepeatDelay, Val(GetEnvStr("MOUSERAT")))  // See below *
    pick_buffer = CreateTempBuffer()
    GotoBufferId(cid)

    Set(CurrVideoMode,_28_LINES_)
    Hook(_ON_CHANGING_FILES_, OnChangingFiles)

    Hook(_ON_FIRST_EDIT_, OnFirstEdit)

End WhenLoaded

/**************************************************************************

===========================================================================
                 Date: 05-23-93  From: JACK HAZLEHURST
                      Subj: DelToBOL with undelete
---------------------------------------------------------------------------
By the way, the delete to BOL routines do it in such a way that you can't
recover with Undelete.  I am now using:

// Delete characters to beginning of line

proc mDelToBOL()
    PushBlock()                 // This does it in a way that can be
    UnMarkBlock()               // recovered by "UnDelete".
    MarkChar()
    BegLine()
    MarkChar()
    DelBlock()
    PopBlock()
end

// proc DelToBOL with undelete

/**************************************************************************

===========================================================================
                 Date: 05-23-93  From: GEORGE DE BRUIN
                  Subj: History Buffer suggested uses
---------------------------------------------------------------------------

The "File(s) to edit:" prompt in TSE has a history that keeps track of
the last 500 entries.  If you have already loaded a file from the
directory you want to go to, all you have to do is scroll through the
history (using the up arrow or down arrow key) until you find that
entry.  Then, delete the file name, leaving the drive/path in tact
(including the final backslash -- ie, 'c:\tse\ui\') and press enter.
That will bring up the directory listing for you.



A variation on this trick would be to have a macro that is executed when
you load the editor push a bunch of entries on the stack for you.  This
way, all you'd have to do is pick the right entry out of the history
list.

Here's a short example macro I would place in TSE.S:

proc EditHist()

    AddHistoryStr("c:\hold\", _EDIT_HISTORY_)
    AddHistoryStr("c:\tse\src\", _EDIT_HISTORY_)
    AddHistoryStr("c:\tse\ui\", _EDIT_HISTORY_)
    AddHistoryStr("c:\c\src\", _EDIT_HISTORY_)
    AddHistoryStr("c:\c\doc\", _EDIT_HISTORY_)

end DirHist

Now, in your WhenLoaded() in TSE.S you would add a call to EditHist()
like this:

proc WhenLoaded()

    /*
     * Whatever else you have in your when loaded.
     *
     */

     EditHist()

end

Of course, after editing TSE.S you'd need to exit TSE and re-burn in
your configuration. (With 'sc -be.exe ui\tse.s')

If you wanted to get real fancy, you could have EditHist() load a file
of the paths you want in the history and insert them into the edit
history.  That way, you could just edit the file instead of having to
change and re-burn in the macro all the time.  (I won't take the time to
develop this right now, but if you are interested, I will put it
together for you.)

/**************************************************************************

===========================================================================
                    Date: 05-25-93  From: MEL HULSE
                    Subj:  Examples of WhenLoaded()
---------------------------------------------------------------------------

That's it.  Here's the relevant code:

Proc WhenLoaded()
    integer cid = GetBufferId()             /* ppp */

    LoadMacro("c:\SE\macros\utility1")
    LoadMacro("c:\SE\macros\utility2")
    LoadMacro("c:\SE\macros\utility3")

    Set(MacPath, "c:\se\macros\")           // Default Path
    SetGlobalStr("Ruler", "4")

    Set(MouseRepeatDelay, Val(GetEnvStr("MOUSERAT")))  // See below *
    pick_buffer = CreateTempBuffer()
    GotoBufferId(cid)

    Set(CurrVideoMode,_28_LINES_)
    Hook(_ON_CHANGING_FILES_, OnChangingFiles)

    Hook(_ON_FIRST_EDIT_, OnFirstEdit)

End WhenLoaded

/**************************************************************************

===========================================================================
                    Date: 05-27-93  From: JAN NOLAN
                 Subj:  Combining SS.mac & SS_Block.mac
---------------------------------------------------------------------------

SS.mac & SS_Block.mac can be easily combined into a single macro. Just
add a new main routine that decides which to do

      if isCursorInBlock() == _LINE_  // Chks for block & block type
           ss_block()                 // ie. the old main() in ss_block
           else
           ss_doc()                   // ie. the old main() in ss.s

/**************************************************************************

===========================================================================
                   Date: 05-31-93  From: ALAN KELLEY
                          Subj: myLoadFiles()
---------------------------------------------------------------------------
  Could you write a macro that calls EditFile, extracts
the directory from the loaded file and issues a dos
call to change to this directory:

Hi Klaus,

Thanks for the myLoadFile() macro. I did have to extend it to work
across drives. This is what I came up with (though I think there must be
an easier way):

proc myEditFile()                //<Alt E>

  string directory[40],
         drive[1]

  if EditFile()
    drive = SplitPath(CurrFileName(), _DRIVE_)
    directory = SplitPath(CurrFileName(), _PATH_)
    if drive == GetDrive()
      Dos ('CD '+directory+'.', _DONT_CLEAR_)
    else
      LogDrive(drive)
      Dos ('CD '+directory+'.', _DONT_CLEAR_)
    endif
  endif

end

Another trick I came up with to use along with this one is to pop up the
directory listing for the directory of the current file with this:

proc myPickFile()                //<F6>

  string filename[40]

  filename = SplitPath(CurrFileName(), _DRIVE_ | _PATH_) + "*.*"

  if EditFile(filename)
    AddHistoryStr(filename, _EDIT_HISTORY_)
  endif

end


  END of LoadFile() TSE macro Monday; May 31 at 0641 hrs  
/**************************************************************************

===========================================================================
                   Date: 06-01-93  From: KYLE WATKINS
                      Subj: TSE START-UP SWITCHES
---------------------------------------------------------------------------
-> The same command with TSE gives a dupe of the first window, rather
-> than a blank, which confuses me. Try changing to something like
-> below:

/**************************************************************************

proc   mhwindow()
         if hwindow()
           editfile()
         endif
end

<key>   mhwindow()

/**************************************************************************
            END  TSE startup switches Wednesday; June 2   
/**************************************************************************

===========================================================================
                  Date: 06-02-93  From: SAMMY MITCHELL
                        Subj: TSE this and that
---------------------------------------------------------------------------

AC> *   Date and time are stamped together -- should be two separate
AC>     commands.

This is actually just a macro:

proc mDateTimeStamp()
    InsertText(GetDateStr(), _INSERT_)
    InsertText(" ", _INSERT_)
    InsertText(GetTimeStr(), _INSERT_)
end

So, for instance, if you wanted <f1> to insert just the date:

<f1> InsertText(GetDateStr(), _INSERT_)

// END of some date inserts

/**************************************************************************
/**************************************************************************

===========================================================================
                  Date: 05-29-93  From: BARRY HARRIDGE
          Subj: mCompile() not within TSE not indicating error
---------------------------------------------------------------------------
I foolishly tried Ctrl-f9 Compile when SC.EXE was neither in my
directory nor on my path. The status line gave the message "unknown
command SC" but then a little menu popped up saying "Compile successful"
and inviting me to Load or Execute! I looked at your proc mCompile(),
then unerased my $errors$.tmp and found it was zero bytes as expected. I
believe that the trouble lies in proc mCompile() where it has

  AbandonFile()
  if NumLines() == 0
    ..
  else
    ..
  endif

because the NumLines() now refers to the current *.S file, not the error
file. I fixed it by moving AbandonFile() to after the "if" , and after
the "else".

/**************************************************************************
/**************************************************************************

===========================================================================
                    Date: 06-04-93  From: MEL HULSE
                        Subj: WhenLoaded() hints
---------------------------------------------------------------------------
?)  Make up files of macros (each with all there PROCs) and their
    bound keystrokes.  I call these files UTILITY1.S,
    UTILITY2.S...  Put the keybindings at the bottom so you can
    copy them easily (see below.) Each file needs to compile to
    less than 16k.

    In the TSE.S WhenLoaded() PROC load these macro files as
    follows:

Proc WhenLoaded()
    integer cid = GetBufferId()

    LoadMacro("c:\TSE\mac\utility1")
    LoadMacro("c:\TSE\mac\utility2")
    LoadMacro("c:\TSE\mac\utility3")
    .   .   .   .   .   .   .   .   .   .

1)  Go into TSE.KEY and copy the keybindings from the other files
    in a commented area.  That way, when you need a new
    keybinding, you can "Find" in TSE.KEY to see if what you want
    is used.

//END WhenLoaded() hints

/**************************************************************************
/**************************************************************************

===========================================================================
                   Date: 06-06-93  From: TOM WHEELER
          Subj: Macro to reverse all lines in a marked block.
---------------------------------------------------------------------------
DN> I am looking for a macro which will reverse the order of all lines in a
DN> marked block, which may not necessarily be in alphabetical order..

It's simple.

  x = number of lines in block.
  while (x)
    gotoblockbegin()
    deleteline()
    gotoblockend()
    down()
    undelete()
  endwhile

/**************************************************************************
 END of:
 Reversing the order of lines marked in a block.Wednesday -  June 9, 1993
/**************************************************************************

/**************************************************************************
/**************************************************************************

===========================================================================
                    Date: 06-09-93  From: MEL HULSE
                        Subj: Format left margin
---------------------------------------------------------------------------

 Ĵ TOM WHEELER on Monday the 7th of June 1993
 HS> Does anyone have a simple way I must be overlooking to start all
 HS> text in a file from column 2 (or 3, or whatever)?
 >

 o TSE mReturn2(),
 ...which does Return(), Right(), Right().  If you want to be able
 to modify the indentation level use a global variable and
 RepeatCommand().  Damn, just checked the book, and it says
 RepeatCommand() asks the user.
 o

If you want to do it this way, an undocumented feature takes care
of this.
              Ŀ
               Implement within the TSE.S environment.
              

Integer Ndent               // global variable

Somewhere in WhenLoaded():

    NDent = 2

PROC SetNdent()
    String sNdent[2] = Str(Ndent)

    If Ask("Left Margin...", sNdent)
        Ndent = val(sNdent)
    EndIf
END

PROC DoNdent()
    CReturn()
    Right(Ndent)             // Note cursor movements can take an integer
End

<key            SetNdent()
<Enter>         DoNdent()

// END of TSE procedure to Format left margin

/**************************************************************************
 END   TSE Format left margin with SetNDent() & DoNdent()  06/10/93
/**************************************************************************

/**************************************************************************
Thursday -  June 10, 1993  Changed ClipboardMenu() in 'tak.s' to add
                           turn WordWrap ON/OFF.  changes marked with
                           //tak
/**************************************************************************
Menu ClipboardMenu()

    history

    "Cu&t"              ,   Cut()
    "C&ut Append"       ,   Cut(_APPEND_)
    "&Copy"             ,   Copy()
    "Cop&y Append"      ,   Copy(_APPEND_)
    ""                  ,                       , Divide
    "&Paste"            ,   Paste()
    "Paste &Over"       ,   Paste(_OVERWRITE_)


    ""                  ,                       , Divide
    "&Named ClipBoards  ", NamedClipBoardMenu(), DontClose

//tak additions below

    ""                  ,                       , Divide
    "&WordWrap ON"      ,   Set(WordWrap,ON)
    "WordWrap &OFF"     ,   Set(WordWrap,OFF)

//tak additions END

end //  ClipBoardMenu()
/**************************************************************************
 END changes to 'tak.s' to add selection of WordWrap ON/OFF to
     ClipBoardMenu()  6-10-93
/**************************************************************************

/**************************************************************************

===========================================================================
                   Date: 06-09-93  From: RAY OCONNOR
---------------------------------------------------------------------------
//tak tickler:  Make a menu selection for Help() <F1> and the selection
      will be context selectable.  e.g.  Block operations, file operations,
      make one option the ability to view the '*.hlp' file

  Online documentation is something I have become quite dependent upon.
  Use it all the time for C++.   The online docs don't replace the manuals
  but, they are a great supplement.

   proc Help()

       EditFile("TSE_HELP.ME")
       mCompressView(1)

   end Help

   <hot_key>  Help()

/**************************************************************************
 Tickler for making F1 help() a menu with selectable help files by context
/**************************************************************************

//*************************************************************************
/************************  Start Comment Area *****************************

===========================================================================
                    Date: 06-13-93  From: MEL HULSE
              Subj: TSE - adding to block to TAK Commenter
---------------------------------------------------------------------------

 
 e.g. Paragraph after running Commenter v2.0
 
 REM  The SemWare Editor (or TSE, as affectionately named by our beta
 REM  testers) is licensed, commercial software.  Please help us stay in
 REM  business by respecting our copyright and keeping this version
      private.
 > MEL HULSE

Oh!  That should be easy.  The key is being sure the text to be
REM'd is marked.

1)  Save the right margin to a variable and change it to the
    value you want minus the space for REM.

2)  While the text is blocked, do a WrapPara() from the block
    begining.  You don't need my macro.

3)  GotoBlockBegin()

4)  Do this:

  *************************************************************************/
//tak******************* END of Comment Area ******************************

    While IsCursorInBlock()
        InsertText("REM ", _INSERT_).
        Down()
    EndWhile

5)  UnMark the block and restore the right margin.

That'll put the REM in front of each line of the text.

That do what you want?

//tak**********************************************************************
//END  Adding to block in TAK Commenter  Monday -  June 14, 1993
//tak**********************************************************************

===========================================================================
                   Date: 06-14-93  From: DAVID MARCUS
                   Subj: Removing Double Blank Lines
---------------------------------------------------------------------------

This macro deletes all blank lines that are adjacent to another blank
line or at top or bottom of file. Useful for cleaning up text files or
screen captures.

proc deblank()
        integer old = NumLines()
     PushPosition()
        BegFile()
        while CurrChar() < 0     // remove blanks from beginning
                DelLine()
        endwhile
        repeat                          // remove from body of file
          if CurrChar() < 0
                Down()
                while ( CurrChar() < 0 )
                  AND ( CurrLine() < NumLines () )
                        DelLine()
                endwhile
          endif
        until NOT Down()
     while CurrChar() < 0     // remove from end of file
           DelLine()
           Up()
     endwhile
     PopPosition()
     UpdateDisplay()
        Message( Str( old - NumLines() ) + " lines deleted")
end

//tak**********************************************************************
//TSE macro to Remove double blank lines. Tuesday -  June 15, 1993
//tak**********************************************************************

//*************************************************************************

===========================================================================
                Date: 06-17-93  From: RICHARD HENDRICKS
                            Subj: '}' & '{'
---------------------------------------------------------------------------
JH>I am having trouble with TSE with the '}' and '{' keys.  They seem to
JH>invoke some special formatting stuff and jump to wierd places.  Is
JH>there some way to deactivate this and have '{' and '}' be just like
JH>any other letter?  John Ham

In your TSE.S file, you probably have some lines something like the
following...

// Global variables - assumes globals initialized to 0. // Line 76 or so

integer
    cmode,              // used to invoke C-mode
    language,           // used to invoke language package

// ....

proc OnChangingFiles()
    string fn[65] = CurrFilename()
    integer mk, cid = GetBufferId()

// .....

    language = FALSE
    cmode = FALSE
    case CurrExt()
        when ".s",".asm",".pas",".inc",".prg"
            language = TRUE
        when ".c",".h",".cpp",".hpp"
            language = TRUE
            cmode = TRUE
    endcase
end

Depending on the settings for 'language' and 'cmode' the '{' and '}' will be
handled specially.

//*************************************************************************
  Handling of { and } ----- 'language' and 'cmode' need to be set
//*************************************************************************
===========================================================================
                    Date: 06-19-93  From: MEL HULSE
                    Subj: Cheap and Dirty WHILE loop
---------------------------------------------------------------------------

PROC foo()
    Integer i = 10
    While i = 0
        [command to be repeated]
        i = i - 1
    EndWhile
END

===========================================================================
                Date: 06-22-93  From: RICHARD HENDRICKS
                    Subj: Convert:Grphic Box 2 Text
---------------------------------------------------------------------------
Sometimes I need to convert all the Extended ASCII graphics characters to
more printable or e-mailable characters. Here is a macro that I wrote that
does that.                                    ͻ
                                              ͹
For example -- the file contains boxes like:                        
                                                                    
                                              ͼ

                                   +----------------------+
run GRP2TXT and you will now have: +----------------------+
                                   |                      |
                                   |                      |
                                   +----------------------+

Have fun..
    Richard // Saturday June 19, 1993 at 14:56:34 EST

// grp2txt.S  03/27/1992  12/09/1992
// by Richard Hendricks

// Suggests by STEVE WATKINS, SemWare & RICHARD BLACKBURN, SemWare

proc Main()
    pushposition()
    begfile()
    replace('[]','+','qxnq')
    // replace('[----]','+','gxnq') --- shorter but less
    // readable form of line above
    begfile()
    replace('[]', '|', 'gxnq')
    begfile()
    replace('[]', '-', 'gxnq')
    popposition()
end main

// end-of-message
//*************************************************************************
  Convert boxes to text characters
//*************************************************************************

===========================================================================
                   Date: 06-19-93  From: TOM WHEELER
                          Subj: Comment macro
---------------------------------------------------------------------------
Here's one for formatting comments in C++ or SAL code.

It either creates a "comment header" ("// "), or makes sure the comment
starts at the correct column.  Then it puts the cursor just past the
header for text insertion/editing.  I hardcoded the column at 41.  A
neat expansion would be the ability to reformat the comments in a block.

I hereby donate this code to the public domain.  Use it, abuse it,
or misuse it as you see fit, unfit, or misfit.

/*************************************************************************
  mComment()                                    6-19-93 Tom Wheeler

  Macro to Create or edit/format a C++ style comment on the cursor line

  Algorithm:

  If there is no comment header ("// ") on the line then it creates
    one either at column 41 or at the first tabstop past end of
    line, if the line is longer than 41 characters
  Otherwise, try to make sure the comment starts at column 41
  Go right 3 characters

*************************************************************************/
proc mComment()
    integer save_insertmode = Query (Insert)
    integer ComCol = 41                 // hardcoded - so who cares?

    Set (Insert, 1)

    BegLine()
    PushBlock()
    MarkLine() MarkLine()
    if (not lFind ("// ", "l"))
        EndLine()
        if (CurrCol() < ComCol)
            GotoColumn (ComCol)
        else
            GotoColumn (CurrCol() + DistanceToTab (1))
        endif
        InsertText ("// ")
    else
        if (CurrCol() < ComCol)
            while (CurrCol() <> ComCol)
                InsertText (" ")
            endwhile
        elseif (CurrCol() > ComCol)
            while (CurrCol() <> ComCol and mLeftChar() == 32)
                BackSpace()
            endwhile
            if (mLeftChar() <> 32)
                InsertText ("   ")      // Note - this is a physical
                                        // tab (ASCII 9), NOT SPACES
            endif
        endif

        Right (3)
    endif
    UnmarkBlock()
    PopBlock()
    Set (Insert, save_insertmode)
end

//*************************************************************************
  Inserts comments '//' at column 41
//*************************************************************************

  06/24/93  If you want a macro to open HWindow() and you want it to
  start from the initial command the put UpdateDisplay() before the
  HWindow() command in the macro.
//*************************************************************************
//*************************************************************************

===========================================================================
                  Date: 06-26-93  From: VERNON LEONARD
                    Subj: Vernon's Commenter macro
---------------------------------------------------------------------------

    I haven't seen your marco to do the comments, it may be close to
    the one I did (below). I also added a few lines to remove the
    the comment lines since I was usally trying to find where the
    problem was in the code.

//*************************************************************************
    proc mComment()
        integer type = 0
        string word[12] = ""

        type = isCursorInBlock()    // see if the cursor is in the block
        if type
            GotoBlockBegin()        // we are so goto the begining of block
            Begline()               // make sure we are in 1st column
        endif
        PushPosition()              // Save where we are at just in case
        word = GetText(CurrCol(),2) // get the first word on the line
        PopPosition()               // now go back there
        if word == "//"             // we are in comments block
            while type              // start loop
                DelChar()           // delete the comments
                DelChar()
                DelChar()           // and the space
                Down()              // got down a line
                type = isCursorInBlock()  // are we still in the block
            endwhile                // end loop
        else                        // no comments
            while type              // begin loop for comments
                BegLine()           // make sure we are at 1st column
                InsertText("// ")   // insert the comments
                Down()              // down a line
                type = isCursorInBlock()  // are we still in the block
            endwhile                // end the while loop
        endif
        UnMarkBlock()               // unmark the block
    end mComment                    // that's all folks

//*************************************************************************
===========================================================================
                    Date: 06-26-93  From: MEL HULSE
                      Subj: Better Movement Macros
---------------------------------------------------------------------------

 Ĵ RAY ASBURY on Friday the 25th
 In the case of GotoColumn() and GotoLine(), I wanted a combined
 command, similar to the "-n" command line option of TSE (by the
 way - another tester help some with the replacement macro for
 these, but I can't for the life of me remember who it was <b>).
 > ALL

Do you mean this one <g>:
    -   -   -   -   -   -   -   -   -   -   -   -   -   -   -
/*  Goto Line and/or column.

    Bind to a key.

    Use.

    To a line only          - Answer prompt with the line number.
    To a column only        - Answer prompt with a comma followed
                              by the column number.
    To a line and column    - Answer prompt with the line number,
                              a comma and the column number.

    Ray Asbury, David Marcus, and Mel Hulse
    March 28, 1993
*/

PROC GoCol(STRING s)
    GotoColumn(val (SubStr(s,Pos(',', s)+1 ,3)) )
END

PROC linecolumn()

    STRING  s[10] = ''
    Integer linecol_hist = 250

     if Ask('Goto [line][,column]:', s, linecol_hist)
          If s == ""
            message("No Entry...")
          elseif s[1] == ","
             GoCol(s)
          elseif NOT Pos(',', s)
             GotoLine(Val(s))
          else
             GotoLine(val (SubStr(s, 1, Pos(',', s) -1)) )
             GoCol(s)
          endif
     endif
END
===========================================================================
===========================================================================
                   Date: 06-28-93  From: KYLE WATKINS
                          Subj: Sizing Windows
---------------------------------------------------------------------------

   You can use PushKey() with the appropriate cursor keys to resize
   a window.  When you use PushKey() to push keystrokes on the stack,
   it is on a LIFO (Last In First Out) basis.  PushKey() is described on
   page 151 of the Advanced User's Guide.

   The following example procedure will open a Horizontal window and
   then reduce the height of the new window by 4 lines.

proc mReduceWindow()
        if hwindow()
            pushkey(<enter>)
            pushkey(<cursordown>)
            pushkey(<cursordown>)
            pushkey(<cursordown>)
            pushkey(<cursordown>)
            pushkey(<cursorup>)
            resizewindow()
        endif
end


   When Resizewindow() is called, the pushkey(<cursorup>) selects the top
of the window, the 4 pushkey(<cursordown>) moves the bar down for
positions, and the pushkey(<enter>) causes the window changes to be
accepted.
   If a new horizontal window cannot be opened, the resizewindow() is
bypassed.

===========================================================================
                   Date: 06-29-93  From: KYLE WATKINS
                       Subj: Regular Expressions
---------------------------------------------------------------------------

   You can use "regular expressions" with the Find() command to find the
   occurrence of "-" at the end of a line.  See page 75-82 of the
   "User's Guide" for information about "regular expressions".

For instance:

   Find("-$","X") will find any "-" that is the last character on a
   line. The "$" specifies the end of line, and the "X" specifies to use
   "regular expressions".

You can have:

   while Find("-$","X")
        delchar()
        joinline()
        wordright()  //assumes that you remain on the same line.
                     //you may want to adjust macro to take into
                     //account that this may carry you to next line
                     //and also adjust for a blank line following.

        splitline()
   endwhile

I am not sure how you are defining the page..... if your page has a
FormFeed character present in the file, then you can account for this by
checking to see if the Formfeed character follows finding the "-" at the
end of line.

//*************************************************************************
//*************************************************************************

===========================================================================
                   Date: 06-29-93  From: KYLE WATKINS
                     Subj: More Regular Expressions
---------------------------------------------------------------------------

-> 'any occurrence of a period followed by a nonwhitespace'

    Find("\.[~\d009~\d032]","X+")

-> 'all occurrences of a numeral preceding a period'

    Find("[0-9]\.","X+")

-> 'find period whitespace lowercase-alphacharacter ". (a-z)" '

    Find("\.[\d009\d032][a-z]","X+")

//*************************************************************************
//*************************************************************************
===========================================================================
                    Date: 07-07-93  From: RAY ASBURY
                       Subj: PROJECTS Suggestion
---------------------------------------------------------------------------

After seeing a message you sent to George telling him that you're about
to release a new verison of PROJECTS, I wanted to suggest something.  I
would very much like to be able to specify whether to return to the
"current directory" as saved in the project file, or to return to the
"actual" current directory when TSE was started.  Maybe even a user
prompt

    "Return To Original Directory"
    "Stay In Project's Home Directory"
    "Abort Exit"

Just a thought.

<1 Hrs Later>

Heck, I went ahead and did it myself!  Here are the changes that I made
(ALL TO PROJECTS.S):

    ADD THE FOLLOWING PRETTY MUCH ANYWHERE:

        PROC mGetStartupDirectory()
            DOS("CD > C:\TEMP\@@ERA@@~", _DONT_CLEAR_|_DONT_PROMPT_)
        END mGetStartupDirectory

        PROC mRestoreStartupDirectory()
            EditFile("C:\TEMP\@@ERA@@~")
            LogDrive(Chr(CurrChar()))
            MarkStream()
            EndLine()
            Left()
            MarkStream()
            DOS ("chdir " + GetMarkedText(), _DONT_CLEAR_|_DONT_PROMPT_)
        END mRestoreStartupDirectory

        MENU menuExitDirectory()
            Title = "Exit To Startup Directory?"
            History

            "&Yes"
            "&No"
        END menuExitDirectory

    IMMEDIATELY BEFORE THE SAVEALLANDEXIT() CALL IN
    mSaveFilesWithStatus(), ADD THE FOLLOWING:

        again:
            menuExitDirectory()
            CASE (MenuOption())
                WHEN 1
                    mRestoreStartupDirectory()
                WHEN 2
                    UpdateDisplay()
                OTHERWISE
                    goto again
            ENDCASE

    SOMEWHERE IN WhenLoaded(), ADD THE FOLLOWING:

        mGetStartupDirectory()

//*************************************************************************
  TSE select directory up exit                     Thursday -  July 8, 1993
//*************************************************************************

//*************************************************************************

===========================================================================
                        Sunday -  July 11, 1993
---------------------------------------------------------------------------
RA> using Shift, pressing Alt-Q, P would only work if the Cap Locks is OFF.
RA> Key binds are case sensitive ONLY on the second key and ONLY when using
RA> two-key <Alt>'s, such as <Alt Q><P> & <Alt Q><Shift P>.  I don't believe
RA> the single keys, or the first key of a two-key bind, are case sensitive.

Finally it's cleared up!!  The below works:

---------------------------------------------------
proc Test1()
    Message ("Test 1")
end

proc Test2()
    Message ("Test 2")
end

<Alt p><X>             test1()
<Alt P><Shift x>       test2()
//*************************************************************************
                        Sunday -  July 11, 1993
//*************************************************************************

===========================================================================
                 Date: 07-12-93  From: GEORGE DE BRUIN
                    Subj: TSE - Query(Type of block)
---------------------------------------------------------------------------

--> Is there any way to detect the block type?

Both the "isBlockInCurrFile" and "isCursorInBlock" procs will return the
block type.  I used them in BoxIt! to check for the presence of a block,
and the type of block (example follows):

    if isBlockInCurrFile() <> _COLUMN_  // Is there a column block in current
        message("No Column Block In File.") // buffer? If not, then return.
        return()
    endif

    if isCursorInBlock() <> _COLUMN_    // Is the cursor in the block?
        message("Cursor Not In Block.") // If not, then return.
        return()
    endif

The first "if" does what you want it to.
//*************************************************************************
  Detecting Block Type                           Wednesday -  July 14, 1993
//*************************************************************************

===========================================================================
                   Date: 07-13-93  From: KYLE WATKINS
                   Subj: Endless loops...(BREAK, ON)
---------------------------------------------------------------------------
-> Is there a way to interrupt a macro when its trapped in an endless loop?

    Page 189 of the Advanced User's Guide contains a description of the
Break editor variable. You can set this ON at the beginning of your macro
,saving the current state of the Break variable before setting it ON so
that you can restore it to the state it was in before running your macro.

e.g.

proc something()
   integer breakset=set(break,on)
         .....
         .....
      your routine
         ....
         ....
    set(break,breakset)
end

   You can now use <CTRL BREAK> to stop the running macro.
//*************************************************************************
  Using BREAK to stop an runaway TSE macro       Wednesday -  July 14, 1993
//*************************************************************************

===========================================================================
                    Date: 07-11-93  From: RAY ASBURY
                            Subj: TSE hooks
---------------------------------------------------------------------------

There is also a very round about way of doing this via the Hook()
command, but I'm not even going to think I could explain it fully.  The
idea is to Hook() a macro in TSE.S just before calling an external
macro.  Then, anytime you wanted to execute a macro in TSE.S, just cause
the Hook()'d condition to occur.  For example, in TSE.S,

    CONSTANT INCREMENTAL_SEARCH_MACRO = 1, CURRENT_EXT_MACRO = 2 // etc.

    PROC mCallExtMacro()
        Hook(_ON_CHANGING_FILES_, mCallTSEDotSMacro)
        ExecMacro("ExtMacro")
        Hook(_ON_CHANGING_FILES_, YourUsualHookedMacro)
    END

    PROC mCallTSEDotSMacro()
        CASE GetGlobalInt("gTseDotSMacroToRun")
            WHEN INCREMENTAL_SEARCH_MACRO
                mIncrementalSearch()
            WHEN CURRENT_EXT_MACRO
                mCurrExt()
        ENDCASE
    END

Then, your external macro could simply do something like

    CONSTANT INCREMENTAL_SEARCH_MACRO = 1, CURRENT_EXT_MACRO = 2 // etc.

    SetGlobalInt("gTseDotSMacroToRun", INCREMENTAL_SEARCH_MACRO)
    EditFile(CurrFileName())

Ta-da!!  You just called a TSE.S macro from inside an external macro!  I
know, it's not very clean, but it does work. <G>
//*************************************************************************
  Utilizing hooks                                Wednesday -  July 14, 1993
//*************************************************************************

===========================================================================
                   Date: 07-15-93  From: DAVID MARCUS
                           Subj: NameClip Fix
---------------------------------------------------------------------------
The following is a fix to a bug in NameClip that was causing the
UnMarkAfterCopy switch to not work.  The changes are in the proc named
Clipboard, which begins at about line 310 in nameclip.s.

1. Find these lines:

    UMAP = set(UnMarkAfterPaste,FALSE)
    if UMAP
          PushBlock()
    endif

Change to:

    if operation == PASTE_APPEND or operation == PASTE_OVERWRITE
          UMAP = set(UnMarkAfterPaste,FALSE)
          if UMAP
               PushBlock()
          endif
    endif

2. Find these lines:

    if UMAP
         PopBlock()
    endif
    set(UnMarkAfterPaste,UMAP)

Change them to:

    if operation == PASTE_APPEND or operation == PASTE_OVERWRITE
        if UMAP
               PopBlock()
          endif
          set(UnMarkAfterPaste,UMAP)
     endif

This will be incorporated into the next version of NameClip, but I
wanted to send them now to avoid any frutration. As far as I know they
only affect UnMarkAfterCopy.

//*************************************************************************
  TSE 'nameclip.s' fix to umark block after copy                   07/16/93
//*************************************************************************

===========================================================================
                   Date: 07-15-93  From: DAVID MARCUS
                 Subj: NameClip() Same Fix as above???
---------------------------------------------------------------------------

I've found the reason that the UnMarkAfterCopy after failing ... it
was a poor implementation of my UnMarkAfterPaste switch. You can fix
it yourself by changing the following in your code. Both of these
examples are in the proc Clipboard(), which begins at line 1826 in the
file you sent me.

1. Go to line 1892 and add this line _after_ it:

     endif

2. Go to line 1888 and add these two lines _after_ it:

    if operation == PASTE_APPEND or
       operation == PASTE_OVERWRITE

The result is:

    if operation == PASTE_APPEND or
       operation == PASTE_OVERWRITE
    if UMAP
          PopBlock()
    endif
    set(UnMarkAfterPaste,UMAP)

3. Go to line 1847 and add this line _after_ it:

     endif

4. Go to line 1843 and add these two lines _after_ it:

btw, Line 1558 was still missing the  terminating /

Let me know if anything else comes up. I'll be getting this fix to the
copy on the BBS soonish.

=d=

    if operation == PASTE_APPEND or
       operation == PASTE_OVERWRITE

The result is:

    if operation == PASTE_APPEND or
       operation == PASTE_OVERWRITE
    UMAP = set(UnMarkAfterPaste,FALSE)  // This allows us our choice
    if UMAP                             // of beg/end block after paste
          PushBlock()
    endif
    endif

//*************************************************************************
  TSE unmark block after copy. Could be the same as previous.      07/16/93
//*************************************************************************

===========================================================================
                  Date: 07-24-93  From: SAMMY MITCHELL
                        Subj: FIND PASTED STRING
---------------------------------------------------------------------------

I'll do my best to try to explain the concepts behind what is going on
(and maybe even why!).

First, lets look at the goals.  Do you want to
a> mark the string, cut it, and then run the macro (3 steps) or
b> mark the string, and run the macro (2 steps)

In designing TSE, we felt like b> was what users wanted to do most of
the time, so we proceeded accordingly.

QEdit, because of its simple-minded scripting capability, enticed users
to do a> (even though b> could have been done in QEdit, it wasn't quite
a straight forward, and as reliable).

In TSE, you can _interactively_ copy a marked string into a prompt via
the CopyBlock command (you could _not_ do this in QEdit - you _had_ to
first copy/cut it to the Clipboard), or a string in the Clipboard via
the Paste command.

In macros, things are a little different.  In TSE, built-in
commands/functions take either integer or string input.  And TSE has
macro-oriented commands to extract strings (and string blocks) from the
currently edited file.  These commands are GetText, and GetMarkedText.
For example, in a macro, to find the next occurrence of the currently
marked string:

    lFind(GetMarkedText(), "")

And TSE commands return either a string or an integer.  For example, the
Paste command, pastes the Clipboard contents at the current position,
whether it be a file or a prompt.  However, the Paste command returns an
integer, indicating whether the operation was successful or not.

I hope this helps explain some of the concepts!  Now on to your specific
problem,  "How to get a string out of the Clipboard, for use in a macro".


/**********************************************************************
  Macro to get a string from the Clipboard.  The current contents of
  the Clipboard are unchanged.

  Returns only the first line of the text in the Clipboard.

  Notes:  We could use PushPosition/PopPosition in lieu of GotoBufferId;
  however, this could produce side-effects (the 'hook' functions), so
  just to be save, we use the latter.
 **********************************************************************/
string proc ClipBoard2String()
    integer id = GetBufferId()          // save where we're at
    string s[80]

    GotoBufferId(GetClipBoardId())      // switch to clipboard
    s = GetText(1, sizeof(s))
    GotoBufferId(id)                    // and return to previous file
    return (s)                          // return string to caller
end

proc DelSaved()
    lFind(ClipBoard2String(), "")
    DelLine()
end

<alt f6>DelSaved()

Of course, you might want to add just a little error checking to your
DelSaved routine, to keep from inadvertently deleting lines, in case you
forget to place something in the ClipBoard in the first place, or no
further occurrences of the string are found.

proc DelSaved()
    string s[80] = ClipBoard2String()

    if Length(s) <> 0
        if lFind(s, "")
            DelLine()
        else
            Message(s, " not found...")
        endif
    else
        Warn("Clipboard empty")
    endif
end


And now, after all that, here is something I've been using to do things
with strings - find and delete them, copy or cut them to the Clipboard.
I hope you can make use of it too!

To use it, assign mFindAndDo() to a key (or place it under the Search
menu like I did - I've replaced the 'Count' function with it, since it
can also 'count' occurrences of a string).  Now, either place your
string in the Clipboard, or just mark it.  Execute FindAndDo, and you'll
have the option of counting, deleting, copying/cutting all lines that
contain the requested string.  You'll get a find prompt; just either
type the string in, or press CopyBlock or Paste to get a saved one.

Anyway, hope this is of interest:


/***********************************************************************
  Find and do.

  Applies one of several options to a found string.
 ***********************************************************************/
constant
    dofCOUNT = 1, dofDELLINE = 2, dofCUTAPPEND = 3, dofCOPYAPPEND = 4

menu FindAndDoMenu()
    History
    Title = "After Find do"

    "Cou&nt"
    "&Delete Line"
    "C&ut Append"
    "&Copy Append"
end

proc mFindAndDo()
    integer choice, curr_id, count, n, old_sound
    string find_st[65] = '', find_option_st[12] = ''

    curr_id = GetBufferId()
    choice = FindAndDoMenu()
    case choice
        when 0
            return ()
        when dofCUTAPPEND, dofCOPYAPPEND    // cut/copy to buffer
            GotoBufferId(GetClipBoardId())
            EmptyBuffer()
            GotoBufferId(curr_id)
    endcase
    count = 0
    PushPosition()
    if Ask("Search for:", find_st, _FIND_HISTORY_) and Ask("Options [BGLIWX]
(Back Global Local Ignore-case Words reg-eXp):", find_option_st,
_FIND_OPTIONS_HISTORY_) and lFind(find_st, find_option_st)
        old_sound = Set(sound, off)
        repeat
            count = count + 1
            n = NumLines()
            case choice
                when dofDELLINE
                    DelLine()
                when dofCUTAPPEND, dofCOPYAPPEND
                    PushBlock()
                    MarkLine()
                    MarkLine()
                    if choice == dofCUTAPPEND
                        Cut(_APPEND_)
                    else
                        Copy(_APPEND_)
                    endif
                    PopBlock()
            endcase
            if NumLines() < n
                BegLine()
                PrevChar()
            endif
        until not lRepeatFind()
        Set(sound, old_sound)
    endif
    PopPosition()
    Message(count, " occurrences found")
end
//*************************************************************************
  TSE find pasted string explanation by Sammy Mitchel              07/25/93
//*************************************************************************

===========================================================================
                  Date: 07-24-93  From: SAMMY MITCHELL

---------------------------------------------------------------------------

Did you know you can have the statusline on the bottom and the help line
on the top?  But anyway, as for the 'toggle help/statusline on/off':

<f1> // Toggles between statusline/helpline on bottom of screen
    if Query(ShowStatusLine)
        Set(StatuslineAtTop, ON)
        Set(ShowStatusLine, OFF)
        Set(ShowHelpLine, ON)
    else
        Set(StatusLineAtTop, OFF)
        Set(ShowStatusLine, ON)
        Set(ShowHelpLine, OFF)
    endif
    UpdateDisplay()

//*************************************************************************
  Toggling statusline/helpline ON-OFF                             07/25/93
//*************************************************************************

===========================================================================
                   Date: 07-25-93  From: DAVID MARCUS

               Subj: rePos(), reSubStr(), rePlaceChars()
---------------------------------------------------------------------------

One of the occasional frustrations in TSElife for me has been that I
cannot use regular expressions in the Pos() and SubString() commands.

Being that my wife is out of town for a fortnight, we now can use
these. I've developed three macros that I am uploading in subsequent
messages:

       rePos() : Returns the start position of 'needle' within
                 'haystack,' using regular expression search
                 and any additional specified search s and replace
                 options.

    reSubStr() : Returns the string matching regular expression
                 'needle' from within string 'haystack', using options
                 specified (if any).

rePlaceChars() : Returns a string calculated by taking string
                 'haystack' and replacing string 'needle' with string
                 'thread', using regular expression search and any
                 specified options. This 12-line proc can also be used
                 to:
                 * delete needle from haystack
                 * trim all spaces from the beginning or end of a string
                 * insert one string into another at a specified
                   position.
                 * do multiple replaces within the string (argument
                   specifies how many, or all)
                 * do multiple deletes within the string (argument
                   specifies how many, or all)

Please let me know any problems with these, or ways that they can be
enhanced to make them more useful for you!

===========================================================================
                             Subj: rePos()
---------------------------------------------------------------------------

/**************************************************************************
     rePos() : Returns the start position of 'needle' within
               'haystack,' using regular expression search and any
               additional specified search and replace options.

               Examples:

                    n = rePos(last_name, full_name, 'i')

                    if rePos('M[r]?s.', full_name, '^i')
                         sex = 'F'
                    endif

                    (last_name and full_name are two strings in your
                     proc.)

               Returns 0 (FALSE) if not found.

 *************************************************************************/

integer proc rePos(STRING needle, STRING haystack, STRING options)
     integer bid = CreateTempBuffer(),
             location = 0
     AddLine(haystack)
     if lfind(needle, options + 'x')
          location = CurrPos()
     endif
     AbandonFile(bid)
     Return(location)
end

---
===========================================================================
                          Subj: reSubString()
---------------------------------------------------------------------------
/********************************************************************
 reSubStr() : Returns the string matching regular expression 'needle'
              from within string 'haystack', using any additional
              search/replace options specified (if any).

              Returns '' (empty string) if not found.

              Example:
                    title =  rePos('[DM][r]?[s]?\.', full_name, '^')
              Returns
                    Dr.  Mr.  Mrs.  Ms.
                    Title is equal to any of these if they are at the
                    beginning of full_name.



**************************************************************************/
string  proc reSubStr(STRING needle, STRING haystack, STRING options)
     integer
          bid = CreateTempBuffer()
     string
          s[255] = ''
     PushBlock()
     UnMarkBlock()
     AddLine(haystack)
     if lfind(needle, options + 'x')
          MarkChar()
          BegLine()
          if lfind(needle + '\c', options + 'x')
               MarkChar()
               s = GetMarkedText()
          else
               s = ''
          endif
     endif
     AbandonFile(bid)
     PopBlock()
     Return(s)
end

---
===========================================================================
                          Subj: rePlaceChars()
---------------------------------------------------------------------------
/**************************************************************************
rePlaceChars()

NOTE: 12 lines--80 bytes compiled--possibly the most useful and
      versatile single proc I've ever written.

Returns a string calculated by taking string 'haystack' and replacing
string 'needle' with string 'thread' using regular expression search
and any specified options. Returns haystack (unchanged) if no find
occurs. Example:

     full_name = rePlaceChars( first_name,    // find this
                               full_name,     // in this
                               initial,       // replace with this
                               'wi')          // using these opts

Use of ^ and $ in options allows this to be used to delete a string
[of spaces or text] from the start or end. To trim all spaces from
the end of a string, for instance:

     old_str = rePlaceChars( ' #',      // 1 or more spaces
                             old_str,
                             '',        // replaced with ;;
                             '^' )      // beginning

To trim them from the end of the string replace '^' with '$', above.
To trim them from both the beginning and the end:

     old_str = rePlaceChars( '{^ #}|{ #$}',  // see your manual
                             old_str,
                             '',
                             '2' )           // must allow 2 replaces

You can use rePlaceChars to insert a string into the middle of another
at aspecified position. For instance:

     old_str = rePlaceChars(
                              Format( '' : 5 :'.' ),  // 5 = insert pos
                              old_str,                // string input
                              '\0' + ins_str,
                              ''                      // no special opts
                            )

To place it 5 chars before the END of old_str, change '' to '$'.

Finally, you can use a number as part of option string to have that
nunber of occurrences of needle replaced by thread (if it occurs > 1
time).  Use 0 to mean 'replace all occurrences'.

     old_str = rePlaceChars(
                              ' ',               // space
                              old_str,           // string input
                              ''                 // no replace
                              '12'               // number of times
                            )
This deletes the first 12 spaces anywhere in the string.
**************************************************************************/
string  proc rePlaceChars(STRING needle, STRING haystack,
                          STRING thread, STRING options)
     integer
          bid = CreateTempBuffer()
     string
          s[255] = ''
     AddLine(haystack)
     lreplace(needle, thread, options + 'xn1')
     s = GetText(1,CurrLineLen())
     AbandonFile(bid)
     Return(s)
end
---
//*************************************************************************
             rePos(), reSubStr(), rePlaceChars()  07/26/93
//*************************************************************************

===========================================================================
                   Date: 07-20-93  From: BOB CAMPBELL
              Subj: Deleting Blank Lines macro DelBlank()
---------------------------------------------------------------------------
/**************************************************************************
 Written by Bob Campbell 5/8/93
 DelBlank.mac deletes all blank lines saving only one blank
 between paragraphs.  Printer FormFeeds will be converted
 to an extra blank line.

 Usage:  ExecMacro("DelBlank")
 **************************************************************************/

integer Proc mIsParaEnd()
   integer  CurLine,  NextLine
       CurLine = CurrLineLen()
       Down()
       NextLine = CurrLineLen()
       Up()
       If Curline >= 1 and NextLine == 0
           Return (TRUE)           // And return success
       Endif
           Return (FALSE)          // And return false
end

proc mDelBlanks()
    if  CurrLineLen() >= 1
        if mIsParaEnd()
           Down(2)
        else
           Down()
        Endif
    else
        DelLine()
    Endif
end

proc Main()
    string x[1], y[1], z[2]
     x=""        // Form feed
     y=" "        // Replacement for form feed characters
     z="gn"       // Start search at file beginning, do not confirm
    BegFile()
    while Down()
       up()
       mDelBlanks()
    endwhile
    Replace(x,y,z)  // Replace form feeds with spaces
end

//*************************************************************************
                    DelBlank()             07/26/93
//*************************************************************************

===========================================================================
                   Date: 07-23-93  From: IAN CAMPBELL
                      Subj: mListOpenFiles changes
---------------------------------------------------------------------------

PreScript:  08/08/93:  TAK a complete macro with even more changes is
                       available as 'a:\listopen.s' on TSE[2]

Here's a little macro change for TSE.S that you might be interested in
incorporating into your copy of the editor.

Did you ever notice that when you bring up TSE's buffer list (default
keystroke = <Alt 0>) that it just displays all of the files in the
same order that they exist in the ring, with the current file on the
top of the list?

This makes finding things a bit TEDIOUS, particularly when you have a
lot of files open, since files tend to MOVE AROUND as new ones are
brought to the "top of the list".

Now, there is no way to change the order of the files within the ring,
but it is fairly simple to sort the files just before displaying them
in the picklist.  The beauty of this approach is that all files within
a group will ALWAYS be displayed identically, with the same files in
the same position each time.  This makes finding a file in a large
group MUCH simpler.

Heres how to do it:

In your "TSE.S" file locate the macro mListOpenFiles().  Add a new
string definition "string fnOrg[65] = CurrFilename()" just below the
"string fn[65]" definition.

Find the following two lines in the macro (somewhere near the bottom
of the macro):

    GotoBufferID(filelist)
    BegFile()

Replace these two lines with the following lines:

    GotoBufferID(filelist)      // go to the buffer with the filenames
    PushBlock()                 // save old marking information that might
exist
    UnMarkBlock()               // turn off any old marking if it exists
    BegFile()                   // start at the beginning of the file
    Right()                     // skip the * field for the column mark
    MarkColumn()                // start marking a column
    EndFile()                   // go the the end of the file
    GotoColumn(79)              // get entire drive/pathname in column mark
    MarkColumn()                // mark the end of the column
    Sort()                      // sort the lines based on the columns marked
    PopBlock()                  // put back any old marking that might exist
    lFind(fnOrg, "B")           // cursor to original file (search backwards)
    GotoBufferID(start_file)    // back to the original file for a screen
update
    UpdateDisplay()             // update the screen now
    GotoBufferID(filelist)      // back to the file list with all the
filenames

Voila!  An alphabetically sorted picklist, with the current file
hilited!  If you're working with a lot of open files, and you
frequently switch between them to using mListOpenFiles(), then you
will probably LOVE this change!

//*************************************************************************
//  Changes to mListOpenFiles() to sort the open files buffer        07/26/93

//  PostScript:  08/08/93:  TAK a complete macro with even more changes is
//                          available as 'a:\listopen.s' on TSE[2]
//*************************************************************************


===========================================================================
                   Date: 07-27-93  From: DAVID MARCUS
                             Subj: reLength
---------------------------------------------------------------------------
Here are two more commands to let you use regular expression syntax
more widely. These are based on and require the reSubStr() command I
uploaded in a message yesterday.

Enjoy.

=d=

/**************************************************************************
   reLength(): Returns the length of 'needle' within  'haystack,'
               using regular expression search and any additional specified
               search and replace options. Examples:
                    n = reLength(last_name, full_name, 'i')
               where last_name and full_name are two strings in your proc.

               Returns 0 (FALSE) if not found.
                                           Copyright: (c) 1993 David Marcus
 **************************************************************************/

integer proc reLength(STRING needle,
                      STRING haystack,
                      STRING options)
     return(Length(reSubStr(needle, haystack, options)))
end

/********************************************************************
 reGetText(): Returns the string matching regular expression 'needle'
              from within the current line, using any additional
              search/replace options specified (if any). Example:

                    title =  '[DM][r]?[s]?\.'
                    reGetText(title,         // search for
                              30,            // starting at
                              4,             // for up to 4 chars
                              '^')           // must be at begining
                                             // i.e., col 30
              Returns
                    Dr.  Mr.  Mrs.  Ms. D. M. Drs.
                    (Title is equal to any of these if they begin at
                     position 30. 4 is the max length I think might
                     be found.)

               Returns '' (empty string) if not found.
                                      Copyright: (c) 1993 David Marcus
**********************************************************************/

string  proc reGetText(STRING needle,
                       INTEGER start_point,
                       INTEGER str_length,
                       STRING options)
     return(reSubStr(needle, GetText(start_point,str_length), options))
end
//*************************************************************************
                          reLength()  07/27/93
//*************************************************************************

===========================================================================
                Date: 07-28-93  From: RICHARD HENDRICKS
                     Subj: Line Drawing with MOUSE
---------------------------------------------------------------------------

// DRAW.S  11/20/1992  01/28/1993
// by Richard Hendricks

// Press a key or click the mouse to stop drawing

proc Main()
  integer x, xl, y, yl
  integer vert, horiz

  LineTypeMenu() // select the desired line type

  GoToMouseCursor() // get mouse and text cursor together
  MouseStatus()     // make current and last values the same
  MouseStatus()

  xl = query( MouseX )
  yl = query( MouseY )

  repeat
    if WaitForMouseEvent( _Mouse_Move_ )
      MouseStatus()

      x  = query( MouseX )
//    xl = query( LastMouseX )   // removed in .65
      y  = query( MouseY )
//    yl = query( LastMouseY )   // removed in .65

      if y <> yl
        vert = abs(y - yl)
        if y < yl
          repeat
            vert = vert - 1
            LineDraw(_up_)
          until not vert
        else
          repeat
            vert = vert - 1
            LineDraw(_down_)
          until not vert
        endif
      endif

      if x <> xl
        horiz = abs(x - xl)
        if x < xl
          repeat
            horiz = horiz - 1
            LineDraw(_left_)
          until not horiz
        else
          repeat
            horiz = horiz - 1
            LineDraw(_right_)
          until not horiz
        endif
      endif
      GoToMouseCursor() // get mouse and text cursor together
      xl = x  // query( LastMouseX )  -- 01/28/1993
      yl = y  // query( LastMouseY )  -- 01/28/1993
    endif
  until keypressed()
end Main

//*************************************************************************
//END of TSE macro DRAW.S to line draw with the MOUSE              07/28/93
//*************************************************************************

===========================================================================
                    Date: 07-30-93  From: RAY ASBURY
                    Subj: Alternate keyboards in TS
---------------------------------------------------------------------------
Hi Dave,

<<< DAVE BACHMANN >>>Ŀ
Am I trying to do something that can't be done?  Do I have to burn-in
2 separate versions of TSE and rename one?  Any suggestions will be  
gratefully accepted.                                                 
>>> ALL <<<

It can be done and it won't require two versions.  Keep you 'normal'
setup as it is.  Then, create a macro file similar to the following:

    HELP EmulateHelp            // JUST AN EXAMPLE
        "This is my emulator"
    END EmulateHelp

    // IF ANY OF THE KEYS IN EmulateKeys (BELOW) HAVE MACROS ASSIGNED TO
    THEM, PUT THEM HERE.

    KEYDEF EmulateKeys

        // PUT YOUR KEY ASSIGNMENTS HERE, SUCH AS

        <F1>                Help(EmulateHelp)

    END EmulateKeys

    PROC Main()
        Enable(EmulateKeys, _EXCLUSIVE_) // THIS "TURNS ON" THE KEYS IN
                                         // EmulateHelp, AND "TURNS OFF"
                                         // ALL OTHER ASSIGNABLE KEYS
    END Main

Save this file (such as emulate.s) and compile it with "SC EMULATE".
(Be sure to put it in the same directory as E.EXE or in the directory
you have MacPath set to).

Now, just use a command similar to "E <file(s) to edit> /Eemulate", and
viola, you now have a different version of TSE!!

"Buddy" E. Ray Asbury, Jr.
Team TSE
//*************************************************************************
  EmulateKeys suggestions for multiple key assignments             07/31/93
//*************************************************************************

===========================================================================
                Date: 08-04-93  From: RICHARD BLACKBURN
                     Subj: mouse programming source
---------------------------------------------------------------------------

What are you wanting to do with the mouse?  Here is an example of making
the HelpLine mousable:

    You can add mouse support to the HelpLine with macros.  The following
    macro will add mouse support for the default HelpLine in TSE.  You
    should be able to modify this to work with your HelpLine.

    /***********************************************************************
      This procedure when tied to the <LeftBtn> will work like the default
      TSE, with the exception that if you click on the help line, it will
      process the command in the associated location.
    ***********************************************************************/
    proc LeftBtn()
        if NOT ProcessHotSpot()
    end
//*************************************************************************

===========================================================================
                   Date: 08-04-93  From: BOB CAMPBELL
                     Subj: Obscure forgotten Macros
---------------------------------------------------------------------------
If  you're  like  me  you have macros assigned to  keys  that  you  have
forgotten. I've got lots of these handy little macros that are so seldom
used that I've found the only way to recall them is from a Menu.

But  that circumvents the quick intuitive response of TSE.  For  example
I've  got a macro that deletes to the beginning of the line.  This is  a
dangerous  type  of macro to have assigned to a key in the  first  place
,especially if you forget what that key does, but since I may find a use
for  it  I  keep it available.  Trouble is it's too  cumbersome  to  run
through the menus if I what to use it repeatedly.

So  here's my solution.  mRepeatMenuOption replays the last menu  option
with  the push of one key.  Simply use it once and then recall it  overe
and over with this hotkey.

proc mRepeatMenuOption()
    pushkey(<Enter>)   // pushes the menu option when mainmenu() is called
    pushkey(<Enter>)
    MainMenu()
end

<F12> mRepeatMenuOption()

Now I can keep all my obscure functions available with descriptions by menu
and still be able to repeat the command quickly.

When I first began adding features to my TSE I would simply add them to my
source file and assign a key, but the EXE file finally got too big to
compile and I ran out of keys.  Using this method allows me to run most of
my macro externally, thereby keeping the .EXE program size down to a
reasonable size.

The use of the MainMenu() is only an example  You might be better off
making a separate menu.

Menu ForgottenProcedures()
...
end

//*************************************************************************
  mRepeatMenuOption macro                                          08/07/93
//*************************************************************************

===========================================================================
                Date: 08-09-93  From: RICHARD BLACKBURN
            Subj: Save Changes / Lose Changes prompt change
---------------------------------------------------------------------------
Thanks for the suggestion of changing the QuitFile() menu prompt.  We had a
lot of people that had requested the prompt changed to "Save Changes".  You
could use a macro to change the prompt to "Lose Changes".

integer proc mPQuit()
    if NumFiles() == 0
        return (AbandonEditor())
    endif
    if isChanged()
        case YesNo( "Lose changes?" )
            when 0, 3           // Escape or Cancel
                return (FALSE)
            when 2              // No
                return (SaveAndQuitFile())
        endcase                 // Let "Yes" case fall through
    endif
    return(iif(NumFiles() == 1, AbandonEditor(), AbandonFile()))
end
//*************************************************************************
  Change QuitFile() prompt from Save Changes to Lose Changes      08/10/93
//*************************************************************************

===========================================================================
                   Date: 08-08-93  From: MAYNARD HOGG
                     Subj: Obscure Forgotten Macros
---------------------------------------------------------------------------

BC>I've got a macro that deletes to the beginning of the line. This is a
  >dangerous type of macro to have assigned to a key in the first place

Not if you make the macro undoable as the ^Q-Del combination has been
since WordStar 4!

proc DelToBol() //reversible!           //M. Hogg 06/09/93
    if CurrChar() < 0                   // are we past end of line?
        BegLine()
        DelToEOL()                      // let the editor do it for us
    else
        PushBlock()
        MarkChar()
        BegLine()
        MarkChar()
        DelBlock()
        PopBlock()
    endif
end
//*************************************************************************
  DelToBOL  with the ability to undo                              08/13/93
//*************************************************************************

===========================================================================
                    Date: 08-12-93  From: MEL HULSE
                      Subj: Indent a block  in TSE
---------------------------------------------------------------------------

The Tab key and shift tab keys shift a block right and left for me.

I use the following macros in TSE.S:

PROC TabBlockLeft()

    Iif(isCursorInBlock(), mShiftBlock(-(Query(TabWidth))), TabLeft())
END

PROC TabBlockRight()
    Iif(isCursorInBlock(), mShiftBlock(Query(TabWidth)), TabRight())
END

proc TabBlockLeft()
proc TabBlockRight()


<shift tab>          TabBlockLeft()
<tab>                TabBlockRight()

//*************************************************************************
  Procedures to use TAB for shifting marked blocks                 08/14/93
//*************************************************************************

===========================================================================
                   Date: 08-15-93  From: DAVID MARCUS
                      Subj: Video Cursor Position
---------------------------------------------------------------------------
After having a bit of difficulty with how set my video cursor when I
want video output to be at the current text cursor position, I have come
up with this formulation, which may be of help to others:

integer X11, Y11

          X11 = CurrCol() + Query(WindowX1) -1
          Y11 = CurrRow() + Query(WindowY1) -1
          ... do stuff ...
          GotoXY(X11, Y11)

This works regardless of numberof windows, whether display is boxed or
zoomed, and statusline position.


p.s. - Semware: WhereX() and WhereY() ought to have WindowX1 and WindowY1
          as 'See Also' references.
//*************************************************************************
  Video cursor                                                     08/16/93
//*************************************************************************

===========================================================================
                  Date: 08-18-93  From: SAMMY MITCHELL
                     Subj: BLOCK INDENTATION IN TSE
---------------------------------------------------------------------------
JK> I also think QEDIT handled this better than TSE.  If the cursor was in a
JK> block and you used the tab key, the whole block moved.  You didn't have
JK> to fuss around with <Ctrl F7>.  Wouldn't it be better to make TSE work
JK> the same way?

I have to disagree.  I _much_ prefer the new way.  But, implementing the
QEdit style is simple: (Note that this routine requires the mShiftBlock
procedure and associated constants from the TSE.S file.  You can place it in
TSE.S just after the mShiftBlock procedure, or at the beginning of your
TSE.KEY file.)


proc QEditTab(integer direction)
    if Query(Insert) and isCursorInBlock()
        mShiftBlock(Query(TabWidth) * direction)
    else
        if direction == SHIFTRIGHT
            TabRight()
        else
            TabLeft()
        endif
    endif
end

<Tab>       QEditTab(SHIFTRIGHT)
<Shift Tab> QEditTab(SHIFTLEFT)

//*************************************************************************
//Block indentation change from default to use ShiftTAB            08/19/93
//*************************************************************************

===========================================================================
                 Date: 08-18-93  From: GEORGE DE BRUIN
                        Subj: Feeding keystrokes
---------------------------------------------------------------------------
 From  FRED BRUCKER

If CopyBlock() isn't bound to a key, then how else could it be
executed in a dialog box?  I'm lost here.

   To  GEORGE DE BRUIN

Whoops.  I think I wasn't too clear on this...  Let's try again:

    <ALT C>     CopyBlock()         // When compiled is seen by TSE as a
                                    // native command

    <ALT Z>     CopyBlock(_DEFAULT_)// When compiled is seen by TSE as a
                                    // macro

Since <Alt C> is seen as a native command by TSE it works in the prompt
windows.  However, since <ALT Z> is seen as a macro (not a native
command) in TSE it does not function in the prompt boxes.

Does that make things any clearer?


Another dialog box problem:  In QEdit I could "feed" keystrokes to
the dialog box with the likes of this:

          MacroBegin EditFile DelLine Return 'g'

This would bring up the file list at the first file starting with
"g".  How can I do this in TSE?


You would use the PushKey() function to "stack" the keystrokes in the
sequence you want, then call the command.  Something like this:

proc OpnSrcMnu()
    Pushkey(<s>) PushKey(<escape>)          // Pull up Search Menu
end

Note that the keystrokes must be pushed on the stack in backwards order
(ie, it is a true stack).


I'm having trouble loading and executing a macro from the command
line.  I have this command line:  tse file1 file2 -k -emsgmac.mac.

Here's the macro:

proc WhenLoaded()
    Set(Wordwrap,ON)
    HWindow()
end


Change it so that it is not a WhenLoaded().  Place it in a Main(), like
this:


proc main()
    Set(WordWrap, ON)
    HWindow()
end

Now it should work.

OPENING TSE WITH TWO HORIZONTAL WINDOWS IS DISCUSSED IN THE NEXT NOT
SEE 'Opening TSE with two windows' on 8-20-93.

//*************************************************************************
//Feeding keystrokes and much, much more                           08/19/93
//*************************************************************************

===========================================================================
                   Date: 08-20-93  From: FRED BRUCKER
                  Subj:  Opening TSE with two windows
---------------------------------------------------------------------------

Well, either I've mis-communicated my split-window-on-startup problem or
all of you wizards are asleep at the switch. After getting familiar with
UpdateDisplay() from our earlier discussions, I tried this as my startup
macro in my mail reader:

proc WhenLoaded()
   UpdateDisplay()
   Set(Wordwrap,ON) HWindow() NextWindow()
end

Works like the proverbial charm!  I even like the appearance of the
boxed windows in this situation. <reeking with shame>

This macro splits the screen on startup with the original message in
the upper window and the reply (usually empty, unless a re-reply) in
the lower.  The two filenames and the macro are supplied on the
command line.  It switches the active window to the upper so I'm
ready to get a quote.

//*************************************************************************
  Open TSE with two horizontal windows                             08/20/93
//*************************************************************************

===========================================================================
                   Date: 08-21-93  From: KYLE WATKINS
                     Subj: VARIABLE TABULATOR INPUT
---------------------------------------------------------------------------
   The following macro will allow you to toggle the variable tab stop at
   the cursor location.

/*** START HERE ***/

integer t_unit, t_bit, vartabset
string vtab[32], s_unit[1]

proc ToggleTab()
    if vartabset
        s_unit=chr(asc(s_unit)&(~(1 shl t_bit)))
        vartabset=FALSE
    else
        s_unit=chr(asc(s_unit)|(1 shl t_bit))
        vartabset=TRUE
    endif
    vtab=substr(vtab,1,t_unit-1)+s_unit+substr(vtab,t_unit+1,32)
    set(vartabs,vtab)
end


string proc querytab()
    if currcol() <256
        t_unit=(currcol()/8)+1    //Get vartab string element
        t_bit=(currcol() mod 8)   //Get bit of vartab string element
        vtab=query(vartabs)
        s_unit=vtab[t_unit]

        if (asc(s_unit)&(1 shl t_bit))
            vartabset=TRUE
            return("_SET_ ")
        else
            vartabset=FALSE
            return("CLEAR ")
        endif
    endif
    return("INVALID")
end


menu tabmenu()
  Title="Variable Tab Toggle"
  Command=ToggleTab()
  "Variable Tab is" [querytab()+" at column "+str(currcol()):22]
                                                     ,,DONTCLOSE
end

<f1> tabmenu()   //Example key assignment

//*************************************************************************
//Toggle the TAB stop variable                                     08/22/93
//*************************************************************************

===========================================================================
                 Date: 08-24-93  From: GEORGE DE BRUIN
                         Subj: KillMax Variable
---------------------------------------------------------------------------

Whoops.  An oversight in the manual...  Right now you can set KillMax in
the TSE.CFG file.  Right now it can only be set for 0 or non-zero (ie,
it will go back to the default value).

Just add a line that says:

    KillMax         =   0

to the TSE.CFG file (make sure it is between the Config / EndConfig
lines.  This will set it so that no kills are added to the buffer.

If you want to change the value so it is just different (say to 10), add
the following to the WhenLoaded() proc in TSE.S:

    set(KillMax, 10)

//*************************************************************************
//KillMax Variable                                                 08/25/93
//*************************************************************************

===========================================================================
                    Date: 08-31-93  From: PAUL LENZ
                  Subj: Three (3) MARGIN SETING MACROS
---------------------------------------------------------------------------
Here are 3 macros which set margins quickly and easyly.
They work like WordStar's ctrl-o-r, ctrl-o-l, and ctrl-o-g.

Paul Lenz


/*************************************************************************

MARGIN.S contains:    SetLeftMargin()     sets left margin
                      SetRightMargin()    sets right margin
                      MarginFromLine()    sets left and right margins
                                          dependig of cursor line

31.8.1993 by Paul Lenz
             Friesenstrasse 22
             30161 Hannover
             Germany

*************************************************************************/


proc SetLeftMargin()
    string lm[3] = ""
    if Ask("Left Margin or ESC for current position",lm)
        if val(lm) > 0
            Set(LeftMargin,val(lm))
        endif
    else
        Set(LeftMargin,CurrPos())
    endif
end


proc SetRightMargin()
    string rm[3] = ""
    if Ask("Right Margin or ESC for current position",rm)
        if val(rm) > 0
            Set(RightMargin,val(rm))
        endif
    else
        Set(RightMargin,CurrPos())
    endif
end


proc MarginFromLine()
        Set(RightMargin,PosLastNonWhite())
        Set(LeftMargin,PosFirstNonWhite())
        Message(str(PosFirstNonWhite())+" <---Margins--->
"+str(PosLastNonWhite
end

---
//*************************************************************************
             Subj: Three (3) MARGIN SETING MACROS  09/02/93
//*************************************************************************
//*************************************************************************
/************************  Start Comment Area *****************************

===========================================================================
                    Date: 09-01-93  From: MEL HULSE
                      Subj: RT MARGIN Toggle MACRO
---------------------------------------------------------------------------

WHAT IT DOES: It toggles between 64 and 72 characters for the right
              margin and displays the RT Margin setting in the upper
              right hand corner.


    ****************** RIGHT MARGIN MACRO ************************
        Macro to toggle RT Margin between 72 and 64 characters
                       Creation date: 04/15/93
      H. Garth McKay (with a little bit of help! from Mel Hulse)
                         Source File: RTMGN.S
                       Assigned Macro Key <F12>
    **************************************************************

  *************************************************************************/
//tak******************* END of Comment Area ******************************

proc Main()
    Integer Timer = 18          // 27 is about 1 1/2 seconds
    IF Query(RightMargin) == 72
        Set(RightMargin,64)
    Else
        IF Query(RightMargin) == 64
            Set(RightMargin,72)
        endif
    endif
    Message("           Rt Margin... ", (Query(RightMargin)))
    Delay(Timer)                            // Added
    UpdateDisplay(_STATUS_LINE_REFRESH_)    // Added
End

//*************************************************************************
//                   Right Margin Toggle  09/02/93
//*************************************************************************
===========================================================================
                   Date: 09-05-93  From: DAVID MARCUS
                      Subj: mouse keys and TSE.KEY
---------------------------------------------------------------------------
Define these constants .....

constant
     LeftRightBtn  = <LeftBtn> | <RightBtn>,
     LeftCenterBtn = <LeftBtn> | <CenterBtn>,
     RightCenterBtn=<RightBtn> | <CenterBtn>,
     LeftRightCenterBtn = <LeftBtn> | <RightBtn> | <CenterBtn>

And then you can use them for key definitions:

<      CenterBtn>
<Alt   CenterBtn>
<Ctrl  CenterBtn>
<Shift CenterBtn>

<      LeftBtn>
<Alt   LeftBtn>
<Ctrl  LeftBtn>
<Shift LeftBtn>

<      RightBtn>
<Alt   RightBtn>
<Ctrl  RightBtn>
<Shift RightBtn>

<      LeftCenterBtn>
<Alt   LeftCenterBtn>
<Ctrl  LeftCenterBtn>
<Shift LeftCenterBtn>

<      LeftRightBtn>
<Alt   LeftRightBtn>
<Ctrl  LeftRightBtn>
<Shift LeftRightBtn>

<      LeftRightCenterBtn>
<Alt   LeftRightCenterBtn>
<Ctrl  LeftRightCenterBtn>
<Shift LeftRightCenterBtn>

<      RightCenterBtn>
<Alt   RightCenterBtn>
<Ctrl  RightCenterBtn>
<Shift RightCenterBtn>

p.s. - I will not swear that 100% of these combinations work.

//*************************************************************************
                  Mouse button combinations  09/06/93
//*************************************************************************
===========================================================================
                  Date: 09-07-93  From: SAMMY MITCHELL
    Subj: MYSTERY CODE - DelExtraBlankLines() w/detailed explanation
---------------------------------------------------------------------------

// Remove all occurrences of more than one consecutive blank line, starting
// at the current line

proc DelExtraBlankLines()
    loop

// Loop, until an empty line (PosFirstNonWhite() == 0) is found, or until the
// end of file is reached (Down() == FALSE, which is also 'not Down()').

        repeat
        until PosFirstNonWhite() == 0 or not Down()

// We are either at the eof, or on a blank line.  Determine which

        if not Down()       // if Down() == FALSE, we're at eof, so stop
            break
        endif

// We are not at eof, so the line we were on must be blank.  Now delete
// additional blanks lines.  PosFirstNonWhite() == 0 signifies a blank line.
// PosFirstNonWhite() <> 0 means we have a non-empty line.  A shortcut way
// of writing PosFirstNonWhite() <> 0 is 'if PosFirstNonWhite()'.
// DelLine will return FALSE if there are no more lines to Delete, as might
// happen if we reach eof.

        repeat
        until PosFirstNonWhite() or not DelLine()
    endloop
end
//*************************************************************************
 Subj: MYSTERY CODE - DelExtraBlankLines() w/detailed explanation  09/08/93
//*************************************************************************

===========================================================================
                Date: 09-07-93  From: RICHARD BLACKBURN
                 Subj: Switche examples within a macro
---------------------------------------------------------------------------

> Will it work with EditFile(-b file.xyz) in a macro?

Yes, that will work!  The "-n" goto line/column will also work in a macro.

                     e.g.  EditFile(-n## file.xyz)

//*************************************************************************
                                09/08/93
//*************************************************************************

===========================================================================
                Date: 09-07-93  From: RICHARD BLACKBURN
                             Subj: HELPLINE
---------------------------------------------------------------------------

>  How can I turn the HelpLine on and off from within a macro?

>  Can I have different HelpLine text for different macros?

>  Can I change the HelpLine text for different parts of the same macro?

Ans.  Yes, Yes, Yes

To turn the HelpLine on/off in a macro:

    Set(ShowHelpLine, On/Off)

To change the HelpLine when you load a macro, just assign the HelpLine in
your macro like a key assignment.

To have different help lines while a macro is running, you can put the
different HelpLines in a KeyDef and enable them when you want the HelpLine
to change.

===========================================================================
                   Date: 09-09-93  From: FRED BRUCKER
                         Subj: Binary edit mode
---------------------------------------------------------------------------
    >> If I remember correctly you had some trouble getting TSE to
    split a window using HWindow() in a main() or whenloaded(). <<

Thanks for your suggestion using Pushkey().  I also got it to work
using UpdateDisplay() in the Whenloaded():

proc WhenLoaded()
   UpdateDisplay()
   HWindow()
end

//*************************************************************************
            Opening TSE with a Horizontal Windows  09/09/93
//*************************************************************************

===========================================================================
                   Date: 09-09-93  From: DAVID MARCUS
                    Subj: WordWrap with spaces macr
---------------------------------------------------------------------------
Here is a first try at a paragraph wrapping macro that preserves [and
forces!] two spaces at the end of each sentence except when the sentence
ends a line.

forward proc endpara()
forward proc begpara()

proc wrap_with_spaces()
   PushBlock()
   PushPosition()
   WrapPara()

   PopPosition()
   PushPosition()
   MarkChar()
   EndPara()
   MarkChar()
   PopPosition()
   while lfind("[\.\!\?][\d034'\)]@ \c", 'xln1')
     if CurrChar() > 0 and CurrChar() <> 32
        InsertText(' ', _INSERT_)
     endif
     PushPosition()
     BegLine()           WrapPara()
     PopPosition()
     PushPosition()
     MarkChar()
     EndPara()
     MarkChar()
     PopPosition()
   endwhile
   Down()
   BegLine()
   PopBlock()
end

proc EndPara()
   Down()
   if CurrLineLen() == 0 BegPara() endif
   repeat until ( Down() AND CurrLineLen() == 0 )
        OR ( CurrLine() == NumLines() )
   if CurrLine() <> NumLines() Up() endif
   EndLine()
end

proc BegPara()
   if CurrLineLen() == 0
     repeat until ( Down() AND CurrLineLen() <> 0 )
          OR ( CurrLine() == NumLines() )
   else repeat until ( Up() AND CurrLineLen() == 0 )
          OR ( CurrLine() == 1 )
     if currline() <> 1 Down() endif
   endif
   GotoPos(PosFirstNonWhite())
end

//*************************************************************************
            WordWrap with two spaces after a comma  09/10/93
//*************************************************************************

===========================================================================
                    Date: 09-15-93  From: RAY ASBURY
                              Subj: Ruler
---------------------------------------------------------------------------

  Here's a simple one that a fellow tester made available quite a while
  back that I like very well.  Although it is not sticky (as to it's
  location), it has served me quite well:

    PROC mRuler()   // originally written by Peter Birch, but released to PD

        INTEGER i = 1,
                j = Query(WindowCols),
                k = CurrXOffset() + 1,
                nRow = CurrRow() + Query(Windowy1)

        IF (CurrRow() == Query(WindowRows))
            nRow = nRow  - 2
        ENDIF
        VGotoXY(Query(Windowx1), nRow)
        WHILE (i <= j)
            IF (k MOD 10 == 0)
                Write(SubStr(Format(k:4:'0'), 3, 1))
            ELSEIF (k MOD 5 == 0)
                Write("")
            ELSE
                Write("")
            ENDIF
            i = i + 1
            k = k + 1
        ENDWHILE
        VGotoXY(Query(Windowx1), nRow)
        PutAttr(Color(Bright White ON Red), j)
    END mRuler

//*************************************************************************
                            RULER  09/16/93
//*************************************************************************

===========================================================================
                   From: IAN CAMPBELL  Date: 09-17-93
                  Subj: Switch between Last 2 Buffers
---------------------------------------------------------------------------
Hi ALL,

One of the strengths of the TSE editor is its ability to load a
seemingly endless number of files.  It doesn't seem to matter what you
throw at this editor, it just takes it in stride.  However, a problem
develops when there are a lot of files loaded -- it becomes difficult
to find them all!

Now, I've been using the "Buffer List" (Alt-0) command to bring up the
open files menu, and to switch between them, (and I've even modified
the buffer list code so that things are sorted alphabetically and I
can consistently find all of the files).  But when one file starts
with, say, an "A", and another starts with a "W",  and there are
thirty or so files open, it can take a while to move from one end of
the buffer list to the other.

This becomes especially tiresome when you are moving bits and pieces
from one file to another, and must continually switch back and forth
between the two of them.  So I cooked up a little macro to allow
toggling between just the last two files that you have looked at.  It
doesn't matter how many files are open, just touch one key and you're
instantly in the previous file.  Touch it again and you're back where
you were!

Here's the macro:

---------------------------------------------------------------------
integer PreviousID = 0, CurrentID = 0
proc mTrackFileChanges()
    if PreviousID == 0
        PreviousID = GetBufferID()
        CurrentID = GetBufferID()
    elseif GetBufferID() <> CurrentID
        PreviousID = CurrentID
        CurrentID = GetBufferID()
    endif
end mTrackFileChanges

proc mToggleBuffers()
    if PreviousID
        GotoBufferID(PreviousID)
        EditFile(Currfilename())
    endif
end mToggleBuffers

---------------------------------------------------------------------------

Add the line:

Hook(_ON_CHANGING_FILES_, mTrackFileChanges)

to the Whenloaded() macro in TSE.S, and add the above two macros into
TSE.S just above the WhenLoaded() macro.

Finally, bind the mToggleBuffers() macro to a suitable key.  You might
want to choose a single key if you can find one.  I used the <GreyEnter>
key on the lower right corner of the keyboard.  I found that I always
used the left <Enter> key for my editing, so this key was available.
And it is VERY convenient <grin>.  Anyway, my key mapping went as
follows:

<GreyEnter> mToggleBuffers()

I find that I REALLY LIKE this macro.  Let me know what you think!

//*************************************************************************
            Switch between last two files(buffers)  09/18/93
//*************************************************************************

===========================================================================
                Date: 09-19-93  From: DAVID MAYEROVITCH
                      Subj: RECURSIVE CALLS IN SAL
---------------------------------------------------------------------------

                      integer proc Content ( string book )
                        integer real = true
                        integer unreal = false

                        if Great(book) == true
                          return ( real )
                          else return ( unreal )
                          endif

                      end Content

//*************************************************************************
                        Recursive Calls 09/20/93
//*************************************************************************

===========================================================================
                Date: 09-27-93  From: RICHARD BLACKBURN
                           Subj: Macro Repeat
---------------------------------------------------------------------------

.....what code do I need to add to the macro to make it loop 162 times?

I assume you are referring to a TSE macro, so you could have loop with a
variable you decrement, for example:

proc test()
    integer i = 162

    while i <> 0
        i = i - 1
        // Do whatever you want in the loop
    endwhile
end

//*************************************************************************
                 Example of a simple 'WHILE'  09/28/93
//*************************************************************************

===========================================================================
                Date: 09-28-93  From: RICHARD BLACKBURN
                         Subj: KEY ASSIGNMENTS
---------------------------------------------------------------------------
> The default TSE.KEY file has RepeatCmd() assigned to <Ctrl q><Ctrl q>.
> How come pressing either <Ctrl q><Ctrl q> or <Ctrl q><q> executes
> the RepeatCmd()?  I'm sure the answer to the previous question will
> clear up what is happening with my four key assignments below:
>
> <Ctrl e><Ctrl e> Message("<Ctrl e><Ctrl e>")
> <Ctrl e><Alt e> Message("<Ctrl e><Alt e>")
> <Ctrl e><Shift e> Message("<Ctrl e><Shift e>")
> <Ctrl e><e> Message("<Ctrl e><e>")
>
> I placed them at the end of TSE.KEY.
> When I compile I get duplicate key warnings for the last two.
>
> Warning 056  (280,1)    duplicate key defined... ignored
> Warning 056  (281,1)    duplicate key defined... ignored
>
> Those four assignments are the only ones using <Ctrl e>.

For ctrl two keys are relaxed for the 2nd key.  The following keys are the
same:

<Ctrl E><Ctrl E>
<Ctrl E><Shift E>
<Ctrl E><E>

Since the 2nd key is relaxed the only shift state TSE will see for the 2nd
key is if you use Alt.

//*************************************************************************
                   Relaxed Key Assignments  09/28/93
//*************************************************************************

===========================================================================
                 Date: 09-30-93  From: JACK HAZLEHURST
                       Subj: Another STATUS line
---------------------------------------------------------------------------
CM>Is there anyway I can add to the status line how many lines
CM>the current file contains?

I have a bunch of things I like to know about my  settings  in  TSE.
What  I  did  was  to  assign  a key to a macro that builds a string
containing all the little tidbits I want to know about and  displays
it on the message line.  The next keystroke, of course, wipes it out
and brings back the status line, but I can see what I need this way.
There  are  so  many  things  I  want  to  be able to check that I'm
considering adding a second line of stuff (assigned, of  course,  to
another key combination).

//
// Additional status line
//
proc mStatusLine2()
    Message( "ColMod=", OnOffStr(column_mode),
            " FulJst=", OnOffStr( Justify ),
            " TbsOut=", OnOffStr( TabsOut ),
            " ExpTbs=", OnOffStr( Query( ExpandTabs ) ),
            " WrdEnd=", iif( WESwitch, "END", "BEG" ),
            " LngCfg=", MenuStr(StdCfgMenu,CfgID) )
end

"OnOffStr" is a macro you'll find in TSE.S.  The other variables are
peculiar (ve-e-ery peculiar) to my customization  of  TSE,  but  I'm
sure you get the idea.

//*************************************************************************
                     Another STATUS line  09/30/93
//*************************************************************************

===========================================================================
                 Date: 09-29-93  From: GEORGE DE BRUIN
                   Subj: Temporarily changing margin
---------------------------------------------------------------------------

If you just want to change the setting for the right margin while the
mWrapPara() command is being executed, you could write a short macro:

proc mWrap()
    integer rm = Set(RightMargin, 55)  // Set new right margin, save old
                                       // value
    mWrapPara()                        // Wrap the paragraph
    Set(RightMargin, rm)               // Set the right margin back to
                                       // the old value
end

This temporarily sets the margin would keep the right margin set the way
it normally is, but allow you to have it at a different setting for
wrapping.  This macro would need to be inserted in your TSE.S file.  The
best place for the macro would be right above the lines:

//*************************************************************************
                  Temporarily Change Margin  09/30/93
//*************************************************************************

===========================================================================
                  Date: 09-29-93  From: SAMMY MITCHELL
                            Subj: NOT logic
---------------------------------------------------------------------------
> I do have a question about this segment of the macro though:
>
>           if NOT Down()
>               break
>           endif
>
> I understand the "NOT" logic, the "break," and why it's necessary
> to prevent things from getting locked up on the last line of the
> file; however, does the "Not Down()" test actually execute the
> "Down()" function?  It would appear so, or else I can't see what
> advances the process a line at a time.
>
> It seems confusing and incorrect to me that an _IF_ should
> execute the cited function.  Is this documented somewhere?
> One would never expect ordinary compares such as "If X == 3" to
> result in X being set to the value of 3.  Consistency should
> dictate that "If function()" or "If NOT funtion()" should behave
> the same way, shouldn't it?

The if logic above could be rewritten as:

integer ok

ok = Down()     // assign result to ok
if ok == FALSE  // test value of ok
    break
endif

The "if not Down()" form is just a convenient short-cut.

Perhaps you're confusing the assignment operator '=' with the test for
equality operator '==' ?

'a = b' can be read as "assign the value of b to a", while 'if a == b' can
be read "if the value of a is the same as the value of b, do what follows".

Does this make more sense now?  If not, let me know.

Can you think of something we could say in the manual to help make this
point more clear?

By the way, this is the way many other programming languages work, including
C, Pascal and Visual Basic.

//*************************************************************************
                          NOT logic  09/30/93
//*************************************************************************

===========================================================================
                    Date: 10-05-93  From: RAY ASBURY
                       Subj: Menus and time delay
---------------------------------------------------------------------------
<<< STEVE KRAUS >>>Ŀ
Another good idea! I have <Ctrl V> assigned to "View" functions. <Ctrl V><F>
Views Found text (CompressView), while <Ctrl V><O> Views the Old screen, and
<Ctrl V><A> views text found in all files loaded.                           
                                                                            
I do wish for WordStar-style menus that would work like the HelpLines do.   
If I press down the first key of a two-key and wait for some specified time,
it would be nice to pop up a menu.                                          
                                                                            
>>> RAY ASBURY <<<

You could do a WordStar-style menu.  At least, one similar to what you
describe here.  Basically, here what you would need:

    proc OptionOneMacro()
        Message("this is OptionOneMacro()")
    end OptionOneMacro

    proc OptionTwoMacro()
        Message("this is OptionTwoMacro()")
    end OptionTwoMacro

    menu mMenu()
        "Menu Option &One", OptionOneMacro(), CloseAllBefore
        "Menu Option &Two", OptionTwoMacro(), CloseAllBefore
    end mMenu

    proc mShellMenu()
        INTEGER hrs, min, sec, hun, start, keyPress,
                wait = 5 // 5 second wait

        GetTime(hrs, min, sec, hun)
        start = ((((hrs * 60) + min) * 60) + sec) * 60
        REPEAT
            IF (KeyPressed())
                keyPress = GetKey()
                CASE keyPress
                    WHEN <o>
                        OptionOneMacro()
                    WHEN <t>
                        OptionTwoMacro()
                    WHEN <Escape>
                        Return
                ENDCASE
            ENDIF
            GetTime(hrs, min, sec, hun)
        UNTIL ( (start + wait) > (((((hrs * 60) + min) * 60) + sec) * 60) )
        mMenu()
    end mShellMenu

I just put this together without testing, so I may have made a mistake
or two.  Hope this helps get you started.

//*************************************************************************
                     Menus and time delay  10/06/93
//*************************************************************************

===========================================================================
                Date: 10-05-93  From: RICHARD BLACKBURN
                         Subj: Mouse functions
---------------------------------------------------------------------------

If  you  do  not mind losing one of your  mouse  keys,  you  can  assign
TrackMouseCursor()  and  it will scroll the screen while you are holding
the key.

Syntax:     TrackMouseCursor()

Returns:    Nothing.

Notes:      While MouseKeyHeld() is TRUE, this function continuously moves
            the text cursor to the mouse cursor.  If the mouse is moved
            outside the current window, the window is scrolled.

            Any block within the current file is extended to the new cursor.

            Internally this function uses MouseStatus(), which updates
            MouseX, MouseY, and MouseKey.

See Also:   Mousestatus(), MouseKeyHeld()

//*************************************************************************
                       Mouse functions  10/06/93
//*************************************************************************

//*************************************************************************
/************************  Start Comment Area *****************************
//tak**********************************************************************

===========================================================================
                    Date: 10-05-93  From: RAY ASBURY
                        Subj: A statusline clock
---------------------------------------------------------------------------

With a 486/33 my cursor looked as if was having an epileptic seisure it
was blinking so fast!!  I added a check of the last posted time against
the current time and only update the clock if it's changed.  That
eliminated the flicker.  I also added code to use the same colors as the
statusline uses.  Here's you macro with my mods:

  *************************************************************************/
//tak******************* END of Comment Area ******************************

    PROC mClock()
        INTEGER nowTime,
                saveAttr

        IF (Query(EditState) & _STATE_EDIT_MAIN_LOOP_)
            GetTime(gHrs, gHun, gMin, gSec) // global variables in my TSE.S
            nowTime = (gHrs * 60) + gMin
            IF (nowTime <> gLastPostedTime) // must be a global variable
                gLastPostedTime = nowTime
                Set(Cursor,Off)
                GotoXY(Query(ScreenCols) - 8, 1)  // position for time
                saveAttr = Set(Attr, Query(StatusLineAttr))
                PutStr(' '+GetTimeStr()+' ')      // write the time
                Set(Attr, saveAttr)
                Set(Cursor,On)
                UpdateDisplay()
            ENDIF
        ENDIF
    END mClock

Except for the time disappearing for about a 1/2 second when
UpdateDisplay() is called, it now works great.  Thanks for sharing your
macro.

//*************************************************************************
                      Status Line Clock  10/06/93
//*************************************************************************

===========================================================================
                   Date: 10-07-93  From: DAVID MARCUS
                        Subj: TINY BUG IN TSGREP
---------------------------------------------------------------------------

Find these two lines and delete the second line: [line numbers approximate]

1247           while lFind(sstring, options)
1248                AND CurrLine() <> NumLines()  // stops processing if EOF

Find these lines:

1342                else
1343                     Down()                   // AND down
1344                     BegLine()                // to beginning of next line
1345                endif
1346                check_for_abort()
1347           endwhile

and change to:

1342                else
1343                     if NOT Down()
                              goto end_of_file
                         endif
1344                     BegLine()                // to beginning of next line
1345                endif
1346                check_for_abort()
1347           endwhile
             end_of_file:

//*************************************************************************
                   Tiny bug fix in TSEGREP5  10/07/93
//*************************************************************************
//*************************************************************************
/************************  Start Comment Area *****************************

===========================================================================
                Date: 10-10-93  From: LOUIS VONDERSCHEER
                    Subj: Displaying compile errors
---------------------------------------------------------------------------

  *************************************************************************/
//tak******************* END of Comment Area ******************************

Integer Proc JumpToError(String Type)
  String   Colm[3],
           Line[4],
           ErrMsg[78]
  If GotoBufferId(Errors)
    If LFind(Type,'w+')
      ErrMsg = GetText(PosFirstNonWhite(),PosLastNonWhite())
      Message('['+ErrMsg+']')
      Line = GetText(Pos('(',ErrMsg)+1,(Pos(',',ErrMsg)-Pos('(',ErrMsg))-1)
      Colm = GetText(Pos(',',ErrMsg)+1,(Pos(')',ErrMsg)-Pos(',',ErrMsg))-1)
      GotoBufferId(source)
      GotoLine(Val(Line,10))
      GotoColumn(Val(Colm,10))
      ScrollToRow(Query(WindowRows)/2)
    Else
      BegFile()
      GotoBufferId(source)
        If Flag
          Return(False)
        Else
          GotoBufferId(source)
          Beep(1)
          Message('No '+Type+'s found...')
          Return(false)
        EndIf
    EndIf
  Else
    Message('Error Buffer not found...')
    halt
  EndIf
  Return(true)
End JumpToError
//----------
Proc ShowErrors()
  string temp[10] = ''
  if not gotobufferid(source) Source = GetBufferId() endif
  If GotoBufferId(Errors)
    if lList('Errors',80,Query(ScreenRows),0)
      BegLine()
      EndWord()
      temp=GetText(1,CurrPos())
      if Pos('Error',temp) or Pos('Warning',Temp) or Pos('Note',Temp)
        Up() // move up a line so jump to err find it
        JumpToError(temp)
      EndIf
    EndIf
    GotoBufferId(Source)
    Return()
  Else
    GotoBufferId(Source)
    Return()
  EndIf
End ShowErrors
.
.
.
<Ctrl e> JumpToError('Error')       // find next error
<Ctrl w> JumpToError('Warning')     // find next warning
<Ctrl v> ShowErrors()

//*************************************************************************
/************************  Start Comment Area *****************************

These are some excerpts from my sCompile macro.  I use message() to put
the error on the status line rather then open another window.  To see
the entire error output I press <ctrl v>.  At that point I can pick the
specific error/warning/note to jump to.  I like it this way but milage
may vary...

  *************************************************************************/
//tak******************* END of Comment Area ******************************

===========================================================================
                Date: 10-04-93  From: RICHARD BLACKBURN
                       Subj: Inserting LetterHaed
---------------------------------------------------------------------------
You could do your letterhead by setting it up as a DATA structure in your
TSE.S file, for example (NOTE, I shortened it for the message):

DATA LetterHead
"                    TAKnet Infromation Exchange     ..."
"                          Fort Wayne, Indiana             ..."
"  ..."
"<::::]    <::::]    <::::]    <::::]      <::::]    <:::  ..."
"Ŀ      ..."
"                                    ====                ..."
"      CALL: (219) 745-3635                              ..."
"..."
END

Then you can assign the the following to a key to insert your letter head
into the file:

InsertData(LetterHead) // Insert the LetterHead DATA into the file.

Once you have done this, be sure to use SC.EXE to update E.EXE with the
changes.

//*************************************************************************
               Adding Letterhead by using DATA  10/14/93
//*************************************************************************

===========================================================================
            Date: 10-14-93  From: JONATHAN DE BOYNE POLLARD
                  Subj: Regular expressions [General]
---------------------------------------------------------------------------

  Having never used TSE, but having use regular expressions in other
  programs for a long time, you will probably find most of these
  supported everywhere.

      .  Any character                *  Zero or more repetitions
      ?  Zero or one repetitions      +  One or more repetitions
     []  Encloses a character set    ()  Encloses a subexpression
      |  Separates alternatives       \  Quote literal next char
      ^  Match beginning of line      $  Match end of line

  Some programs don't supply | and ().  Other programs add

     \<  Match the start of a word   \>  Match the end of a word
     \(  Start a substring           \)  End a substring

  In the replace part of search and replace, most regexps that support
  \( and \) should also support \1 to \9 for substring insertion.

  How does this lot match against TSE ?

                                             Is there any
   standardization, or do language and system developers define them as
   they please?
  
   I have a vague impression that the idea of regexps comes out of the C
   and Unix world.

  The second is the answer to the first.  They are used extensively in
  UNIX tools such as ex (vi by another name), ed, sed, and grep, although
  I doubt that they originated with UNIX.

  The "standard" regular expressions are usually those documented in the
  UNIX V8 regexp(3) manual, although the \< and \> metasequences are
  part of ex(1).  There is a widely distributed regular expression C
  library written by Henry Spencer of the University of Toronto based
  upon the regexp(3) stuff.

//*************************************************************************
          General discussion of regular expressions  10/15/93
//*************************************************************************

===========================================================================
                Date: 10-15-93  From: DAVID MAYEROVITCH
                   Subj: More on Regular expressions
---------------------------------------------------------------------------

JD>  How does this lot match against TSE ?

JD>      .  Any character                *  Zero or more repetitions
JD>      ?  Zero or one repetitions      +  One or more repetitions
JD>     []  Encloses a character set    ()  Encloses a subexpression
JD>      |  Separates alternatives       \  Quote literal next char
JD>      ^  Match beginning of line      $  Match end of line

TSE includes all of the above, with {} instead of (), and also has ~
for a complement class (you may have omitted this from your list).

JD>  Some programs don't supply | and ().  Other programs add

JD>     \<  Match the start of a word   \>  Match the end of a word
JD>     \(  Start a substring           \)  End a substring

TSE lacks the preceding four.

JD>  In the replace part of search and replace, most regexps that support
JD>  \( and \) should also support \1 to \9 for substring insertion.

TSE does this too.

TSE also includes @, which is similar to * but matches with maximum
closure where * matches with minimum closure, and it includes #, which
stands in a similar relation to +.

JD>                                             Is there any
JD>   standardization, or do language and system developers define them as
JD>   they please?

JD>  The "standard" regular expressions are usually those documented in the
JD>  UNIX V8 regexp(3) manual, although the \< and \> metasequences are

//*************************************************************************
                 More on regular expressions  10/16/93
//*************************************************************************

===========================================================================
                 Date: 10-15-93  From: ANDREAS MARTINI
                         Subj: PEARL OF WISDOM
---------------------------------------------------------------------------
Hello to Sammy Mitchell

the man who invented
        home   MacroBegin FirstNonWhite jTrue done: Begline done:

also known as
        <Home>    IF not BegLine()
                      GotoPos(PosFirstNonWhite())
                  Endif

From this great man, to whom I am not worth to clean his shoes, I took
his wisdom and changed the lines in the unchangeable TSE.KEY file to

// if Remove Trailing Whitespace is set to OFF
        <End>     If not EndLine()
                      GotoPos(PosLastNonWhite())
                      Right()
                  EndIf

//*************************************************************************
                                10/16/93
//*************************************************************************

===========================================================================
                    Date: 10-15-93  From: MEL HULSE
              Subj: Cursor commands that accept an Integer
---------------------------------------------------------------------------

Here's the cursor commands I know of that work with an integer
parameter:

    Backspace() DelChar() DelLeftWord() DelLine() DelRightWord()
    Down() DupLine() Left() NextFile() PageDown() PageDown()
    PageUp() PrevChar() PrevFile() Right() RollDown() RollLeft()
    RollRight() RollUp() ScrollDown() ScrollLeft() ScrollRight()
    ScrollUp() SplitLine() TabLeft() TabRight() Up() WordLeft()
    WordRight()

Unfortunatly, CRETURN() doesn't work with an integer parameter.

//*************************************************************************
              Command that accept Integer value  10/16/93
//*************************************************************************
==========================================================================
              Date: 10-15-93  From: David Daniel Anderson
                          Subj: mAbandonAll()
---------------------------------------------------------------------------

     proc mAbandonAll()
       while NextFile() <> 0
         AbandonFile()
     endwhile
       AbandonFile()
     end

//*************************************************************************
                        mAbandonAll()  10/16/93
//*************************************************************************

===========================================================================
              Date: 10-16-93  From: DAVID DANIEL ANDERSON
                         Subj: Old TSE Macros
                         Reload file from disk
---------------------------------------------------------------------------

 It allows the user to get the most recent "saved to disk" version of
the current file.

It prompts for confirmation, and defaults to "y" if only enter is
pressed.  This could be changed to "n" to make it safer (see the
second line).

proc mRefreshFile()
     string rfr[1]="y"
     string ThisFile[80] = CurrFileName()
     Ask("Do You Want to Get the Saved Copy of This File?", rfr)
     if rfr == "y"
        ChangeCurrFileName("#tsetemp")
        EditFile(ThisFile)
        PrevFile()
        AbandonFile()
        EditFile(ThisFile)
     endif
end

It could be enhanced to save the current position in the file and
restore that position when the saved version is reloaded, should
you desire.  I don't care to do it, though.

//*************************************************************************
                    Reload file from disk  10/16/93
//*************************************************************************

===========================================================================
                  Date: 10-20-93  From: SAMMY MITCHELL
                    Subj: FIND & REMOVE BLANK LINES
---------------------------------------------------------------------------
Here it is (msg 708) and probably in a file too:

// Remove all occurrences of more than one consecutive blank line,
// starting at the current line
proc DelExtraBlankLines()
    loop
        repeat
        until PosFirstNonWhite() == 0 or not Down()
        if not Down()
            break
        endif
        repeat
        until PosFirstNonWhite() or not DelLine()
    endloop
end

<f1> DelExtraBlankLines()

//*************************************************************************
                 DelExtraBlankLines()  again?  10/20/93
//*************************************************************************

===========================================================================
                    Date: 10-18-93  From: BOB KOWITT
                         Subj: Reload from disk
---------------------------------------------------------------------------

//  Abandons file on screen and reloads same file

        proc Reload()
            string fn[65] = CurrFilename()
            AbandonFile()
            EditFile(fn)
        end

//*************************************************************************
                                10/20/93
//*************************************************************************

===========================================================================
                Date: 10-20-93  From: RICHARD BLACKBURN
                       Subj: Synchronized Windows
---------------------------------------------------------------------------
SEE SYNCHRONIZED FIX!!! - later in this file

>  What is the possibility of getting Synchronized Windows for at  least
>  two of the windows. It would help.

The following macro will scroll all windows together.  You need to assign
ScrollWindows() to a key.  When you want to lock the windows together press
the key you have assigned to ScrollWindows().  When you want to stop
scrolling the windows press <Escape>:

constant    cLEFT        = 1,
            cRIGHT       = 2,
            cUP          = 3,
            cDOWN        = 4,
            cPAGEUP      = 5,
            cPAGEDOWN    = 6,
            cBEGLINE     = 7,
            cBEGFILE     = 8,
            cENDLINE     = 9,
            cENDFILE     = 10

proc mScrollWindows(integer direction)
    integer winid = WindowId(), num = 1

    while num < 10
        if GotoWindow(num)
            case direction
                when cLEFT           Left()
                when cRIGHT          Right()
                when cUP             Up()
                when cDOWN           Down()
                when cPAGEUP         PageUp()
                when cPAGEDOWN       PageDown()
                when cBEGLINE        BegLine()
                when cBEGFILE        BegFile()
                when cENDLINE        EndLine()
                when cENDFILE        EndFile()
            endcase
        endif
        num = num + 1
    endwhile
    GotoWindow(winid)
end

keydef ScrollKeys
<CursorLeft>        mScrollWindows(cLEFT)
<CursorRight>       mScrollWindows(cRIGHT)
<CursorUp>          mScrollWindows(cUP)
<CursorDown>        mScrollWindows(cDOWN)
<PgUp>              mScrollWindows(cPAGEUP)
<PgDn>              mScrollWindows(cPAGEDOWN)
<Home>              mScrollWindows(cBEGLINE)
<Ctrl PgUp>         mScrollWindows(cBEGFILE)
<End>               mScrollWindows(cENDLINE)
<Ctrl PgDn>         mScrollWindows(cENDFILE)
<Escape>            EndProcess()
end

proc ScrollWindows()
    Enable(ScrollKeys)
    Process()
    Disable(ScrollKeys)
end

//*************************************************************************
                 Syncronize Window Scrolling  10/20/93
//*************************************************************************

===========================================================================
                  Date: 10-23-93  From: SAMMY MITCHELL
                 Subj: Find & remove *ALL* blank lines
---------------------------------------------------------------------------

If you want to delete _all_ blank lines, how about:

proc DeleteAllBlankLines()
    PushPosition()                  // save our place
    loop
        if PosFirstNonWhite() == 0
            if not DelLine()
                break               // if eof
            endif
        elseif not Down()           // if eof
            break
        endif
    endloop
    PopPosition()
end

<f1> DeleteAllBlankLines()

//*************************************************************************
            Subj: Find & remove *ALL* blank lines  10/24/93
//*************************************************************************

                 Ŀ
                 SYNCHRONIZED FIX!!! from macro above
                 

===========================================================================
                Date: 10-25-93  From: RICHARD BLACKBURN
                 Subj: Synchronized Windows Macro FIX!!
---------------------------------------------------------------------------
DD>   Richard, when I implemented your macro, I noticed that with 2 windows
DD>   opened vertically, if the cursor is in window 1 when I invoke the
DD>   macro, only window 2 scrolls, windows 1 is locked.  If I'm in window
DD>   2, then both windows scroll together.  Is this the way it's supposed
DD>   to work?  This is with v1.00z.  Thanks.

The following macro should fix the problem:

constant    cLEFT        = 1,
            cRIGHT       = 2,
            cUP          = 3,
            cDOWN        = 4,
            cPAGEUP      = 5,
            cPAGEDOWN    = 6,
            cBEGLINE     = 7,
            cBEGFILE     = 8,
            cENDLINE     = 9,
            cENDFILE     = 10

proc Scroll(integer direction)
    case direction
        when cLEFT           Left()
        when cRIGHT          Right()
        when cUP             Up()
        when cDOWN           Down()
        when cPAGEUP         PageUp()
        when cPAGEDOWN       PageDown()
        when cBEGLINE        BegLine()
        when cBEGFILE        BegFile()
        when cENDLINE        EndLine()
        when cENDFILE        EndFile()
    endcase
end

proc mScrollWindows(integer direction)
    integer winid = WindowId(), num = 1

    while num < 10
        if GotoWindow(num)
            Scroll(direction)
        endif
        num = num + 1
    endwhile
    GotoWindow(winid)
    if winid == 1
        Scroll(direction)
    endif
end

keydef ScrollKeys
<CursorLeft>        mScrollWindows(cLEFT)
<CursorRight>       mScrollWindows(cRIGHT)
<CursorUp>          mScrollWindows(cUP)
<CursorDown>        mScrollWindows(cDOWN)
<PgUp>              mScrollWindows(cPAGEUP)
<PgDn>              mScrollWindows(cPAGEDOWN)
<Home>              mScrollWindows(cBEGLINE)
<Ctrl PgUp>         mScrollWindows(cBEGFILE)
<End>               mScrollWindows(cENDLINE)
<Ctrl PgDn>         mScrollWindows(cENDFILE)
<Escape>            EndProcess()
end

proc ScrollWindows()
    Enable(ScrollKeys)
    Process()
    Disable(ScrollKeys)
end

<F7> ScrollWindows()

//*************************************************************************
                Lock scrolling Windows FIX!!!  10/26/93
//*************************************************************************

===========================================================================
                   Date: 10-25-93  From: DAVID MARCUS
                     Subj: Making New CmdLine Opts
---------------------------------------------------------------------------

        ALSO see next message for CmdLine() use with NameClip()

I am uploading to the library here a pair of helper macros that
faciliate (make easy!) the creation of custom command line options.

They allow you to test to see if any option [1 or more letters
preceded by a '-'] was used on the TSE commandline and what argument,
if any, followed the option. They also allow you to retrieve the
filespecs used on the command line.

Included are two command line options:

     * -p to print those files included on the command line.
     * -N to goto line,col rather than just going to line.

        For instance

               tse -p c:\autoexec.bat c:\config.sys

        prints both these files, first querying to print all (2)
        files. If you say yes, it does. If you say no, it queries
        on an individual basis for printing each file.

        In any case, the editor ends after printing.

        And:

               tse *.s -n5,10

        goes to line 5, column 10 of the first file loaded.

The file name is CmdLine3.ZIP.

       Ŀ
       ALSO see next message for CmdLine() use with NameClip()
       

//*************************************************************************
                        CmdLine3 Macro  10/26/93
//*************************************************************************

===========================================================================
                   Date: 10-26-93  From: DAVID MARCUS
                    Subj: Load Named Clipboards Cmd
---------------------------------------------------------------------------

SEE CmdLine() in previous message

Ŀ
        PLUG:  Using the CmdLine helper macros, the TSE command        
        line option described here took less than 15 minutes to        
        conceive, implement, and test.                                 


For NameClip() users only ... a command line option to load a stored
clipboard file at startup.

You can use my CmdLine helper macros to create a command line option to
automatically load a file of saved clipboards.  Note: To do this, you
must have included NameClip as part of your TSE configuration [that is,
using a #INCLUDE rather than loading it as an external macro].

To do this....

1. Find the GET_CLIPS_FROM_FILE() proc in NameClip.S and find these
   lines:

          if Ask('File name for clipboards?', saveclipfilename) Ŀ
               AND Length(saveclipfilename)                      
          else                                                   
               msg = 'bad file name'                             Ŀ
               pop_message('', Query(MsgAttr), 19)                   
               goto ending                                           
          endif                                                     
                                                                      
2. Wrap these lines in an add'l   if...else...endif:                  
                                                                      
     if Length(GetGlobalStr(global_saveclipfilename))                 
          saveclipfilename = GetGlobalStr(global_saveclipfilename)    
     else                                                             
          if Ask('File name for clipboards?', saveclipfilename) //*Ŀ 
               AND Length(saveclipfilename)                     //*  
          else                                                  //*  
               msg = 'bad file name'                            //* 
               pop_message('', Query(MsgAttr), 19)              //* 
               goto ending                                      //* 
          endif                                                 //*
     endif

                    //* these lines don't change, they are just wrapped
                    //* in the extra "if...endif"

3. Add this to your WhenLoaded() in your TSE config file:

  /* Load clipboard file */

     if CmdLineOptionUsed('cb')
        AND Length(GetGlobalStr('CmdLineArgForcb'))
          SetGlobalStr( 'global_saveclipfilename',
                         GetGlobalStr('CmdLineArgForcb') )
          get_clips_from_file()
     endif

4. Recompile TSE.

You can now start TSE like this:

     e filespecs -cbCLIP_FILE_NAME

   where CLIP_FILE_NAME is the name of the file you have previously
   specified when storing clipboards to a file using the named clipboard
   Other Functions menu.

Command line helper macros are in file CmdLine3.ZIP, in Conference 4,
when released by sysops.

//*************************************************************************
                  CmdLine3() and NameClip()  10/27/93
//*************************************************************************


===========================================================================
                    Date: 10-26-93  From: MEL HULSE
                     Subj: TSE REGULAR EXPRESSIONS
---------------------------------------------------------------------------
Here's a post from Internet that should prove helpful.

Here are some quick and dirties from my files. Also attached is a brief
description of each regexp character.

expr = "^\@major head"

expr = "{^\@major head}|{^\@med head}"

expr = "<\$\!\.{NOT }?INCLUDE"

expr = "^{\@maj}|{\@med}|{\@min}|{\@command name}"

expr = "^{forward }?{public }?{{integer }|{string }}?{proc }|{menu }"

expr = "\<\$[IAS]"

expr = "{else }|{elseif }|{while }|{repeat }|{loop }|{for }|{switch}
         |{case }|{

expr = "{unix}|{vms}|{vax}|{aos}|{non-}|{dos}|{windows}|{motif}|{iq[wx]}"

expr = "^{forward }?{public }?{{integer }|{string }}?{proc }|{menu }"

expr = "{<\$M}|{<\$R\[}"


  Symbol   Regular Expression Search Behavior
  ......   ....................................................................

    .      Matches any single character (except end-of-line).

    ^      Beginning of line/block

    $      End of line/block

    \n     In a REPLACE pattern:  references a tagged component pattern
           from th search pattern, where "n" is a single-digit number
           from 0 through 9.

    |      "Or" operator:  matches the preceding or the following pattern.

    ?      Optionally matches the preceding pattern.

   [ ]     Identifies a Class of characters against which to match a single
            character.

  [ - ]    Indicates a range of characters (based on ASCII sequence)
           when used BETWEEN characters in a Class.

  [~ ]     Identifies a complement Class of characters to match against
           a single character, when "~" is used as the first character
           within the Class

    *      Matches 0 or more occurrences of the preceding pattern, with
           minimum closure.

    +      Matches 1 or more occurrences of the preceding pattern, with
           minimum closure.

    @      Matches 0 or more occurrences of the preceding pattern, with
           maximum closure.  (See "Minimum/Maximum Closure" below).

    #      Matches 1 or more occurrences of the preceding pattern, with
           maximum closure.  (See "Minimum/Maximum Closure" below).

   { }     Serve as Tags to identify a pattern group or component
           pattern withi the search pattern.  Tagged patterns can be
           nested.

    \      Serves as an Escape operator.  This symbol is used to
           override a Regular Expression operator so the operator symbol
           is treated as a literal character.  It is also used with
           certain other characters to indicate additional Regular
           Expression options; and is used within a Replace pattern to
           reference a Tagged component (see the explanation of "{ }"
           (Tags) above).

    \a     Matches the alert (beep) character (^G or ASCII 7).
    \b     Matches the backspace character (^H or ASCII 8).
    \f     Matches the formfeed character (^L or ASCII 12).
    \n     Matches the newline (line feed) character (^J or ASCII 10). **
    \r     Matches the return character (^M or ASCII 13). **
    \t     Matches the tab character (^Ior ASCII 9).
    \v     Matches the vertical tab character (^K or ASCII 11).
    \c     Designates the placement of the cursor within the
            located string whe used with the Find command.

  \xnn     Matches the character equivalent to the indicated hexadecimal
            value,

  \dnnn    Matches the character equivalent to the indicated decimal value,

  \onnn    Matches the character equivalent to the indicated octal
            value, where

//*************************************************************************
             Information on 'regular expressions'  10/28/93
//*************************************************************************

           File:  'tse_tip1.txt  Tuesday -  November 9, 1993
       Snippets of information from messages on various networks
                    From May 1993 thru October 1993
                                  END
