Lugaru's Epsilon
Programmer's
Editor 14.04

Context:
Epsilon User's Manual and Reference
   Primitives and EEL Subroutines
      Display Primitives
         . . .
         Window Titles and Mode Lines
         Normal Buffer Display
            Screen Dimensions
            Character Display
            Character Widths and Columns
         Displaying Status Messages
         . . .

Previous   Up    Next
Character Display  Primitives and EEL Subroutines   Displaying Status Messages


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

Character Widths and Columns

int display_width(int ch, int col)
move_to_column(int col)
int column_to_pos(int col)

The number of characters that fit on each screen line depends on the display codes of the characters in the line. Epsilon moves characters with multi-character representations as a unit to the next screen line when they don't fit at the end of the previous one (except in horizontal scrolling mode). Tab characters also vary in width depending upon the column they start in. There are several primitives that count screen columns using display class information.

The display_width( ) primitive is the simplest. It returns the width a character ch would have if it were at column col. The move_to_column( ) primitive moves to column col in the current line, or to the end of the line if it does not reach to column col. The column_to_pos( ) subroutine accepts a column number but doesn't move point; instead it returns the buffer position of that column.

int horizontal(int pos)
int current_column()
int get_column(int pos)         /* indent.e */
int get_indentation(int pos)    /* indent.e */
int give_position_at_column(int p, int col)
to_column(int col)              /* indent.e */
indent_to_column(int col)       /* indent.e */
insert_to_column(int start, int end) /* indent.e */
indent_like_tab()               /* indent.e */

The horizontal( ) primitive returns the number of columns from point to position pos. Point doesn't change. It must be before pos. The primitive returns -1 if there is a newline character between point and pos. This primitive returns the current column when point is in column 0, and the current screen column when point is at the start of a screen line. With other starting positions, tab characters may not expand to the same number of columns as they would on screen.

The current_column( ) primitive uses the horizontal( ) primitive to return the number of the current column.

The get_column( ) subroutine returns the column number of a given buffer position. The get_indentation( ) subroutine returns the indentation of the line containing position pos.

The give_position_at_column( ) subroutine returns the buffer position of the character at column col on the line containing position p; the column may be -1 to retrieve the position of the end of p's line.

The to_column( ) subroutine indents so that the character immediately after point winds up in column col. It replaces any spaces and tabs before point with the new indentation. It doesn't modify any characters after point.

The indent_to_column( ) subroutine indents so that the next non-whitespace character on the line winds up in column col. It replaces any spaces and tabs before or after point. The older insert_to_column( ) function inserts spaces and tabs in a simpler way, and must be told what starting column to assume. In most cases indent_to_column( ) is a better choice.

The indent_like_tab( ) subroutine indents like inserting a <Tab> character at point would. However, it respects the indent-with-tabs variable and avoids using tabs when the variable is zero. It also converts spaces and tabs immediately before point so that they match indent-with-tabs and use the minimum number of characters.

force_to_column(int col)    /* indent.e */

The force_to_column( ) subroutine tries to move to column col. If the line doesn't reach to that column, the function indents out to the column. If the column occurs inside a tab character, the function converts the tab to spaces.

user window short cursor_to_column;
to_virtual_column(int col)  /* basic.e */
int virtual_column()        /* basic.e */
int virtual_mark_column()   /* basic.e */

The window-specific cursor_to_column variable lets users position the cursor in a part of a window where there are no characters. It's normally -1, and the cursor stays on the character after point. If it's non-negative in the current window, Epsilon puts the cursor at the specified column in the window instead. Epsilon resets cursor_to_column to -1 whenever the buffer changes, or point moves from where it was when you last set cursor_to_column. (Epsilon only checks these conditions when it redisplays the window, so you can safely move point temporarily.)

Similarly, the window-specific mark_to_column variable lets you position the mark in a part of a window where there are no characters. Epsilon uses this variable when it displays a region that runs to the mark's position, and swaps the variable with cursor_to_column when you exchange the point and mark. It's normally -1, so Epsilon highlights up to the actual buffer position of the mark. If it's non-negative in the current window, Epsilon highlights up to the specified column instead. Epsilon resets mark_to_column to -1 just as described above for cursor_to_column.

