Lugaru's Epsilon
Programmer's
Editor

Context:
Epsilon User's Manual and Reference
   Primitives and EEL Subroutines
      Buffer Primitives
         Changing Buffer Contents
         Moving Text Between Buffers
         Getting Text from a Buffer
         . . .
         Listing Buffers
      Display Primitives
         . . .
         Printf-style Format Strings
         Other Display Primitives
         Highlighted Regions
         Character Coloring
         Code Coloring Internals
         . . .
      File Primitives
         File Reading Primitives
         File Writing Primitives
         Line Translation Primitives
         . . .
         Tagging Internals
      . . .

Previous   Up    Next
Other Display Primitives  Primitives and EEL Subroutines   Character Coloring


Epsilon User's Manual and Reference > Primitives and EEL Subroutines > Display Primitives >

Highlighted Regions

Epsilon can display portions of a buffer in a different color than the rest of the buffer. We call each such portion a region. The most familiar region is the one between point and mark. Epsilon defines this region automatically each time you create a new buffer. (Also see the description of character coloring in Character Coloring.)

Epsilon can display a region in several ways. The most common method corresponds to the one you see when you set the mark (by typing Ctrl-@) and then move around: Epsilon highlights each of the characters between point and mark. If you use the mark-rectangle command on Ctrl-X # to define a rectangular region, the highlighting appears on all columns between point and mark, on all lines between point and mark. The pop-up windows of the completion facility illustrate a third type of highlighting, where complete lines appear highlighted. The header file codes.h defines these types of regions as (respectively) REGNORM, REGRECT, and REGLINE. Epsilon won't do any highlighting for a region that has type 0.

A fourth type of highlighting, REGINCL, is similar to REGNORM, but includes an additional character at the end of the region. If a REGNORM region runs between position 10 and position 20 in the buffer, Epsilon would highlight the 10 characters between the two positions. But if the region were a REGINCL region, it would include 11 characters: the characters at positions 10 and 20, and all the characters between.

int add_region(spot from, spot to, int color,
               int type, ?int handle)
remove_region(int handle)
int modify_region(int handle, int code, int val)
window char _highlight_control;

You can define new regions with add_region( ). It takes a pair of spots, a color class expression such as color_class highlight, a region display type (as described above), and, optionally, a numeric "handle". It returns a nonzero numeric handle which you can use to refer to the region later. You can provide the spots in either order, and you may give the same spot twice (for example, in conjunction with REGLINE, to always highlight a single line). See Setting Colors for basic information on color classes, and Constants and Identifiers for details on the syntax of color class expressions).

When you omit the handle parameter to add_region( ) (or provide a handle of zero) add_region( ) assigns an unused handle to the new region. You can also provide the handle of an existing region, and add_region( ) will assign the same handle to the new region. Any changes you make to one region by using modify_region( ) will now apply to both, and a single remove_region( ) call will remove both. You can link any number of regions in the same buffer in this way. The special handle value 1 refers to the region between point and mark that Epsilon creates automatically.

The remove_region( ) primitive takes a region handle, and deletes all regions with that handle. The handle may belong to a region in another buffer. Epsilon signals an error if the handle doesn't refer to any region.

The modify_region( ) primitive retrieves or sets some of the attributes of one or more regions. It takes a region handle, a modify code (one of the MR... codes below), and a new value. If you provide a "new value" that's out of range (such as -2, out of range for all modify codes), Epsilon will not change that attribute of the region, but will simply return its value. If you provide a valid new value, Epsilon will set that attribute of the region, and will return its previous value.

When several regions share the same handle, it's possible they will have different attribute settings. In this case, which region's attribute Epsilon returns is undefined. If you specify a new value for an attribute, it will apply to all regions with that handle.

The modify code MRCOLOR may be used to get or change a region's color class. The modify code MRTYPE may be used to get or change a region's display type, such as REGRECT. The codes MRSTART and MREND may be used to set the two spots of a region; however, Epsilon will not return the spot identifier for a region, but rather its current buffer position.

You can force a region's starting and ending positions to specific columns using the modify codes MRSTARTCOL and MRENDCOL. For example, if a region runs from point to mark, and you set its MRSTARTCOL to 3, the region will start at column 3 of whatever line point is on. A column setting of -1 here makes Epsilon use the actual column value of the spot; no column will be forced.

You can set up a region to be "controlled" by any numeric global variable. Epsilon will display the region only if the variable is nonzero. This is especially useful because the variable may be window-specific. Since regions are associated with buffers, this is needed so that a buffer displayed in two windows can have a region that appears in only one of them.

The standard region between point and mark is controlled by the window-specific character variable _highlight_control. By default, other regions are not controlled by any variable. The modify code MRCONTROL may be used with modify_region( ) to associate a controlling variable with a region. Provide the global variable's name table index (obtainable through find_index( )) as the value to set.

A region may be given an auto-delete property using the MRAUTODEL macro. Pass a value of 1 to enable auto-deleting, 0 to disable it. When you delete an auto-deleting region, it automatically deletes the two spots assigned to it. By default, no region is auto-deleting. The spots used for an auto-deleting region should not be shared with other regions, or system spots like point_spot or mark_spot.

