From: Gabriel Ivăncescu Subject: [PATCH 17/17] shell32/autocomplete: Use the optional IACList interface and IACList::Expand, if available Message-Id: <49be75d6724060be70b51c90082251c1a5af007b.1536163731.git.gabrielopcode@gmail.com> Date: Wed, 5 Sep 2018 19:13:19 +0300 In-Reply-To: <695190c8471230e6a87e237a7c4a86e3281525b8.1536163731.git.gabrielopcode@gmail.com> References: <695190c8471230e6a87e237a7c4a86e3281525b8.1536163731.git.gabrielopcode@gmail.com> Signed-off-by: Gabriel Ivăncescu --- 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. After this patch series, it now matches Windows behavior very closely, and it finally makes AutoComplete useable for me. :) dlls/shell32/autocomplete.c | 75 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/dlls/shell32/autocomplete.c b/dlls/shell32/autocomplete.c index c145dc0..5262a9f 100644 --- a/dlls/shell32/autocomplete.c +++ b/dlls/shell32/autocomplete.c @@ -2,6 +2,7 @@ * AutoComplete interfaces implementation. * * Copyright 2004 Maxime Bellengé + * Copyright 2018 Gabriel Ivăncescu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,7 +24,7 @@ - ACO_AUTOAPPEND style - ACO_AUTOSUGGEST style - ACO_UPDOWNKEYDROPSLIST style - + - IACList::Expand - Handle pwzsRegKeyPath and pwszQuickComplete in Init TODO: @@ -78,6 +79,7 @@ typedef struct WCHAR *txtbackup; WCHAR *quickComplete; IEnumString *enumstr; + IACList *aclist; } IAutoCompleteImpl; static const WCHAR autocomplete_propertyW[] = {'W','i','n','e',' ','A','u','t','o', @@ -117,6 +119,61 @@ static void hide_listbox(IAutoCompleteImpl *ac, HWND hwnd) send_to_LB(ac, hwnd, LB_RESETCONTENT, 0, 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 */ + p = &txt[i]; + while (*p != '\0') { + if (*p == '\\' || *p == '/') { + last_delim = p; + do { + p++; + if (*p == '\\' || *p == '/') + last_delim = p; + } while(*p != '\0'); + goto expand; + } + p++; + } + + /* txt has no delim after i, check for a delim further in old_txt */ + p = &old_txt[i]; + while (*p != '\0') { + 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 */ + } + p++; + } + + /* 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 destroy_autocomplete_object(IAutoCompleteImpl *ac) { ac->hwndEdit = NULL; @@ -295,6 +352,16 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, if (len+1 != old_len) hwndText = heap_realloc(hwndText, len+1); + /* 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(This->enumstr); + if (This->aclist) { + aclist_expand(This, hwndText); + if (hwndText[len-1] == '\\' || hwndText[len-1] == '/') + noautoappend = TRUE; + } + /* Set txtbackup to point to hwndText itself (which must not be released) */ heap_free(This->txtbackup); This->txtbackup = hwndText; @@ -306,7 +373,6 @@ static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, send_to_LB(This, This->hwndListBox, WM_SETREDRAW, FALSE, 0); send_to_LB(This, This->hwndListBox, LB_RESETCONTENT, 0, 0); } - IEnumString_Reset(This->enumstr); for(cpt = 0;;) { LPOLESTR strs = NULL; ULONG fetched; @@ -504,6 +570,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; @@ -567,6 +635,9 @@ static HRESULT WINAPI IAutoComplete2_fnInit( return E_NOINTERFACE; } + if (FAILED (IUnknown_QueryInterface (punkACL, &IID_IACList, (LPVOID*)&This->aclist))) + This->aclist = NULL; + This->initialized = TRUE; This->hwndEdit = hwndEdit; -- 1.9.1