[PATCH v2 6/7] shell32/autocomplete: Use the optional IACList interface and IACList::Expand, if available

Gabriel Ivăncescu gabrielopcode at gmail.com
Fri Sep 28 06:44:11 CDT 2018


Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---

This enables Total Commander to show full paths on many edit boxes, like
on Windows, instead of just the current directory's entries.

I couldn't get the / delimiter to work at all on Windows XP, so MSDN is
probably wrong here. Despite that, I've actually added support for it in
this patch, as a Wine extension, to help with unix-style paths autocompletion
since we also support those.

 dlls/shell32/autocomplete.c | 73 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c
index 43c93ef..cd2abd3 100644
--- a/dlls/shell32/autocomplete.c
+++ b/dlls/shell32/autocomplete.c
@@ -2,6 +2,7 @@
  *	AutoComplete interfaces implementation.
  *
  *	Copyright 2004	Maxime Bellengé <maxime.bellenge at laposte.net>
+ *	Copyright 2018	Gabriel Ivăncescu <gabrielopcode at gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,7 +25,7 @@
   - ACO_AUTOSUGGEST style
   - ACO_UPDOWNKEYDROPSLIST style
   - ACO_USETAB style
-
+  - IACList::Expand
   - Handle pwzsRegKeyPath and pwszQuickComplete in Init
 
   TODO:
@@ -76,6 +77,7 @@ typedef struct
     WCHAR *txtbackup;
     WCHAR *quickComplete;
     IEnumString *enumstr;
+    IACList *aclist;
     AUTOCOMPLETEOPTIONS options;
     UCHAR no_fwd_char;
 } IAutoCompleteImpl;
@@ -229,6 +231,54 @@ static LRESULT change_selection(IAutoCompleteImpl *ac, HWND hwnd, UINT key)
     return 0;
 }
 
+static void aclist_expand(IAutoCompleteImpl *ac, WCHAR *txt)
+{
+    /* call IACList::Expand only when needed
+       '/' is allowed as a delim for unix paths */
+    WCHAR c, *p, *last_delim, *old_txt = ac->txtbackup;
+    size_t i = 0;
+
+    /* skip the shared prefix */
+    while ((c = tolowerW(txt[i])) == tolowerW(old_txt[i]))
+    {
+        if (c == '\0') return;
+        i++;
+    }
+
+    /* they differ at this point, check for a delim further in txt */
+    last_delim = NULL;
+    for (p = &txt[i]; *p != '\0'; p++)
+        if (*p == '\\' || *p == '/')
+            last_delim = p;
+    if (last_delim)
+        goto expand;
+
+    /* txt has no delim after i, check for a delim further in old_txt */
+    for (p = &old_txt[i]; *p != '\0'; p++)
+        if (*p == '\\' || *p == '/')
+        {
+            /* find the delim before i (if any) */
+            while (i--)
+            {
+                if (txt[i] == '\\' || txt[i] == '/')
+                {
+                    last_delim = &txt[i];
+                    goto expand;
+                }
+            }
+            break;  /* Windows doesn't expand without a delim */
+        }
+
+    /* they differ, but without any different delims, so no need to expand */
+    return;
+
+expand:
+    c = last_delim[1];
+    last_delim[1] = '\0';
+    IACList_Expand(ac->aclist, txt);
+    last_delim[1] = c;
+}
+
 static void autoappend_str(IAutoCompleteImpl *ac, WCHAR *text, UINT len, WCHAR *str, HWND hwnd)
 {
     DWORD sel_start;
@@ -276,6 +326,17 @@ static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_
     if (len + 1 != size)
         text = heap_realloc(text, (len + 1) * sizeof(WCHAR));
 
+    /* Reset it here to simplify the logic in aclist_expand for
+       empty strings, since it tracks changes using txtbackup,
+       and Reset needs to be called before IACList::Expand */
+    IEnumString_Reset(ac->enumstr);
+    if (ac->aclist)
+    {
+        aclist_expand(ac, text);
+        if (text[len - 1] == '\\' || text[len - 1] == '/')
+            flag = autoappend_flag_no;
+    }
+
     /* Set txtbackup to point to text itself (which must not be released) */
     heap_free(ac->txtbackup);
     ac->txtbackup = text;
@@ -285,7 +346,6 @@ static void autocomplete_text(IAutoCompleteImpl *ac, HWND hwnd, enum autoappend_
         SendMessageW(ac->hwndListBox, WM_SETREDRAW, FALSE, 0);
         SendMessageW(ac->hwndListBox, LB_RESETCONTENT, 0, 0);
     }
-    IEnumString_Reset(ac->enumstr);
     for (cpt = 0;;)
     {
         LPOLESTR strs = NULL;
@@ -615,6 +675,8 @@ static ULONG WINAPI IAutoComplete2_fnRelease(
         heap_free(This->txtbackup);
         if (This->enumstr)
             IEnumString_Release(This->enumstr);
+        if (This->aclist)
+            IACList_Release(This->aclist);
         heap_free(This);
     }
     return refCount;
@@ -671,6 +733,13 @@ static HRESULT WINAPI IAutoComplete2_fnInit(
         return E_NOINTERFACE;
     }
 
+    /* Prevent txtbackup from ever being NULL to simplify aclist_expand */
+    if ((This->txtbackup = heap_alloc_zero(sizeof(WCHAR))) == NULL)
+        return E_OUTOFMEMORY;
+
+    if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IACList, (LPVOID*)&This->aclist)))
+        This->aclist = NULL;
+
     This->initialized = TRUE;
     This->hwndEdit = hwndEdit;
 
-- 
1.9.1




More information about the wine-devel mailing list