The to_virtual_column( ) subroutine positions the cursor to column col on the current line. It tries to simply move to the correct position in the buffer, but if no buffer character begins at that column, it uses the cursor_to_column variable to get the cursor to the right place without immediately modifying the buffer. In that case, it also arranges for an on_modify( ) function to run just before any subsequent modification of that buffer. If the cursor is still in virtual space when the on_modify( ) function runs, that function adds spaces and tabs as needed to reach the given column, so any text inserted is positioned at the desired column. (EEL programmers usually use move_to_column( ) to position to a column instead of this function's more complicated semantics, and use indent_to_column( ) or to_column( ) to explicitly add whitespace characters when needed.)

The virtual_column( ) subroutine provides the column the cursor would appear in: either the value of the cursor_to_column variable, or (if it's negative) the current column. Similarly, the virtual_mark_column( ) subroutine provides the column for the mark, taking mark_to_column into account.

tab_convert(int from, int to, int totabs)
hack_tabs(int offset)
int maybe_indent_rigidly(int rev)
int standard_tab_cmd(int (*func)(), int indent, int flags)

The tab_convert( ) subroutine converts tabs to spaces in the specified region when its parameter totabs is zero. When totabs is nonzero, it converts spaces to tabs.

The hack_tabs( ) subroutine converts tabs to spaces in the offset columns following point. If offset is negative, the function converts tabs in the columns preceding point.

Commands bound to <Tab> often call the maybe_indent_rigidly( ) subroutine. If a region's been highlighted, this subroutine indents it using the indent-rigidly command and then returns nonzero. Otherwise, it returns zero. If its parameter rev is nonzero, the subroutine unindents; a command bound to Shift-<Tab> often provides a nonzero rev, but for commands on <Tab> this is typically zero.

The standard_tab_cmd( ) subroutine packages a lot of standard functionality often found on the <Tab> key for a mode. A mode's command for the <Tab> key can call it, passing it the mode's indenter function (see below).

If there's a highlighted region, it calls maybe_indent_rigidly( ) and returns 1. Otherwise, if the cursor is past the current line's indentation, it indents to the next level, where the indent parameter supplies the number of columns to indent for each level, returning 2. (Epsilon uses the tab-size if indent is zero or negative.)

Next, if the user's pressed <Tab> twice or more in a row, it indents one level more and returns 3; otherwise it calls the indenting function and returns 4. But if the indenting function supplies no indentation (placing the line at the left margin), there was no indentation on the line before, and the 1 bit in the flags argument is provided, the function adds one level of indentation and returns 5.

buffer int (*indenter)(); /* EEL variable */
user buffer int auto_indent;   /* EEL variable */
prev_indenter()           /* indent.e */
zeroed int indenter_action; // Bits for why we're indenting.
#define IACT_AUTO_INDENT        1
#define IACT_AUTO_FILL          2
#define IACT_COMMENT            4
#define IACT_FILL_COMMENT       8
#define IACT_AUTO_FILL_COMMENT  16
#define IACT_REINDENT_PREV      32

The normal-character command provides a hook for automatic line indentation when it inserts the newline character. If the buffer-specific variable auto-indent is nonzero, the normal-character command will call the function pointed to by the variable indenter, a buffer-specific function pointer, after inserting a newline character. By default, it calls the prev_indenter( ) subroutine, which indents to the same indentation as the previous line.

Various other functions call a buffer's indenter function (if nonzero) at certain times.

Whenever Epsilon calls a buffer's indenter function, it sets the indenter_action variable to a value that indicates why it's indenting, so modes can vary indentation behavior based on context. The value IACT_AUTO_INDENT indicates the user pressed <Enter> in a buffer with auto-indenting enabled, as above.

The value IACT_AUTO_FILL indicates Epsilon broke a long line due to auto-filling, and it's now indenting the new line. The commenting commands indent-for-comment and set-comment-column use the value IACT_COMMENT when indenting comments.

The fill-comment command uses the value IACT_FILL_COMMENT when creating new lines for the comment. (In some modes it doesn't use the indenter when creating new lines.) Auto-filling of long comment lines uses the value IACT_AUTO_FILL_COMMENT.

The value IACT_REINDENT_PREV indicates the user pressed <Enter>, and a mode-specific setting caused Epsilon to reindent the existing line. See the default-reindent-previous-line variable.

The possible values of indenter_action are arranged as bits, so a function can use a bitmask to select particular sets of conditions.



Previous   Up    Next
Character Display  Primitives and EEL Subroutines   Displaying Status Messages


Lugaru Epsilon Programmer's Editor 14.04 manual. Copyright (C) 1984, 2021 by Lugaru Software Ltd. All rights reserved.