Lugaru's Epsilon
Programmer's
Editor

Context:
Epsilon User's Manual and Reference
   Primitives and EEL Subroutines
      Input Primitives
         . . .
         Window Events
         Completion
            Completion Internals
            Listing Commands & Buffers & Files
         Other Input Functions
         . . .

Previous   Up    Next
Completion  Primitives and EEL Subroutines   Listing Commands & Buffers & Files


Epsilon User's Manual and Reference > Primitives and EEL Subroutines > Input Primitives > Completion >

Completion Internals

   /* bits for finder func */
#define STARTMATCH      1
#define EXACTONLY       2
#define LISTMATCH       4
#define FM_NO_DIRS      (0x10)
#define FM_ONLY_DIRS    (0x20)
char *b_match(char *partial, int flags)
                 /* sample finder */

comp_read(char *response, char *prmpt,
          char *(*finder)(), int flags, char *def)

   /* bits for comp_read() */
#define CAUTIOUS        (0x100)
#define COMP_FOLD       (0x200)
#define MUST_MATCH      (0x400)
#define NONE_OK         (0x800)
#define POP_UP_PROMPT   (0x1000)
#define COMP_FILE       (0x2000 | CAUTIOUS)
#define PASSWORD_PROMPT (0x4000)
#define SPACE_VALID     (0x8000)

prompt_comp_read(char *response, char *prmpt,
                 char *(*finder)(), int flags, 
                 char *def)
zeroed char completion_column_marker;

It's easy to add new subroutines that can complete on other things. First, you must write a "finder" function that returns each of the possible matches, one at a time, for something the user has typed. For example, the get_buf( ) subroutine uses the finder function b_match( ).

A finder function takes a parameter partial which contains what the user's typed so far, and a set of flags. If the STARTMATCH flag is on, the function must return the first match of partial. If STARTMATCH is off, it should return the next match. The function should return 0 when there are no more matches. The LISTMATCH flag is on when Epsilon is preparing a list of choices because the user has pressed "?". This is so that a finder function can format the results differently in that case. If the EXACTONLY flag is on, the finder function should return only exact matches for partial. If the finder function is matching file names, you may also provide the FM_NO_DIRS flag, to exclude directory names, or FM_ONLY_DIRS to retrieve only directory names.

Next, write a subroutine like the various get_ routines described above, all of which are defined in complete.e. It should take a prompt string, possibly a default string, and a character pointer in which to put the user's response. It passes these to the comp_read( ) subroutine, along with the name of your finder function (as a function pointer).

The comp_read( ) subroutine also takes a flags parameter. If the CAUTIOUS flag is zero, comp_read( ) assumes that all matches for a certain string will begin with that string, and that if there is only one match for a certain string, adding characters to that string won't generate any more matches. These assumptions are true for most things Epsilon completes on, but they're not true for files. (For example, if the only match for x is xyz, but xyz is a directory with many files, the second assumption would be false. The first assumption is false when Epsilon completes on wildcard patterns like *.c, since none of the matches will start with the * character.) If you provide the CAUTIOUS flag when you call comp_read( ), Epsilon doesn't make those assumptions, and completion is somewhat slower.

Actually, when completing on files, provide the COMP_FILE macro instead of just CAUTIOUS; this includes CAUTIOUS but also makes Epsilon use some special rules necessary for completing on file names.

If you provide the COMP_FOLD flag to comp_read( ), it will do case-folding when comparing possible completions.

The MUST_MATCH flag tells comp_read( ) that if the user types a response that the finder function doesn't recognize, it's probably a mistake. The comp_read( ) subroutine will then offer a list of possible responses, even though the user may not have pressed a key that ordinarily triggers completion. The comp_read( ) subroutine might still return with an unrecognized response, though. This flag is simply advice to comp_read( ). The NONE_OK flag is used only with MUST_MATCH. It tells comp_read( ) that an empty response (just typing <Enter>) is ok.

Under Epsilon for Windows, the POP_UP_PROMPT flag tells comp_read( ) to immediately pop up a one-line dialog box when prompting. Right now, this flag may only be used when no completion is involved, and comp_read( ) is simply prompting for a line of text.

The PASSWORD_PROMPT flag tells comp_read( ) to display each character of the response as a * character. When the Internet functions prompt for a password they use this flag.

The SPACE_VALID flag tells comp_read( ) that a <Space> character is valid in the response. Since <Space> is also a completion character, comp_read( ) tries to guess whether to add a <Space> or complete, by examining possible matches.

A finder function receives any of the above flags that were passed to comp_read( ), so it can alter its behavior if it wants.

The comp_read( ) subroutine uses the prompt you supply as-is. Usually, the prompt should end with a colon and a space, like "Find file: ". By contrast, the prompt_comp_read( ) subroutine adds to the supplied prompt by showing the default value inside square brackets, when insert-default-response is zero. The prompt string you supply to it should not end with a colon and space, since Epsilon will add these. If you provide a prompt such as "Buffer name" and a default value of "main", Epsilon will display Buffer name [main]: . If the default value you provide is empty or too long, Epsilon will instead display Buffer name: , omitting the default. Whether or not Epsilon displays the default, if the user doesn't enter any text at the prompt the prompt_comp_read( ) subroutine substitutes the default value by copying def to response.

