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.
