Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] XDG support #3198

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 4 additions & 19 deletions src/nvim/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1837,16 +1837,9 @@ static void source_startup_scripts(mparm_T *parmp)
* - second user exrc file ($VIM/.exrc for Dos)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above comment is pretty outdated.

* The first that exists is used, the rest is ignored.
*/
char_u *user_vimrc = (char_u *)get_from_user_conf("init.vim");
if (process_env("VIMINIT", true) != OK) {
if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL
#ifdef USR_VIMRC_FILE2
&& do_source((char_u *)USR_VIMRC_FILE2, TRUE,
DOSO_VIMRC) == FAIL
#endif
#ifdef USR_VIMRC_FILE3
&& do_source((char_u *)USR_VIMRC_FILE3, TRUE,
DOSO_VIMRC) == FAIL
#endif
if (do_source(user_vimrc, true, DOSO_VIMRC) == FAIL
&& process_env("EXINIT", FALSE) == FAIL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true

&& do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL) {
#ifdef USR_EXRC_FILE2
Expand All @@ -1872,16 +1865,8 @@ static void source_startup_scripts(mparm_T *parmp)
secure = p_secure;

i = FAIL;
if (path_full_compare((char_u *)USR_VIMRC_FILE,
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
#ifdef USR_VIMRC_FILE2
&& path_full_compare((char_u *)USR_VIMRC_FILE2,
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
#endif
#ifdef USR_VIMRC_FILE3
&& path_full_compare((char_u *)USR_VIMRC_FILE3,
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
#endif
if (path_full_compare(user_vimrc,
(char_u *)VIMRC_FILE, false) != kEqualFiles
#ifdef SYS_VIMRC_FILE
&& path_full_compare((char_u *)SYS_VIMRC_FILE,
(char_u *)VIMRC_FILE, FALSE) != kEqualFiles
Expand Down
15 changes: 15 additions & 0 deletions src/nvim/option.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,15 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
# include "option.c.generated.h"
#endif

static void set_runtimepath_default(void)
{
garray_T rtp_ga;
ga_init(&rtp_ga, (int)sizeof(const char *), 1);
GA_APPEND(const char *, &rtp_ga, get_user_conf_dir());
GA_APPEND(const char *, &rtp_ga, concat_fnames(get_user_conf_dir(), "after", true));
set_string_default("runtimepath", ga_concat_strings(&rtp_ga));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The memory allocated by concat_fnames must be xfreed. Doesn't look like we gain much by using garray_T here. sprintf() (or the custom vim variant) might be more appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you suggest that I precomute the length of the rtp string like this?
ZyX-I@b4331ac

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The safest bet for allocating path names is just xmalloc(PATH_MAX). If you care about over-allocated memory, you can xrealloc(rtp strlen(rtp) + 1) later, but it's not necessary.

I just realized another issue: It looks like the resulting string will be "{get_user_conf_dir()}{get_user_conf_dir()}/after". Could just do this:

char* conf_dir = get_user_conf_dir();
set_string_default("runtimepath", concat_fnames(conf_dir, "after", true);
xfree(conf_dir);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relying on PATH_MAX is extremely silly and not a very well researched suggestion. Consider the implications of what you're suggesting on a portability level. No, correct handling of paths involve using calloc and snprintf. (I assume xmalloc is just a wrapper around malloc that provides overflow checking like calloc but without the guarantee of zero initialised memory.)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately (I guess), we have a lot of code that check paths are less than the maximum, so this convention wouldn't be easy to remove from the codebase, even if it's wrong. For the moment, I think it would be correct to just say "we don't support unreasonably large paths," and if supporting them means unleashing such inefficient code such as in the linked article, I don't see any benefit.

Also, I double checked: I should have said MAXPATHL, an os-independent variable that we define.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@splinterofchaos Why not simply use my code with minimal modifications (to use different functions to get XDG_* variables)? I see that this variant uses only XDG_CONFIG_HOME which is not enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Note: do not use the commit you referenced, use the head of pr-3120 branch.)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZyX-I “53. So many good ideas are never heard from again once they embark in a voyage on the semantic gulf.” — Alan J. Perlis

}

/*
* Initialize the options, first part.
*
Expand Down Expand Up @@ -437,6 +446,12 @@ void set_init_1(void)
"system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error"
);

set_string_default("viewdir", (char_u *)get_from_user_data("view"));
set_string_default("backupdir", (char_u *)get_from_user_data("backup"));
set_string_default("directory", (char_u *)get_from_user_data("swap"));
set_string_default("undodir", (char_u *)get_from_user_data("undo"));
set_runtimepath_default();

/*
* Set all the options (except the terminal options) to their default
* value. Also set the global value for local options.
Expand Down
10 changes: 5 additions & 5 deletions src/nvim/options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ return {
vi_def=true,
expand=true,
varname='p_bdir',
defaults={if_true={vi=macros('DFLT_BDIR')}}
defaults={if_true={vi=''}}
},
{
full_name='backupext', abbreviation='bex',
Expand Down Expand Up @@ -619,7 +619,7 @@ return {
vi_def=true,
expand=true,
varname='p_dir',
defaults={if_true={vi=macros('DFLT_DIR')}}
defaults={if_true={vi=''}}
},
{
full_name='display', abbreviation='dy',
Expand Down Expand Up @@ -1908,7 +1908,7 @@ return {
vi_def=true,
expand=true,
varname='p_rtp',
defaults={if_true={vi=macros('DFLT_RUNTIMEPATH')}}
defaults={if_true={vi=''}}
},
{
full_name='scroll', abbreviation='scr',
Expand Down Expand Up @@ -2508,7 +2508,7 @@ return {
vi_def=true,
expand=true,
varname='p_udir',
defaults={if_true={vi="."}}
defaults={if_true={vi=''}}
},
{
full_name='undofile', abbreviation='udf',
Expand Down Expand Up @@ -2569,7 +2569,7 @@ return {
vi_def=true,
expand=true,
varname='p_vdir',
defaults={if_true={vi=macros('DFLT_VDIR')}}
defaults={if_true={vi=''}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that only viewdir is touched. Are there plans for other options from #78? Especially for &runtimepath.

Don’t forget that for default &runtimepath value you may take code from my pr-3120 branch:

diff --git a/src/nvim/option.c b/src/nvim/option.c
index 9a375c0..f9b8924 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -301,6 +301,148 @@ static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
 # include "option.c.generated.h"
 #endif

+/// Count commas in the given string
+static size_t count_commas(const char *const s, size_t len)
+  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+  size_t ret = 0;
+  for (size_t i = 0; i < len; i++) {
+    if (s[i] == ',') {
+      ret++;
+    }
+  }
+  return ret;
+}
+
+/// Append string with escaped commas
+static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
+  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+  size_t shift = 0;
+  for (size_t i = 0; i < len; i++) {
+    if (src[i] == ',') {
+      dest[i + shift++] = '\\';
+    }
+    dest[i + shift] = src[i];
+  }
+  return &dest[len + shift];
+}
+
+/// Set &runtimepath to default value
+static void set_runtimepath_default(void)
+{
+  size_t rtp_size = 0;
+  char *const data_home = vim_getenv("XDG_DATA_HOME");
+  char *const config_home = vim_getenv("XDG_CONFIG_HOME");
+  char *const vimruntime = vim_getenv("VIMRUNTIME");
+  char *const data_dirs = vim_getenv("XDG_DATA_DIRS");
+  char *const config_dirs = vim_getenv("XDG_CONFIG_DIRS");
+#define NVIM_SIZE (sizeof("/nvim") - 1)
+#define SITE_SIZE (sizeof("/site") - 1)
+#define AFTER_SIZE (sizeof("/after") - 1)
+  size_t data_len;
+  size_t config_len;
+  size_t vimruntime_len;
+  if (data_home != NULL) {
+    data_len = strlen(data_home);
+    rtp_size += ((data_len + count_commas(data_home, data_len)
+                  + NVIM_SIZE + SITE_SIZE) * 2 + AFTER_SIZE) + 2;
+  }
+  if (config_home != NULL) {
+    config_len = strlen(config_home);
+    rtp_size += ((config_len + count_commas(config_home, config_len)
+                  + NVIM_SIZE) * 2 + AFTER_SIZE) + 2;
+  }
+  if (vimruntime != NULL) {
+    vimruntime_len = strlen(vimruntime);
+    rtp_size += vimruntime_len + count_commas(vimruntime, vimruntime_len) + 1;
+  }
+#define COMPUTE_COLON_LEN(rtp_size, additional_size, val) \
+  do { \
+    if (val != NULL) { \
+      const void *iter = NULL; \
+      do { \
+        size_t dir_len; \
+        const char *dir; \
+        iter = vim_colon_env_iter(val, iter, &dir, &dir_len); \
+        if (dir != NULL && dir_len > 0) { \
+          rtp_size += ((dir_len + count_commas(dir, dir_len) \
+                        + NVIM_SIZE + additional_size) * 2 \
+                       + AFTER_SIZE) + 2; \
+        } \
+      } while (iter != NULL); \
+    } \
+  } while (0)
+  COMPUTE_COLON_LEN(rtp_size, SITE_SIZE, data_dirs);
+  COMPUTE_COLON_LEN(rtp_size, 0, config_dirs);
+#undef COMPUTE_COLON_LEN
+  if (rtp_size == 0) {
+    return;
+  }
+  // All additions were including comma.
+  rtp_size--;
+  char *const rtp = xmallocz(rtp_size);
+  char *rtp_cur = rtp;
+#define ADD_STRING(tgt, src, len) \
+  tgt = strcpy_comma_escaped(tgt, src, len)
+#define ADD_STATIC_STRING(tgt, src) \
+  do { memmove(tgt, src, sizeof(src) - 1); tgt += sizeof(src) - 1; } while (0)
+#define ADD_COLON_DIRS(tgt, val, suffix, revsuffix) \
+  do { \
+    if (val != NULL) { \
+      const void *iter = NULL; \
+      do { \
+        size_t dir_len; \
+        const char *dir; \
+        iter = vim_colon_env_iter##revsuffix(val, iter, &dir, &dir_len); \
+        if (dir != NULL && dir_len > 0) { \
+          ADD_STRING(rtp_cur, dir, dir_len); \
+          ADD_STATIC_STRING(rtp_cur, "/nvim" suffix ","); \
+        } \
+      } while (iter != NULL); \
+    } \
+  } while (0)
+  if (config_home != NULL) {
+    ADD_STRING(rtp_cur, config_home, config_len);
+    ADD_STATIC_STRING(rtp_cur, "/nvim,");
+  }
+  ADD_COLON_DIRS(rtp_cur, config_dirs, "", );
+  if (data_home != NULL) {
+    ADD_STRING(rtp_cur, data_home, data_len);
+    ADD_STATIC_STRING(rtp_cur, "/nvim/site,");
+  }
+  ADD_COLON_DIRS(rtp_cur, data_dirs, "/site", );
+  if (vimruntime != NULL) {
+    ADD_STRING(rtp_cur, vimruntime, vimruntime_len);
+    *rtp_cur++ = ',';
+  }
+  ADD_COLON_DIRS(rtp_cur, data_dirs, "/site/after", _rev);
+  if (data_home != NULL) {
+    ADD_STRING(rtp_cur, data_home, data_len);
+    ADD_STATIC_STRING(rtp_cur, "/nvim/site/after,");
+  }
+  ADD_COLON_DIRS(rtp_cur, config_dirs, "/after", _rev);
+  if (config_home != NULL) {
+    ADD_STRING(rtp_cur, config_home, config_len);
+    ADD_STATIC_STRING(rtp_cur, "/nvim/after");
+  } else {
+    // Strip trailing comma.
+    rtp[rtp_size] = NUL;
+  }
+#undef ADD_COLON_DIRS
+#undef ADD_STATIC_STRING
+#undef ADD_STRING
+#undef NVIM_SIZE
+#undef SITE_SIZE
+#undef AFTER_SIZE
+  set_string_default("runtimepath", (char_u *)rtp);
+  xfree(data_dirs);
+  xfree(config_dirs);
+  xfree(data_home);
+  xfree(config_home);
+  xfree(vimruntime);
+}
+
 /*
  * Initialize the options, first part.
  *
@@ -437,6 +579,10 @@ void set_init_1(void)
       "system('lpr' . (&printdevice == '' ? '' : ' -P' . &printdevice) . ' ' . v:fname_in) . delete(v:fname_in) + v:shell_error"
       );

+  // Set default for &runtimepath. All necessary expansions are performed in 
+  // this function.
+  set_runtimepath_default();
+
   /*
    * Set all the options (except the terminal options) to their default
    * value.  Also set the global value for local options.
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 7be8a86..e47a63b 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -415,6 +415,74 @@ static char *remove_tail(char *p, char *pend, char *name)
   return pend;
 }

+/// Iterate over colon-separated list
+///
+/// @note Environment variables must not be modified during iteration.
+///
+/// @param[in]   val   Value of the environment variable to iterate over.
+/// @param[in]   iter  Pointer used for iteration. Must be NULL on first
+///                    iteration.
+/// @param[out]  dir   Location where pointer to the start of the current
+///                    directory name should be saved. May be set to NULL.
+/// @param[out]  len   Location where current directory length should be saved.
+///
+/// @return Next iter argument value or NULL when iteration should stop.
+const void *vim_colon_env_iter(const char *const val,
+                               const void *const iter,
+                               const char **const dir,
+                               size_t *const len)
+  FUNC_ATTR_NONNULL_ARG(1,3,4) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+  const char *varval = (const char *) iter;
+  if (varval == NULL) {
+    varval = val;
+  }
+  *dir = varval;
+  const char *const dirend = strchr(varval, ':');
+  if (dirend == NULL) {
+    *len = strlen(varval);
+    return NULL;
+  } else {
+    *len = (size_t) (dirend - varval);
+    return dirend + 1;
+  }
+}
+
+/// Iterate over colon-separated list in reverse order
+///
+/// @note Environment variables must not be modified during iteration.
+///
+/// @param[in]   val   Value of the environment variable to iterate over.
+/// @param[in]   iter  Pointer used for iteration. Must be NULL on first
+///                    iteration.
+/// @param[out]  dir   Location where pointer to the start of the current
+///                    directory name should be saved. May be set to NULL.
+/// @param[out]  len   Location where current directory length should be saved.
+///
+/// @return Next iter argument value or NULL when iteration should stop.
+const void *vim_colon_env_iter_rev(const char *const val,
+                                   const void *const iter,
+                                   const char **const dir,
+                                   size_t *const len)
+  FUNC_ATTR_NONNULL_ARG(1,3,4) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+  const char *varend = (const char *) iter;
+  if (varend == NULL) {
+    varend = val + strlen(val) - 1;
+  }
+  const size_t varlen = (size_t) (varend - val) + 1;
+  const char *const colon = xmemrchr(val, ':', varlen);
+  if (colon == NULL) {
+    *len = varlen;
+    *dir = val;
+    return NULL;
+  } else {
+    *dir = colon + 1;
+    *len = (size_t) (varend - colon);
+    return colon - 1;
+  }
+}
+
 /// Vim's version of getenv().
 /// Special handling of $HOME, $VIM and $VIMRUNTIME, allowing the user to
 /// override the vim runtime directory at runtime.  Also does ACP to 'enc'

, just replace vim_getenv calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I plan to do all of it. Just want to make sure that everyone else agrees with this approach first.

},
{
full_name='viewoptions', abbreviation='vop',
Expand Down
1 change: 1 addition & 0 deletions src/nvim/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# include "os/mem.h.generated.h"
# include "os/env.h.generated.h"
# include "os/users.h.generated.h"
# include "os/stdpaths.h.generated.h"
#endif

#endif // NVIM_OS_OS_H
100 changes: 100 additions & 0 deletions src/nvim/os/stdpaths.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "nvim/os/os.h"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a comment up here mentioning this implements the XDG specification, with a link to the spec.

#include "nvim/strings.h"
#include "nvim/path.h"
#include "nvim/garray.h"

typedef enum {
kXDGConfigHome,
kXDGDataHome,
kXDGCacheHome,
kXDGRuntimeDir,
kXDGConfigDirs,
kXDGDataDirs,
} XDGDirType;

static const char *xdg_env_vars[] = {
[kXDGConfigHome] = "XDG_CONFIG_HOME",
[kXDGDataHome] = "XDG_DATA_HOME",
[kXDGCacheHome] = "XDG_CACHE_HOME",
[kXDGRuntimeDir] = "XDG_RUNTIME_DIR",
[kXDGConfigDirs] = "XDG_CONFIG_DIRS",
[kXDGDataDirs] = "XDG_DATA_DIRS",
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZyX-I I changed the enum field names as per the style guide.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Common prefix for all enum values is just k. I do not think this is a good idea, I would use kXDG even for local enums.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, these should be renamed like:

typedef enum {
  kXDGConfigHome,
  kXDGDataHome,
  ...
  kXDGDataDirs,
} XDGDirType;

static const char *const xdg_defaults[] = {
// Windows, Apple stuff are just shims right now
#ifdef WIN32
// Windows
#elif APPLE
// Apple (this includes iOS, which we might need to handle differently)
[kXDGConfigHome] = "~/Library/Preferences",
[kXDGDataHome] = "~/Library/Application Support",
[kXDGCacheHome] = "~/Library/Caches",
[kXDGRuntimeDir] = "~/Library/Application Support",
[kXDGConfigDirs] = "/Library/Application Support",
[kXDGDataDirs] = "/Library/Application Support",
#else
// Linux, BSD, CYGWIN
[kXDGConfigHome] = "~/.config",
[kXDGDataHome] = "~/.local/share",
[kXDGCacheHome] = "~/.cache",
[kXDGRuntimeDir] = "",
[kXDGConfigDirs] = "/etc/xdg/",
[kXDGDataDirs] = "/usr/local/share/:/usr/share/",
};
#endif
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pyrohh Does this look good?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer explicit defines (as opposed to else), but in this case why not.
CYGWIN <-> ~ ??

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jck Looks fine to me, no comment on the actual defines though. I'm not sure if it should instead be __WIN32__ and __APPPLE__, but we'll deal with that later.


static const char *get_xdg(XDGDirType idx)
{
const char *env = xdg_env_vars[idx];
const char *fallback = xdg_defaults[idx];

const char *ret = os_getenv(env);
if (!ret && fallback) {
ret = (const char *)expand_env_save((char_u *)fallback);
}

return ret;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns statically allocated memory when os_getenv(env) returns non-null, and heap-allocated memory when it returns null and fallback isn't null. How does the caller know whether the return value requires an xfree()? We could add a parameter, bool *must_free, but it may be simpler to always return allocated memory.

const char *ret = os_getenv(env);
if (ret) {
  ret = xstrdup(ret);
} else if (fallback) {
  // ... same as before
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ This. This should fix the leak ASAN is complainign about.

}

static const char *get_xdg_home(XDGDirType idx)
{
const char *dir = get_xdg(idx);
if (dir) {
dir = (const char *)concat_fnames(dir, "nvim", true);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just return (const char *)concat_fnames(dir, "nvim", true);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because xdg_runtime_dir has no default value. When we reach a consensus on how we handle that, I'll change this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a leak here, according to ASAN

}
return dir;
}

static void create_dir(const char *dir, int mode, const char *suffix)
{
char *failed;
if (!os_mkdir_recurse(dir, mode, &failed)) {
// TODO: Create a folder in $TMPDIR instead
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't fully implemented, but it might be better off in os/fs.c.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but right now what I have in mind is that this function will be tailored to create data,cache and runtime dirs. Let us revisit this later.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I don't want to bog this down in minutiae.

DLOG("Create dir failed");
}
}

const char *get_user_conf_dir(void)
{
return get_xdg_home(kXDGConfigHome);
}

const char *get_from_user_conf(const char * fname)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be no space between * and fname

{
return (const char *)concat_fnames(get_user_conf_dir(), fname, true);
}

const char *get_user_data_dir(void)
{
return get_xdg_home(kXDGDataHome);
}

const char *get_from_user_data(const char * fname)
{
const char *dir = (const char *)concat_fnames(get_user_data_dir(), fname, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clint says this line is too long

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there is a leak here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking of that, is there any static analysis planned ? It could be a nice addition.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have static analysis:

https://neovim.io/doc/reports/clang/
https://scan.coverity.com/projects/2227

However coverity has been broken for weeks.

if (!os_isdir((char_u *)dir)) {
create_dir(dir, 0755, fname);
}
return dir;
}
29 changes: 0 additions & 29 deletions src/nvim/os/unix_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@
#ifndef USR_EXRC_FILE
# define USR_EXRC_FILE "~/.exrc"
#endif
#ifndef USR_VIMRC_FILE
# define USR_VIMRC_FILE "~/.nvimrc"
#endif
#ifndef USR_VIMRC_FILE2
# define USR_VIMRC_FILE2 "~/.nvim/nvimrc"
#endif
#ifndef EXRC_FILE
# define EXRC_FILE ".exrc"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that users will be forced to use the new location? Isn't it better to use the old files in case it is not found in the XDG dirs? cc @justinmk

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #78 @ZyX-I made the case that there is no reason for us to support both old and new config locations. It bothers me because it means the default location is different on each system (this makes support more difficult, and requires extra setup to share configs across systems using GitHub etc).

I would be less bothered by it if we defaulted to ~/.config on all systems (unix, windows, osx) instead of the terrible ~/Library and %APPDATA% paths. (No one really wants their configs there, do they?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not your place to question it really. These are the standards set forth by the operating systems you target. I'll quote some of Raymond Chen's ironic maxims about his frustration when dealing with software during the MS-DOS to Windows 95 transition:

4. Manuals are a waste of time.
9. Find a rule and break it as blatantly as possible.
19. Second-guess the specification whenever possible.

Please don't keep repeating the same mistakes. As for support, different locations is trivial to deal with, please don't use it as an excuse to do the wrong thing.

12. It is better to be lucky than good.

@tarruda This software is pre-1.0 release (assuming you're following semver), there is no reason to support legacy. Just do the right thing now instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm with @Earnestly (and @ZyX-I) on this one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Earnestly Where does the standard specify the default locations for OSX and Windows? So far only source examples like https://github.com/ActiveState/appdirs/blob/master/appdirs.py have been offered, which indicate "best guesses" about default locations, there is no reference to a specification.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kopischke I'm not a OSX user (never really used it, actually), so I was just being conservative ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmk Taking a look at the basedir spec again, most of the XDG_ variables are defined relative to $HOME, which has its equivalent in %UserProfile% under Windows. I guess in that sense using that should be the correct behavior as per the basedir spec. However, XDG_DATA_DIRS and XDG_CONFIG_DIRS are undefined, since they default to paths Windows doesn't have.

http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justinmk Windows is out of scope of XDG Basedir, follow Windows' standards for Windows instead. For example, Vala's Environment.get_user_config_dir() uses CSIDL_LOCAL_APPDATA for Windows.

What you want to do about Windows however is up to you,
thank you for working on this btw. ❤

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fmoralesc nothing wrong with that, especially as OS X’ “almost, but not quite, Unix” system does need special treatment in many areas. The XDG spec as applied to CLI applications is not one of them, however, so let’s count our blessings and limit special treatment to The Odd Man Out™, aka Windows :).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kopischke 👍

#endif
Expand All @@ -47,27 +41,4 @@
# define VIMINFO_FILE "~/.nviminfo"
#endif

// Default for 'backupdir'.
#ifndef DFLT_BDIR
# define DFLT_BDIR ".,~/tmp,~/"
#endif

// Default for 'directory'.
#ifndef DFLT_DIR
# define DFLT_DIR ".,~/tmp,/var/tmp,/tmp"
#endif

// Default for 'viewdir'.
#ifndef DFLT_VDIR
# define DFLT_VDIR "~/.nvim/view"
#endif

#ifdef RUNTIME_GLOBAL
# define DFLT_RUNTIMEPATH "~/.nvim," RUNTIME_GLOBAL ",$VIMRUNTIME," \
RUNTIME_GLOBAL "/after,~/.nvim/after"
#else
# define DFLT_RUNTIMEPATH \
"~/.nvim,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after,~/.nvim/after"
#endif

#endif // NVIM_OS_UNIX_DEFS_H
1 change: 0 additions & 1 deletion src/nvim/os/win_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

// Defines needed to fix the build on Windows:
// - USR_EXRC_FILE
// - USR_VIMRC_FILE
// - VIMINFO_FILE
// - DFLT_DIR
// - DFLT_BDIR
Expand Down
15 changes: 0 additions & 15 deletions src/nvim/version.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,21 +1067,6 @@ void list_version(void)
version_msg(SYS_VIMRC_FILE);
version_msg("\"\n");
#endif // ifdef SYS_VIMRC_FILE
#ifdef USR_VIMRC_FILE
version_msg(_(" user vimrc file: \""));
version_msg(USR_VIMRC_FILE);
version_msg("\"\n");
#endif // ifdef USR_VIMRC_FILE
#ifdef USR_VIMRC_FILE2
version_msg(_(" 2nd user vimrc file: \""));
version_msg(USR_VIMRC_FILE2);
version_msg("\"\n");
#endif // ifdef USR_VIMRC_FILE2
#ifdef USR_VIMRC_FILE3
version_msg(_(" 3rd user vimrc file: \""));
version_msg(USR_VIMRC_FILE3);
version_msg("\"\n");
#endif // ifdef USR_VIMRC_FILE3
#ifdef USR_EXRC_FILE
version_msg(_(" user exrc file: \""));
version_msg(USR_EXRC_FILE);
Expand Down