Language Indenting and Templates


 Introduction
  

Two of the most useful features of the SemWare Editor are Language
Support and Templates.

Language Support handles the formatting of source code.  Using Language
Support, you don't have to keep track of indentation levels.  This is
useful for programmers who write a lot of code and want consistent
formatting.

In the standard configuration, the SemWare Editor uses formatting for C
programs as defined in "The C Programming Language" by Kernighan and
Ritchie.  A standard piece of formatted code would look like this:

    if (a) {
        s1();
    }

Many people wish to modify this to use a style that is equally
consistent and easier for some people to read, such as having the braces
out-dented in a manner similar to Pascal's begin...end:

    if (a)
    {
        s1();
    }

While others would like to have the braces indented:

    if (a)
        {
        s1();
        }

This document will show you how to modify the TSE User Interface to
allow for these styles of indentation in your C programs.  Adding
Language Support for other languages is also covered in this document.

Templates allow you to define an abbreviation that the editor will
expand into a piece of code or other text.  Additionally, you can tell
the editor where to place the cursor in the expanded template. Templates
can be used with the Language Support features of TSE to increase your
productivity.


 Using Templates in Conjunction with Language Support
  

The Language Support and Template Editing facilities in the SemWare
Editor are designed to work together.  You may use either Language
Support or Template Editing individually, or both at once.

For information on how TSE's Language Support works, see the
"Explanation of How Language Support Works" section of this document.
For information on removing and / or modifying Language Support,
see the "Making Modifications to the Language Support", "Removing a
Language from Language Support" and "Completely Disabling Language
Support" sections of this documentation.

For information on using Template Editing, see the "Templates" section
of this documentation.

 Language Support
  

The Language Support provided in The SemWare Editor consists of several
macros included in the user interface for the editor.

Modifying the Language Support in TSE is easy once you understand how
the it is implemented.  To simplify the process, we'll talk about how
Language Support is implemented.  Next, we'll look at the places to make
changes, and how to modify the user interface.  Finally, we'll talk
about adding support for other languages to the existing language
support.

Note that cmode assumes that AutoIndent is on, and works best if AutoIndent
is set to STICKY.

   Explanation of How Language Support Works
    

The editor maintains a pair of internal settings that are used to
determine when you are working on a programming file.  The editor checks
each time you switch from one file to another, and changes these
settings accordingly.

The two settings are defined as follows:

    CMode - set non-zero _only_ if the file you are working on has a .c, .h,
            .cpp, .hpp or .java extension, otherwise CMode is set false.

    Language - set true if you are working on a file with a .ui, .s,
               .asm, .pas, .inc, .prg, .c, .h, .cpp, .hpp or .java extension,
               otherwise Language Mode is set to false.

When you press <enter>, or type a closing curly-brace (a '}' character)
the editor checks these settings, and performs one of the following
actions:

    - On pressing <Enter>:

      * Language Mode Processing: TSE looks at the Language setting. If
        Language is true, then TSE checks to see if the first word on
        the line is in the keyword list.  If it is TSE inserts a
        carriage return (using the setting of ReturnEqNextLine) and tabs
        to the right once, otherwise TSE inserts a carriage return.

      * CMode Processing: If CMode is true, TSE looks for a '{' on the
        current line. If TSE finds a '{', it inserts a carriage return
        (using the setting of ReturnEqNextLine) and tabs to the right,
        otherwise TSE inserts a carriage return.

    - When you type a '}':

      * CMode Processing: TSE looks at the CMode setting.  If it is set
        to true, TSE tabs left and then inserts a '}', otherwise TSE
        inserts '}' character at the current cursor position.

   Locating the Language Support in TSE.UI
    

The Language Support in TSE is located in three places in the TSE.UI
file:

    OnChangingFiles() - Adjusts the Language and CMode settings.
    mCReturn()        - Handles Language Mode and CMode indentation
                        processing.
    mCloseBrace()     - Handles CMode indentation processing.

   Making Modifications to the Language Support
    

In most cases modifying the Language Support in The SemWare Editor
requires a bit of familiarity with the SAL Macro Language.  This section
will alleviate this need by providing several common Language Support
modifications, with replacement source code where needed.

For c/c++/java language mode, we show you how to use any of 4 different
styles:


o   In the OnChangingFiles() proc, set cmode to 1..4 depending on the style
    wanted - none of the changes below will work unless you select the
    proper cmode style!

      The following c/c++/java Styles are supported:

      1)    if (cond) {
                s();
            }

      2)    if (cond) {
                s();
                }

      3)    if (cond)
            {
                s();
            }

      4)    if (cond)
                {
                s();
                }

