aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--runtime/autoload/provider/clipboard.vim1
-rw-r--r--runtime/doc/change.txt19
-rw-r--r--runtime/doc/eval.txt52
-rw-r--r--runtime/doc/windows.txt1
-rwxr-xr-xscripts/vim-patch.sh27
-rw-r--r--src/nvim/ascii.h31
-rw-r--r--src/nvim/charset.c98
-rw-r--r--src/nvim/eval.c331
-rw-r--r--src/nvim/event/libuv_process.c3
-rw-r--r--src/nvim/event/process.c23
-rw-r--r--src/nvim/event/process.h5
-rw-r--r--src/nvim/ex_cmds.c150
-rw-r--r--src/nvim/ex_getln.c31
-rw-r--r--src/nvim/keymap.c79
-rw-r--r--src/nvim/message.c141
-rw-r--r--src/nvim/ops.c305
-rw-r--r--src/nvim/option.c51
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/screen.c88
-rw-r--r--src/nvim/spell.c54
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test39.in106
-rw-r--r--src/nvim/testdir/test39.okbin585 -> 0 bytes
-rw-r--r--src/nvim/version.c4
-rw-r--r--src/nvim/vim.h2
-rw-r--r--test/functional/eval/printf_spec.lua60
-rw-r--r--test/functional/job/job_spec.lua29
-rw-r--r--test/functional/legacy/035_increment_and_decrement_spec.lua26
-rw-r--r--test/functional/legacy/039_visual_block_mode_commands_spec.lua234
-rw-r--r--test/functional/legacy/057_sort_spec.lua35
31 files changed, 1277 insertions, 715 deletions
diff --git a/.gitignore b/.gitignore
index ed452c03a9..23c8fd1957 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,4 +68,4 @@ local.mk
/runtime/doc/errors.log
# clint errors, generated by `make lint`
-errors.json
+/errors.json
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 5d1ce7896d..3728eb9367 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -83,6 +83,7 @@ function! s:clipboard.set(lines, regtype, reg)
end
let selection.data = [a:lines, a:regtype]
let argv = split(s:copy[a:reg], " ")
+ let selection.detach = s:cache_enabled
let jobid = jobstart(argv, selection)
if jobid <= 0
echohl WarningMsg
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 0fa383bc67..42dc84e0de 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -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
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 1f1dc71f28..f0747dad1b 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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 ~
@@ -1894,6 +1896,7 @@ isdirectory( {directory}) Number TRUE if {directory} is a directory
islocked( {expr}) Number TRUE if {expr} is locked
items( {dict}) List key-value pairs in {dict}
jobclose({job}[, {stream}]) Number Closes a job stream(s)
+jobpid({job}) Number Returns pid of a job.
jobresize({job}, {width}, {height})
Number Resize {job}'s pseudo terminal window
jobsend({job}, {data}) Number Writes {data} to {job}'s stdin
@@ -4157,6 +4160,9 @@ jobclose({job}[, {stream}]) {Nvim} *jobclose()*
Close {job}'s {stream}, which can be one "stdin", "stdout" or
"stderr". If {stream} is omitted, all streams are closed.
+jobpid({job}) {Nvim} *jobpid()*
+ Return the pid (process id) of {job}.
+
jobresize({job}, {width}, {height}) {Nvim} *jobresize()*
Resize {job}'s pseudo terminal window to {width} and {height}.
This function will fail if used on jobs started without the
@@ -4194,6 +4200,10 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
- width: Width of the terminal screen(only if pty is set)
- height: Height of the terminal screen(only if pty is set)
- TERM: $TERM environment variable(only if pty is set)
+ - detach: Detach the job process from the nvim process. The
+ process won't get killed when nvim exists. If the process
+ dies before nvim exits, on_exit will still be invoked.
+ This option is only allowed for non-pty jobs.
Either funcrefs or function names can be passed as event
handlers. The {opts} object is also used as the "self"
argument for the callback, so the caller may pass arbitrary
@@ -4911,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
@@ -4997,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
@@ -6126,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.
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 56f57c21c5..eee171b7da 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -681,7 +681,6 @@ can also get to them with the buffer list commands, like ":bnext".
When using the |:tab| modifier each argument is opened in a
tab page. The last window is used if it's empty.
Also see |++opt| and |+cmd|.
- {only available when compiled with a GUI}
==============================================================================
8. Do a command in all buffers or windows *list-repeat*
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index badf747742..bdd3d6209b 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -161,29 +161,19 @@ list_vim_patches() {
printf "\nVim patches missing from Neovim:\n"
- # Get tags since 7.4.442.
- local vim_tags=$(cd "${VIM_SOURCE_DIR}" && git tag --contains v7.4.442)
-
- # Get non-versioned commits since e2719096.
- if git log -1 --grep='.' --invert-grep > /dev/null 2>&1 ; then
- local vim_runtime_commits=$(cd "${VIM_SOURCE_DIR}" && \
- git log --reverse --format='%H' --grep='^patch' --grep='^updated for version' \
- --invert-grep e2719096250a19ecdd9a35d13702879f163d2a50..HEAD)
- else # --invert-grep requires git 2.4+
- echo "Warning: some runtime updates may not be listed (requires git 2.4+)."
- local vim_runtime_commits=$(cd "${VIM_SOURCE_DIR}" && \
- git log --reverse --format='%H' --grep='Updated' e2719096250a19ecdd9a35d13702879f163d2a50..HEAD)
- fi
+ # Get commits since 7.4.602.
+ local vim_commits=$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v7.4.602..HEAD)
local vim_commit
- for vim_commit in ${vim_tags} ${vim_runtime_commits}; do
+ for vim_commit in ${vim_commits}; do
local is_missing
- if [[ ${vim_commit} =~ v([0-9].[0-9].([0-9]{3,4})) ]]; then
- local patch_number="${BASH_REMATCH[2]}"
+ local vim_tag=$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)
+ if [[ -n "${vim_tag}" ]]; then
+ local patch_number="${vim_tag:5}" # Remove prefix like "v7.4."
# Tagged Vim patch, check version.c:
is_missing="$(sed -n '/static int included_patches/,/}/p' "${NEOVIM_SOURCE_DIR}/src/nvim/version.c" |
grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")"
- vim_commit="${BASH_REMATCH[1]//-/.}"
+ vim_commit="${vim_tag#v}"
else
# Untagged Vim patch (e.g. runtime updates), check the Neovim git log:
is_missing="$(cd "${NEOVIM_SOURCE_DIR}" &&
@@ -203,6 +193,9 @@ list_vim_patches() {
echo
echo " Examples: '${BASENAME} -p 7.4.487'"
echo " '${BASENAME} -p 1e8ebf870720e7b671f98f22d653009826304c4f'"
+ echo
+ echo " NOTE: Please port the _oldest_ patch if you possibly can."
+ echo " Out-of-order patches increase the possibility of bugs."
}
review_pr() {
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 2b3e94d5a0..44ff540b40 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -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.
///
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index b93eafbf60..e0c9443511 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -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) {
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 7ac51d7bd7..a5a8671697 100644
--- a/src/nvim/eval.c
+++ b/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) {
@@ -7236,6 +7219,7 @@ static struct fst {
{ "islocked", 1, 1, f_islocked },
{ "items", 1, 1, f_items },
{ "jobclose", 1, 2, f_jobclose },
+ { "jobpid", 1, 1, f_jobpid },
{ "jobresize", 3, 3, f_jobresize },
{ "jobsend", 2, 2, f_jobsend },
{ "jobstart", 1, 2, f_jobstart },
@@ -11611,6 +11595,31 @@ static void f_jobclose(typval_T *argvars, typval_T *rettv)
}
}
+// "jobpid(id)" function
+static void f_jobpid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
+ EMSG(_(e_invjob));
+ return;
+ }
+
+ Process *proc = (Process *)&data->proc;
+ rettv->vval.v_number = proc->pid;
+}
+
// "jobsend()" function
static void f_jobsend(typval_T *argvars, typval_T *rettv)
{
@@ -11771,8 +11780,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
}
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
+ bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, pty);
+ job_opts, pty, detach);
Process *proc = (Process *)&data->proc;
if (pty) {
@@ -15971,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;
@@ -15982,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;
}
@@ -16776,7 +16789,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
}
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, true);
+ job_opts, true, false);
data->proc.pty.width = curwin->w_width;
data->proc.pty.height = curwin->w_height;
data->proc.pty.term_name = xstrdup("xterm-256color");
@@ -18271,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"));
@@ -18285,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;
}
@@ -21782,8 +21798,13 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)
return ret;
}
-static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
- ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty)
+static inline TerminalJobData *common_job_init(char **argv,
+ ufunc_T *on_stdout,
+ ufunc_T *on_stderr,
+ ufunc_T *on_exit,
+ dict_T *self,
+ bool pty,
+ bool detach)
{
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
data->stopped = false;
@@ -21806,6 +21827,7 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
}
proc->cb = on_process_exit;
proc->events = data->events;
+ proc->detach = detach;
return data;
}
@@ -21833,8 +21855,13 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,
static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)
{
- data->refcount++;
Process *proc = (Process *)&data->proc;
+ if (proc->type == kProcessTypePty && proc->detach) {
+ EMSG2(_(e_invarg2), "terminal/pty job cannot be detached");
+ return false;
+ }
+
+ data->refcount++;
char *cmd = xstrdup(proc->argv[0]);
if (!process_spawn(proc)) {
EMSG2(_(e_jobspawn), cmd);
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 44305c69bc..9ef3468284 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -21,6 +21,9 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE
| UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
+ if (proc->detach) {
+ uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
+ }
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = NULL;
uvproc->uvopts.env = NULL;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 0336eb880a..e6012595fd 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -29,6 +29,7 @@
} \
} while (0)
+static bool process_is_tearing_down = false;
bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
{
@@ -112,11 +113,22 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
{
+ process_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
- uv_kill(proc->pid, SIGTERM);
- proc->term_sent = true;
- process_stop(proc);
+ if (proc->detach) {
+ // Close handles to process without killing it.
+ CREATE_EVENT(loop->events, process_close_handles, 1, proc);
+ } else {
+ if (proc->type == kProcessTypeUv) {
+ uv_kill(proc->pid, SIGTERM);
+ proc->term_sent = true;
+ process_stop(proc);
+ } else { // kProcessTypePty
+ process_close_streams(proc);
+ pty_process_close_master((PtyProcess *)proc);
+ }
+ }
}
// Wait until all children exit
@@ -303,6 +315,10 @@ static void decref(Process *proc)
static void process_close(Process *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
+ if (process_is_tearing_down && proc->detach && proc->closed) {
+ // If a detached process dies while tearing down it might get closed twice.
+ return;
+ }
assert(!proc->closed);
proc->closed = true;
switch (proc->type) {
@@ -333,6 +349,7 @@ static void on_process_exit(Process *proc)
DLOG("Stopping process kill timer");
uv_timer_stop(&loop->children_kill_timer);
}
+
// Process handles are closed in the next event loop tick. This is done to
// give libuv more time to read data from the OS after the process exits(If
// process_close_streams is called with data still in the OS buffer, we lose
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 45edc46b95..e23c8ea60f 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -25,7 +25,7 @@ struct process {
Stream *in, *out, *err;
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
- bool closed, term_sent;
+ bool closed, term_sent, detach;
Queue *events;
};
@@ -48,7 +48,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.closed = false,
.term_sent = false,
.internal_close_cb = NULL,
- .internal_exit_cb = NULL
+ .internal_exit_cb = NULL,
+ .detach = false
};
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 29d87d0fc1..407dded6af 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -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));
+ }
}
/*
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index eca62da949..87a6bf8901 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -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;
}
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index b2fd929714..7054bb822a 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -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:
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 66b8b9b5d2..00f4c0a85c 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -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) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c3d968ca51..19dbd0f9f6 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1991,6 +1991,7 @@ void op_insert(oparg_T *oap, long count1)
char_u *firstline, *ins_text;
struct block_def bd;
int i;
+ pos_T t1;
/* edit() changes this - record it for OP_APPEND */
bd.is_MAX = (curwin->w_curswant == MAXCOL);
@@ -2053,7 +2054,16 @@ void op_insert(oparg_T *oap, long count1)
}
}
- edit(NUL, FALSE, (linenr_T)count1);
+ t1 = oap->start;
+ edit(NUL, false, (linenr_T)count1);
+
+ // When a tab was inserted, and the characters in front of the tab
+ // have been converted to a tab as well, the column of the cursor
+ // might have actually been reduced, so need to adjust here. */
+ if (t1.lnum == curbuf->b_op_start_orig.lnum &&
+ lt(curbuf->b_op_start_orig, t1)) {
+ oap->start = curbuf->b_op_start_orig;
+ }
/* If user has moved off this line, we don't know what to do, so do
* nothing.
@@ -2069,21 +2079,23 @@ void op_insert(oparg_T *oap, long count1)
if (oap->start.lnum == curbuf->b_op_start_orig.lnum && !bd.is_MAX) {
if (oap->op_type == OP_INSERT
&& oap->start.col + oap->start.coladd
- != curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) {
+ != curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) {
+ size_t t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
- pre_textlen -= getviscol2(oap->start.col, oap->start.coladd)
- - oap->start_vcol;
- oap->start_vcol = getviscol2(oap->start.col, oap->start.coladd);
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
} else if (oap->op_type == OP_APPEND
&& oap->end.col + oap->end.coladd
- >= curbuf->b_op_start_orig.col
- + curbuf->b_op_start_orig.coladd) {
+ >= curbuf->b_op_start_orig.col
+ + curbuf->b_op_start_orig.coladd) {
+ size_t t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
/* reset pre_textlen to the value of OP_INSERT */
pre_textlen += bd.textlen;
- pre_textlen -= getviscol2(oap->start.col, oap->start.coladd)
- - oap->start_vcol;
- oap->start_vcol = getviscol2(oap->start.col, oap->start.coladd);
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
oap->op_type = OP_INSERT;
}
}
@@ -4186,75 +4198,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 +4302,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;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 2ac1abeeba..b4054dc28c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -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;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 0eccf63e15..3dd37cb5dc 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -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',
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index ed02c28272..9a64a7c3a9 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -752,10 +752,11 @@ static void win_update(win_T *wp)
lnumt = wp->w_lines[i].wl_lastlnum + 1;
if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) {
lnumb = wp->w_lines[i].wl_lnum;
- /* When there is a fold column it might need updating
- * in the next line ("J" just above an open fold). */
- if (wp->w_p_fdc > 0)
- ++lnumb;
+ // When there is a fold column it might need updating
+ // in the next line ("J" just above an open fold).
+ if (compute_foldcolumn(wp, 0) > 0) {
+ lnumb++;
+ }
}
}
@@ -1567,10 +1568,11 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
{
int n = 0;
# define FDC_OFF n
+ int fdc = compute_foldcolumn(wp, 0);
if (wp->w_p_rl) {
- /* No check for cmdline window: should never be right-left. */
- n = wp->w_p_fdc;
+ // No check for cmdline window: should never be right-left.
+ n = fdc;
if (n > 0) {
/* draw the fold column at the right */
@@ -1610,8 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
wp->w_wincol, wp->w_wincol + n,
cmdwin_type, ' ', hl_attr(HLF_AT));
}
- if (wp->w_p_fdc > 0) {
- int nn = n + wp->w_p_fdc;
+ if (fdc > 0) {
+ int nn = n + fdc;
/* draw the fold column at the left */
if (nn > wp->w_width)
@@ -1654,6 +1656,20 @@ static int advance_color_col(int vcol, int **color_cols)
return **color_cols >= 0;
}
+// Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
+// space is available for window "wp", minus "col".
+static int compute_foldcolumn(win_T *wp, int col)
+{
+ int fdc = wp->w_p_fdc;
+ int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
+ int wwidth = wp->w_width;
+
+ if (fdc > wwidth - (col + wmw)) {
+ fdc = wwidth - (col + wmw);
+ }
+ return fdc;
+}
+
/*
* Display one folded line.
*/
@@ -1692,12 +1708,9 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
++col;
}
- /*
- * 2. Add the 'foldcolumn'
- */
- fdc = wp->w_p_fdc;
- if (fdc > wp->w_width - col)
- fdc = wp->w_width - col;
+ // 2. Add the 'foldcolumn'
+ // Reduce the width when there is not enough space.
+ fdc = compute_foldcolumn(wp, col);
if (fdc > 0) {
fill_foldcolumn(buf, wp, TRUE, lnum);
if (wp->w_p_rl) {
@@ -2018,37 +2031,42 @@ fill_foldcolumn (
int level;
int first_level;
int empty;
+ int fdc = compute_foldcolumn(wp, 0);
- /* Init to all spaces. */
- memset(p, ' ', (size_t)wp->w_p_fdc);
+ // Init to all spaces.
+ memset(p, ' ', (size_t)fdc);
level = win_foldinfo.fi_level;
if (level > 0) {
- /* If there is only one column put more info in it. */
- empty = (wp->w_p_fdc == 1) ? 0 : 1;
+ // If there is only one column put more info in it.
+ empty = (fdc == 1) ? 0 : 1;
- /* If the column is too narrow, we start at the lowest level that
- * fits and use numbers to indicated the depth. */
- first_level = level - wp->w_p_fdc - closed + 1 + empty;
- if (first_level < 1)
+ // If the column is too narrow, we start at the lowest level that
+ // fits and use numbers to indicated the depth.
+ first_level = level - fdc - closed + 1 + empty;
+ if (first_level < 1) {
first_level = 1;
+ }
- for (i = 0; i + empty < wp->w_p_fdc; ++i) {
+ for (i = 0; i + empty < fdc; i++) {
if (win_foldinfo.fi_lnum == lnum
- && first_level + i >= win_foldinfo.fi_low_level)
+ && first_level + i >= win_foldinfo.fi_low_level) {
p[i] = '-';
- else if (first_level == 1)
+ } else if (first_level == 1) {
p[i] = '|';
- else if (first_level + i <= 9)
+ } else if (first_level + i <= 9) {
p[i] = '0' + first_level + i;
- else
+ } else {
p[i] = '>';
- if (first_level + i == level)
+ }
+ if (first_level + i == level) {
break;
+ }
}
}
- if (closed)
- p[i >= wp->w_p_fdc ? i - 1 : i] = '+';
+ if (closed) {
+ p[i >= fdc ? i - 1 : i] = '+';
+ }
}
/*
@@ -2629,11 +2647,13 @@ win_line (
}
if (draw_state == WL_FOLD - 1 && n_extra == 0) {
+ int fdc = compute_foldcolumn(wp, 0);
+
draw_state = WL_FOLD;
- if (wp->w_p_fdc > 0) {
- /* Draw the 'foldcolumn'. */
- fill_foldcolumn(extra, wp, FALSE, lnum);
- n_extra = wp->w_p_fdc;
+ if (fdc > 0) {
+ // Draw the 'foldcolumn'.
+ fill_foldcolumn(extra, wp, false, lnum);
+ n_extra = fdc;
p_extra = extra;
p_extra[n_extra] = NUL;
c_extra = NUL;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 420e8e2b70..b2028109be 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -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(&regmatch, 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)) {
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index bc245b21f4..aaa6f4b97e 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -14,7 +14,7 @@ SCRIPTS := test_eval.out \
test24.out \
test30.out \
test32.out test34.out \
- test36.out test37.out test39.out test40.out \
+ test36.out test37.out test40.out \
test42.out test45.out \
test47.out test48.out test49.out \
test52.out test53.out test55.out \
diff --git a/src/nvim/testdir/test39.in b/src/nvim/testdir/test39.in
deleted file mode 100644
index ebbcbd6d0d..0000000000
--- a/src/nvim/testdir/test39.in
+++ /dev/null
@@ -1,106 +0,0 @@
-
-Test Visual block mode commands
-And test "U" in Visual mode, also on German sharp S.
-
-STARTTEST
-:so small.vim
-:so mbyte.vim
-/^abcde
-:" Test shift-right of a block
-jlllljj>wlljlll>
-:" Test shift-left of a block
-G$hhhhkk<
-:" Test block-insert
-GklkkkIxyz
-:" Test block-replace
-Gllllkkklllrq
-:" Test block-change
-G$khhhhhkkcmno
-:$-4,$w! test.out
-:" Test block-insert using cursor keys for movement
-/^aaaa/
-:exe ":norm! l\<C-V>jjjlllI\<Right>\<Right> \<Esc>"
-:/^aa/,/^$/w >> test.out
-/xaaa$/
-:exe ":norm! \<C-V>jjjI<>\<Left>p\<Esc>"
-:/xaaa$/,/^$/w >> test.out
-:" Test for Visual block was created with the last <C-v>$
-/^A23$/
-:exe ":norm! l\<C-V>j$Aab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block was created with the middle <C-v>$ (1)
-/^B23$/
-:exe ":norm! l\<C-V>j$hAab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block was created with the middle <C-v>$ (2)
-/^C23$/
-:exe ":norm! l\<C-V>j$hhAab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block insert when virtualedit=all and utf-8 encoding
-:set ve=all
-:/\t\tline
-:exe ":norm! 07l\<C-V>jjIx\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block append when virtualedit=all
-:exe ":norm! 012l\<C-v>jjAx\<Esc>"
-:set ve=
-:.,/^$/w >> test.out
-:" gUe must uppercase a whole word, also when ß changes to SS
-Gothe youtußeuu endYpk0wgUe
-:" gUfx must uppercase until x, inclusive.
-O- youßtußexu -0fogUfx
-:" VU must uppercase a whole line
-YpkVU
-:" same, when it's the last line in the buffer
-YPGi111VUddP
-:" Uppercase two lines
-Oblah di
-doh dutVkUj
-:" Uppercase part of two lines
-ddppi333k0i222fyllvjfuUk
-:" visual replace using Enter or NL
-G3o1234567892k05l2jr G3o987652k02l2jr
-G3o1234567892k05l2jr
-G3o987652k02l2jr
-:"
-:" Test cursor position. When ve=block and Visual block mode and $gj
-:set ve=block
-:exe ":norm! 2k\<C-V>$gj\<Esc>"
-:let cpos=getpos("'>")
-:$put ='col:'.cpos[2].' off:'.cpos[3]
-:/^the/,$w >> test.out
-:qa!
-ENDTEST
-
- line1
- line2
- line3
-
-aaaaaa
-bbbbbb
-cccccc
-dddddd
-
-xaaa
-bbbb
-cccc
-dddd
-
-yaaa
-¿¿¿
-bbb
-
-A23
-4567
-
-B23
-4567
-
-C23
-4567
-
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
diff --git a/src/nvim/testdir/test39.ok b/src/nvim/testdir/test39.ok
deleted file mode 100644
index 198e5b14dc..0000000000
--- a/src/nvim/testdir/test39.ok
+++ /dev/null
Binary files differ
diff --git a/src/nvim/version.c b/src/nvim/version.c
index e221001e35..9b4c191d89 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -508,7 +508,7 @@ static int included_patches[] = {
// 619 NA
// 618 NA
617,
- // 616,
+ 616,
615,
614,
// 613,
@@ -521,7 +521,7 @@ static int included_patches[] = {
606,
605,
604,
- // 603,
+ 603,
602,
601,
600,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 71d7556880..2e20d48f90 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -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
diff --git a/test/functional/eval/printf_spec.lua b/test/functional/eval/printf_spec.lua
new file mode 100644
index 0000000000..6180f4156a
--- /dev/null
+++ b/test/functional/eval/printf_spec.lua
@@ -0,0 +1,60 @@
+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()
+ before_each(clear)
+
+ 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)
diff --git a/test/functional/job/job_spec.lua b/test/functional/job/job_spec.lua
index 0915ab0955..d21b9051e2 100644
--- a/test/functional/job/job_spec.lua
+++ b/test/functional/job/job_spec.lua
@@ -142,6 +142,35 @@ describe('jobs', function()
nvim('command', "call jobstart(['cat', '-'], g:job_opts)")
end)
+ it('can get the pid value using getpid', function()
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
+ local pid = eval('jobpid(j)')
+ eq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ nvim('command', 'call jobstop(j)')
+ eq({'notification', 'exit', {0, 0}}, next_msg())
+ neq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ end)
+
+ it("doesn't survive the exit of nvim", function()
+ -- use sleep, which doesn't die on stdin close
+ nvim('command', "let j = jobstart(['sleep', '1000'], g:job_opts)")
+ local pid = eval('jobpid(j)')
+ eq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ clear()
+ neq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ end)
+
+ it('can survive the exit of nvim with "detach"', function()
+ nvim('command', 'let g:job_opts.detach = 1')
+ nvim('command', "let j = jobstart(['sleep', '1000'], g:job_opts)")
+ local pid = eval('jobpid(j)')
+ eq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ clear()
+ eq(0,os.execute('ps -p '..pid..' > /dev/null'))
+ -- clean up after ourselves
+ os.execute('kill -9 '..pid..' > /dev/null')
+ end)
+
it('can pass user data to the callback', function()
nvim('command', 'let g:job_opts.user = {"n": 5, "s": "str", "l": [1]}')
nvim('command', "call jobstart(['echo'], g:job_opts)")
diff --git a/test/functional/legacy/035_increment_and_decrement_spec.lua b/test/functional/legacy/035_increment_and_decrement_spec.lua
index 20c0cc4206..e6252c384b 100644
--- a/test/functional/legacy/035_increment_and_decrement_spec.lua
+++ b/test/functional/legacy/035_increment_and_decrement_spec.lua
@@ -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)
diff --git a/test/functional/legacy/039_visual_block_mode_commands_spec.lua b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
new file mode 100644
index 0000000000..55db9169fa
--- /dev/null
+++ b/test/functional/legacy/039_visual_block_mode_commands_spec.lua
@@ -0,0 +1,234 @@
+-- Test Visual block mode commands
+-- And test "U" in Visual mode, also on German sharp S.
+
+local helpers = require('test.functional.helpers')
+local nvim, eq = helpers.meths, helpers.eq
+local insert, feed = helpers.insert, helpers.feed
+local clear, expect = helpers.clear, helpers.expect
+local source, execute = helpers.source, helpers.execute
+
+describe('Visual block mode', function()
+
+ before_each(function()
+ clear()
+
+ execute('set ts&vi sw&vi sts&vi noet') -- Vim compatible
+ end)
+
+ it('should shift, insert, replace and change a block', function()
+ insert([[
+ abcdefghijklm
+ abcdefghijklm
+ abcdefghijklm
+ abcdefghijklm
+ abcdefghijklm]])
+
+ feed('gg')
+ -- Test shift-right of a block
+ feed('jllll<C-v>jj>wll<C-v>jlll><CR>')
+ -- Test shift-left of a block
+ feed('G$hhhh<C-v>kk<lt>')
+ -- Test block-insert
+ feed('Gkl<C-v>kkkIxyz<ESC>')
+ -- Test block-replace
+ feed('Gllll<C-v>kkklllrq')
+ -- Test block-change
+ feed('G$khhh<C-v>hhkkcmno<ESC>')
+
+ expect([[
+ axyzbcdefghijklm
+ axyzqqqq mno ghijklm
+ axyzqqqqef mno ghijklm
+ axyzqqqqefgmnoklm
+ abcdqqqqijklm]])
+ end)
+
+ it('should insert a block using cursor keys for movement', function()
+ insert([[
+ aaaaaa
+ bbbbbb
+ cccccc
+ dddddd
+
+ xaaa
+ bbbb
+ cccc
+ dddd]])
+
+ execute('/^aa')
+ feed('l<C-v>jjjlllI<Right><Right> <ESC>')
+ execute('/xaaa$')
+ feed('<C-v>jjjI<lt>><Left>p<ESC>')
+
+ expect([[
+ aaa aaa
+ bbb bbb
+ ccc ccc
+ ddd ddd
+
+ <p>xaaa
+ <p>bbbb
+ <p>cccc
+ <p>dddd]])
+ end)
+
+ it('should create a block', function()
+ insert([[
+ A23
+ 4567
+
+ B23
+ 4567
+
+ C23
+ 4567]])
+
+ -- Test for Visual block was created with the last <C-v>$.
+ execute('/^A23$/')
+ feed('l<C-v>j$Aab<ESC>')
+ -- Test for Visual block was created with the middle <C-v>$ (1).
+ execute('/^B23$/')
+ feed('l<C-v>j$hAab<ESC>')
+ -- Test for Visual block was created with the middle <C-v>$ (2).
+ execute('/^C23$/')
+ feed('l<C-v>j$hhAab<ESC>')
+
+ expect([[
+ A23ab
+ 4567ab
+
+ B23 ab
+ 4567ab
+
+ C23ab
+ 456ab7]])
+ end)
+
+ it('should insert and append a block when virtualedit=all', function()
+ insert([[
+ line1
+ line2
+ line3
+ ]])
+
+ -- Test for Visual block insert when virtualedit=all and utf-8 encoding.
+ execute('set ve=all')
+ execute('/\t\tline')
+ feed('07l<C-v>jjIx<ESC>')
+
+ expect([[
+ x line1
+ x line2
+ x line3
+ ]])
+
+ -- Test for Visual block append when virtualedit=all.
+ feed('012l<C-v>jjAx<ESC>')
+
+ expect([[
+ x x line1
+ x x line2
+ x x line3
+ ]])
+ end)
+
+ it('should make a selected part uppercase', function()
+ -- GUe must uppercase a whole word, also when ß changes to SS.
+ feed('Gothe youtußeuu end<ESC>Ypk0wgUe<CR>')
+ -- GUfx must uppercase until x, inclusive.
+ feed('O- youßtußexu -<ESC>0fogUfx<CR>')
+ -- VU must uppercase a whole line.
+ feed('YpkVU<CR>')
+ -- Same, when it's the last line in the buffer.
+ feed('YPGi111<ESC>VUddP<CR>')
+ -- Uppercase two lines.
+ feed('Oblah di<CR>')
+ feed('doh dut<ESC>VkUj<CR>')
+ -- Uppercase part of two lines.
+ feed('ddppi333<ESC>k0i222<esc>fyllvjfuUk<CR>')
+
+ expect([[
+
+ the YOUTUSSEUU end
+ - yOUSSTUSSEXu -
+ THE YOUTUSSEUU END
+ 111THE YOUTUSSEUU END
+ BLAH DI
+ DOH DUT
+ 222the yoUTUSSEUU END
+ 333THE YOUTUßeuu end]])
+ end)
+
+ it('should replace using Enter or NL', function()
+ -- Visual replace using Enter or NL.
+ feed('G3o123456789<ESC>2k05l<C-v>2jr<CR>')
+ feed('G3o98765<ESC>2k02l<C-v>2jr<C-v><CR>')
+ feed('G3o123456789<ESC>2k05l<C-v>2jr<CR>')
+ feed('G3o98765<ESC>2k02l<C-v>2jr<C-v><Nul>')
+
+ local expected = [[
+
+ 12345
+ 789
+ 12345
+ 789
+ 12345
+ 789
+ 98<CR>65
+ 98<CR>65
+ 98<CR>65
+ 12345
+ 789
+ 12345
+ 789
+ 12345
+ 789
+ 98<Nul>65
+ 98<Nul>65
+ 98<Nul>65]]
+ expected = expected:gsub('<CR>', '\r')
+ expected = expected:gsub('<Nul>', '\x00')
+
+ expect(expected)
+ end)
+
+ it('should treat cursor position correctly when virtualedit=block', function()
+ insert([[
+ 12345
+ 789
+ 98765]])
+
+ -- Test cursor position. When virtualedit=block and Visual block mode and $gj.
+ execute('set ve=block')
+ feed('G2l')
+ feed('2k<C-v>$gj<ESC>')
+ execute([[let cpos=getpos("'>")]])
+ local cpos = nvim.get_var('cpos')
+ local expected = {
+ col = 4,
+ off = 0
+ }
+ local actual = {
+ col = cpos[3],
+ off = cpos[4]
+ }
+
+ eq(expected, actual)
+ end)
+
+ it('should replace spaces in front of the block with tabs', function()
+ insert([[
+ #define BO_ALL 0x0001
+ #define BO_BS 0x0002
+ #define BO_CRSR 0x0004]])
+
+ -- Block_insert when replacing spaces in front of the block with tabs.
+ execute('set ts=8 sts=4 sw=4')
+ feed('ggf0<C-v>2jI<TAB><ESC>')
+
+ expect([[
+ #define BO_ALL 0x0001
+ #define BO_BS 0x0002
+ #define BO_CRSR 0x0004]])
+ end)
+end)
diff --git a/test/functional/legacy/057_sort_spec.lua b/test/functional/legacy/057_sort_spec.lua
index 585b391198..65defbae96 100644
--- a/test/functional/legacy/057_sort_spec.lua
+++ b/test/functional/legacy/057_sort_spec.lua
@@ -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)