Neomutt completion API #3955
Replies: 7 comments 6 replies
-
Great topic!
Are you asking this because it's a potentially costly operation that you need to do it anyway ? As for array vs multiple compl_add. Does it really matter ? I mean you already do ARRAY_FOREACH with compl_add() on compl_from_array. Is this going to be different ?
like going from icase to case runtime ? That would be nice, but how do you actually see this ? binding another key ? like ctrl tab or so ? or perhaps prefix the search with something ? |
Beta Was this translation helpful? Give feedback.
-
While further going through the code, I realized that we should actually initialize the I will have a look where I need to attach the |
Beta Was this translation helpful? Give feedback.
-
Another thing: can we watch the user typed string for changes? |
Beta Was this translation helpful? Give feedback.
-
Read with a pinch of salt :-)
Yes.
Yes, the caller knows exactly what's going on.
I think it's important to make a distinction here. I don't think we want the Editor to complete from a list. The Editor will keep a data pointer for the Completion and will make its data available for manipulation. This way, Completion is free to do anything:
Yes, I think a single opaque struct pointer.
Currently no.
Do we need to? Unless, Completion has taken over, e.g. a popup.
We could certainly add more functions to the Completion API, so that it's aware of everything that the user is doing. |
Beta Was this translation helpful? Give feedback.
-
Here's the layout of functions in Auto-Completion: |
Beta Was this translation helpful? Give feedback.
-
OK, time for a detailed walk-through... Let's start with get_source_file(buf, start_dir)
{
struct Completion *comp = comp_file_new(CF_FILES, "*.c", start_dir);
mw_get_field(prompt, comp, buf);
comp_free(&comp);
}
struct Completion
{
int type; ///< Completion type
struct CompletionAPI *api; ///< Functions this API supports
struct StringArray matches; ///< Current results
int selection; ///< Currently selected item
char *word; ///< Current word being completed
int num_tabs; ///< Number of times <tab>'s been hit
void *cdata; ///< Private completion data
}; The Completion API might look like: struct CompletionAPI
{
int tab_pressed(struct Completion *comp); ///< Perform work
void free_cdata(void **ptr); ///< Function to free private data
}; We'll need more functions later, but that may be enough to start. Now, when the user hits <tab>, int op_editor_complete(struct EnterWindowData *wdata, int op)
{
comp_complete(wdata->comp, wdata->buf, wdata->pos);
return FR_SUCCESS;
}
When the user hits <tab> again, we have a choice. For the simple cases -- a fixed list of matches -- the core completion code can do all the work. For dynamic cases, e.g. a directory is selected, it will need to update the "current word" |
Beta Was this translation helpful? Give feedback.
-
However, first we need to move the completion functions: They all have the same prototype, so Steps:
|
Beta Was this translation helpful? Give feedback.
-
Following up from a discussion with @flatcap and some experimental development on my side, I am proposing the new completion API for neomutt.
The plan is to replace all the different spots in neomutt, where users can complete filenames/aliases/notmuch tags etc., with a unified completion API.
The current state of the completion can be found at here, and features a bunch of tests and different completion modes (fuzzy, regex, exact), as well as a state machine that allows to "tab" through different matches one at a time.
It is not yet integrated into neomutt itself (I am working on that), but before I open a pull request, I would like to get some feedback and discuss a few key questions.
But let's lead with an example:
The completion has currently three matching modes:
COMPL_MODE_EXACT
: characters need to match exactlyCOMPL_MODE_FUZZY
: match "distance" is computed by counting insertion/deletions/substitution/transposition of single characters (damereau-levenshtein distance, see here for an introduction)COMPL_MODE_REGEX
: we useregex.h
(regcomp) to compute regular expression matchingFor all of these modes, each entry in the completion list gets assigned a match distance (int), which is lower for closer matches.
For the exact matching, this is the count of characters needed to be added to the typed string.
For regex this is currently a naive implementation (length difference between regular expression and match).
For fuzzy matching, this resolves to the damerau-levenshtein distance.
All of the entries are then sorted according to their match distance (closest first), and then alphabetically, leaving no-matches at the end of the list.
The
COMPL_MODE
can be further configured by theCOMPL_MATCH
flags (e.g.COMPL_MATCH_IGNORECASE
).For the next steps, I would like to get some input on these questions:
@flatcap has gathered all the potential touch points of the completion API (calls to
mw_get_field
):If you know/think of any other potential users of the completion, let me know.
I hope I have explained everything well enought, and I look forward to some feedback!
Cheers,
Simon
Beta Was this translation helpful? Give feedback.
All reactions