This is an Engineering Note Book post.  Feel free to ignore.

At present, tab-cycling is actively dangerous.  It works most of the time, 
but when it fails it will have you execute an unexpected command.  This is 
totally unacceptable.

I know from experience that tweaking this kind of code just makes matters 
worse.  Instead, I'll state some terms and principles that may clarify 
matters.

===== Overview

Tabs are used in two or three distinct ways:

1. Tab can be an escape.  For example, typing tab in the minibuffer find 
command terminates the find pattern and prompts for he replacement pattern.

This usage of tab *probably* won't cause any problems, but it definitely 
should terminate any tab cycling.

2. Tab can cause cycling from one of a list of possibilities to another.

3. Tab can cause the minibuffer to extend to the longest common prefix of a 
list of possible completions.

The problem is to distinguish cases 2 and 3 in a simple, foolproof manner.

===== Terms

The **initial completion list** is the list of all possible completions.  
For our purposes, the initial completion list never changes.  When doing 
command-name completion, this list is sorted(c.commandsDict.keys()).  In 
practice, the initial completion list is the tabList argument to ga.do_tab.

The **present completion list** is the list of completions being shown to 
the user.  The present completion list is completely determined by the 
initial completion list and the **present common prefix** (or **prefix**, 
for short).

Important: yes, the prefix is (or should be) the longest common prefix of 
all items in the present completion list.  However, the trick is to change 
the prefix as needed (case 3 above), thereby changing the present 
completion list.  In other words, the prefix should determine the present 
completion list, not the other way around!

The **label** is the changeable part of the minibuffer.  k.getLabel() 
returns the label.

k.mb_prefix is the *unchangeable* prefix of the minibuffer.  Do not confuse 
k.mb_prefix with "the prefix", they are totally different.

===== Guiding principles

1. Tab cycling should change neither the prefix nor present completion list.

Failure to follow this principle cause tab cycling to fail in various nasty 
ways.

2. Typing a non-tab character *always* increases the length of the prefix, 
thereby decreasing the number of entries in the present completion list.

I have found it best to allow the prefix to expand even if the present 
completions list becomes empty as a result.

3. It is valid for len(label) < len(prefix)  This will often be the case 
until the user hits the first tab.

4. It is valid for  len(label) > len(prefix).  This will usually be the 
case as the user cycles through completions by typing tab.

5. When the tab cycling is *not* in effect, typing tab will set the label 
to the prefix, so their lengths will be the same.

===== The real problem

Therefore, the essence of the problem is to determine whether or not tab 
cycling is in effect.  I did not realize this when I first started this 
post :-)

We can break the problem into: What starts tab cycling?  What ends tab 
cycling?

The following end tab cycling:

1. We can not be tab cycling if the len(label) < len(prefix) because in 
that case hitting tab will set the label to the prefix.

2. Hitting a non-tab character must unconditionally end tab cycling, 
regardless of whether the prefix would change if the user would hit tab.

3. Ctrl-G, escape or return must unconditionally end tab cycling.

Ok, what begins tab cycling?

When the user hits tab, we can enter tab cycling only if len(label) == 
len(prefix).  If not, a tab will recompute the prefix *without* starting 
tab cycling.

===== Summary

It is easy to forget cases or to make mistakes in this kind of code.  There 
is no guarantee that everything in the post is correct.  Having said that, 
it should be easier now to get something working now that things are 
clearer in my mind.  We shall see :-)

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to