mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge #3916 "Add support for binary numbers".
This commit is contained in:
commit
9eb6a44564
@ -371,8 +371,10 @@ CTRL-X Subtract [count] from the number or alphabetic
|
||||
character at or after the cursor.
|
||||
|
||||
The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned
|
||||
octal and hexadecimal numbers and alphabetic characters. This depends on the
|
||||
'nrformats' option.
|
||||
binary/octal/hexadecimal numbers and alphabetic characters. This
|
||||
depends on the 'nrformats' option.
|
||||
- When 'nrformats' includes "bin", Vim considers numbers starting with '0b' or
|
||||
'0B' as binary.
|
||||
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
|
||||
to be octal, unless the number includes a '8' or '9'. Other numbers are
|
||||
decimal and may have a preceding minus sign.
|
||||
@ -386,6 +388,10 @@ octal and hexadecimal numbers and alphabetic characters. This depends on the
|
||||
under or after the cursor. This is useful to make lists with an alphabetic
|
||||
index.
|
||||
|
||||
For decimals a leading negative sign is considered for incrementing or
|
||||
decrementing, for binary and octal and hex values, it won't be considered. To
|
||||
ignore the sign Visually select the number before using CTRL-A or CTRL-X.
|
||||
|
||||
For numbers with leading zeros (including all octal and hexadecimal numbers),
|
||||
Vim preserves the number of characters in the number when possible. CTRL-A on
|
||||
"0077" results in "0100", CTRL-X on "0x100" results in "0x0ff".
|
||||
@ -397,6 +403,10 @@ octal number.
|
||||
Note that when 'nrformats' includes "octal", decimal numbers with leading
|
||||
zeros cause mistakes, because they can be confused with octal numbers.
|
||||
|
||||
Note similarly, when 'nrformats' includes "bin", binary numbers with a leading
|
||||
'0x' or '0X' can be interpreted as hexadecimal rather than binary since '0b'
|
||||
are valid hexadecimal digits.
|
||||
|
||||
The CTRL-A command is very useful in a macro. Example: Use the following
|
||||
steps to make a numbered list.
|
||||
|
||||
@ -1602,7 +1612,7 @@ Vim has a sorting function and a sorting command. The sorting function can be
|
||||
found here: |sort()|, |uniq()|.
|
||||
|
||||
*:sor* *:sort*
|
||||
:[range]sor[t][!] [i][u][r][n][x][o] [/{pattern}/]
|
||||
:[range]sor[t][!] [i][u][r][n][x][o][b] [/{pattern}/]
|
||||
Sort lines in [range]. When no range is given all
|
||||
lines are sorted.
|
||||
|
||||
@ -1622,6 +1632,9 @@ found here: |sort()|, |uniq()|.
|
||||
With [o] sorting is done on the first octal number in
|
||||
the line (after or inside a {pattern} match).
|
||||
|
||||
With [b] sorting is done on the first binary number in
|
||||
the line (after or inside a {pattern} match).
|
||||
|
||||
With [u] only keep the first of a sequence of
|
||||
identical lines (ignoring case when [i] is used).
|
||||
Without this flag, a sequence of identical lines
|
||||
|
@ -65,14 +65,16 @@ the Number. Examples:
|
||||
Number 0 --> String "0" ~
|
||||
Number -1 --> String "-1" ~
|
||||
*octal*
|
||||
Conversion from a String to a Number is done by converting the first digits
|
||||
to a number. Hexadecimal "0xf9" and Octal "017" numbers are recognized. If
|
||||
the String doesn't start with digits, the result is zero. Examples:
|
||||
Conversion from a String to a Number is done by converting the first digits to
|
||||
a number. Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
|
||||
recognized. If the String doesn't start with digits, the result is zero.
|
||||
Examples:
|
||||
String "456" --> Number 456 ~
|
||||
String "6bar" --> Number 6 ~
|
||||
String "foo" --> Number 0 ~
|
||||
String "0xf1" --> Number 241 ~
|
||||
String "0100" --> Number 64 ~
|
||||
String "0b101" --> Number 5 ~
|
||||
String "-8" --> Number -8 ~
|
||||
String "+8" --> Number 0 ~
|
||||
|
||||
@ -4919,6 +4921,9 @@ printf({fmt}, {expr1} ...) *printf()*
|
||||
%c single byte
|
||||
%d decimal number
|
||||
%5d decimal number padded with spaces to 5 characters
|
||||
%b binary number
|
||||
%08b binary number padded with zeros to at least 8 characters
|
||||
%B binary number using upper case letters
|
||||
%x hex number
|
||||
%04x hex number padded with zeros to at least 4 characters
|
||||
%X hex number using upper case letters
|
||||
@ -5005,20 +5010,19 @@ printf({fmt}, {expr1} ...) *printf()*
|
||||
|
||||
The conversion specifiers and their meanings are:
|
||||
|
||||
*printf-d* *printf-o* *printf-x* *printf-X*
|
||||
doxX The Number argument is converted to signed decimal
|
||||
(d), unsigned octal (o), or unsigned hexadecimal (x
|
||||
and X) notation. The letters "abcdef" are used for
|
||||
x conversions; the letters "ABCDEF" are used for X
|
||||
conversions.
|
||||
The precision, if any, gives the minimum number of
|
||||
digits that must appear; if the converted value
|
||||
requires fewer digits, it is padded on the left with
|
||||
zeros.
|
||||
In no case does a non-existent or small field width
|
||||
cause truncation of a numeric field; if the result of
|
||||
a conversion is wider than the field width, the field
|
||||
is expanded to contain the conversion result.
|
||||
*printf-d* *printf-b* *printf-B* *printf-o* *printf-x* *printf-X*
|
||||
dbBoxX The Number argument is converted to signed decimal (d),
|
||||
unsigned binary (b and B), unsigned octal (o), or
|
||||
unsigned hexadecimal (x and X) notation. The letters
|
||||
"abcdef" are used for x conversions; the letters
|
||||
"ABCDEF" are used for X conversions. The precision, if
|
||||
any, gives the minimum number of digits that must
|
||||
appear; if the converted value requires fewer digits, it
|
||||
is padded on the left with zeros. In no case does a
|
||||
non-existent or small field width cause truncation of a
|
||||
numeric field; if the result of a conversion is wider
|
||||
than the field width, the field is expanded to contain
|
||||
the conversion result.
|
||||
|
||||
*printf-c*
|
||||
c The Number argument is converted to a byte, and the
|
||||
@ -6134,12 +6138,14 @@ str2float( {expr}) *str2float()*
|
||||
|
||||
str2nr( {expr} [, {base}]) *str2nr()*
|
||||
Convert string {expr} to a number.
|
||||
{base} is the conversion base, it can be 8, 10 or 16.
|
||||
{base} is the conversion base, it can be 2, 8, 10 or 16.
|
||||
When {base} is omitted base 10 is used. This also means that
|
||||
a leading zero doesn't cause octal conversion to be used, as
|
||||
with the default String to Number conversion.
|
||||
When {base} is 16 a leading "0x" or "0X" is ignored. With a
|
||||
different base the result will be zero.
|
||||
different base the result will be zero. Similarly, when {base}
|
||||
is 8 a leading "0" is ignored, and when {base} is 2 a leading
|
||||
"0b" or "0B" is ignored.
|
||||
Text after the number is silently ignored.
|
||||
|
||||
|
||||
|
@ -85,10 +85,25 @@
|
||||
# define PATHSEPSTR "/"
|
||||
#endif
|
||||
|
||||
static inline bool ascii_iswhite(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
|
||||
static inline bool ascii_isdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
|
||||
static inline bool ascii_isxdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
|
||||
static inline bool ascii_isspace(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
|
||||
static inline bool ascii_iswhite(int)
|
||||
REAL_FATTR_CONST
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
static inline bool ascii_isdigit(int)
|
||||
REAL_FATTR_CONST
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
static inline bool ascii_isxdigit(int)
|
||||
REAL_FATTR_CONST
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
static inline bool ascii_isbdigit(int)
|
||||
REAL_FATTR_CONST
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
static inline bool ascii_isspace(int)
|
||||
REAL_FATTR_CONST
|
||||
REAL_FATTR_ALWAYS_INLINE;
|
||||
|
||||
/// Checks if `c` is a space or tab character.
|
||||
///
|
||||
@ -122,6 +137,14 @@ static inline bool ascii_isxdigit(int c)
|
||||
|| (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
/// Checks if `c` is a binary digit, that is, 0-1.
|
||||
///
|
||||
/// @see {ascii_isdigit}
|
||||
static inline bool ascii_isbdigit(int c)
|
||||
{
|
||||
return (c == '0' || c == '1');
|
||||
}
|
||||
|
||||
/// Checks if `c` is a white-space character, that is,
|
||||
/// one of \f, \n, \r, \t, \v.
|
||||
///
|
||||
|
@ -1454,6 +1454,24 @@ char_u* skipdigits(char_u *q)
|
||||
return p;
|
||||
}
|
||||
|
||||
/// skip over binary digits
|
||||
///
|
||||
/// @param q pointer to string
|
||||
///
|
||||
/// @return Pointer to the character after the skipped digits.
|
||||
const char* skipbin(const char *q)
|
||||
FUNC_ATTR_PURE
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
const char *p = q;
|
||||
while (ascii_isbdigit(*p)) {
|
||||
// skip to next non-digit
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// skip over digits and hex characters
|
||||
///
|
||||
/// @param q
|
||||
@ -1485,6 +1503,24 @@ char_u* skiptodigit(char_u *q)
|
||||
return p;
|
||||
}
|
||||
|
||||
/// skip to binary character (or NUL after the string)
|
||||
///
|
||||
/// @param q pointer to string
|
||||
///
|
||||
/// @return Pointer to the binary character or (NUL after the string).
|
||||
const char* skiptobin(const char *q)
|
||||
FUNC_ATTR_PURE
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
FUNC_ATTR_NONNULL_RET
|
||||
{
|
||||
const char *p = q;
|
||||
while (*p != NUL && !ascii_isbdigit(*p)) {
|
||||
// skip to next digit
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// skip to hex character (or NUL after the string)
|
||||
///
|
||||
/// @param q
|
||||
@ -1720,67 +1756,77 @@ int vim_isblankline(char_u *lbuf)
|
||||
}
|
||||
|
||||
/// Convert a string into a long and/or unsigned long, taking care of
|
||||
/// hexadecimal and octal numbers. Accepts a '-' sign.
|
||||
/// If "hexp" is not NULL, returns a flag to indicate the type of the number:
|
||||
/// hexadecimal, octal and binary numbers. Accepts a '-' sign.
|
||||
/// If "prep" is not NULL, returns a flag to indicate the type of the number:
|
||||
/// 0 decimal
|
||||
/// '0' octal
|
||||
/// 'B' bin
|
||||
/// 'b' bin
|
||||
/// 'X' hex
|
||||
/// 'x' hex
|
||||
/// If "len" is not NULL, the length of the number in characters is returned.
|
||||
/// If "nptr" is not NULL, the signed result is returned in it.
|
||||
/// If "unptr" is not NULL, the unsigned result is returned in it.
|
||||
/// If "dobin" is non-zero recognize binary numbers, when > 1 always assume
|
||||
/// binary number.
|
||||
/// If "dooct" is non-zero recognize octal numbers, when > 1 always assume
|
||||
/// octal number.
|
||||
/// If "dohex" is non-zero recognize hex numbers, when > 1 always assume
|
||||
/// hex number.
|
||||
///
|
||||
/// @param start
|
||||
/// @param hexp Returns type of number 0 = decimal, 'x' or 'X' is hex,
|
||||
// '0' = octal
|
||||
/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
|
||||
// '0' = octal, 'b' or 'B' is bin
|
||||
/// @param len Returns the detected length of number.
|
||||
/// @param dobin recognize binary number
|
||||
/// @param dooct recognize octal number
|
||||
/// @param dohex recognize hex number
|
||||
/// @param nptr Returns the signed result.
|
||||
/// @param unptr Returns the unsigned result.
|
||||
void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
|
||||
void vim_str2nr(char_u *start, int *prep, int *len,
|
||||
int dobin, int dooct, int dohex,
|
||||
long *nptr, unsigned long *unptr)
|
||||
{
|
||||
char_u *ptr = start;
|
||||
int hex = 0; // default is decimal
|
||||
int negative = FALSE;
|
||||
int pre = 0; // default is decimal
|
||||
int negative = false;
|
||||
unsigned long un = 0;
|
||||
int n;
|
||||
|
||||
if (ptr[0] == '-') {
|
||||
negative = TRUE;
|
||||
++ptr;
|
||||
negative = true;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// Recognize hex and octal.
|
||||
// Recognize hex, octal, and bin.
|
||||
if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) {
|
||||
hex = ptr[1];
|
||||
pre = ptr[1];
|
||||
|
||||
if (dohex
|
||||
&& ((hex == 'X') || (hex == 'x'))
|
||||
&& ((pre == 'X') || (pre == 'x'))
|
||||
&& ascii_isxdigit(ptr[2])) {
|
||||
// hexadecimal
|
||||
ptr += 2;
|
||||
} else if (dobin
|
||||
&& ((pre == 'B') || (pre == 'b'))
|
||||
&& ascii_isbdigit(ptr[2])) {
|
||||
// binary
|
||||
ptr += 2;
|
||||
} else {
|
||||
// default is decimal
|
||||
hex = 0;
|
||||
pre = 0;
|
||||
|
||||
if (dooct) {
|
||||
// Don't interpret "0", "08" or "0129" as octal.
|
||||
for (n = 1; ascii_isdigit(ptr[n]); ++n) {
|
||||
if (ptr[n] > '7') {
|
||||
// can't be octal
|
||||
hex = 0;
|
||||
pre = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ptr[n] >= '0') {
|
||||
// assume octal
|
||||
hex = '0';
|
||||
pre = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1788,14 +1834,26 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
|
||||
}
|
||||
|
||||
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
|
||||
if ((hex == '0') || (dooct > 1)) {
|
||||
if ((pre == 'B') || (pre == 'b') || (dobin > 1)) {
|
||||
// bin
|
||||
if (pre != 0) {
|
||||
n += 2; // skip over "0b"
|
||||
}
|
||||
while ('0' <= *ptr && *ptr <= '1') {
|
||||
un = 2 * un + (unsigned long)(*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
} else if ((pre == '0') || (dooct > 1)) {
|
||||
// octal
|
||||
while ('0' <= *ptr && *ptr <= '7') {
|
||||
un = 8 * un + (unsigned long)(*ptr - '0');
|
||||
ptr++;
|
||||
}
|
||||
} else if ((hex != 0) || (dohex > 1)) {
|
||||
} else if (pre != 0 || dohex > 1) {
|
||||
// hex
|
||||
if (pre != 0) {
|
||||
n += 2; // skip over "0x"
|
||||
}
|
||||
while (ascii_isxdigit(*ptr)) {
|
||||
un = 16 * un + (unsigned long)hex2nr(*ptr);
|
||||
ptr++;
|
||||
@ -1808,8 +1866,8 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
|
||||
}
|
||||
}
|
||||
|
||||
if (hexp != NULL) {
|
||||
*hexp = hex;
|
||||
if (prep != NULL) {
|
||||
*prep = pre;
|
||||
}
|
||||
|
||||
if (len != NULL) {
|
||||
|
283
src/nvim/eval.c
283
src/nvim/eval.c
@ -1113,19 +1113,17 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Call some vimL function and return the result in "*rettv".
|
||||
* Uses argv[argc] for the function arguments. Only Number and String
|
||||
* arguments are currently supported.
|
||||
* Returns OK or FAIL.
|
||||
*/
|
||||
int
|
||||
call_vim_function (
|
||||
// Call some vimL function and return the result in "*rettv".
|
||||
// Uses argv[argc] for the function arguments. Only Number and String
|
||||
// arguments are currently supported.
|
||||
//
|
||||
// Return OK or FAIL.
|
||||
int call_vim_function(
|
||||
char_u *func,
|
||||
int argc,
|
||||
char_u **argv,
|
||||
int safe, /* use the sandbox */
|
||||
int str_arg_only, /* all arguments are strings */
|
||||
int safe, // use the sandbox
|
||||
int str_arg_only, // all arguments are strings
|
||||
typval_T *rettv
|
||||
)
|
||||
{
|
||||
@ -1138,18 +1136,19 @@ call_vim_function (
|
||||
typval_T *argvars = xmalloc((argc + 1) * sizeof(typval_T));
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
/* Pass a NULL or empty argument as an empty string */
|
||||
// Pass a NULL or empty argument as an empty string
|
||||
if (argv[i] == NULL || *argv[i] == NUL) {
|
||||
argvars[i].v_type = VAR_STRING;
|
||||
argvars[i].vval.v_string = (char_u *)"";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_arg_only)
|
||||
if (str_arg_only) {
|
||||
len = 0;
|
||||
else
|
||||
/* Recognize a number argument, the others must be strings. */
|
||||
vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL);
|
||||
} else {
|
||||
// Recognize a number argument, the others must be strings.
|
||||
vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL);
|
||||
}
|
||||
if (len != 0 && len == (int)STRLEN(argv[i])) {
|
||||
argvars[i].v_type = VAR_NUMBER;
|
||||
argvars[i].vval.v_number = n;
|
||||
@ -1166,16 +1165,17 @@ call_vim_function (
|
||||
|
||||
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
|
||||
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&doesrange, TRUE, NULL);
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&doesrange, true, NULL);
|
||||
if (safe) {
|
||||
--sandbox;
|
||||
restore_funccal(save_funccalp);
|
||||
}
|
||||
xfree(argvars);
|
||||
|
||||
if (ret == FAIL)
|
||||
if (ret == FAIL) {
|
||||
clear_tv(rettv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -4025,38 +4025,35 @@ eval6 (
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle sixth level expression:
|
||||
* number number constant
|
||||
* "string" string constant
|
||||
* 'string' literal string constant
|
||||
* &option-name option value
|
||||
* @r register contents
|
||||
* identifier variable value
|
||||
* function() function call
|
||||
* $VAR environment variable
|
||||
* (expression) nested expression
|
||||
* [expr, expr] List
|
||||
* {key: val, key: val} Dictionary
|
||||
*
|
||||
* Also handle:
|
||||
* ! in front logical NOT
|
||||
* - in front unary minus
|
||||
* + in front unary plus (ignored)
|
||||
* trailing [] subscript in String or List
|
||||
* trailing .name entry in Dictionary
|
||||
*
|
||||
* "arg" must point to the first non-white of the expression.
|
||||
* "arg" is advanced to the next non-white after the recognized expression.
|
||||
*
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
eval7 (
|
||||
// Handle sixth level expression:
|
||||
// number number constant
|
||||
// "string" string constant
|
||||
// 'string' literal string constant
|
||||
// &option-name option value
|
||||
// @r register contents
|
||||
// identifier variable value
|
||||
// function() function call
|
||||
// $VAR environment variable
|
||||
// (expression) nested expression
|
||||
// [expr, expr] List
|
||||
// {key: val, key: val} Dictionary
|
||||
//
|
||||
// Also handle:
|
||||
// ! in front logical NOT
|
||||
// - in front unary minus
|
||||
// + in front unary plus (ignored)
|
||||
// trailing [] subscript in String or List
|
||||
// trailing .name entry in Dictionary
|
||||
//
|
||||
// "arg" must point to the first non-white of the expression.
|
||||
// "arg" is advanced to the next non-white after the recognized expression.
|
||||
//
|
||||
// Return OK or FAIL.
|
||||
static int eval7(
|
||||
char_u **arg,
|
||||
typval_T *rettv,
|
||||
int evaluate,
|
||||
int want_string /* after "." operator */
|
||||
int want_string // after "." operator
|
||||
)
|
||||
{
|
||||
long n;
|
||||
@ -4066,24 +4063,19 @@ eval7 (
|
||||
int ret = OK;
|
||||
char_u *alias;
|
||||
|
||||
/*
|
||||
* Initialise variable so that clear_tv() can't mistake this for a
|
||||
* string and free a string that isn't there.
|
||||
*/
|
||||
// Initialise variable so that clear_tv() can't mistake this for a
|
||||
// string and free a string that isn't there.
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
|
||||
/*
|
||||
* Skip '!' and '-' characters. They are handled later.
|
||||
*/
|
||||
// Skip '!' and '-' characters. They are handled later.
|
||||
start_leader = *arg;
|
||||
while (**arg == '!' || **arg == '-' || **arg == '+')
|
||||
while (**arg == '!' || **arg == '-' || **arg == '+') {
|
||||
*arg = skipwhite(*arg + 1);
|
||||
}
|
||||
end_leader = *arg;
|
||||
|
||||
switch (**arg) {
|
||||
/*
|
||||
* Number constant.
|
||||
*/
|
||||
// Number constant.
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
@ -4096,27 +4088,30 @@ eval7 (
|
||||
case '9':
|
||||
{
|
||||
char_u *p = skipdigits(*arg + 1);
|
||||
int get_float = FALSE;
|
||||
int get_float = false;
|
||||
|
||||
/* We accept a float when the format matches
|
||||
* "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
|
||||
* strict to avoid backwards compatibility problems.
|
||||
* Don't look for a float after the "." operator, so that
|
||||
* ":let vers = 1.2.3" doesn't fail. */
|
||||
// We accept a float when the format matches
|
||||
// "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
|
||||
// strict to avoid backwards compatibility problems.
|
||||
// Don't look for a float after the "." operator, so that
|
||||
// ":let vers = 1.2.3" doesn't fail.
|
||||
if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
|
||||
get_float = TRUE;
|
||||
get_float = true;
|
||||
p = skipdigits(p + 2);
|
||||
if (*p == 'e' || *p == 'E') {
|
||||
++p;
|
||||
if (*p == '-' || *p == '+')
|
||||
if (*p == '-' || *p == '+') {
|
||||
++p;
|
||||
if (!ascii_isdigit(*p))
|
||||
get_float = FALSE;
|
||||
else
|
||||
}
|
||||
if (!ascii_isdigit(*p)) {
|
||||
get_float = false;
|
||||
} else {
|
||||
p = skipdigits(p + 1);
|
||||
}
|
||||
}
|
||||
if (ASCII_ISALPHA(*p) || *p == '.') {
|
||||
get_float = false;
|
||||
}
|
||||
if (ASCII_ISALPHA(*p) || *p == '.')
|
||||
get_float = FALSE;
|
||||
}
|
||||
if (get_float) {
|
||||
float_T f;
|
||||
@ -4127,7 +4122,7 @@ eval7 (
|
||||
rettv->vval.v_float = f;
|
||||
}
|
||||
} else {
|
||||
vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL);
|
||||
vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL);
|
||||
*arg += len;
|
||||
if (evaluate) {
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
@ -4137,62 +4132,47 @@ eval7 (
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* String constant: "string".
|
||||
*/
|
||||
// String constant: "string".
|
||||
case '"': ret = get_string_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Literal string constant: 'str''ing'.
|
||||
*/
|
||||
// Literal string constant: 'str''ing'.
|
||||
case '\'': ret = get_lit_string_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* List: [expr, expr]
|
||||
*/
|
||||
// List: [expr, expr]
|
||||
case '[': ret = get_list_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Dictionary: {key: val, key: val}
|
||||
*/
|
||||
// Dictionary: {key: val, key: val}
|
||||
case '{': ret = get_dict_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Option value: &name
|
||||
*/
|
||||
// Option value: &name
|
||||
case '&': ret = get_option_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Environment variable: $VAR.
|
||||
*/
|
||||
// Environment variable: $VAR.
|
||||
case '$': ret = get_env_tv(arg, rettv, evaluate);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Register contents: @r.
|
||||
*/
|
||||
// Register contents: @r.
|
||||
case '@': ++*arg;
|
||||
if (evaluate) {
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc);
|
||||
}
|
||||
if (**arg != NUL)
|
||||
if (**arg != NUL) {
|
||||
++*arg;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* nested expression: (expression).
|
||||
*/
|
||||
// nested expression: (expression).
|
||||
case '(': *arg = skipwhite(*arg + 1);
|
||||
ret = eval1(arg, rettv, evaluate); /* recursive! */
|
||||
if (**arg == ')')
|
||||
ret = eval1(arg, rettv, evaluate); // recursive!
|
||||
if (**arg == ')') {
|
||||
++*arg;
|
||||
else if (ret == OK) {
|
||||
} else if (ret == OK) {
|
||||
EMSG(_("E110: Missing ')'"));
|
||||
clear_tv(rettv);
|
||||
ret = FAIL;
|
||||
@ -4204,71 +4184,72 @@ eval7 (
|
||||
}
|
||||
|
||||
if (ret == NOTDONE) {
|
||||
/*
|
||||
* Must be a variable or function name.
|
||||
* Can also be a curly-braces kind of name: {expr}.
|
||||
*/
|
||||
// Must be a variable or function name.
|
||||
// Can also be a curly-braces kind of name: {expr}.
|
||||
s = *arg;
|
||||
len = get_name_len(arg, &alias, evaluate, TRUE);
|
||||
if (alias != NULL)
|
||||
len = get_name_len(arg, &alias, evaluate, true);
|
||||
if (alias != NULL) {
|
||||
s = alias;
|
||||
}
|
||||
|
||||
if (len <= 0)
|
||||
if (len <= 0) {
|
||||
ret = FAIL;
|
||||
else {
|
||||
if (**arg == '(') { /* recursive! */
|
||||
/* If "s" is the name of a variable of type VAR_FUNC
|
||||
* use its contents. */
|
||||
} else {
|
||||
if (**arg == '(') { // recursive!
|
||||
// If "s" is the name of a variable of type VAR_FUNC
|
||||
// use its contents.
|
||||
s = deref_func_name(s, &len, !evaluate);
|
||||
|
||||
/* Invoke the function. */
|
||||
// Invoke the function.
|
||||
ret = get_func_tv(s, len, rettv, arg,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&len, evaluate, NULL);
|
||||
|
||||
/* If evaluate is FALSE rettv->v_type was not set in
|
||||
* get_func_tv, but it's needed in handle_subscript() to parse
|
||||
* what follows. So set it here. */
|
||||
// If evaluate is false rettv->v_type was not set in
|
||||
// get_func_tv, but it's needed in handle_subscript() to parse
|
||||
// what follows. So set it here.
|
||||
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
|
||||
rettv->vval.v_string = empty_string;
|
||||
rettv->v_type = VAR_FUNC;
|
||||
}
|
||||
|
||||
/* Stop the expression evaluation when immediately
|
||||
* aborting on error, or when an interrupt occurred or
|
||||
* an exception was thrown but not caught. */
|
||||
// Stop the expression evaluation when immediately
|
||||
// aborting on error, or when an interrupt occurred or
|
||||
// an exception was thrown but not caught.
|
||||
if (aborting()) {
|
||||
if (ret == OK)
|
||||
if (ret == OK) {
|
||||
clear_tv(rettv);
|
||||
}
|
||||
ret = FAIL;
|
||||
}
|
||||
} else if (evaluate)
|
||||
ret = get_var_tv(s, len, rettv, TRUE, FALSE);
|
||||
else
|
||||
} else if (evaluate) {
|
||||
ret = get_var_tv(s, len, rettv, true, false);
|
||||
} else {
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
xfree(alias);
|
||||
}
|
||||
|
||||
*arg = skipwhite(*arg);
|
||||
|
||||
/* Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||
* expr(expr). */
|
||||
if (ret == OK)
|
||||
ret = handle_subscript(arg, rettv, evaluate, TRUE);
|
||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||
// expr(expr).
|
||||
if (ret == OK) {
|
||||
ret = handle_subscript(arg, rettv, evaluate, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||
*/
|
||||
// Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||
if (ret == OK && evaluate && end_leader > start_leader) {
|
||||
int error = FALSE;
|
||||
int error = false;
|
||||
int val = 0;
|
||||
float_T f = 0.0;
|
||||
|
||||
if (rettv->v_type == VAR_FLOAT)
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = rettv->vval.v_float;
|
||||
else
|
||||
} else {
|
||||
val = get_tv_number_chk(rettv, &error);
|
||||
}
|
||||
if (error) {
|
||||
clear_tv(rettv);
|
||||
ret = FAIL;
|
||||
@ -4276,15 +4257,17 @@ eval7 (
|
||||
while (end_leader > start_leader) {
|
||||
--end_leader;
|
||||
if (*end_leader == '!') {
|
||||
if (rettv->v_type == VAR_FLOAT)
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = !f;
|
||||
else
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
} else if (*end_leader == '-') {
|
||||
if (rettv->v_type == VAR_FLOAT)
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = -f;
|
||||
else
|
||||
} else {
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
@ -15998,9 +15981,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv)
|
||||
rettv->v_type = VAR_FLOAT;
|
||||
}
|
||||
|
||||
/*
|
||||
* "str2nr()" function
|
||||
*/
|
||||
// "str2nr()" function
|
||||
static void f_str2nr(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
int base = 10;
|
||||
@ -16009,16 +15990,21 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
base = get_tv_number(&argvars[1]);
|
||||
if (base != 8 && base != 10 && base != 16) {
|
||||
if (base != 2 && base != 8 && base != 10 && base != 16) {
|
||||
EMSG(_(e_invarg));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
p = skipwhite(get_tv_string(&argvars[0]));
|
||||
if (*p == '+')
|
||||
if (*p == '+') {
|
||||
p = skipwhite(p + 1);
|
||||
vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL);
|
||||
}
|
||||
vim_str2nr(p, NULL, NULL,
|
||||
base == 2 ? 2 : 0,
|
||||
base == 8 ? 2 : 0,
|
||||
base == 16 ? 2 : 0,
|
||||
&n, NULL);
|
||||
rettv->vval.v_number = n;
|
||||
}
|
||||
|
||||
@ -18298,9 +18284,10 @@ long get_tv_number_chk(typval_T *varp, int *denote)
|
||||
EMSG(_("E703: Using a Funcref as a Number"));
|
||||
break;
|
||||
case VAR_STRING:
|
||||
if (varp->vval.v_string != NULL)
|
||||
if (varp->vval.v_string != NULL) {
|
||||
vim_str2nr(varp->vval.v_string, NULL, NULL,
|
||||
TRUE, TRUE, &n, NULL);
|
||||
true, true, true, &n, NULL);
|
||||
}
|
||||
return n;
|
||||
case VAR_LIST:
|
||||
EMSG(_("E745: Using a List as a Number"));
|
||||
@ -18312,10 +18299,12 @@ long get_tv_number_chk(typval_T *varp, int *denote)
|
||||
EMSG2(_(e_intern2), "get_tv_number()");
|
||||
break;
|
||||
}
|
||||
if (denote == NULL) /* useful for values that must be unsigned */
|
||||
if (denote == NULL) {
|
||||
// useful for values that must be unsigned
|
||||
n = -1;
|
||||
else
|
||||
*denote = TRUE;
|
||||
} else {
|
||||
*denote = true;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -329,9 +329,7 @@ static int sort_compare(const void *s1, const void *s2)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ":sort".
|
||||
*/
|
||||
// ":sort".
|
||||
void ex_sort(exarg_T *eap)
|
||||
{
|
||||
regmatch_T regmatch;
|
||||
@ -343,17 +341,19 @@ void ex_sort(exarg_T *eap)
|
||||
char_u *p;
|
||||
char_u *s;
|
||||
char_u *s2;
|
||||
char_u c; /* temporary character storage */
|
||||
int unique = FALSE;
|
||||
char_u c; // temporary character storage
|
||||
int unique = false;
|
||||
long deleted;
|
||||
colnr_T start_col;
|
||||
colnr_T end_col;
|
||||
int sort_oct; /* sort on octal number */
|
||||
int sort_hex; /* sort on hex number */
|
||||
int sort_bin; // sort on bin number
|
||||
int sort_oct; // sort on octal number
|
||||
int sort_hex; // sort on hex number
|
||||
|
||||
/* Sorting one line is really quick! */
|
||||
if (count <= 1)
|
||||
// Sorting one line is really quick!
|
||||
if (count <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
|
||||
return;
|
||||
@ -362,47 +362,51 @@ void ex_sort(exarg_T *eap)
|
||||
regmatch.regprog = NULL;
|
||||
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
|
||||
|
||||
sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;
|
||||
sort_abort = sort_ic = sort_rx = sort_nr = sort_bin = sort_oct = sort_hex = 0;
|
||||
|
||||
for (p = eap->arg; *p != NUL; ++p) {
|
||||
if (ascii_iswhite(*p))
|
||||
;
|
||||
else if (*p == 'i')
|
||||
sort_ic = TRUE;
|
||||
else if (*p == 'r')
|
||||
sort_rx = TRUE;
|
||||
else if (*p == 'n')
|
||||
if (ascii_iswhite(*p)) {
|
||||
} else if (*p == 'i') {
|
||||
sort_ic = true;
|
||||
} else if (*p == 'r') {
|
||||
sort_rx = true;
|
||||
} else if (*p == 'n') {
|
||||
sort_nr = 2;
|
||||
else if (*p == 'o')
|
||||
} else if (*p == 'b') {
|
||||
sort_bin = 2;
|
||||
} else if (*p == 'o') {
|
||||
sort_oct = 2;
|
||||
else if (*p == 'x')
|
||||
} else if (*p == 'x') {
|
||||
sort_hex = 2;
|
||||
else if (*p == 'u')
|
||||
unique = TRUE;
|
||||
else if (*p == '"') /* comment start */
|
||||
} else if (*p == 'u') {
|
||||
unique = true;
|
||||
} else if (*p == '"') {
|
||||
// comment start
|
||||
break;
|
||||
else if (check_nextcmd(p) != NULL) {
|
||||
} else if (check_nextcmd(p) != NULL) {
|
||||
eap->nextcmd = check_nextcmd(p);
|
||||
break;
|
||||
} else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) {
|
||||
s = skip_regexp(p + 1, *p, TRUE, NULL);
|
||||
s = skip_regexp(p + 1, *p, true, NULL);
|
||||
if (*s != *p) {
|
||||
EMSG(_(e_invalpat));
|
||||
goto sortend;
|
||||
}
|
||||
*s = NUL;
|
||||
/* Use last search pattern if sort pattern is empty. */
|
||||
// Use last search pattern if sort pattern is empty.
|
||||
if (s == p + 1) {
|
||||
if (last_search_pat() == NULL) {
|
||||
EMSG(_(e_noprevre));
|
||||
goto sortend;
|
||||
}
|
||||
regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
|
||||
} else
|
||||
} else {
|
||||
regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
|
||||
if (regmatch.regprog == NULL)
|
||||
}
|
||||
if (regmatch.regprog == NULL) {
|
||||
goto sortend;
|
||||
p = s; /* continue after the regexp */
|
||||
}
|
||||
p = s; // continue after the regexp
|
||||
regmatch.rm_ic = p_ic;
|
||||
} else {
|
||||
EMSG2(_(e_invarg2), p);
|
||||
@ -410,28 +414,27 @@ void ex_sort(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
|
||||
/* Can only have one of 'n', 'o' and 'x'. */
|
||||
if (sort_nr + sort_oct + sort_hex > 2) {
|
||||
// Can only have one of 'n', 'b', 'o' and 'x'.
|
||||
if (sort_nr + sort_bin + sort_oct + sort_hex > 2) {
|
||||
EMSG(_(e_invarg));
|
||||
goto sortend;
|
||||
}
|
||||
|
||||
/* From here on "sort_nr" is used as a flag for any number sorting. */
|
||||
sort_nr += sort_oct + sort_hex;
|
||||
// From here on "sort_nr" is used as a flag for any number sorting.
|
||||
sort_nr += sort_bin + sort_oct + sort_hex;
|
||||
|
||||
/*
|
||||
* Make an array with all line numbers. This avoids having to copy all
|
||||
* the lines into allocated memory.
|
||||
* When sorting on strings "start_col_nr" is the offset in the line, for
|
||||
* numbers sorting it's the number to sort on. This means the pattern
|
||||
* matching and number conversion only has to be done once per line.
|
||||
* Also get the longest line length for allocating "sortbuf".
|
||||
*/
|
||||
// Make an array with all line numbers. This avoids having to copy all
|
||||
// the lines into allocated memory.
|
||||
// When sorting on strings "start_col_nr" is the offset in the line, for
|
||||
// numbers sorting it's the number to sort on. This means the pattern
|
||||
// matching and number conversion only has to be done once per line.
|
||||
// Also get the longest line length for allocating "sortbuf".
|
||||
for (lnum = eap->line1; lnum <= eap->line2; ++lnum) {
|
||||
s = ml_get(lnum);
|
||||
len = (int)STRLEN(s);
|
||||
if (maxlen < len)
|
||||
if (maxlen < len) {
|
||||
maxlen = len;
|
||||
}
|
||||
|
||||
start_col = 0;
|
||||
end_col = len;
|
||||
@ -439,34 +442,41 @@ void ex_sort(exarg_T *eap)
|
||||
if (sort_rx) {
|
||||
start_col = (colnr_T)(regmatch.startp[0] - s);
|
||||
end_col = (colnr_T)(regmatch.endp[0] - s);
|
||||
} else
|
||||
} else {
|
||||
start_col = (colnr_T)(regmatch.endp[0] - s);
|
||||
} else if (regmatch.regprog != NULL)
|
||||
}
|
||||
} else if (regmatch.regprog != NULL) {
|
||||
end_col = 0;
|
||||
}
|
||||
|
||||
if (sort_nr) {
|
||||
/* Make sure vim_str2nr doesn't read any digits past the end
|
||||
* of the match, by temporarily terminating the string there */
|
||||
// Make sure vim_str2nr doesn't read any digits past the end
|
||||
// of the match, by temporarily terminating the string there
|
||||
s2 = s + end_col;
|
||||
c = *s2;
|
||||
*s2 = NUL;
|
||||
/* Sorting on number: Store the number itself. */
|
||||
// Sorting on number: Store the number itself.
|
||||
p = s + start_col;
|
||||
if (sort_hex)
|
||||
if (sort_hex) {
|
||||
s = skiptohex(p);
|
||||
else
|
||||
} else if (sort_bin) {
|
||||
s = (char_u*) skiptobin((char*) p);
|
||||
} else {
|
||||
s = skiptodigit(p);
|
||||
if (s > p && s[-1] == '-')
|
||||
--s; /* include preceding negative sign */
|
||||
if (*s == NUL)
|
||||
/* empty line should sort before any number */
|
||||
}
|
||||
if (s > p && s[-1] == '-') {
|
||||
--s; // include preceding negative sign
|
||||
}
|
||||
if (*s == NUL) {
|
||||
// empty line should sort before any number
|
||||
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
|
||||
else
|
||||
vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,
|
||||
&nrs[lnum - eap->line1].start_col_nr, NULL);
|
||||
} else {
|
||||
vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex,
|
||||
&nrs[lnum - eap->line1].start_col_nr, NULL);
|
||||
}
|
||||
*s2 = c;
|
||||
} else {
|
||||
/* Store the column to sort at. */
|
||||
// Store the column to sort at.
|
||||
nrs[lnum - eap->line1].start_col_nr = start_col;
|
||||
nrs[lnum - eap->line1].end_col_nr = end_col;
|
||||
}
|
||||
@ -479,17 +489,17 @@ void ex_sort(exarg_T *eap)
|
||||
goto sortend;
|
||||
}
|
||||
|
||||
/* Allocate a buffer that can hold the longest line. */
|
||||
// Allocate a buffer that can hold the longest line.
|
||||
sortbuf1 = xmalloc(maxlen + 1);
|
||||
sortbuf2 = xmalloc(maxlen + 1);
|
||||
|
||||
/* Sort the array of line numbers. Note: can't be interrupted! */
|
||||
// Sort the array of line numbers. Note: can't be interrupted!
|
||||
qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
|
||||
|
||||
if (sort_abort)
|
||||
goto sortend;
|
||||
|
||||
/* Insert the lines in the sorted order below the last one. */
|
||||
// Insert the lines in the sorted order below the last one.
|
||||
lnum = eap->line2;
|
||||
for (i = 0; i < count; ++i) {
|
||||
s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum);
|
||||
@ -507,19 +517,22 @@ void ex_sort(exarg_T *eap)
|
||||
goto sortend;
|
||||
}
|
||||
|
||||
/* delete the original lines if appending worked */
|
||||
if (i == count)
|
||||
for (i = 0; i < count; ++i)
|
||||
ml_delete(eap->line1, FALSE);
|
||||
else
|
||||
// delete the original lines if appending worked
|
||||
if (i == count) {
|
||||
for (i = 0; i < count; ++i) {
|
||||
ml_delete(eap->line1, false);
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/* Adjust marks for deleted (or added) lines and prepare for displaying. */
|
||||
// Adjust marks for deleted (or added) lines and prepare for displaying.
|
||||
deleted = (long)(count - (lnum - eap->line2));
|
||||
if (deleted > 0)
|
||||
if (deleted > 0) {
|
||||
mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
|
||||
else if (deleted < 0)
|
||||
} else if (deleted < 0) {
|
||||
mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
|
||||
}
|
||||
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
|
||||
|
||||
curwin->w_cursor.lnum = eap->line1;
|
||||
@ -530,8 +543,9 @@ sortend:
|
||||
xfree(sortbuf1);
|
||||
xfree(sortbuf2);
|
||||
vim_regfree(regmatch.regprog);
|
||||
if (got_int)
|
||||
if (got_int) {
|
||||
EMSG(_(e_interr));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4767,35 +4767,40 @@ int del_history_idx(int histype, int idx)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get indices "num1,num2" that specify a range within a list (not a range of
|
||||
* text lines in a buffer!) from a string. Used for ":history" and ":clist".
|
||||
* Returns OK if parsed successfully, otherwise FAIL.
|
||||
*/
|
||||
/// Get indices that specify a range within a list (not a range of text lines
|
||||
/// in a buffer!) from a string. Used for ":history" and ":clist".
|
||||
///
|
||||
/// @param str string to parse range from
|
||||
/// @param num1 from
|
||||
/// @param num2 to
|
||||
///
|
||||
/// @return OK if parsed successfully, otherwise FAIL.
|
||||
int get_list_range(char_u **str, int *num1, int *num2)
|
||||
{
|
||||
int len;
|
||||
int first = FALSE;
|
||||
int first = false;
|
||||
long num;
|
||||
|
||||
*str = skipwhite(*str);
|
||||
if (**str == '-' || ascii_isdigit(**str)) { /* parse "from" part of range */
|
||||
vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
|
||||
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
|
||||
vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
|
||||
*str += len;
|
||||
*num1 = (int)num;
|
||||
first = TRUE;
|
||||
first = true;
|
||||
}
|
||||
*str = skipwhite(*str);
|
||||
if (**str == ',') { /* parse "to" part of range */
|
||||
if (**str == ',') { // parse "to" part of range
|
||||
*str = skipwhite(*str + 1);
|
||||
vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
|
||||
vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
|
||||
if (len > 0) {
|
||||
*num2 = (int)num;
|
||||
*str = skipwhite(*str + len);
|
||||
} else if (!first) /* no number given at all */
|
||||
} else if (!first) { // no number given at all
|
||||
return FAIL;
|
||||
} else if (first) /* only one number given */
|
||||
}
|
||||
} else if (first) { // only one number given
|
||||
*num2 = *num1;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -531,17 +531,14 @@ trans_special (
|
||||
return dlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try translating a <> name at (*srcp)[], return the key and modifiers.
|
||||
* srcp is advanced to after the <> name.
|
||||
* returns 0 if there is no match.
|
||||
*/
|
||||
int
|
||||
find_special_key (
|
||||
// Try translating a <> name at (*srcp)[], return the key and modifiers.
|
||||
// srcp is advanced to after the <> name.
|
||||
// returns 0 if there is no match.
|
||||
int find_special_key(
|
||||
char_u **srcp,
|
||||
int *modp,
|
||||
int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
|
||||
int keep_x_key /* don't translate xHome to Home key */
|
||||
int keycode, // prefer key code, e.g. K_DEL instead of DEL
|
||||
int keep_x_key // don't translate xHome to Home key
|
||||
)
|
||||
{
|
||||
char_u *last_dash;
|
||||
@ -558,24 +555,26 @@ find_special_key (
|
||||
if (src[0] != '<')
|
||||
return 0;
|
||||
|
||||
/* Find end of modifier list */
|
||||
// Find end of modifier list
|
||||
last_dash = src;
|
||||
for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
|
||||
if (*bp == '-') {
|
||||
last_dash = bp;
|
||||
if (bp[1] != NUL) {
|
||||
if (has_mbyte)
|
||||
if (has_mbyte) {
|
||||
l = mb_ptr2len(bp + 1);
|
||||
else
|
||||
} else {
|
||||
l = 1;
|
||||
if (bp[l + 1] == '>')
|
||||
bp += l; /* anything accepted, like <C-?> */
|
||||
}
|
||||
if (bp[l + 1] == '>') {
|
||||
bp += l; // anything accepted, like <C-?>
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
|
||||
bp += 3; /* skip t_xx, xx may be '-' or '>' */
|
||||
else if (STRNICMP(bp, "char-", 5) == 0) {
|
||||
vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL);
|
||||
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
|
||||
bp += 3; // skip t_xx, xx may be '-' or '>'
|
||||
} else if (STRNICMP(bp, "char-", 5) == 0) {
|
||||
vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL);
|
||||
bp += l + 5;
|
||||
break;
|
||||
}
|
||||
@ -589,55 +588,53 @@ find_special_key (
|
||||
for (bp = src + 1; bp < last_dash; bp++) {
|
||||
if (*bp != '-') {
|
||||
bit = name_to_mod_mask(*bp);
|
||||
if (bit == 0x0)
|
||||
break; /* Illegal modifier name */
|
||||
if (bit == 0x0) {
|
||||
break; // Illegal modifier name
|
||||
}
|
||||
modifiers |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Legal modifier name.
|
||||
*/
|
||||
// Legal modifier name.
|
||||
if (bp >= last_dash) {
|
||||
if (STRNICMP(last_dash + 1, "char-", 5) == 0
|
||||
&& ascii_isdigit(last_dash[6])) {
|
||||
/* <Char-123> or <Char-033> or <Char-0x33> */
|
||||
vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n);
|
||||
// <Char-123> or <Char-033> or <Char-0x33>
|
||||
vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n);
|
||||
key = (int)n;
|
||||
} else {
|
||||
/*
|
||||
* Modifier with single letter, or special key name.
|
||||
*/
|
||||
if (has_mbyte)
|
||||
if (has_mbyte) {
|
||||
l = mb_ptr2len(last_dash + 1);
|
||||
else
|
||||
} else {
|
||||
l = 1;
|
||||
if (modifiers != 0 && last_dash[l + 1] == '>')
|
||||
}
|
||||
if (modifiers != 0 && last_dash[l + 1] == '>') {
|
||||
key = PTR2CHAR(last_dash + 1);
|
||||
else {
|
||||
} else {
|
||||
key = get_special_key_code(last_dash + 1);
|
||||
if (!keep_x_key)
|
||||
if (!keep_x_key) {
|
||||
key = handle_x_keys(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get_special_key_code() may return NUL for invalid
|
||||
* special key name.
|
||||
*/
|
||||
// get_special_key_code() may return NUL for invalid
|
||||
// special key name.
|
||||
if (key != NUL) {
|
||||
/*
|
||||
* Only use a modifier when there is no special key code that
|
||||
* includes the modifier.
|
||||
*/
|
||||
// Only use a modifier when there is no special key code that
|
||||
// includes the modifier.
|
||||
key = simplify_key(key, &modifiers);
|
||||
|
||||
if (!keycode) {
|
||||
/* don't want keycode, use single byte code */
|
||||
if (key == K_BS)
|
||||
// don't want keycode, use single byte code
|
||||
if (key == K_BS) {
|
||||
key = BS;
|
||||
else if (key == K_DEL || key == K_KDEL)
|
||||
} else if (key == K_DEL || key == K_KDEL) {
|
||||
key = DEL;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal Key with modifier:
|
||||
|
@ -3037,7 +3037,7 @@ static double tv_float(typval_T *tvs, int *idxp)
|
||||
* http://www.ijs.si/software/snprintf/
|
||||
*
|
||||
* This snprintf() only supports the following conversion specifiers:
|
||||
* s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
|
||||
* s, c, b, B, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
|
||||
* with flags: '-', '+', ' ', '0' and '#'.
|
||||
* An asterisk is supported for field width as well as precision.
|
||||
*
|
||||
@ -3103,8 +3103,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
char *p = fmt;
|
||||
int arg_idx = 1;
|
||||
|
||||
if (!p)
|
||||
if (!p) {
|
||||
p = "";
|
||||
}
|
||||
while (*p) {
|
||||
if (*p != '%') {
|
||||
// copy up to the next '%' or NUL without any changes
|
||||
@ -3176,9 +3177,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
if (*p == '*') {
|
||||
p++;
|
||||
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
|
||||
if (j >= 0)
|
||||
if (j >= 0) {
|
||||
min_field_width = j;
|
||||
else {
|
||||
} else {
|
||||
min_field_width = -j;
|
||||
justify_left = 1;
|
||||
}
|
||||
@ -3187,8 +3188,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
// argument like common implementations do
|
||||
unsigned int uj = *p++ - '0';
|
||||
|
||||
while (ascii_isdigit((int)(*p)))
|
||||
while (ascii_isdigit((int)(*p))) {
|
||||
uj = 10 * uj + (unsigned int)(*p++ - '0');
|
||||
}
|
||||
min_field_width = uj;
|
||||
}
|
||||
|
||||
@ -3199,9 +3201,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
if (*p == '*') {
|
||||
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
|
||||
p++;
|
||||
if (j >= 0)
|
||||
if (j >= 0) {
|
||||
precision = j;
|
||||
else {
|
||||
} else {
|
||||
precision_specified = 0;
|
||||
precision = 0;
|
||||
}
|
||||
@ -3210,8 +3212,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
// treat argument like common implementations do
|
||||
unsigned int uj = *p++ - '0';
|
||||
|
||||
while (ascii_isdigit((int)(*p)))
|
||||
while (ascii_isdigit((int)(*p))) {
|
||||
uj = 10 * uj + (unsigned int)(*p++ - '0');
|
||||
}
|
||||
precision = uj;
|
||||
}
|
||||
}
|
||||
@ -3262,14 +3265,13 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
if (!str_arg) {
|
||||
str_arg = "[NULL]";
|
||||
str_arg_l = 6;
|
||||
}
|
||||
// make sure not to address string beyond the specified precision
|
||||
else if (!precision_specified)
|
||||
} else if (!precision_specified) {
|
||||
// make sure not to address string beyond the specified precision
|
||||
str_arg_l = strlen(str_arg);
|
||||
// truncate string if necessary as requested by precision
|
||||
else if (precision == 0)
|
||||
} else if (precision == 0) {
|
||||
// truncate string if necessary as requested by precision
|
||||
str_arg_l = 0;
|
||||
else {
|
||||
} else {
|
||||
// memchr on HP does not like n > 2^31
|
||||
// TODO(elmart): check if this still holds / is relevant
|
||||
str_arg_l = (size_t)((char *)xmemscan(str_arg,
|
||||
@ -3283,8 +3285,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
- mb_string2cells((char_u *) str_arg);
|
||||
if (precision) {
|
||||
char_u *p1 = (char_u *)str_arg;
|
||||
for (size_t i = 0; i < precision && *p1; i++)
|
||||
for (size_t i = 0; i < precision && *p1; i++) {
|
||||
p1 += mb_ptr2len(p1);
|
||||
}
|
||||
str_arg_l = precision = p1 - (char_u *)str_arg;
|
||||
}
|
||||
}
|
||||
@ -3295,9 +3298,14 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
|
||||
// u, o, x, X and p conversion specifiers imply the value is unsigned;
|
||||
// d implies a signed value
|
||||
case 'd':
|
||||
case 'u':
|
||||
case 'b': case 'B':
|
||||
case 'o':
|
||||
case 'x': case 'X':
|
||||
case 'p': {
|
||||
// u, b, B, o, x, X and p conversion specifiers imply
|
||||
// the value is unsigned; d implies a signed value
|
||||
|
||||
// 0 if numeric argument is zero (or if pointer is NULL for 'p'),
|
||||
// +1 if greater than zero (or non NULL for 'p'),
|
||||
@ -3325,8 +3333,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
if (fmt_spec == 'p') {
|
||||
length_modifier = '\0';
|
||||
ptr_arg = tvs ? (void *)tv_str(tvs, &arg_idx) : va_arg(ap, void *);
|
||||
if (ptr_arg)
|
||||
if (ptr_arg) {
|
||||
arg_sign = 1;
|
||||
}
|
||||
} else if (fmt_spec == 'd') {
|
||||
// signed
|
||||
switch (length_modifier) {
|
||||
@ -3334,25 +3343,28 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
case 'h':
|
||||
// char and short arguments are passed as int
|
||||
int_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
|
||||
if (int_arg > 0)
|
||||
if (int_arg > 0) {
|
||||
arg_sign = 1;
|
||||
else if (int_arg < 0)
|
||||
} else if (int_arg < 0) {
|
||||
arg_sign = -1;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
long_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, long int);
|
||||
if (long_arg > 0)
|
||||
if (long_arg > 0) {
|
||||
arg_sign = 1;
|
||||
else if (long_arg < 0)
|
||||
} else if (long_arg < 0) {
|
||||
arg_sign = -1;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
long_long_arg = tvs ? tv_nr(tvs, &arg_idx)
|
||||
: va_arg(ap, long long int);
|
||||
if (long_long_arg > 0)
|
||||
: va_arg(ap, long long int); // NOLINT (runtime/int)
|
||||
if (long_long_arg > 0) {
|
||||
arg_sign = 1;
|
||||
else if (long_long_arg < 0)
|
||||
} else if (long_long_arg < 0) {
|
||||
arg_sign = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@ -3362,24 +3374,23 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
case 'h':
|
||||
uint_arg = tvs ? (unsigned)tv_nr(tvs, &arg_idx)
|
||||
: va_arg(ap, unsigned int);
|
||||
if (uint_arg != 0)
|
||||
arg_sign = 1;
|
||||
if (uint_arg != 0) { arg_sign = 1; }
|
||||
break;
|
||||
case 'l':
|
||||
ulong_arg = tvs ? (unsigned long)tv_nr(tvs, &arg_idx)
|
||||
: va_arg(ap, unsigned long int);
|
||||
if (ulong_arg != 0)
|
||||
arg_sign = 1;
|
||||
if (ulong_arg != 0) { arg_sign = 1; }
|
||||
break;
|
||||
case '2':
|
||||
ulong_long_arg = tvs ? (unsigned long long)tv_nr(tvs, &arg_idx)
|
||||
: va_arg(ap, unsigned long long int);
|
||||
if (ulong_long_arg) arg_sign = 1;
|
||||
ulong_long_arg = tvs
|
||||
? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int)
|
||||
: va_arg(ap, unsigned long long int); // NOLINT (runtime/int)
|
||||
if (ulong_long_arg) { arg_sign = 1; }
|
||||
break;
|
||||
case 'z':
|
||||
size_t_arg = tvs ? (size_t)tv_nr(tvs, &arg_idx)
|
||||
: va_arg(ap, size_t);
|
||||
if (size_t_arg) arg_sign = 1;
|
||||
if (size_t_arg) { arg_sign = 1; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3390,16 +3401,19 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
// For d, i, u, o, x, and X conversions, if precision is specified,
|
||||
// '0' flag should be ignored. This is so with Solaris 2.6, Digital UNIX
|
||||
// 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
|
||||
if (precision_specified)
|
||||
if (precision_specified) {
|
||||
zero_padding = 0;
|
||||
}
|
||||
|
||||
if (fmt_spec == 'd') {
|
||||
if (force_sign && arg_sign >= 0)
|
||||
if (force_sign && arg_sign >= 0) {
|
||||
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
|
||||
}
|
||||
// leave negative numbers for sprintf to handle, to
|
||||
// avoid handling tricky cases like (short int)-32768
|
||||
} else if (alternate_form) {
|
||||
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) {
|
||||
if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' ||
|
||||
fmt_spec == 'b' || fmt_spec == 'B')) {
|
||||
tmp[str_arg_l++] = '0';
|
||||
tmp[str_arg_l++] = fmt_spec;
|
||||
}
|
||||
@ -3407,20 +3421,20 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
}
|
||||
|
||||
zero_padding_insertion_ind = str_arg_l;
|
||||
if (!precision_specified)
|
||||
if (!precision_specified) {
|
||||
precision = 1; // default precision is 1
|
||||
}
|
||||
if (precision == 0 && arg_sign == 0) {
|
||||
// when zero value is formatted with an explicit precision 0,
|
||||
// resulting formatted string is empty (d, i, u, o, x, X, p)
|
||||
// resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
|
||||
} else {
|
||||
char f[5];
|
||||
int f_l = 0;
|
||||
|
||||
// construct a simple format string for sprintf
|
||||
f[f_l++] = '%';
|
||||
if (!length_modifier)
|
||||
;
|
||||
else if (length_modifier == '2') {
|
||||
if (!length_modifier) {
|
||||
} else if (length_modifier == '2') {
|
||||
f[f_l++] = 'l';
|
||||
f[f_l++] = 'l';
|
||||
} else
|
||||
@ -3441,6 +3455,41 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
case '2': str_arg_l += sprintf(tmp + str_arg_l, f, long_long_arg);
|
||||
break;
|
||||
}
|
||||
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
|
||||
// binary
|
||||
size_t bits = 0;
|
||||
switch (length_modifier) {
|
||||
case '\0':
|
||||
case 'h': for (bits = sizeof(unsigned) * 8; bits > 0; bits--) {
|
||||
if ((uint_arg >> (bits - 1)) & 0x1) { break; } }
|
||||
|
||||
while (bits > 0) {
|
||||
tmp[str_arg_l++] =
|
||||
((uint_arg >> --bits) & 0x1) ? '1' : '0'; }
|
||||
break;
|
||||
case 'l': for (bits = sizeof(unsigned long) * 8; bits > 0; bits--) {
|
||||
if ((ulong_arg >> (bits - 1)) & 0x1) { break; } }
|
||||
|
||||
while (bits > 0) {
|
||||
tmp[str_arg_l++] =
|
||||
((ulong_arg >> --bits) & 0x1) ? '1' : '0'; }
|
||||
break;
|
||||
case '2': for (bits = sizeof(unsigned long long) * 8; // NOLINT (runtime/int)
|
||||
bits > 0; bits--) {
|
||||
if ((ulong_long_arg >> (bits - 1)) & 0x1) { break; } }
|
||||
|
||||
while (bits > 0) {
|
||||
tmp[str_arg_l++] =
|
||||
((ulong_long_arg >> --bits) & 0x1) ? '1' : '0'; }
|
||||
break;
|
||||
case 'z': for (bits = sizeof(size_t) * 8; bits > 0; bits--) {
|
||||
if ((size_t_arg >> (bits - 1)) & 0x1) { break; } }
|
||||
|
||||
while (bits > 0) {
|
||||
tmp[str_arg_l++] =
|
||||
((size_t_arg >> --bits) & 0x1) ? '1' : '0'; }
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// unsigned
|
||||
switch (length_modifier) {
|
||||
@ -3464,7 +3513,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
if (zero_padding_insertion_ind + 1 < str_arg_l
|
||||
&& tmp[zero_padding_insertion_ind] == '0'
|
||||
&& (tmp[zero_padding_insertion_ind + 1] == 'x'
|
||||
|| tmp[zero_padding_insertion_ind + 1] == 'X'))
|
||||
|| tmp[zero_padding_insertion_ind + 1] == 'X'
|
||||
|| tmp[zero_padding_insertion_ind + 1] == 'b'
|
||||
|| tmp[zero_padding_insertion_ind + 1] == 'B'))
|
||||
zero_padding_insertion_ind += 2;
|
||||
}
|
||||
|
||||
@ -3507,7 +3558,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
// floating point
|
||||
char format[40];
|
||||
int l;
|
||||
int remove_trailing_zeroes = FALSE;
|
||||
int remove_trailing_zeroes = false;
|
||||
|
||||
double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
|
||||
double abs_f = f < 0 ? -f : f;
|
||||
@ -3518,7 +3569,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
|
||||
fmt_spec = 'f';
|
||||
else
|
||||
fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
|
||||
remove_trailing_zeroes = TRUE;
|
||||
remove_trailing_zeroes = true;
|
||||
}
|
||||
|
||||
if (fmt_spec == 'f' && abs_f > 1.0e307) {
|
||||
|
273
src/nvim/ops.c
273
src/nvim/ops.c
@ -4186,75 +4186,102 @@ static void reverse_line(char_u *s)
|
||||
|
||||
# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
|
||||
|
||||
/*
|
||||
* add or subtract 'Prenum1' from a number in a line
|
||||
* 'command' is CTRL-A for add, CTRL-X for subtract
|
||||
*
|
||||
* return FAIL for failure, OK otherwise
|
||||
*/
|
||||
/// Add or subtract from a number in a line.
|
||||
///
|
||||
/// @param command CTRL-A for add, CTRL-X for subtract
|
||||
// @param Prenum1 number to add or subtract
|
||||
///
|
||||
/// @return FAIL for failure, OK otherwise
|
||||
int do_addsub(int command, linenr_T Prenum1)
|
||||
{
|
||||
int col;
|
||||
char_u *buf1;
|
||||
char_u buf2[NUMBUFLEN];
|
||||
int hex; /* 'X' or 'x': hex; '0': octal */
|
||||
static int hexupper = FALSE; /* 0xABC */
|
||||
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
|
||||
static int hexupper = false; // 0xABC
|
||||
unsigned long n, oldn;
|
||||
char_u *ptr;
|
||||
int c;
|
||||
int length = 0; /* character length of the number */
|
||||
int length = 0; // character length of the number
|
||||
int todel;
|
||||
int dohex;
|
||||
int dooct;
|
||||
int dobin;
|
||||
int doalp;
|
||||
int firstdigit;
|
||||
int negative;
|
||||
int subtract;
|
||||
|
||||
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
|
||||
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
|
||||
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
|
||||
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
|
||||
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
|
||||
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
|
||||
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
|
||||
|
||||
ptr = get_cursor_line_ptr();
|
||||
RLADDSUBFIX(ptr);
|
||||
|
||||
/*
|
||||
* First check if we are on a hexadecimal number, after the "0x".
|
||||
*/
|
||||
// First check if we are on a hexadecimal number, after the "0x".
|
||||
col = curwin->w_cursor.col;
|
||||
if (dohex)
|
||||
while (col > 0 && ascii_isxdigit(ptr[col]))
|
||||
--col;
|
||||
if ( dohex
|
||||
&& col > 0
|
||||
&& (ptr[col] == 'X'
|
||||
|| ptr[col] == 'x')
|
||||
&& ptr[col - 1] == '0'
|
||||
&& ascii_isxdigit(ptr[col + 1])) {
|
||||
/*
|
||||
* Found hexadecimal number, move to its start.
|
||||
*/
|
||||
--col;
|
||||
|
||||
if (dobin) {
|
||||
while (col > 0 && ascii_isbdigit(ptr[col])) {
|
||||
col--;
|
||||
}
|
||||
}
|
||||
|
||||
if (dohex) {
|
||||
while (col > 0 && ascii_isxdigit(ptr[col])) {
|
||||
col--;
|
||||
}
|
||||
}
|
||||
if (dobin
|
||||
&& dohex
|
||||
&& !((col > 0
|
||||
&& (ptr[col] == 'X' ||
|
||||
ptr[col] == 'x')
|
||||
&& ptr[col - 1] == '0'
|
||||
&& ascii_isxdigit(ptr[col + 1])))) {
|
||||
// In case of binary/hexadecimal pattern overlap match, rescan
|
||||
|
||||
col = curwin->w_cursor.col;
|
||||
|
||||
while (col > 0 && ascii_isdigit(ptr[col])) {
|
||||
col--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dohex
|
||||
&& col > 0
|
||||
&& (ptr[col] == 'X'
|
||||
|| ptr[col] == 'x')
|
||||
&& ptr[col - 1] == '0'
|
||||
&& ascii_isxdigit(ptr[col + 1])) ||
|
||||
(dobin
|
||||
&& col > 0
|
||||
&& (ptr[col] == 'B'
|
||||
|| ptr[col] == 'b')
|
||||
&& ptr[col - 1] == '0'
|
||||
&& ascii_isbdigit(ptr[col + 1]))) {
|
||||
// Found hexadecimal or binary number, move to its start.
|
||||
col--;
|
||||
} else {
|
||||
/*
|
||||
* Search forward and then backward to find the start of number.
|
||||
*/
|
||||
// Search forward and then backward to find the start of number.
|
||||
col = curwin->w_cursor.col;
|
||||
|
||||
while (ptr[col] != NUL
|
||||
&& !ascii_isdigit(ptr[col])
|
||||
&& !(doalp && ASCII_ISALPHA(ptr[col])))
|
||||
++col;
|
||||
&& !(doalp && ASCII_ISALPHA(ptr[col]))) {
|
||||
col++;
|
||||
}
|
||||
|
||||
while (col > 0
|
||||
&& ascii_isdigit(ptr[col - 1])
|
||||
&& !(doalp && ASCII_ISALPHA(ptr[col])))
|
||||
--col;
|
||||
&& !(doalp && ASCII_ISALPHA(ptr[col]))) {
|
||||
col--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If a number was found, and saving for undo works, replace the number.
|
||||
*/
|
||||
// If a number was found, and saving for undo works, replace the number.
|
||||
firstdigit = ptr[col];
|
||||
RLADDSUBFIX(ptr);
|
||||
if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
|
||||
@ -4263,152 +4290,170 @@ int do_addsub(int command, linenr_T Prenum1)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
/* get ptr again, because u_save() may have changed it */
|
||||
// get ptr again, because u_save() may have changed it
|
||||
ptr = get_cursor_line_ptr();
|
||||
RLADDSUBFIX(ptr);
|
||||
|
||||
if (doalp && ASCII_ISALPHA(firstdigit)) {
|
||||
/* decrement or increment alphabetic character */
|
||||
// decrement or increment alphabetic character
|
||||
if (command == Ctrl_X) {
|
||||
if (CharOrd(firstdigit) < Prenum1) {
|
||||
if (isupper(firstdigit))
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'A';
|
||||
else
|
||||
} else {
|
||||
firstdigit = 'a';
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
firstdigit -= Prenum1;
|
||||
}
|
||||
} else {
|
||||
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
|
||||
if (isupper(firstdigit))
|
||||
if (isupper(firstdigit)) {
|
||||
firstdigit = 'Z';
|
||||
else
|
||||
} else {
|
||||
firstdigit = 'z';
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
firstdigit += Prenum1;
|
||||
}
|
||||
}
|
||||
curwin->w_cursor.col = col;
|
||||
(void)del_char(FALSE);
|
||||
(void)del_char(false);
|
||||
ins_char(firstdigit);
|
||||
} else {
|
||||
negative = FALSE;
|
||||
if (col > 0 && ptr[col - 1] == '-') { /* negative number */
|
||||
negative = false;
|
||||
if (col > 0 && ptr[col - 1] == '-') { // negative number
|
||||
--col;
|
||||
negative = TRUE;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
/* get the number value (unsigned) */
|
||||
vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
|
||||
// get the number value (unsigned)
|
||||
vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n);
|
||||
|
||||
/* ignore leading '-' for hex and octal numbers */
|
||||
if (hex && negative) {
|
||||
// ignore leading '-' for hex, octal and bin numbers
|
||||
if (pre && negative) {
|
||||
++col;
|
||||
--length;
|
||||
negative = FALSE;
|
||||
negative = false;
|
||||
}
|
||||
|
||||
/* add or subtract */
|
||||
subtract = FALSE;
|
||||
if (command == Ctrl_X)
|
||||
subtract ^= TRUE;
|
||||
if (negative)
|
||||
subtract ^= TRUE;
|
||||
// add or subtract
|
||||
subtract = false;
|
||||
if (command == Ctrl_X) {
|
||||
subtract ^= true;
|
||||
}
|
||||
if (negative) {
|
||||
subtract ^= true;
|
||||
}
|
||||
|
||||
oldn = n;
|
||||
if (subtract)
|
||||
n -= (unsigned long)Prenum1;
|
||||
else
|
||||
n += (unsigned long)Prenum1;
|
||||
|
||||
/* handle wraparound for decimal numbers */
|
||||
if (!hex) {
|
||||
n = subtract ? n - (unsigned long) Prenum1
|
||||
: n + (unsigned long) Prenum1;
|
||||
|
||||
// handle wraparound for decimal numbers
|
||||
if (!pre) {
|
||||
if (subtract) {
|
||||
if (n > oldn) {
|
||||
n = 1 + (n ^ (unsigned long)-1);
|
||||
negative ^= TRUE;
|
||||
negative ^= true;
|
||||
}
|
||||
} else { /* add */
|
||||
if (n < oldn) {
|
||||
n = (n ^ (unsigned long)-1);
|
||||
negative ^= TRUE;
|
||||
negative ^= true;
|
||||
}
|
||||
}
|
||||
if (n == 0)
|
||||
negative = FALSE;
|
||||
if (n == 0) {
|
||||
negative = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete the old number.
|
||||
*/
|
||||
// Delete the old number.
|
||||
curwin->w_cursor.col = col;
|
||||
todel = length;
|
||||
c = gchar_cursor();
|
||||
/*
|
||||
* Don't include the '-' in the length, only the length of the part
|
||||
* after it is kept the same.
|
||||
*/
|
||||
if (c == '-')
|
||||
|
||||
// Don't include the '-' in the length, only the length of the part
|
||||
// after it is kept the same.
|
||||
if (c == '-') {
|
||||
--length;
|
||||
}
|
||||
while (todel-- > 0) {
|
||||
if (c < 0x100 && isalpha(c)) {
|
||||
if (isupper(c))
|
||||
hexupper = TRUE;
|
||||
else
|
||||
hexupper = FALSE;
|
||||
if (isupper(c)) {
|
||||
hexupper = true;
|
||||
} else {
|
||||
hexupper = false;
|
||||
}
|
||||
}
|
||||
/* del_char() will mark line needing displaying */
|
||||
(void)del_char(FALSE);
|
||||
// del_char() will mark line needing displaying
|
||||
(void)del_char(false);
|
||||
c = gchar_cursor();
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the leading characters in buf1[].
|
||||
* When there are many leading zeros it could be very long. Allocate
|
||||
* a bit too much.
|
||||
*/
|
||||
// Prepare the leading characters in buf1[].
|
||||
// When there are many leading zeros it could be very long. Allocate
|
||||
// a bit too much.
|
||||
buf1 = xmalloc(length + NUMBUFLEN);
|
||||
ptr = buf1;
|
||||
if (negative) {
|
||||
*ptr++ = '-';
|
||||
}
|
||||
if (hex) {
|
||||
if (pre) {
|
||||
*ptr++ = '0';
|
||||
--length;
|
||||
}
|
||||
if (hex == 'x' || hex == 'X') {
|
||||
*ptr++ = hex;
|
||||
if (pre == 'b' || pre == 'B' ||
|
||||
pre == 'x' || pre == 'X') {
|
||||
*ptr++ = pre;
|
||||
--length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the number characters in buf2[].
|
||||
*/
|
||||
if (hex == 0)
|
||||
sprintf((char *)buf2, "%" PRIu64, (uint64_t)n);
|
||||
else if (hex == '0')
|
||||
sprintf((char *)buf2, "%" PRIo64, (uint64_t)n);
|
||||
else if (hex && hexupper)
|
||||
sprintf((char *)buf2, "%" PRIX64, (uint64_t)n);
|
||||
else
|
||||
sprintf((char *)buf2, "%" PRIx64, (uint64_t)n);
|
||||
// Put the number characters in buf2[].
|
||||
if (pre == 'b' || pre == 'B') {
|
||||
size_t bits = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
// leading zeros
|
||||
for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) {
|
||||
if ((n >> (bits - 1)) & 0x1) { break; }
|
||||
}
|
||||
|
||||
while (bits > 0) {
|
||||
buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0';
|
||||
}
|
||||
|
||||
buf2[pos] = '\0';
|
||||
|
||||
} else if (pre == 0) {
|
||||
snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n);
|
||||
} else if (pre == '0') {
|
||||
snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n);
|
||||
} else if (pre && hexupper) {
|
||||
snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n);
|
||||
} else {
|
||||
snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n);
|
||||
}
|
||||
length -= (int)STRLEN(buf2);
|
||||
|
||||
/*
|
||||
* Adjust number of zeros to the new number of digits, so the
|
||||
* total length of the number remains the same.
|
||||
* Don't do this when
|
||||
* the result may look like an octal number.
|
||||
*/
|
||||
if (firstdigit == '0' && !(dooct && hex == 0))
|
||||
while (length-- > 0)
|
||||
// Adjust number of zeros to the new number of digits, so the
|
||||
// total length of the number remains the same.
|
||||
// Don't do this when
|
||||
// the result may look like an octal number.
|
||||
if (firstdigit == '0' && !(dooct && pre == 0)) {
|
||||
while (length-- > 0) {
|
||||
*ptr++ = '0';
|
||||
}
|
||||
}
|
||||
*ptr = NUL;
|
||||
STRCAT(buf1, buf2);
|
||||
ins_str(buf1); /* insert the new number */
|
||||
xfree(buf1);
|
||||
}
|
||||
--curwin->w_cursor.col;
|
||||
curwin->w_set_curswant = TRUE;
|
||||
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
|
||||
curwin->w_set_curswant = true;
|
||||
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
|
||||
RLADDSUBFIX(ptr);
|
||||
return OK;
|
||||
}
|
||||
|
@ -258,30 +258,31 @@ typedef struct vimoption {
|
||||
|
||||
#define PARAM_COUNT ARRAY_SIZE(options)
|
||||
|
||||
static char *(p_ambw_values[]) = {"single", "double", NULL};
|
||||
static char *(p_bg_values[]) = {"light", "dark", NULL};
|
||||
static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
|
||||
static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
|
||||
static char *(p_wop_values[]) = {"tagfile", NULL};
|
||||
static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
|
||||
static char *(p_mousem_values[]) =
|
||||
{"extend", "popup", "popup_setpos", "mac", NULL};
|
||||
static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
|
||||
static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
|
||||
static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
|
||||
static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
|
||||
static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
|
||||
static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
|
||||
static char *(p_buftype_values[]) =
|
||||
{"nofile", "nowrite", "quickfix", "help", "acwrite", "terminal", NULL};
|
||||
static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
|
||||
static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
|
||||
static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
|
||||
"diff",
|
||||
NULL};
|
||||
static char *(p_fcl_values[]) = {"all", NULL};
|
||||
static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
|
||||
"noinsert", "noselect", NULL};
|
||||
static char *(p_ambw_values[]) = { "single", "double", NULL };
|
||||
static char *(p_bg_values[]) = { "light", "dark", NULL };
|
||||
static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL };
|
||||
static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
|
||||
static char *(p_wop_values[]) = { "tagfile", NULL };
|
||||
static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
|
||||
static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",
|
||||
"mac", NULL };
|
||||
static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
|
||||
static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
|
||||
static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
|
||||
static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
|
||||
static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
|
||||
static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
|
||||
static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
|
||||
"help", "acwrite", "terminal", NULL };
|
||||
|
||||
static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
|
||||
"wipe", NULL };
|
||||
static char *(p_bs_values[]) = { "indent", "eol", "start", NULL };
|
||||
static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
|
||||
"syntax", "diff", NULL };
|
||||
static char *(p_fcl_values[]) = { "all", NULL };
|
||||
static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
|
||||
"noinsert", "noselect", NULL };
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "option.c.generated.h"
|
||||
@ -1431,7 +1432,7 @@ do_set (
|
||||
} else if (*arg == '-' || ascii_isdigit(*arg)) {
|
||||
// Allow negative (for 'undolevels'), octal and
|
||||
// hex numbers.
|
||||
vim_str2nr(arg, NULL, &i, true, true, &value, NULL);
|
||||
vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL);
|
||||
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
|
||||
errmsg = e_invarg;
|
||||
goto skip;
|
||||
|
@ -1599,7 +1599,7 @@ return {
|
||||
deny_duplicates=true,
|
||||
alloced=true,
|
||||
varname='p_nf',
|
||||
defaults={if_true={vi="octal,hex", vim="hex"}}
|
||||
defaults={if_true={vi="bin,octal,hex", vim="bin,hex"}}
|
||||
},
|
||||
{
|
||||
full_name='number', abbreviation='nu',
|
||||
|
@ -1063,8 +1063,7 @@ static char_u *repl_to = NULL;
|
||||
//
|
||||
// Returns the length of the word in bytes, also when it's OK, so that the
|
||||
// caller can skip over the word.
|
||||
size_t
|
||||
spell_check (
|
||||
size_t spell_check(
|
||||
win_T *wp, // current window
|
||||
char_u *ptr,
|
||||
hlf_T *attrp,
|
||||
@ -1082,12 +1081,14 @@ spell_check (
|
||||
|
||||
// A word never starts at a space or a control character. Return quickly
|
||||
// then, skipping over the character.
|
||||
if (*ptr <= ' ')
|
||||
if (*ptr <= ' ') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Return here when loading language files failed.
|
||||
if (GA_EMPTY(&wp->w_s->b_langp))
|
||||
if (GA_EMPTY(&wp->w_s->b_langp)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(&mi, 0, sizeof(matchinf_T));
|
||||
|
||||
@ -1095,10 +1096,13 @@ spell_check (
|
||||
// 0X99FF. But always do check spelling to find "3GPP" and "11
|
||||
// julifeest".
|
||||
if (*ptr >= '0' && *ptr <= '9') {
|
||||
if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
|
||||
if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) {
|
||||
mi.mi_end = (char_u*) skipbin((char*) ptr + 2);
|
||||
} else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
|
||||
mi.mi_end = skiphex(ptr + 2);
|
||||
else
|
||||
} else {
|
||||
mi.mi_end = skipdigits(ptr);
|
||||
}
|
||||
nrlen = (size_t)(mi.mi_end - ptr);
|
||||
}
|
||||
|
||||
@ -1113,12 +1117,14 @@ spell_check (
|
||||
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) {
|
||||
// Check word starting with capital letter.
|
||||
c = PTR2CHAR(ptr);
|
||||
if (!SPELL_ISUPPER(c))
|
||||
if (!SPELL_ISUPPER(c)) {
|
||||
wrongcaplen = (size_t)(mi.mi_fend - ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (capcol != NULL)
|
||||
if (capcol != NULL) {
|
||||
*capcol = -1;
|
||||
}
|
||||
|
||||
// We always use the characters up to the next non-word character,
|
||||
// also for bad words.
|
||||
@ -1131,8 +1137,9 @@ spell_check (
|
||||
|
||||
// case-fold the word with one non-word character, so that we can check
|
||||
// for the word end.
|
||||
if (*mi.mi_fend != NUL)
|
||||
if (*mi.mi_fend != NUL) {
|
||||
mb_ptr_adv(mi.mi_fend);
|
||||
}
|
||||
|
||||
(void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1);
|
||||
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
|
||||
@ -1149,8 +1156,9 @@ spell_check (
|
||||
|
||||
// If reloading fails the language is still in the list but everything
|
||||
// has been cleared.
|
||||
if (mi.mi_lp->lp_slang->sl_fidxs == NULL)
|
||||
if (mi.mi_lp->lp_slang->sl_fidxs == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for a matching word in case-folded words.
|
||||
find_word(&mi, FIND_FOLDWORD);
|
||||
@ -1181,18 +1189,18 @@ spell_check (
|
||||
// If we found a number skip over it. Allows for "42nd". Do flag
|
||||
// rare and local words, e.g., "3GPP".
|
||||
if (nrlen > 0) {
|
||||
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
|
||||
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
|
||||
return nrlen;
|
||||
}
|
||||
}
|
||||
} else if (!spell_iswordp_nmw(ptr, wp)) {
|
||||
// When we are at a non-word character there is no error, just
|
||||
// skip over the character (try looking for a word after it).
|
||||
else if (!spell_iswordp_nmw(ptr, wp)) {
|
||||
if (capcol != NULL && wp->w_s->b_cap_prog != NULL) {
|
||||
regmatch_T regmatch;
|
||||
|
||||
// Check for end of sentence.
|
||||
regmatch.regprog = wp->w_s->b_cap_prog;
|
||||
regmatch.rm_ic = FALSE;
|
||||
regmatch.rm_ic = false;
|
||||
int r = vim_regexec(®match, ptr, 0);
|
||||
wp->w_s->b_cap_prog = regmatch.regprog;
|
||||
if (r) {
|
||||
@ -1204,12 +1212,12 @@ spell_check (
|
||||
return (size_t)(*mb_ptr2len)(ptr);
|
||||
}
|
||||
return 1;
|
||||
} else if (mi.mi_end == ptr)
|
||||
} else if (mi.mi_end == ptr) {
|
||||
// Always include at least one character. Required for when there
|
||||
// is a mixup in "midword".
|
||||
mb_ptr_adv(mi.mi_end);
|
||||
else if (mi.mi_result == SP_BAD
|
||||
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
|
||||
} else if (mi.mi_result == SP_BAD
|
||||
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
|
||||
char_u *p, *fp;
|
||||
int save_result = mi.mi_result;
|
||||
|
||||
@ -1219,11 +1227,12 @@ spell_check (
|
||||
if (mi.mi_lp->lp_slang->sl_fidxs != NULL) {
|
||||
p = mi.mi_word;
|
||||
fp = mi.mi_fword;
|
||||
for (;; ) {
|
||||
for (;;) {
|
||||
mb_ptr_adv(p);
|
||||
mb_ptr_adv(fp);
|
||||
if (p >= mi.mi_end)
|
||||
if (p >= mi.mi_end) {
|
||||
break;
|
||||
}
|
||||
mi.mi_compoff = (int)(fp - mi.mi_fword);
|
||||
find_word(&mi, FIND_COMPOUND);
|
||||
if (mi.mi_result != SP_BAD) {
|
||||
@ -1235,12 +1244,13 @@ spell_check (
|
||||
}
|
||||
}
|
||||
|
||||
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
|
||||
if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
|
||||
*attrp = HLF_SPB;
|
||||
else if (mi.mi_result == SP_RARE)
|
||||
} else if (mi.mi_result == SP_RARE) {
|
||||
*attrp = HLF_SPR;
|
||||
else
|
||||
} else {
|
||||
*attrp = HLF_SPL;
|
||||
}
|
||||
}
|
||||
|
||||
if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE)) {
|
||||
|
@ -35,7 +35,7 @@ Error: configure did not run properly.Check auto/config.log.
|
||||
|
||||
#include "nvim/os/os_defs.h" /* bring lots of system header files */
|
||||
|
||||
#define NUMBUFLEN 30 /* length of a buffer to store a number in ASCII */
|
||||
#define NUMBUFLEN 65 // length of a buffer to store a number in ASCII
|
||||
|
||||
#define MAX_TYPENR 65535
|
||||
|
||||
|
58
test/functional/eval/printf_spec.lua
Normal file
58
test/functional/eval/printf_spec.lua
Normal file
@ -0,0 +1,58 @@
|
||||
local helpers = require('test.functional.helpers')
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local funcs = helpers.funcs
|
||||
local exc_exec = helpers.exc_exec
|
||||
|
||||
describe('printf()', function()
|
||||
it('works with zero and %b', function()
|
||||
eq('0', funcs.printf('%lb', 0))
|
||||
eq('0', funcs.printf('%llb', 0))
|
||||
eq('0', funcs.printf('%zb', 0))
|
||||
end)
|
||||
it('works with one and %b', function()
|
||||
eq('1', funcs.printf('%b', 1))
|
||||
eq('1', funcs.printf('%lb', 1))
|
||||
eq('1', funcs.printf('%llb', 1))
|
||||
eq('1', funcs.printf('%zb', 1))
|
||||
end)
|
||||
it('works with 0xff and %b', function()
|
||||
eq('11111111', funcs.printf('%b', 0xff))
|
||||
eq('11111111', funcs.printf('%lb', 0xff))
|
||||
eq('11111111', funcs.printf('%llb', 0xff))
|
||||
eq('11111111', funcs.printf('%zb', 0xff))
|
||||
end)
|
||||
it('accepts width modifier with %b', function()
|
||||
eq(' 1', funcs.printf('%3b', 1))
|
||||
end)
|
||||
it('accepts prefix modifier with %b', function()
|
||||
eq('0b1', funcs.printf('%#b', 1))
|
||||
end)
|
||||
it('writes capital B with %B', function()
|
||||
eq('0B1', funcs.printf('%#B', 1))
|
||||
end)
|
||||
it('accepts prefix, zero-fill and width modifiers with %b', function()
|
||||
eq('0b001', funcs.printf('%#05b', 1))
|
||||
end)
|
||||
it('accepts prefix and width modifiers with %b', function()
|
||||
eq(' 0b1', funcs.printf('%#5b', 1))
|
||||
end)
|
||||
it('does not write prefix for zero with prefix and width modifier used with %b', function()
|
||||
eq(' 0', funcs.printf('%#5b', 0))
|
||||
end)
|
||||
it('accepts precision modifier with %b', function()
|
||||
eq('00000', funcs.printf('%.5b', 0))
|
||||
end)
|
||||
it('accepts all modifiers with %b at once', function()
|
||||
-- zero-fill modifier is ignored when used with left-align
|
||||
-- force-sign and add-blank are ignored
|
||||
-- use-grouping-characters modifier is ignored always
|
||||
eq('0b00011 ', funcs.printf('% \'+#0-10.5b', 3))
|
||||
end)
|
||||
it('errors out when %b modifier is used for a list', function()
|
||||
eq('Vim(call):E745: Using a List as a Number', exc_exec('call printf("%b", [])'))
|
||||
end)
|
||||
it('errors out when %b modifier is used for a float', function()
|
||||
eq('Vim(call):E805: Using a Float as a Number', exc_exec('call printf("%b", 3.1415926535)'))
|
||||
end)
|
||||
end)
|
@ -11,34 +11,40 @@ describe('increment and decrement commands', function()
|
||||
it('should work', function()
|
||||
-- Insert some numbers in various bases.
|
||||
insert([[
|
||||
100 0x100 077 0
|
||||
100 0x100 077
|
||||
0b101 100 0x100 077 0
|
||||
0b101 100 0x100 077
|
||||
100 0x100 077 0xfF 0xFf
|
||||
100 0x100 077]])
|
||||
100 0x100 077
|
||||
0x0b101 0b1101]])
|
||||
|
||||
-- Increment and decrement numbers in the first row, interpreting the
|
||||
-- numbers as decimal, octal or hexadecimal.
|
||||
execute('set nrformats=octal,hex', '1')
|
||||
feed('102ll64128$')
|
||||
execute('set nrformats=bin,octal,hex', '1')
|
||||
feed('63l102ll64128$')
|
||||
|
||||
-- For the second row, treat the numbers as decimal or octal.
|
||||
-- 0x100 should be interpreted as decimal 0, the character x, and decimal 100.
|
||||
execute('set nrformats=octal', '2')
|
||||
feed('0102l2w65129blx6lD')
|
||||
feed('0w102l2w65129blx6lD')
|
||||
|
||||
-- For the third row, treat the numbers as decimal or hexadecimal.
|
||||
-- 077 should be interpreted as decimal 77.
|
||||
execute('set nrformats=hex', '3')
|
||||
feed('0101l257Txldt ')
|
||||
|
||||
-- For the last row, interpret all numbers as decimal.
|
||||
-- For the fourth row, interpret all numbers as decimal.
|
||||
execute('set nrformats=', '4')
|
||||
feed('0200l100w78')
|
||||
|
||||
-- For the last row, interpret as binary and hexadecimal.
|
||||
execute('set nrformats=bin,hex', '5')
|
||||
feed('010065l6432')
|
||||
|
||||
expect([[
|
||||
0 0x0ff 0000 -1
|
||||
0 1x100 0777777
|
||||
0b011 0 0x0ff 0000 -1
|
||||
1b101 0 1x100 0777777
|
||||
-1 0x0 078 0xFE 0xfe
|
||||
-100 -100x100 000]])
|
||||
-100 -100x100 000
|
||||
0x0b0de 0b0101101]])
|
||||
end)
|
||||
end)
|
||||
|
@ -600,4 +600,39 @@ describe(':sort', function()
|
||||
eq('Vim(sort):E474: Invalid argument', eval('tmpvar'))
|
||||
expect(text)
|
||||
end)
|
||||
|
||||
it('binary', function()
|
||||
insert([[
|
||||
0b111000
|
||||
0b101100
|
||||
0b101001
|
||||
0b101001
|
||||
0b101000
|
||||
0b000000
|
||||
0b001000
|
||||
0b010000
|
||||
0b101000
|
||||
0b100000
|
||||
0b101010
|
||||
0b100010
|
||||
0b100100
|
||||
0b100010]])
|
||||
execute([[sort b]])
|
||||
expect([[
|
||||
0b000000
|
||||
0b001000
|
||||
0b010000
|
||||
0b100000
|
||||
0b100010
|
||||
0b100010
|
||||
0b100100
|
||||
0b101000
|
||||
0b101000
|
||||
0b101001
|
||||
0b101001
|
||||
0b101010
|
||||
0b101100
|
||||
0b111000]])
|
||||
end)
|
||||
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user