o   Insert the following routines, before the mBackspace() proc:

        // used to force TabRight to a 'fixed' mode
        proc mTabRight()
            integer save_tabtype = Query(TabType)

            if not (Query(TabType) in _SOFT_, _HARD_)
                save_tabtype = Set(TabType, _SOFT_)     // force fixed tabs
            endif

            TabRight()
            Set(TabType, save_tabtype)              // restore tabtype
        end

        // used to force TabLeft to a 'fixed' mode
        proc mTabLeft()
            integer save_tabtype = Set(TabType, _SOFT_)     // force fixed tabs
            TabLeft()
            Set(TabType, save_tabtype)              // restore tabtype
        end

        // Helper routine for mCreturn in cmode
        integer proc LastCloseSquiggly()
            integer i, p = 0, p2

            PushPosition()
            for i = 1 to 25
                if not Up()
                    break
                endif
                p2 = PosFirstNonWhite()
                if p2
                    if GetText(p2, 1) == '}'
                        p = p2
                    endif
                    break
                endif
            endfor
            PopPosition()
            return (p)
        end

        // Helper routine for mCreturn in cmode
        integer proc LineEndsInOpenBrace(integer p)
            if PosLastNonWhite() == p
                return (TRUE)
            endif
            PushPosition()
            GotoPos(p)
            while (Right())
                case CurrChar()
                    when _AT_EOL_, _BEYOND_EOL_
                        PopPosition()
                        return (FALSE)
                    when Asc('/')
                        if CurrChar(CurrPos() + 1) in Asc('/'), Asc('*')
                            PopPosition()
                            return (TRUE)
                        endif
                endcase
            endwhile
            PopPosition()
            return (FALSE)
        end

o   Delete the mCreturn() proc, and replace it with this one:

        /****************************************************************************
          Fancy CarriageReturn command.  Works if language mode is on.

          11-05-93 SEM Handle SmartTabs
         ***************************************************************************/
        proc mCReturn()
            integer p, indent = 0, curpos = CurrPos()

            if language and CurrPos() > PosFirstNonWhite()
                if cmode <> 3 and Pos(Lower(GetFirstWord()), KeyWords) > 0     // line begins with keyword
                    indent = 1
                elseif cmode in 1,2,3
                    p = Pos('{', GetText(1, CurrPos() - 1))
                    if p > 0                                    // line contains a '{' before curpos
                        if LineEndsInOpenBrace(p)               // line ends in '{' or ('//' or '/*' follows '{')
                            indent = 1
                        endif
                    endif
                endif

                if indent == 0 and cmode in 2,4
                    p = Pos('}', GetText(1, CurrPos() - 1))
                    if p > 0                                    // line contains a '}' before curpos
                        if p == PosFirstNonWhite()              // line begins in '}'
                            indent = -1
                        endif
                    endif
                endif
            endif

            CReturn()

            if indent == 0
                if CurrPos() <> curpos and (cmode in 2,4) and LastCloseSquiggly() == CurrPos()
                    GotoPos(curpos)
                endif
            elseif ((Query(Insert) and Query(ReturnEqNextLine) == FALSE) or PosFirstNonWhite() == 0)
                if indent > 0
                    mTabRight()
                elseif indent < 0
                    mTabLeft()
                endif
            endif
        end

o   Insert this routine just before the existing mCloseBrace() proc:

        /****************************************************************************
          Special handling of { in cmode
         ***************************************************************************/
        proc mOpenBrace()
            integer p

            if cmode == 3
                PushPosition()
                p = iif(Up(), PosFirstNonWhite(), 0)
                PopPosition()
                if p
                    GotoPos(p)
                endif
            endif
            InsertText("{")
        end

o   Delete the mCloseBrace() proc, and replace it with this one:

        /****************************************************************************
          Special handling of } in cmode
         ***************************************************************************/
        proc mCloseBrace()
            if PosFirstNonWhite() == 0
                if (cmode in 1,3) // doesn't work??? or ((cmode in 2,4) and CurrCol() == Query(TabWidth) + 1)
                    mTabLeft()
                endif
            endif
            InsertText("}")
        end

