From: divverent Date: Fri, 25 Jan 2008 09:08:53 +0000 (+0000) Subject: tab completion now allows directories (PLEASE TEST ON WIN32) X-Git-Tag: xonotic-v0.1.0preview~2504 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=680b59ac18ea97699437d26d9cf252af9d3d1d6f;p=xonotic%2Fdarkplaces.git tab completion now allows directories (PLEASE TEST ON WIN32) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@8008 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/console.c b/console.c index d7084e39..a70c05e2 100644 --- a/console.c +++ b/console.c @@ -2245,95 +2245,146 @@ void Con_CompleteCommandLine (void) else { const char *patterns = Cvar_VariableString(va("con_completion_%s", command)); // TODO maybe use a better place for this? - char t[MAX_QPATH]; - stringlist_t resultbuf; - - // Usage: - // // store completion patterns (space separated) for command foo in con_completion_foo - // set con_completion_foo "foodata/*.foodefault *.foo" - // foo - // - // Note: patterns with slash are always treated as absolute - // patterns; patterns without slash search in the innermost - // directory the user specified. There is no way to "complete into" - // a directory as of now, as directories seem to be unknown to the - // FS subsystem. - // - // Examples: - // set con_completion_playermodel "models/player/*.zym models/player/*.md3 models/player/*.psk models/player/*.dpm" - // set con_completion_playdemo "*.dem" - // set con_completion_play "*.wav *.ogg" - // - // TODO somehow add support for directories; these shall complete - // to their name + an appended slash. - - stringlistinit(&resultbuf); - while(COM_ParseToken_Simple(&patterns, false, false)) + + if(patterns && *patterns) { - fssearch_t *search; - if(strchr(com_token, '/')) + char t[MAX_QPATH]; + stringlist_t resultbuf, dirbuf; + + // Usage: + // // store completion patterns (space separated) for command foo in con_completion_foo + // set con_completion_foo "foodata/*.foodefault *.foo" + // foo + // + // Note: patterns with slash are always treated as absolute + // patterns; patterns without slash search in the innermost + // directory the user specified. There is no way to "complete into" + // a directory as of now, as directories seem to be unknown to the + // FS subsystem. + // + // Examples: + // set con_completion_playermodel "models/player/*.zym models/player/*.md3 models/player/*.psk models/player/*.dpm" + // set con_completion_playdemo "*.dem" + // set con_completion_play "*.wav *.ogg" + // + // TODO somehow add support for directories; these shall complete + // to their name + an appended slash. + + stringlistinit(&resultbuf); + stringlistinit(&dirbuf); + while(COM_ParseToken_Simple(&patterns, false, false)) { - search = FS_Search(com_token, true, true); + fssearch_t *search; + if(strchr(com_token, '/')) + { + search = FS_Search(com_token, true, true); + } + else + { + const char *slash = strrchr(s, '/'); + if(slash) + { + strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash + strlcat(t, com_token, sizeof(t)); + search = FS_Search(t, true, true); + } + else + search = FS_Search(com_token, true, true); + } + if(search) + { + for(i = 0; i < search->numfilenames; ++i) + if(!strncmp(search->filenames[i], s, strlen(s))) + if(FS_FileType(search->filenames[i]) == FS_FILETYPE_FILE) + stringlistappend(&resultbuf, search->filenames[i]); + FS_FreeSearch(search); + } } - else + + // In any case, add directory names { + fssearch_t *search; const char *slash = strrchr(s, '/'); if(slash) { strlcpy(t, s, min(sizeof(t), (unsigned int)(slash - s + 2))); // + 2, because I want to include the slash - strlcat(t, com_token, sizeof(t)); + strlcat(t, "/*", sizeof(t)); search = FS_Search(t, true, true); } else - search = FS_Search(com_token, true, true); - } - if(search) - { - for(i = 0; i < search->numfilenames; ++i) - if(!strncmp(search->filenames[i], s, strlen(s))) - stringlistappend(&resultbuf, search->filenames[i]); - FS_FreeSearch(search); - } - } - - if(resultbuf.numstrings > 0) - { - const char *p, *q; - if(resultbuf.numstrings == 1) - { - dpsnprintf(t, sizeof(t), "%s ", resultbuf.strings[0]); + search = FS_Search("*", true, true); + if(search) + { + for(i = 0; i < search->numfilenames; ++i) + if(!strncmp(search->filenames[i], s, strlen(s))) + if(FS_FileType(search->filenames[i]) == FS_FILETYPE_DIRECTORY) + stringlistappend(&dirbuf, search->filenames[i]); + FS_FreeSearch(search); + } } - else + + if(resultbuf.numstrings > 0 || dirbuf.numstrings > 0) { - stringlistsort(&resultbuf); - Con_Printf("\n%i possible filenames\n", resultbuf.numstrings); - for(i = 0; i < resultbuf.numstrings; ++i) + const char *p, *q; + unsigned int matchchars; + if(resultbuf.numstrings == 0 && dirbuf.numstrings == 1) { - Con_Printf("%s\n", resultbuf.strings[i]); + dpsnprintf(t, sizeof(t), "%s/", dirbuf.strings[0]); + } + else + if(resultbuf.numstrings == 1 && dirbuf.numstrings == 0) + { + dpsnprintf(t, sizeof(t), "%s ", resultbuf.strings[0]); + } + else + { + stringlistsort(&resultbuf); // dirbuf is already sorted + Con_Printf("\n%i possible filenames\n", resultbuf.numstrings + dirbuf.numstrings); + for(i = 0; i < dirbuf.numstrings; ++i) + { + Con_Printf("%s/\n", dirbuf.strings[i]); + } + for(i = 0; i < resultbuf.numstrings; ++i) + { + Con_Printf("%s\n", resultbuf.strings[i]); + } + matchchars = sizeof(t) - 1; + if(resultbuf.numstrings > 0) + { + p = resultbuf.strings[0]; + q = resultbuf.strings[resultbuf.numstrings - 1]; + for(; *p && *p == *q; ++p, ++q); + matchchars = p - resultbuf.strings[0]; + } + if(dirbuf.numstrings > 0) + { + p = dirbuf.strings[0]; + q = dirbuf.strings[dirbuf.numstrings - 1]; + for(; *p && *p == *q; ++p, ++q); + matchchars = min(matchchars, p - dirbuf.strings[0]); + } + // now p points to the first non-equal character, or to the end + // of resultbuf.strings[0]. We want to append the characters + // from resultbuf.strings[0] to (not including) p as these are + // the unique prefix + strlcpy(t, (resultbuf.numstrings > 0 ? resultbuf : dirbuf).strings[0], min(matchchars + 1, sizeof(t))); } - p = resultbuf.strings[0]; - q = resultbuf.strings[resultbuf.numstrings - 1]; - for(; *p && *p == *q; ++p, ++q); - // now p points to the first non-equal character, or to the end - // of resultbuf.strings[0]. We want to append the characters - // from resultbuf.strings[0] to (not including) p as these are - // the unique prefix - strlcpy(t, resultbuf.strings[0], min((unsigned int)(p - resultbuf.strings[0] + 1), sizeof(t))); - } - // first move the cursor - key_linepos += (int)strlen(t) - (int)strlen(s); + // first move the cursor + key_linepos += (int)strlen(t) - (int)strlen(s); - // and now do the actual work - *s = 0; - strlcat(key_lines[edit_line], t, MAX_INPUTLINE); - strlcat(key_lines[edit_line], s2, MAX_INPUTLINE); //add back chars after cursor + // and now do the actual work + *s = 0; + strlcat(key_lines[edit_line], t, MAX_INPUTLINE); + strlcat(key_lines[edit_line], s2, MAX_INPUTLINE); //add back chars after cursor - // and fix the cursor - if(key_linepos > (int) strlen(key_lines[edit_line])) - key_linepos = (int) strlen(key_lines[edit_line]); + // and fix the cursor + if(key_linepos > (int) strlen(key_lines[edit_line])) + key_linepos = (int) strlen(key_lines[edit_line]); + } + stringlistfreecontents(&resultbuf); + stringlistfreecontents(&dirbuf); } - stringlistfreecontents(&resultbuf); } } diff --git a/fs.c b/fs.c index 64b27548..8fd5d619 100644 --- a/fs.c +++ b/fs.c @@ -2424,6 +2424,30 @@ void FS_DefaultExtension (char *path, const char *extension, size_t size_path) } +/* +================== +FS_FileType + +Look for a file in the packages and in the filesystem +================== +*/ +int FS_FileType (const char *filename) +{ + searchpath_t *search; + char fullpath[MAX_QPATH]; + + search = FS_FindFile (filename, NULL, true); + if(!search) + return FS_FILETYPE_NONE; + + if(search->pack) + return FS_FILETYPE_FILE; // TODO can't check directories in paks yet, maybe later + + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", search->filename, filename); + return FS_SysFileType(fullpath); +} + + /* ================== FS_FileExists @@ -2444,28 +2468,36 @@ FS_SysFileExists Look for a file in the filesystem only ================== */ -qboolean FS_SysFileExists (const char *path) +int FS_SysFileType (const char *path) { #if WIN32 - int desc; + DWORD result = GetFileAttributes(path); - // TODO: use another function instead, to avoid opening the file - desc = open (path, O_RDONLY | O_BINARY); - if (desc < 0) - return false; + if(result == INVALID_FILE_ATTRIBUTES) + return FS_FILETYPE_NONE; - close (desc); - return true; + if(result & FILE_ATTRIBUTE_DIRECTORY) + return FS_FILETYPE_DIRECTORY; + + return FS_FILETYPE_FILE; #else struct stat buf; if (stat (path,&buf) == -1) - return false; + return FS_FILETYPE_NONE; - return true; + if(S_ISDIR(buf.st_mode)) + return FS_FILETYPE_DIRECTORY; + + return FS_FILETYPE_FILE; #endif } +qboolean FS_SysFileExists (const char *path) +{ + return FS_SysFileType (path) != FS_FILETYPE_NONE; +} + void FS_mkdir (const char *path) { #if WIN32 diff --git a/fs.h b/fs.h index 141886ad..8f31b7cc 100644 --- a/fs.h +++ b/fs.h @@ -100,6 +100,12 @@ qboolean FS_WriteFile (const char *filename, void *data, fs_offset_t len); void FS_StripExtension (const char *in, char *out, size_t size_out); void FS_DefaultExtension (char *path, const char *extension, size_t size_path); +#define FS_FILETYPE_NONE 0 +#define FS_FILETYPE_FILE 1 +#define FS_FILETYPE_DIRECTORY 2 +int FS_FileType (const char *filename); // the file can be into a package +int FS_SysFileType (const char *filename); // only look for files outside of packages + qboolean FS_FileExists (const char *filename); // the file can be into a package qboolean FS_SysFileExists (const char *filename); // only look for files outside of packages