Sometimes it's convenient if a finder function returns matches with additional data after them which shouldn't be included in the returned response. You can set the variable completion_column_marker to a character that marks the start of such extra data. If it's nonzero, and a response from the finder function contains it, Epsilon strips that character and any following text from the response before returning it, if the user selects that choice from the list of completions.

char *(*list_finder)();
list_matches(char *s, char *(*finder)(), int flags, int mbuf)
int *(*completion_lister)();
char resize_menu_list;

The comp_read( ) subroutine looks at several variables whenever it needs to display a list of possible completions (such as when the user types "?"). You can change the way Epsilon displays the list by setting these variables. Typically, you would use the save_var statement to temporarily set one of these while your completion routine runs.

By default, Epsilon calls the list_matches( ) subroutine to prepare its buffer of possible matches. The function takes the string to complete on, the finder function to use, flags as described above, and a buffer number. It calls the finder function repeatedly (passing it the LISTMATCH flag as well as any others passed to list_matches( )) and puts the resulting matches into the indicated buffer, after sorting the matches. If the completion_lister function pointer is non-null, Epsilon calls that function instead of list_matches( ), passing it the same parameters. If, for example, you have to sort the matches in a special order, you can set this variable.

If you simply want a different list of matches when Epsilon lists them, as opposed to when Epsilon completes on them, you can set the list_finder function pointer to point to a different finder function. The list_matches( ) subroutine always uses this variable if non-null, instead of the finder function it receives as a parameter.

An EEL completion function can temporarily set the resize_menu_list variable nonzero to indicate that if the user tries to list possible completion choices, the window displaying the choices should be widened if necessary to fit the widest choice. This variable has no effect on Epsilon windows within GUI dialogs.

int complete(char *response, char *(*finder)(), int flags)

To actually do completion, comp_read( ) calls the complete( ) subroutine. It takes a finder function pointer, flags like CAUTIOUS and COMP_FOLD described above, and a string to complete on. It tries to extend the string with additional characters from the matches, modifying it in place.

The complete( ) subroutine generally returns the number of possible matches for the string. However, it may be able to determine that no more completion is possible before reaching the last match. For example, if the subroutine tries to complete on the file name "foo", and encounters files named "foobar", "foobaz", "foo3", "foo4" and so forth, it can determine on the third file that no completion is possible. In this case, it returns 3, even though there may be additional matches. It can only "give up early" in this way when it has encountered two or more matches. So when the subroutine returns a value of two or greater, there may be additional matches not included in its count.

build_prompt(char *full, char *pr, char *def, int omit, int rel)

The build_prompt( ) subroutine helps construct the text of a prompt. It copies the prompt pr to full, appending the default value def to it (inside brackets).

If the combination would be too wide for the screen, the subroutine abbreviates the default value. If even an abbreviated value would be too wide, or if omit is nonzero, it omits the default from the prompt entirely. If rel is nonzero, it assumes def is an absolute pathname, and uses its relative form.

find_buffer_prefix(int buf, char *prefix)

The find_buffer_prefix( ) subroutine looks through all the lines in the buffer buf to see if they all start with the same string of characters. It puts any such common prefix shared by all the lines in prefix. For instance, if the buffer contains three lines "waters", "watering" and "waterfall", it would put the string "water" in dest.

char *general_matcher(char *s, int flags)

Epsilon providers a general-purpose finder function called general_matcher( ). An EEL function can perform completion on some arbitrary list of words by putting the list of words in a buffer named _MATCH_BUF (a macro defined in eel.h) and then providing general_matcher( ) as a finder function to a subroutine like comp_read( ). Call comp_read( ) with the COMP_FOLD flag if you want general_matcher( ) to ignore case when comparing.

char _doing_input;
keytable comp_tab, menu_tab, view_tab;

An EEL function can tell if Epsilon is currently prompting for a line of input (or performing certain related tasks) by examining the _doing_input variable. It's zero normally. While Epsilon is inside the search_read( ) subroutine or related ones, getting a search string from the user, it's set to DI_SEARCH. While Epsilon is prompting for a line of some other type of input, it's set to DI_LINEINPUT.

While the view_buf( ) subroutine (or a related one) is displaying a pop-up window, _doing_input is set to either DI_VIEW or DI_VIEWLAST, according to whether the last parameter passed to view_buf( ) was zero or not.

When Epsilon prompts for input, it uses certain specialized key tables in the buffer that accepts the input. It uses the comp_tab key table for the one-line buffer where the user types a response, in all the subroutines that accept a line of input (except in search_read( ) and related subroutines that prompt for search strings).

When Epsilon displays a list of possible matches, or previous responses, or similar things, while getting a line of input, it uses the menu_tab key table in the buffer displaying the list.

Finally, subroutines like view_buf( ) normally use the view_tab key table to show a buffer in a pop-up window.



Previous   Up    Next
Completion  Primitives and EEL Subroutines   Listing Commands & Buffers & Files


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