o   Finally, add the following key assignment, just before the mCloseBrace() key assignemt:


        #ifdef WIN32
        <{>                     mOpenBrace()
        #else
        <Shift [>               mOpenBrace()
        #endif

Note that cmode works better if AutoIndent is on, and even better if
AutoIndent is set to STICKY.

   Adding A New Language to the Language Support
    

To add another language to the language support you will need to do two
things:

    - Add the file extensions that identify files for that language.

    - Add any special keywords that TSE should indent the next line
      after it finds one.

For example, say you had a language that used '.X' for it's source
files, and had two keywords ('xfor' and 'start') that you wanted TSE to
handle.

First, in the OnChangingFiles procedure find the line that says:

        when ".ui",".s",".asm",".pas",".inc",".prg"

Add the file extension '.X' to this line:

        when ".ui",".s",".asm",".pas",".inc",".prg",".x"

Next, near the beginning of the TSE.UI file find the KeyWords variable
declaration.  The line should look like this:

    string  KeyWords[] = " case do else elseif for if loop otherwise
                           proc repeat switch when while "

Add the new keywords to this line:

    string  KeyWords[] =  " case do else elseif for if loop otherwise
                            proc repeat switch when while xfor start "

Note: the KeyWords string cannot exceed 256 characters in length.  If
      you need to add many words to the list, you will need to remove
      some words from the provided list.

TSE will now work with your new language, as it does for the other
supported languages.

   Removing a Language from Language Support
    

If you want to exclude files for a particular language from Language
Support handling, just remove the appropriate file extensions from the
OnChangingFiles() section of your TSE.UI file. For example, if you
didn't want support for TSE's SAL language you would modify the
following line:

               when ".ui",".s",".asm",".pas",".inc",".prg"

And make it look like this:

               when ".asm",".pas",".inc",".prg"

And also remove any unique keywords for that language from the KeyWords
string:

    string  KeyWords[] = " if else elseif while repeat loop for switch case
                            when otherwise proc "

Would become (if you were removing the SAL support):

    string  KeyWords[] = " if else while repeat loop for switch case
                            when "

   Completely Disabling Language Support
    

If you want to completely disable the Language Support in The SemWare
Editor, all you need to do is comment out the Language Support section
of OnChangingFiles() in the TSE.UI file:

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

Note: the Language and CMode settings are set false so mCReturn() and
      mCloseBrace() won't perform any Language Mode processing or CMode
      processing.


 Templates
  

Templates provide an alternative to typing long sections of text over
and over again.  You can type the text once, mark it with a block and
tell the template system to assign an abbreviation to it.

When you type the abbreviation, and press the template key, the macro
will automatically replace the keyword with the text that you defined it
to have.

For example, in C it is common to do a lot of 'if' statements that look
like this:

    if (xyz) {
      // do something here
    }

Using the template support in TSE, you could use the abbreviation 'if',
press the Template Expand key, and have the editor produce:

    if () {

    }

And the Template system could place the cursor on the closing
parenthesis automatically for you.  You also can associate abbreviations
with file extensions. This is useful if you work in multiple languages,
and want to have the same abbreviation used for templates specific to
different languages.

   How To Create a Template
    

Say you had to type the following often:

    start ()

    s_quit

And you wanted to define a template called 'sta' associated with files
that have '.X' as the extension.

To define a template you would do the following:

    - Turn Template support on.  (Select "Template Expansion" from the
      Util menu.)

    - Type the text that you want to define as a template.

    - Mark the text with a block.

    - Place the cursor where you want it to be when the template is
      expanded, and type "\C".  (In this case, let's say you want it to
      be on the opening parenthesis.  The template would then look like:)

            start \C()

            s_quit

    - Press <Ctrl Tab> to pull up the menu.

    - Select 'Add Marked Text as Template'.

    - Type 'sta' (without the quotes) in the Keyword prompt and press
      <Enter>.

    - Type '.X' in the Extension prompt.


   How To Expand a Template
    

Now that you have a template defined, you can use it whenever you want.
To expand a Template follow these steps:

    - Make sure Template Support is turned on. (Select "Template
      Expansion" from the Util menu.)

    - Type the abbreviation of the Template you want to expand:

        sta

    - And press the Template Expand key. (<TAB> is used as the standard
      key for this.)

Template system automatically replaces the keyword with the template as
you have defined it, and places the cursor where you want it.

   Using Templates Instead of Language Support
    

With TSE's Template Editing you can turn off Language Support and use
Templates to enter control statements in your documents. Languages can
be individually removed, or you can disable TSE's Language Support
completely.

To do this follow these steps:

    - Make sure that you have all of the templates defined that you need
      to be able to enter your programs.

    - Disable as much, or as little of the Language Support as you need:

      - To use Templates in place of the Language Support for a single
        language, see the "Removing a Language from Language Support"
        section of this document.

      - To use Templates in place of Language Support, see the
        "Completely Disabling Language Support" section of this
        document.

Once you have selected and made one of these modifications, you can use
TSE's Template Editing facility without using Language Support.

