From fd1e2b3d3ccd26fb5bd9d7cbced04f673cfd19ba Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 8 Sep 2024 15:37:03 -0400 Subject: Customizable data directories --- Makefile | 20 +++--- README.md | 8 +++ control | 2 +- main.c | 146 +++++++++++++++++++++++++++------------ ted.h | 2 +- windows_installer/ted/ted.vdproj | 6 +- 6 files changed, 127 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index 50861cd..7a01a86 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,19 @@ +# where to put ted's files +# GLOBAL_DATA_DIR = files shared between all users (e.g. default ted.cfg) +# LOCAL_DATA_DIR = user-specific files +# either one can start with ~ for home directory. +# these are currently ignored for debug builds. +GLOBAL_DATA_DIR?=/usr/share/ted +LOCAL_DATA_DIR?=~/.local/share/ted +INSTALL_BIN_DIR?=/usr/bin + ALL_CFLAGS=$(CFLAGS) -Wall -Wextra -Wshadow -Wconversion -Wpedantic -pedantic -std=gnu11 \ -Wno-unused-function -Wno-fixed-enum-extension -Wimplicit-fallthrough -Wno-format-truncation -Wno-unknown-warning-option \ - -Ipcre2 + -Ipcre2 -DTED_GLOBAL_DATA_DIR='"$(GLOBAL_DATA_DIR)"' -DTED_LOCAL_DATA_DIR='"$(LOCAL_DATA_DIR)"' LIBS=-lSDL2 -lGL -lm libpcre2-32.a libpcre2-8.a RELEASE_CFLAGS=$(ALL_CFLAGS) -O3 PROFILE_CFLAGS=$(ALL_CFLAGS) -O3 -g -DPROFILE=1 -# if you change the directories below, ted won't work. -# we don't yet have support for using different data directories -GLOBAL_DATA_DIR=/usr/share/ted -LOCAL_DATA_DIR=/home/`logname`/.local/share/ted -INSTALL_BIN_DIR=/usr/bin + debug-build: ted compile_commands.json ted: debug/ted @# note: needed so cp doesn't fail if `ted` is busy @@ -33,8 +38,7 @@ install: release @[ -w `dirname $(GLOBAL_DATA_DIR)` ] || { echo "You need permission to write to $(GLOBAL_DATA_DIR). Try running with sudo/as root." && exit 1; } @[ -w `dirname $(INSTALL_BIN_DIR)` ] || { echo "You need permission to write to $(INSTALL_BIN_DIR). Try running with sudo/as root." && exit 1; } - mkdir -p $(GLOBAL_DATA_DIR) $(LOCAL_DATA_DIR) - chown `logname`:`logname` $(LOCAL_DATA_DIR) + mkdir -p $(GLOBAL_DATA_DIR) cp -r assets $(GLOBAL_DATA_DIR) cp -r themes $(GLOBAL_DATA_DIR) install -m 644 ted.cfg $(GLOBAL_DATA_DIR) diff --git a/README.md b/README.md index 06422a9..68cac35 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,14 @@ sudo apt install clang libsdl2-dev cmake imagemagick Then run `make -j8 release` to build or `sudo make install -j8` to build and install. You can also run `make -j8 ted.deb` to build the .deb installer. +This installs ted for all users. If you just want to install it for yourself (or you don't have superuser access), you can do so +with + +```bash +mkdir -p ~/.local/bin ~/.local/share +GLOBAL_DATA_DIR='~/.local/share/ted-data' LOCAL_DATA_DIR='~/.local/share/ted' INSTALL_BIN_DIR='~/.local/bin' make install -j8 +``` + On Windows, install Microsoft Visual Studio 2022, then find and add vcvarsall.bat to your PATH (most likely lives at `C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build`). Also, install the [Visual Studio Installer Projects extension](https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2022InstallerProjects) diff --git a/control b/control index 9525107..49091d0 100644 --- a/control +++ b/control @@ -1,5 +1,5 @@ Package: ted -Version: 2.7.2 +Version: 2.7.3 Section: text Priority: optional Architecture: amd64 diff --git a/main.c b/main.c index 723b748..bace6b8 100644 --- a/main.c +++ b/main.c @@ -2,22 +2,43 @@ FUTURE FEATURES: - more tests - prepare rename support -- autodetect indentation (tabs vs spaces) - custom file/build command associations - config variables - bind key to series of commands - convert macro to command list - plugins? - - built-in plugins + - built-in plugins: - "remove file..." menu - auto-close brackets - with macros we can really test performance of buffer_insert_text_at_pos, etc. (which should ideally be fast) -- manual directory +- better manual - restart LSP server automatically? - LSP request timeout - reflow command */ +/* +macros defining ted data directory locations. +the first character can be interpreted specially if it is one of the following: + ~ home directory + ^ user's AppData\Local directory (Windows only) + @ directory containing ted executable +*/ +#ifndef TED_GLOBAL_DATA_DIR +#if _WIN32 + #define TED_GLOBAL_DATA_DIR "@" +#else + #define TED_GLOBAL_DATA_DIR "/usr/share/ted" +#endif +#endif +#ifndef TED_LOCAL_DATA_DIR +#if _WIN32 + #define TED_LOCAL_DATA_DIR "^/ted" +#else + #define TED_LOCAL_DATA_DIR "~/.local/share/ted" +#endif +#endif + #include "ted-internal.h" #include @@ -369,38 +390,94 @@ int main(int argc, char **argv) { os_get_cwd(ted->start_cwd, sizeof ted->start_cwd); { // get local and global data directory -#if _WIN32 - wchar_t *appdata = NULL; + #if _WIN32 + char *appdata = NULL; + wchar_t *appdata_wide = NULL; KNOWNFOLDERID id = FOLDERID_LocalAppData; - if (SHGetKnownFolderPath(&id, 0, NULL, &appdata) == S_OK) { - strbuf_printf(ted->local_data_dir, "%ls%cted", appdata, PATH_SEPARATOR); - CoTaskMemFree(appdata); + if (SHGetKnownFolderPath(&id, 0, NULL, &appdata_wide) == S_OK) { + size_t sz = wcslen(appdata_wide) * 4 + 1; + appdata = malloc(sz); + snprintf(appdata, sz, "%ls", appdata_wide); + CoTaskMemFree(appdata_wide); appdata_wide = NULL; } id = FOLDERID_Profile; - wchar_t *home = NULL; - if (SHGetKnownFolderPath(&id, 0, NULL, &home) == S_OK) { - strbuf_printf(ted->home, "%ls", home); - CoTaskMemFree(home); + wchar_t *home_wide = NULL; + if (SHGetKnownFolderPath(&id, 0, NULL, &home_wide) == S_OK) { + strbuf_printf(ted->home, "%ls", home_wide); + CoTaskMemFree(home_wide); } - - // on Windows, the global data directory is just the directory where the executable is. WCHAR executable_wide_path[TED_PATH_MAX] = {0}; - char executable_path[TED_PATH_MAX] = {0}; + char executable_dir[TED_PATH_MAX] = {0}; if (GetModuleFileNameW(NULL, executable_wide_path, sizeof executable_wide_path - 1) > 0) { - WideCharToMultiByte(CP_UTF8, 0, executable_wide_path, -1, executable_path, sizeof executable_path, NULL, NULL); - char *last_backslash = strrchr(executable_path, '\\'); + WideCharToMultiByte(CP_UTF8, 0, executable_wide_path, -1, executable_dir, sizeof executable_dir, NULL, NULL); + char *last_backslash = strrchr(executable_dir, '\\'); if (last_backslash) { *last_backslash = '\0'; - strbuf_cpy(ted->global_data_dir, executable_path); } } -#else + #elif __unix__ char *home = getenv("HOME"); strbuf_printf(ted->home, "%s", home); - strbuf_printf(ted->local_data_dir, "%s/.local/share/ted", home); - strbuf_printf(ted->global_data_dir, "/usr/share/ted"); -#endif - + char executable_dir[TED_PATH_MAX] = {0}; + ssize_t len = readlink("/proc/self/exe", executable_dir, sizeof executable_dir - 1); + if (len == -1) { + // some posix systems don't have /proc/self/exe. oh well. + } else { + executable_dir[len] = '\0'; + char *last_slash = strrchr(executable_dir, '/'); + if (last_slash) { + *last_slash = '\0'; + // if we started in the directory where the executable is located, + // we're probably debugging ted, so search the start cwd for ted.cfg, etc. + ted->search_start_cwd = streq(ted->start_cwd, executable_dir); + } + } + #else + #error "unrecognized OS" + #endif + // replace special characters at start of data dirs + typedef struct { + const char *src; + char *dest; + size_t size; + } DataDir; + DataDir data_dirs[] = { + {.src = TED_LOCAL_DATA_DIR, .dest = ted->local_data_dir, .size = sizeof ted->local_data_dir}, + {.src = TED_GLOBAL_DATA_DIR, .dest = ted->global_data_dir, .size = sizeof ted->global_data_dir}, + }; + for (size_t i = 0; i < arr_count(data_dirs); i++) { + const char *src = data_dirs[i].src; + char *dest = data_dirs[i].dest; + size_t size = data_dirs[i].size; + if (!src[0] || !strchr(ALL_PATH_SEPARATORS, src[1])) goto absolute_path; + switch (src[0]) { + case '~': + str_printf(dest, size, "%s%s", ted->home, src + 1); + break; + #if _WIN32 + case '^': + str_printf(dest, size, "%s%s", appdata, src + 1); + break; + #endif + case '@': + str_printf(dest, size, "%s%s", executable_dir, src + 1); + break; + default: + absolute_path: + if (!path_is_absolute(src)) { + die("Data directory %s is not an absolute path", src); + } + str_cpy(dest, size, src); + } + // ensure we always use the same path separator + for (int c = 0; dest[c]; c++) { + if (strchr(ALL_PATH_SEPARATORS, dest[c])) + dest[c] = PATH_SEPARATOR; + } + } + if (fs_path_type(ted->global_data_dir) == FS_NON_EXISTENT) { + die("Couldn't open ted data directory at %s", ted->global_data_dir); + } if (fs_path_type(ted->local_data_dir) == FS_NON_EXISTENT) fs_mkdir(ted->local_data_dir); @@ -424,29 +501,10 @@ int main(int argc, char **argv) { os_get_cwd(ted->cwd, sizeof ted->cwd); } - { // check if this is the installed version of ted (as opposed to just running it from the directory with the source) - #if _WIN32 - // never search cwd; we'll search the executable directory anyways - #else - char executable_path[TED_PATH_MAX] = {0}; - const char *cwd = ted->cwd; - ssize_t len = readlink("/proc/self/exe", executable_path, sizeof executable_path - 1); - if (len == -1) { - // some posix systems don't have /proc/self/exe. oh well. - } else { - executable_path[len] = '\0'; - char *last_slash = strrchr(executable_path, '/'); - if (last_slash) { - *last_slash = '\0'; - ted->search_start_cwd = streq(cwd, executable_path); - } - } - #endif - } - #if TED_FORCE_SEARCH_CWD + #if TED_FORCE_SEARCH_START_CWD // override whether or not we are in the executable's directory // (for testing on Unix systems without /proc) - ted->search_cwd = true; + ted->search_start_cwd = true; #endif PROFILE_TIME(misc_end) diff --git a/ted.h b/ted.h index d95d158..d11c9b7 100644 --- a/ted.h +++ b/ted.h @@ -22,7 +22,7 @@ extern "C" { #include "command.h" /// Version number -#define TED_VERSION "2.7.2" +#define TED_VERSION "2.7.3" /// Maximum path size ted handles. #define TED_PATH_MAX 1024 /// Config filename diff --git a/windows_installer/ted/ted.vdproj b/windows_installer/ted/ted.vdproj index fe1ecda..aac4438 100644 --- a/windows_installer/ted/ted.vdproj +++ b/windows_installer/ted/ted.vdproj @@ -620,15 +620,15 @@ { "Name" = "8:Microsoft Visual Studio" "ProductName" = "8:ted" - "ProductCode" = "8:{952FA867-111C-443C-9AFB-DA084083F038}" - "PackageCode" = "8:{BBBD2CF3-16E0-47E6-B64F-C1C73261D9F2}" + "ProductCode" = "8:{54706FEE-3070-4909-A56B-1FCFE6EB66C3}" + "PackageCode" = "8:{BFB90C03-ECC1-4511-9D2A-C6FEAB445A37}" "UpgradeCode" = "8:{844F6C2B-DF3B-4A81-9BD5-603401BBA651}" "AspNetVersion" = "8:2.0.50727.0" "RestartWWWService" = "11:FALSE" "RemovePreviousVersions" = "11:TRUE" "DetectNewerInstalledVersion" = "11:FALSE" "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:24.07.1801" + "ProductVersion" = "8:24.09.0800" "Manufacturer" = "8:ted" "ARPHELPTELEPHONE" = "8:" "ARPHELPLINK" = "8:" -- cgit v1.2.3