Mercurial > vim
view src/locale.c @ 32721:94f4a488412e v9.0.1683
Updated runtime files
Commit: https://github.com/vim/vim/commit/6efb1980336ff324e9c57a4e282530b952fca816
Author: Christian Brabandt <cb@256bit.org>
Date: Thu Aug 10 05:44:25 2023 +0200
Updated runtime files
This is a collection of various PRs from github that all require a minor
patch number:
1) https://github.com/vim/vim/pull/12612
Do not conflate dictionary key with end of block
2) https://github.com/vim/vim/pull/12729:
When saving and restoring 'undolevels', the constructs `&undolevels` and
`:set undolevels` are problematic.
The construct `&undolevels` reads an unpredictable value; it will be the
local option value (if one has been set), or the global option value
(otherwise), making it unsuitable for saving a value for later
restoration.
Similarly, if a local option value has been set for 'undolevels',
temporarily modifying the option via `:set undolevels` changes the local
value as well as the global value, requiring extra work to restore both
values.
Saving and restoring the option value in one step via the construct
`:let &undolevels = &undolevels` appears to make no changes to the
'undolevels' option, but if a local option has been set to a different
value than the global option, it has the unintended effect of changing
the global 'undolevels' value to the local value.
Update the documentation to explain these issues and recommend explicit
use of global and local option values when saving and restoring. Update
some unit tests to use `g:undolevels`.
3) https://github.com/vim/vim/pull/12702:
Problem: Pip requirements files are not recognized.
Solution: Add a pattern to match pip requirements files.
4) https://github.com/vim/vim/pull/12688:
Add indent file and tests for ABB Rapid
5) https://github.com/vim/vim/pull/12668:
Use Lua 5.1 numeric escapes in tests and add to CI
Only Lua 5.2+ and LuaJIT understand hexadecimal escapes in strings. Lua
5.1 only supports decimal escapes:
> A character in a string can also be specified by its numerical value
> using the escape sequence \ddd, where ddd is a sequence of up to three
> decimal digits. (Note that if a numerical escape is to be followed by a
> digit, it must be expressed using exactly three digits.) Strings in Lua
> can contain any 8-bit value, including embedded zeros, which can be
> specified as '\0'.
To make sure this works with Lua 5.4 and Lua 5.1 change the Vim CI to
run with Lua 5.1 as well as Lua 5.4
6) https://github.com/vim/vim/pull/12631:
Add hurl filetype detection
7) https://github.com/vim/vim/pull/12573:
Problem: Files for haskell persistent library are not recognized
Solution: Add pattern persistentmodels for haskell persistent library
closes: #12612
closes: #12729
closes: #12702
closes: #12688
closes: #12668
closes: #12631
closes: #12573
Co-authored-by: lacygoill <lacygoill@lacygoill.me>
Co-authored-by: Michael Henry <drmikehenry@drmikehenry.com>
Co-authored-by: ObserverOfTime <chronobserver@disroot.org>
Co-authored-by: KnoP-01 <knosowski@graeffrobotics.de>
Co-authored-by: James McCoy <jamessan@jamessan.com>
Co-authored-by: Jacob Pfeifer <jacob@pfeifer.dev>
Co-authored-by: Borys Lykah <lykahb@fastmail.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 10 Aug 2023 06:30:06 +0200 |
parents | 238ca27dbfd2 |
children |
line wrap: on
line source
/* vi:set ts=8 sts=4 sw=4 noet: * * VIM - Vi IMproved by Bram Moolenaar * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * locale.c: functions for language/locale configuration */ #include "vim.h" #if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ && (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG)) # define HAVE_GET_LOCALE_VAL static char_u * get_locale_val(int what) { char_u *loc; // Obtain the locale value from the libraries. loc = (char_u *)setlocale(what, NULL); # ifdef MSWIN if (loc != NULL) { char_u *p; // setocale() returns something like "LC_COLLATE=<name>;LC_..." when // one of the values (e.g., LC_CTYPE) differs. p = vim_strchr(loc, '='); if (p != NULL) { loc = ++p; while (*p != NUL) // remove trailing newline { if (*p < ' ' || *p == ';') { *p = NUL; break; } ++p; } } } # endif return loc; } #endif #ifdef MSWIN /* * On MS-Windows locale names are strings like "German_Germany.1252", but * gettext expects "de". Try to translate one into another here for a few * supported languages. */ static char_u * gettext_lang(char_u *name) { int i; static char *(mtable[]) = { "afrikaans", "af", "czech", "cs", "dutch", "nl", "german", "de", "english_united kingdom", "en_GB", "spanish", "es", "french", "fr", "italian", "it", "japanese", "ja", "korean", "ko", "norwegian", "no", "polish", "pl", "russian", "ru", "slovak", "sk", "swedish", "sv", "ukrainian", "uk", "chinese_china", "zh_CN", "chinese_taiwan", "zh_TW", NULL}; for (i = 0; mtable[i] != NULL; i += 2) if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0) return (char_u *)mtable[i + 1]; return name; } #endif #if defined(FEAT_MULTI_LANG) || defined(PROTO) /* * Return TRUE when "lang" starts with a valid language name. * Rejects NULL, empty string, "C", "C.UTF-8" and others. */ static int is_valid_mess_lang(char_u *lang) { return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]); } /* * Obtain the current messages language. Used to set the default for * 'helplang'. May return NULL or an empty string. */ char_u * get_mess_lang(void) { char_u *p; # ifdef HAVE_GET_LOCALE_VAL # if defined(LC_MESSAGES) p = get_locale_val(LC_MESSAGES); # else // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG // may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME // and LC_MONETARY may be set differently for a Japanese working in the // US. p = get_locale_val(LC_COLLATE); # endif # else p = mch_getenv((char_u *)"LC_ALL"); if (!is_valid_mess_lang(p)) { p = mch_getenv((char_u *)"LC_MESSAGES"); if (!is_valid_mess_lang(p)) p = mch_getenv((char_u *)"LANG"); } # endif # ifdef MSWIN p = gettext_lang(p); # endif return is_valid_mess_lang(p) ? p : NULL; } #endif // Complicated #if; matches with where get_mess_env() is used below. #if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ && defined(LC_MESSAGES))) \ || ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \ && !defined(LC_MESSAGES)) /* * Get the language used for messages from the environment. */ static char_u * get_mess_env(void) { char_u *p; p = mch_getenv((char_u *)"LC_ALL"); if (p != NULL && *p != NUL) return p; p = mch_getenv((char_u *)"LC_MESSAGES"); if (p != NULL && *p != NUL) return p; p = mch_getenv((char_u *)"LANG"); if (p != NULL && VIM_ISDIGIT(*p)) p = NULL; // ignore something like "1043" # ifdef HAVE_GET_LOCALE_VAL if (p == NULL || *p == NUL) p = get_locale_val(LC_CTYPE); # endif return p; } #endif #if defined(FEAT_EVAL) || defined(PROTO) /* * Set the "v:lang" variable according to the current locale setting. * Also do "v:lc_time"and "v:ctype". */ void set_lang_var(void) { char_u *loc; # ifdef HAVE_GET_LOCALE_VAL loc = get_locale_val(LC_CTYPE); # else // setlocale() not supported: use the default value loc = (char_u *)"C"; # endif set_vim_var_string(VV_CTYPE, loc, -1); // When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall // back to LC_CTYPE if it's empty. # if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES) loc = get_locale_val(LC_MESSAGES); # else loc = get_mess_env(); # endif set_vim_var_string(VV_LANG, loc, -1); # ifdef HAVE_GET_LOCALE_VAL loc = get_locale_val(LC_TIME); # endif set_vim_var_string(VV_LC_TIME, loc, -1); # ifdef HAVE_GET_LOCALE_VAL loc = get_locale_val(LC_COLLATE); # else // setlocale() not supported: use the default value loc = (char_u *)"C"; # endif set_vim_var_string(VV_COLLATE, loc, -1); } #endif #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) /* * Setup to use the current locale (for ctype() and many other things). */ void init_locale(void) { setlocale(LC_ALL, ""); # ifdef FEAT_GUI_GTK // Tell Gtk not to change our locale settings. gtk_disable_setlocale(); # endif # if defined(LC_NUMERIC) // Make sure strtod() uses a decimal point, not a comma. setlocale(LC_NUMERIC, "C"); # endif # ifdef MSWIN // Apparently MS-Windows printf() may cause a crash when we give it 8-bit // text while it's expecting text in the current locale. This call avoids // that. setlocale(LC_CTYPE, "C"); # endif # ifdef FEAT_GETTEXT { int mustfree = FALSE; char_u *p; # ifdef DYNAMIC_GETTEXT // Initialize the gettext library dyn_libintl_init(); # endif // expand_env() doesn't work yet, because g_chartab[] is not // initialized yet, call vim_getenv() directly p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); if (p != NULL && *p != NUL) { vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); bindtextdomain(VIMPACKAGE, (char *)NameBuff); } if (mustfree) vim_free(p); textdomain(VIMPACKAGE); } # endif } /* * ":language": Set the language (locale). */ void ex_language(exarg_T *eap) { char *loc; char_u *p; char_u *name; int what = LC_ALL; char *whatstr = ""; # ifdef LC_MESSAGES # define VIM_LC_MESSAGES LC_MESSAGES # else # define VIM_LC_MESSAGES 6789 # endif name = eap->arg; // Check for "messages {name}", "ctype {name}" or "time {name}" argument. // Allow abbreviation, but require at least 3 characters to avoid // confusion with a two letter language name "me" or "ct". p = skiptowhite(eap->arg); if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3) { if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0) { what = VIM_LC_MESSAGES; name = skipwhite(p); whatstr = "messages "; } else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0) { what = LC_CTYPE; name = skipwhite(p); whatstr = "ctype "; } else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0) { what = LC_TIME; name = skipwhite(p); whatstr = "time "; } else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0) { what = LC_COLLATE; name = skipwhite(p); whatstr = "collate "; } } if (*name == NUL) { # ifndef LC_MESSAGES if (what == VIM_LC_MESSAGES) p = get_mess_env(); else # endif p = (char_u *)setlocale(what, NULL); if (p == NULL || *p == NUL) p = (char_u *)"Unknown"; smsg(_("Current %slanguage: \"%s\""), whatstr, p); } else { # ifndef LC_MESSAGES if (what == VIM_LC_MESSAGES) loc = ""; else # endif { loc = setlocale(what, (char *)name); # if defined(LC_NUMERIC) // Make sure strtod() uses a decimal point, not a comma. setlocale(LC_NUMERIC, "C"); # endif } if (loc == NULL) semsg(_(e_cannot_set_language_to_str), name); else { # ifdef HAVE_NL_MSG_CAT_CNTR // Need to do this for GNU gettext, otherwise cached translations // will be used again. extern int _nl_msg_cat_cntr; ++_nl_msg_cat_cntr; # endif // Reset $LC_ALL, otherwise it would overrule everything. vim_setenv((char_u *)"LC_ALL", (char_u *)""); if (what != LC_TIME && what != LC_COLLATE) { // Tell gettext() what to translate to. It apparently doesn't // use the currently effective locale. Also do this when // FEAT_GETTEXT isn't defined, so that shell commands use this // value. if (what == LC_ALL) { vim_setenv((char_u *)"LANG", name); // Clear $LANGUAGE because GNU gettext uses it. vim_setenv((char_u *)"LANGUAGE", (char_u *)""); # ifdef MSWIN // Apparently MS-Windows printf() may cause a crash when // we give it 8-bit text while it's expecting text in the // current locale. This call avoids that. setlocale(LC_CTYPE, "C"); # endif } if (what != LC_CTYPE) { char_u *mname; # ifdef MSWIN mname = gettext_lang(name); # else mname = name; # endif vim_setenv((char_u *)"LC_MESSAGES", mname); # ifdef FEAT_MULTI_LANG set_helplang_default(mname); # endif } } # ifdef FEAT_EVAL // Set v:lang, v:lc_time, v:collate and v:ctype to the final result. set_lang_var(); # endif maketitle(); } } } static char_u **locales = NULL; // Array of all available locales static int did_init_locales = FALSE; /* * Return an array of strings for all available locales + NULL for the * last element. Return NULL in case of error. */ static char_u ** find_locales(void) { garray_T locales_ga; char_u *loc; char_u *locale_list; # ifdef MSWIN size_t len = 0; # endif // Find all available locales by running command "locale -a". If this // doesn't work we won't have completion. # ifndef MSWIN locale_list = get_cmd_output((char_u *)"locale -a", NULL, SHELL_SILENT, NULL); # else // Find all available locales by examining the directories in // $VIMRUNTIME/lang/ { int options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL; expand_T xpc; char_u *p; ExpandInit(&xpc); xpc.xp_context = EXPAND_DIRECTORIES; locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*", NULL, options, WILD_ALL); ExpandCleanup(&xpc); if (locale_list == NULL) // Add a dummy input, that will be skipped lated but we need to // have something in locale_list so that the C locale is added at // the end. locale_list = vim_strsave((char_u *)".\n"); p = locale_list; // find the last directory delimiter while (p != NULL && *p != NUL) { if (*p == '\n') break; if (*p == '\\') len = p - locale_list; p++; } } # endif if (locale_list == NULL) return NULL; ga_init2(&locales_ga, sizeof(char_u *), 20); // Transform locale_list string where each locale is separated by "\n" // into an array of locale strings. loc = (char_u *)strtok((char *)locale_list, "\n"); while (loc != NULL) { int ignore = FALSE; # ifdef MSWIN if (len > 0) loc += len + 1; // skip locales with a dot (which indicates the charset) if (vim_strchr(loc, '.') != NULL) ignore = TRUE; # endif if (!ignore) { if (ga_grow(&locales_ga, 1) == FAIL) break; loc = vim_strsave(loc); if (loc == NULL) break; ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc; } loc = (char_u *)strtok(NULL, "\n"); } # ifdef MSWIN // Add the C locale if (ga_grow(&locales_ga, 1) == OK) ((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = vim_strsave((char_u *)"C"); # endif vim_free(locale_list); if (ga_grow(&locales_ga, 1) == FAIL) { ga_clear(&locales_ga); return NULL; } ((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL; return (char_u **)locales_ga.ga_data; } /* * Lazy initialization of all available locales. */ static void init_locales(void) { if (did_init_locales) return; did_init_locales = TRUE; locales = find_locales(); } # if defined(EXITFREE) || defined(PROTO) void free_locales(void) { int i; if (locales == NULL) return; for (i = 0; locales[i] != NULL; i++) vim_free(locales[i]); VIM_CLEAR(locales); } # endif /* * Function given to ExpandGeneric() to obtain the possible arguments of the * ":language" command. */ char_u * get_lang_arg(expand_T *xp UNUSED, int idx) { if (idx == 0) return (char_u *)"messages"; if (idx == 1) return (char_u *)"ctype"; if (idx == 2) return (char_u *)"time"; if (idx == 3) return (char_u *)"collate"; init_locales(); if (locales == NULL) return NULL; return locales[idx - 4]; } /* * Function given to ExpandGeneric() to obtain the available locales. */ char_u * get_locales(expand_T *xp UNUSED, int idx) { init_locales(); if (locales == NULL) return NULL; return locales[idx]; } #endif