set_region_type()       /* disp.e */
int region_type()       /* disp.e */
highlight_on()          /* disp.e */
highlight_off()         /* disp.e */
int is_highlight_on()   /* disp.e */

Several subroutines let you conveniently control highlighting of the standard region between point and mark. To set the type of the region, call the subroutine set_region_type( ) with the region type code, one of REGNORM, REGRECT, REGLINE, or REGINCL. This doesn't automatically turn on highlighting. Call highlight_on( ) to turn on highlighting, or highlight_off( ) to turn it off.

The region_type( ) subroutine returns the type of the current region, whether or not it's currently highlighted. The is_highlight_on( ) subroutine returns the type of the current region, but only if it's highlighted. It returns 0 if highlighting is off.

There are several subroutines that help you write functions that work with different types of regions. If you've written a function that operates on the text of a normal Epsilon region, add the following lines at the beginning of your function to make it work with inclusive regions and line regions as well:

save_spot point, mark;
fix_region();

When the user has highlighted an inclusive or line region, the fix_region( ) subroutine will reposition point and mark to form a normal Epsilon region with the same characters. (For example, in the case of a line region, Epsilon moves point to the beginning of the line.) The function also swaps point and mark so that point comes first (or equals mark, if the region happens to be empty). This is often convenient.

This procedure assumes your function doesn't plan to modify point or mark, just the characters between them, and it makes sure that point and mark remain in the same place. If your function needs to reposition the point or mark, try omitting the save_spot line. Your function will be responsible for determining where the point and mark wind up.

A function needs to do more work to operate on rectangular regions. If it's built to operate on all the characters in a region, without regard to rectangles or columns, the simplest approach may be to extract the rectangle into a temporary buffer, modify it there, and then replace the rectangle in the original buffer. Several Epsilon subroutines help you do this. For a concrete example, let's look at the function fill_rectangle( ), defined in format.e. The fill-region command calls this function when the current region is rectangular.

// Fill paragraphs in rectangle between point and mark
// to marg columns (relative to rectangle's width if <=0).
fill_rectangle(marg)
{
        int width, orig = bufnum, b = tmp_buf();

        width = extract_rectangle(b, 0);
        save_var bufnum = b;
        mark = 0;
        margin_right = marg + (marg <= 0 ? width : 0);
        do_fill_region();
        xfer_rectangle(orig, width, 1);
        buf_delete(b);
}

The function begins by allocating a temporary buffer using tmp_buf( ). Then it calls the extract_rectangle( ) subroutine to copy the rectangle into the temporary buffer. This function returns the width of the rectangle it copied. The call from fill_rectangle( ) passes the destination buffer number as the first parameter. Then fill_rectangle( ) switches to the temporary buffer and reformats the text. Finally, the subroutine copies the text back into its rectangle by calling xfer_rectangle( ) and deletes the temporary buffer. If the operation you want to perform on the text in the rectangle depends on any buffer-specific variables, be sure to copy them to the temporary buffer.

Now let's look at the two rectangle-manipulating subroutines fill_rectangle( ) calls in more detail.

extract_rectangle(int copybuf, int remove)

The extract_rectangle( ) subroutine operates on the region between point and mark in the current buffer. It treats the region as a rectangle, whether or not region_type( ) returns REGRECT. It can perform several different actions, depending upon its parameters. If copybuf is nonzero, the subroutine inserts a copy of the rectangle into the buffer with that buffer number. The buffer must already exist.

If remove is 1, the subroutine deletes the characters inside the rectangle. If remove is 2, the subroutine replaces the characters with spaces. If remove is 0, the subroutine doesn't change the original rectangle.

The subroutine always leaves point at the upper left corner of the rectangle and mark at the lower right. It return the width of the rectangle.

xfer_rectangle(int dest, int width, int overwrite)

The xfer_rectangle( ) subroutine inserts the current buffer as a rectangle of the given width into buffer number dest, starting at dest's current point. If overwrite is nonzero, the subroutine copies on top of any existing columns. Otherwise it inserts new columns. In the destination buffer, it leaves point at the top left corner of the new rectangle, and mark at the bottom right. The point remains at the same position in the original buffer.

rectangle_standardize()

Functions that manipulate rectangles can sometimes use the rectangle_standardize( ) subroutine to simplify their logic. In a rectangular region, point may be at any one of the four corners of the rectangle. This subroutine moves point and mark so they indicate the same region, but with point at the lower right and mark at the upper left. It's like the rectangular region equivalent of the fix_region( ) subroutine.

do_shift_selects()

Commands bound to cursor keys typically select text when you hold down the shift key. They do this by calling do_shift_selects( ) as they start. This routine looks at the current state of the shift key and whether or not highlighting is already on, and turns highlighting on or off as needed, possibly setting point.

make_line_highlight()     /* complete.e */
remove_line_highlight()   /* complete.e */

The make_line_highlight( ) subroutine uses the add_region( ) primitive to create a region that highlights the current line of the current buffer. When Epsilon puts up a menu of options, it uses this function to keep the current line highlighted. The remove_line_highlight( ) subroutine gets rid of such highlighting.



Previous   Up    Next
Other Display Primitives  Primitives and EEL Subroutines   Character Coloring


Lugaru Copyright (C) 1984, 2012 Lugaru Software Ltd. All Rights Reserved.