2016-08-29 22:49:24 +02:00
|
|
|
/* vi:set ts=8 sts=4 sw=4 noet:
|
2004-06-13 20:20:40 +00:00
|
|
|
*
|
|
|
|
* VIM - Vi IMproved by Bram Moolenaar
|
|
|
|
*
|
|
|
|
* Do ":help uganda" in Vim to read copying and usage conditions.
|
|
|
|
* Do ":help credits" in Vim to see a list of people who contributed.
|
|
|
|
* See README.txt for an overview of the Vim source code.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* misc2.c: Various functions.
|
|
|
|
*/
|
|
|
|
#include "vim.h"
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
static char_u *username = NULL; // cached result of mch_get_user_name()
|
2005-06-25 23:04:51 +00:00
|
|
|
|
2016-01-29 22:36:45 +01:00
|
|
|
static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return TRUE if in the current mode we need to use virtual.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
virtual_active(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2021-07-26 22:19:10 +02:00
|
|
|
unsigned int cur_ve_flags = get_ve_flags();
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// While an operator is being executed we return "virtual_op", because
|
|
|
|
// VIsual_active has already been reset, thus we can't check for "block"
|
|
|
|
// being used.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (virtual_op != MAYBE)
|
|
|
|
return virtual_op;
|
2021-07-26 22:19:10 +02:00
|
|
|
return (cur_ve_flags == VE_ALL
|
2022-05-07 20:01:16 +01:00
|
|
|
|| ((cur_ve_flags & VE_BLOCK) && VIsual_active
|
|
|
|
&& VIsual_mode == Ctrl_V)
|
|
|
|
|| ((cur_ve_flags & VE_INSERT) && (State & MODE_INSERT)));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the screen position of the cursor.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
getviscol(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
colnr_T x;
|
|
|
|
|
|
|
|
getvvcol(curwin, &curwin->w_cursor, &x, NULL, NULL);
|
|
|
|
return (int)x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-05-10 18:00:30 +00:00
|
|
|
* Go to column "wcol", and add/insert white space as necessary to get the
|
2004-06-13 20:20:40 +00:00
|
|
|
* cursor in that column.
|
|
|
|
* The caller must have saved the cursor line for undo!
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
coladvance_force(colnr_T wcol)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int rc = coladvance2(&curwin->w_cursor, TRUE, FALSE, wcol);
|
|
|
|
|
|
|
|
if (wcol == MAXCOL)
|
|
|
|
curwin->w_valid &= ~VALID_VIRTCOL;
|
|
|
|
else
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Virtcol is valid
|
2004-06-13 20:20:40 +00:00
|
|
|
curwin->w_valid |= VALID_VIRTCOL;
|
|
|
|
curwin->w_virtcol = wcol;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-01-11 16:16:01 +01:00
|
|
|
/*
|
|
|
|
* Get the screen position of character col with a coladd in the cursor line.
|
|
|
|
*/
|
|
|
|
int
|
2024-07-28 21:12:20 +02:00
|
|
|
getviscol2(colnr_T col, colnr_T coladd)
|
2019-01-11 16:16:01 +01:00
|
|
|
{
|
|
|
|
colnr_T x;
|
|
|
|
pos_T pos;
|
|
|
|
|
|
|
|
pos.lnum = curwin->w_cursor.lnum;
|
|
|
|
pos.col = col;
|
|
|
|
pos.coladd = coladd;
|
|
|
|
getvvcol(curwin, &pos, &x, NULL, NULL);
|
|
|
|
return (int)x;
|
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
2022-09-10 20:00:56 +01:00
|
|
|
* Try to advance the Cursor to the specified screen column "wantcol".
|
2004-06-13 20:20:40 +00:00
|
|
|
* If virtual editing: fine tune the cursor position.
|
|
|
|
* Note that all virtual positions off the end of a line should share
|
|
|
|
* a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)),
|
|
|
|
* beginning at coladd 0.
|
|
|
|
*
|
|
|
|
* return OK if desired column is reached, FAIL if not
|
|
|
|
*/
|
|
|
|
int
|
2022-09-10 20:00:56 +01:00
|
|
|
coladvance(colnr_T wantcol)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-09-10 20:00:56 +01:00
|
|
|
int rc = getvpos(&curwin->w_cursor, wantcol);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2022-09-10 20:00:56 +01:00
|
|
|
if (wantcol == MAXCOL || rc == FAIL)
|
2004-06-13 20:20:40 +00:00
|
|
|
curwin->w_valid &= ~VALID_VIRTCOL;
|
2004-12-31 20:56:11 +00:00
|
|
|
else if (*ml_get_cursor() != TAB)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Virtcol is valid when not on a TAB
|
2004-06-13 20:20:40 +00:00
|
|
|
curwin->w_valid |= VALID_VIRTCOL;
|
2022-09-10 20:00:56 +01:00
|
|
|
curwin->w_virtcol = wantcol;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-09-10 20:00:56 +01:00
|
|
|
* Return in "pos" the position of the cursor advanced to screen column
|
|
|
|
* "wantcol".
|
2004-06-13 20:20:40 +00:00
|
|
|
* return OK if desired column is reached, FAIL if not
|
|
|
|
*/
|
|
|
|
int
|
2022-09-10 20:00:56 +01:00
|
|
|
getvpos(pos_T *pos, colnr_T wantcol)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-09-10 20:00:56 +01:00
|
|
|
return coladvance2(pos, FALSE, virtual_active(), wantcol);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-01-30 19:39:49 +01:00
|
|
|
coladvance2(
|
|
|
|
pos_T *pos,
|
2019-10-12 16:12:54 +02:00
|
|
|
int addspaces, // change the text to achieve our goal?
|
|
|
|
int finetune, // change char offset for the exact column
|
|
|
|
colnr_T wcol_arg) // column to move to (can be negative)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-10-12 16:12:54 +02:00
|
|
|
colnr_T wcol = wcol_arg;
|
2004-06-13 20:20:40 +00:00
|
|
|
int idx;
|
|
|
|
char_u *line;
|
2024-03-12 21:50:32 +01:00
|
|
|
int linelen;
|
2004-06-13 20:20:40 +00:00
|
|
|
colnr_T col = 0;
|
|
|
|
int csize = 0;
|
|
|
|
int one_more;
|
|
|
|
#ifdef FEAT_LINEBREAK
|
|
|
|
int head = 0;
|
|
|
|
#endif
|
|
|
|
|
2022-05-07 20:01:16 +01:00
|
|
|
one_more = (State & MODE_INSERT)
|
2006-03-16 21:41:35 +00:00
|
|
|
|| restart_edit != NUL
|
|
|
|
|| (VIsual_active && *p_sel != 'o')
|
2021-07-26 22:19:10 +02:00
|
|
|
|| ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL);
|
2009-11-03 15:44:21 +00:00
|
|
|
line = ml_get_buf(curbuf, pos->lnum, FALSE);
|
2024-03-12 21:50:32 +01:00
|
|
|
linelen = ml_get_buf_len(curbuf, pos->lnum);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
if (wcol >= MAXCOL)
|
|
|
|
{
|
2024-03-12 21:50:32 +01:00
|
|
|
idx = linelen - 1 + one_more;
|
2004-06-13 20:20:40 +00:00
|
|
|
col = wcol;
|
|
|
|
|
|
|
|
if ((addspaces || finetune) && !VIsual_active)
|
|
|
|
{
|
2023-08-27 11:17:39 +02:00
|
|
|
curwin->w_curswant = linetabsize(curwin, pos->lnum) + one_more;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (curwin->w_curswant > 0)
|
|
|
|
--curwin->w_curswant;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-09-10 20:00:56 +01:00
|
|
|
int width = curwin->w_width - win_col_off(curwin);
|
|
|
|
chartabsize_T cts;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2005-12-28 22:39:57 +00:00
|
|
|
if (finetune
|
2004-06-13 20:20:40 +00:00
|
|
|
&& curwin->w_p_wrap
|
|
|
|
&& curwin->w_width != 0
|
2021-08-17 22:14:29 +02:00
|
|
|
&& wcol >= (colnr_T)width
|
|
|
|
&& width > 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2025-02-13 20:34:34 +01:00
|
|
|
csize = linetabsize_eol(curwin, pos->lnum);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (csize > 0)
|
|
|
|
csize--;
|
|
|
|
|
2005-12-28 22:39:57 +00:00
|
|
|
if (wcol / width > (colnr_T)csize / width
|
2022-05-07 20:01:16 +01:00
|
|
|
&& ((State & MODE_INSERT) == 0 || (int)wcol > csize + 1))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// In case of line wrapping don't move the cursor beyond the
|
|
|
|
// right screen edge. In Insert mode allow going just beyond
|
|
|
|
// the last character (like what happens when typing and
|
|
|
|
// reaching the right window edge).
|
2004-06-13 20:20:40 +00:00
|
|
|
wcol = (csize / width + 1) * width - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 18:13:54 +01:00
|
|
|
init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line);
|
|
|
|
while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-09-10 20:00:56 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
|
|
|
int at_start = cts.cts_ptr == cts.cts_line;
|
|
|
|
#endif
|
2019-12-21 18:25:54 +01:00
|
|
|
// Count a tab for what it's worth (if list mode not on)
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_LINEBREAK
|
2022-07-25 18:13:54 +01:00
|
|
|
csize = win_lbr_chartabsize(&cts, &head);
|
|
|
|
MB_PTR_ADV(cts.cts_ptr);
|
2004-06-13 20:20:40 +00:00
|
|
|
#else
|
2022-07-25 18:13:54 +01:00
|
|
|
csize = lbr_chartabsize_adv(&cts);
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2022-07-25 18:13:54 +01:00
|
|
|
cts.cts_vcol += csize;
|
2022-09-10 20:00:56 +01:00
|
|
|
#ifdef FEAT_PROP_POPUP
|
|
|
|
if (at_start)
|
|
|
|
// do not count the columns for virtual text above
|
|
|
|
cts.cts_vcol -= cts.cts_first_char;
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2022-07-25 18:13:54 +01:00
|
|
|
col = cts.cts_vcol;
|
|
|
|
idx = (int)(cts.cts_ptr - line);
|
|
|
|
clear_chartabsize_arg(&cts);
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Handle all the special cases. The virtual_active() check
|
|
|
|
* is needed to ensure that a virtual position off the end of
|
|
|
|
* a line has the correct indexing. The one_more comparison
|
|
|
|
* replaces an explicit add of one_more later on.
|
|
|
|
*/
|
|
|
|
if (col > wcol || (!virtual_active() && one_more == 0))
|
|
|
|
{
|
|
|
|
idx -= 1;
|
|
|
|
# ifdef FEAT_LINEBREAK
|
2019-12-21 18:25:54 +01:00
|
|
|
// Don't count the chars from 'showbreak'.
|
2004-06-13 20:20:40 +00:00
|
|
|
csize -= head;
|
|
|
|
# endif
|
|
|
|
col -= csize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virtual_active()
|
|
|
|
&& addspaces
|
2019-10-12 16:12:54 +02:00
|
|
|
&& wcol >= 0
|
2004-06-13 20:20:40 +00:00
|
|
|
&& ((col != wcol && col != wcol + 1) || csize > 1))
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// 'virtualedit' is set: The difference between wcol and col is
|
|
|
|
// filled with spaces.
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
if (line[idx] == NUL)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Append spaces
|
2004-06-13 20:20:40 +00:00
|
|
|
int correct = wcol - col;
|
|
|
|
char_u *newline = alloc(idx + correct + 1);
|
|
|
|
int t;
|
|
|
|
|
|
|
|
if (newline == NULL)
|
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
for (t = 0; t < idx; ++t)
|
|
|
|
newline[t] = line[t];
|
|
|
|
|
|
|
|
for (t = 0; t < correct; ++t)
|
|
|
|
newline[t + idx] = ' ';
|
|
|
|
|
|
|
|
newline[idx + correct] = NUL;
|
|
|
|
|
|
|
|
ml_replace(pos->lnum, newline, FALSE);
|
|
|
|
changed_bytes(pos->lnum, (colnr_T)idx);
|
|
|
|
idx += correct;
|
|
|
|
col = wcol;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Break a tab
|
|
|
|
int correct = wcol - col - csize + 1; // negative!!
|
2006-04-22 22:33:57 +00:00
|
|
|
char_u *newline;
|
2004-06-13 20:20:40 +00:00
|
|
|
int t, s = 0;
|
|
|
|
int v;
|
|
|
|
|
2006-04-22 22:33:57 +00:00
|
|
|
if (-correct > csize)
|
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
newline = alloc(linelen + csize);
|
|
|
|
if (newline == NULL)
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
|
|
|
|
for (t = 0; t < linelen; t++)
|
|
|
|
{
|
|
|
|
if (t != idx)
|
|
|
|
newline[s++] = line[t];
|
|
|
|
else
|
|
|
|
for (v = 0; v < csize; v++)
|
|
|
|
newline[s++] = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
newline[linelen + csize - 1] = NUL;
|
|
|
|
|
|
|
|
ml_replace(pos->lnum, newline, FALSE);
|
|
|
|
changed_bytes(pos->lnum, idx);
|
|
|
|
idx += (csize - 1 + correct);
|
|
|
|
col += correct;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
pos->col = 0;
|
|
|
|
else
|
|
|
|
pos->col = idx;
|
|
|
|
|
|
|
|
pos->coladd = 0;
|
|
|
|
|
|
|
|
if (finetune)
|
|
|
|
{
|
|
|
|
if (wcol == MAXCOL)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// The width of the last character is used to set coladd.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!one_more)
|
|
|
|
{
|
|
|
|
colnr_T scol, ecol;
|
|
|
|
|
|
|
|
getvcol(curwin, pos, &scol, NULL, &ecol);
|
|
|
|
pos->coladd = ecol - scol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int b = (int)wcol - (int)col;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// The difference between wcol and col is used to set coladd.
|
2017-09-22 15:20:32 +02:00
|
|
|
if (b > 0 && b < (MAXCOL - 2 * curwin->w_width))
|
2004-06-13 20:20:40 +00:00
|
|
|
pos->coladd = b;
|
|
|
|
|
|
|
|
col += b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// prevent from moving onto a trail byte
|
2004-06-13 20:20:40 +00:00
|
|
|
if (has_mbyte)
|
2011-07-07 15:08:58 +02:00
|
|
|
mb_adjustpos(curbuf, pos);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-10-12 16:12:54 +02:00
|
|
|
if (wcol < 0 || col < wcol)
|
2004-06-13 20:20:40 +00:00
|
|
|
return FAIL;
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-06-24 21:56:24 +00:00
|
|
|
* Increment the cursor position. See inc() for return values.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
inc_cursor(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
return inc(&curwin->w_cursor);
|
|
|
|
}
|
|
|
|
|
2008-06-24 21:56:24 +00:00
|
|
|
/*
|
|
|
|
* Increment the line pointer "lp" crossing line boundaries as necessary.
|
|
|
|
* Return 1 when going to the next line.
|
|
|
|
* Return 2 when moving forward onto a NUL at the end of the line).
|
|
|
|
* Return -1 when at the end of file.
|
|
|
|
* Return 0 otherwise.
|
|
|
|
*/
|
2004-06-13 20:20:40 +00:00
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
inc(pos_T *lp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-12-19 21:23:21 +01:00
|
|
|
char_u *p;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// when searching position may be set to end of a line
|
2017-12-19 21:23:21 +01:00
|
|
|
if (lp->col != MAXCOL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-12-19 21:23:21 +01:00
|
|
|
p = ml_get_pos(lp);
|
2019-12-21 18:25:54 +01:00
|
|
|
if (*p != NUL) // still within line, move to next char (may be NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-12-19 21:23:21 +01:00
|
|
|
if (has_mbyte)
|
|
|
|
{
|
|
|
|
int l = (*mb_ptr2len)(p);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2017-12-19 21:23:21 +01:00
|
|
|
lp->col += l;
|
|
|
|
return ((p[l] != NUL) ? 0 : 2);
|
|
|
|
}
|
|
|
|
lp->col++;
|
|
|
|
lp->coladd = 0;
|
|
|
|
return ((p[1] != NUL) ? 0 : 2);
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
if (lp->lnum != curbuf->b_ml.ml_line_count) // there is a next line
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
lp->col = 0;
|
|
|
|
lp->lnum++;
|
|
|
|
lp->coladd = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* incl(lp): same as inc(), but skip the NUL at the end of non-empty lines
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
incl(pos_T *lp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if ((r = inc(lp)) >= 1 && lp->col)
|
|
|
|
r = inc(lp);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dec(p)
|
|
|
|
*
|
|
|
|
* Decrement the line pointer 'p' crossing line boundaries as necessary.
|
|
|
|
* Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
dec_cursor(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2017-01-10 13:51:09 +01:00
|
|
|
return dec(&curwin->w_cursor);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
dec(pos_T *lp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char_u *p;
|
|
|
|
|
|
|
|
lp->coladd = 0;
|
2017-12-19 22:25:40 +01:00
|
|
|
if (lp->col == MAXCOL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// past end of line
|
2017-12-19 22:25:40 +01:00
|
|
|
p = ml_get(lp->lnum);
|
2024-03-12 21:50:32 +01:00
|
|
|
lp->col = ml_get_len(lp->lnum);
|
2017-12-19 22:25:40 +01:00
|
|
|
if (has_mbyte)
|
|
|
|
lp->col -= (*mb_head_off)(p, p + lp->col);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lp->col > 0)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// still within line
|
2004-06-13 20:20:40 +00:00
|
|
|
lp->col--;
|
|
|
|
if (has_mbyte)
|
|
|
|
{
|
|
|
|
p = ml_get(lp->lnum);
|
|
|
|
lp->col -= (*mb_head_off)(p, p + lp->col);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-12-19 22:25:40 +01:00
|
|
|
|
|
|
|
if (lp->lnum > 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// there is a prior line
|
2004-06-13 20:20:40 +00:00
|
|
|
lp->lnum--;
|
|
|
|
p = ml_get(lp->lnum);
|
2024-03-12 21:50:32 +01:00
|
|
|
lp->col = ml_get_len(lp->lnum);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (has_mbyte)
|
|
|
|
lp->col -= (*mb_head_off)(p, p + lp->col);
|
|
|
|
return 1;
|
|
|
|
}
|
2017-12-19 22:25:40 +01:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// at start of file
|
2017-12-19 22:25:40 +01:00
|
|
|
return -1;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* decl(lp): same as dec(), but skip the NUL at the end of non-empty lines
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
decl(pos_T *lp)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if ((r = dec(lp)) == 1 && lp->col)
|
|
|
|
r = dec(lp);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2010-05-16 15:46:46 +02:00
|
|
|
/*
|
|
|
|
* Get the line number relative to the current cursor position, i.e. the
|
|
|
|
* difference between line number and cursor position. Only look for lines that
|
|
|
|
* can be visible, folded lines don't count.
|
|
|
|
*/
|
|
|
|
linenr_T
|
2016-01-30 19:39:49 +01:00
|
|
|
get_cursor_rel_lnum(
|
|
|
|
win_T *wp,
|
2019-12-21 18:25:54 +01:00
|
|
|
linenr_T lnum) // line number to get the result for
|
2010-05-16 15:46:46 +02:00
|
|
|
{
|
|
|
|
linenr_T cursor = wp->w_cursor.lnum;
|
|
|
|
linenr_T retval = 0;
|
|
|
|
|
|
|
|
#ifdef FEAT_FOLDING
|
|
|
|
if (hasAnyFolding(wp))
|
|
|
|
{
|
|
|
|
if (lnum > cursor)
|
|
|
|
{
|
|
|
|
while (lnum > cursor)
|
|
|
|
{
|
2013-12-14 12:48:58 +01:00
|
|
|
(void)hasFoldingWin(wp, lnum, &lnum, NULL, TRUE, NULL);
|
2019-12-21 18:25:54 +01:00
|
|
|
// if lnum and cursor are in the same fold,
|
|
|
|
// now lnum <= cursor
|
2010-05-16 15:46:46 +02:00
|
|
|
if (lnum > cursor)
|
|
|
|
retval++;
|
|
|
|
lnum--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (lnum < cursor)
|
|
|
|
{
|
|
|
|
while (lnum < cursor)
|
|
|
|
{
|
2013-12-14 12:48:58 +01:00
|
|
|
(void)hasFoldingWin(wp, lnum, NULL, &lnum, TRUE, NULL);
|
2019-12-21 18:25:54 +01:00
|
|
|
// if lnum and cursor are in the same fold,
|
|
|
|
// now lnum >= cursor
|
2010-05-16 15:46:46 +02:00
|
|
|
if (lnum < cursor)
|
|
|
|
retval--;
|
|
|
|
lnum++;
|
|
|
|
}
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
// else if (lnum == cursor)
|
|
|
|
// retval = 0;
|
2010-05-16 15:46:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
retval = lnum - cursor;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2016-09-04 20:35:01 +02:00
|
|
|
/*
|
|
|
|
* Make sure "pos.lnum" and "pos.col" are valid in "buf".
|
|
|
|
* This allows for the col to be on the NUL byte.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
check_pos(buf_T *buf, pos_T *pos)
|
|
|
|
{
|
|
|
|
colnr_T len;
|
|
|
|
|
|
|
|
if (pos->lnum > buf->b_ml.ml_line_count)
|
|
|
|
pos->lnum = buf->b_ml.ml_line_count;
|
|
|
|
|
|
|
|
if (pos->col > 0)
|
|
|
|
{
|
2024-03-12 21:50:32 +01:00
|
|
|
len = ml_get_buf_len(buf, pos->lnum);
|
2016-09-04 20:35:01 +02:00
|
|
|
if (pos->col > len)
|
|
|
|
pos->col = len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Make sure curwin->w_cursor.lnum is valid.
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
check_cursor_lnum(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
|
|
|
|
{
|
|
|
|
#ifdef FEAT_FOLDING
|
2019-12-21 18:25:54 +01:00
|
|
|
// If there is a closed fold at the end of the file, put the cursor in
|
|
|
|
// its first line. Otherwise in the last line.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!hasFolding(curbuf->b_ml.ml_line_count,
|
|
|
|
&curwin->w_cursor.lnum, NULL))
|
|
|
|
#endif
|
|
|
|
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
|
|
|
|
}
|
|
|
|
if (curwin->w_cursor.lnum <= 0)
|
|
|
|
curwin->w_cursor.lnum = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure curwin->w_cursor.col is valid.
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
check_cursor_col(void)
|
2011-07-07 15:08:58 +02:00
|
|
|
{
|
|
|
|
check_cursor_col_win(curwin);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure win->w_cursor.col is valid.
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
check_cursor_col_win(win_T *win)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2021-07-26 22:19:10 +02:00
|
|
|
colnr_T len;
|
|
|
|
colnr_T oldcol = win->w_cursor.col;
|
|
|
|
colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
|
|
|
|
unsigned int cur_ve_flags = get_ve_flags();
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2024-03-12 21:50:32 +01:00
|
|
|
len = ml_get_buf_len(win->w_buffer, win->w_cursor.lnum);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (len == 0)
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.col = 0;
|
|
|
|
else if (win->w_cursor.col >= len)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Allow cursor past end-of-line when:
|
|
|
|
// - in Insert mode or restarting Insert mode
|
|
|
|
// - in Visual mode and 'selection' isn't "old"
|
|
|
|
// - 'virtualedit' is set
|
2022-05-07 20:01:16 +01:00
|
|
|
if ((State & MODE_INSERT) || restart_edit
|
2004-06-13 20:20:40 +00:00
|
|
|
|| (VIsual_active && *p_sel != 'o')
|
2021-07-26 22:19:10 +02:00
|
|
|
|| (cur_ve_flags & VE_ONEMORE)
|
2004-06-13 20:20:40 +00:00
|
|
|
|| virtual_active())
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.col = len;
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
2007-04-26 08:54:21 +00:00
|
|
|
{
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.col = len - 1;
|
2019-12-21 18:25:54 +01:00
|
|
|
// Move the cursor to the head byte.
|
2007-04-26 08:54:21 +00:00
|
|
|
if (has_mbyte)
|
2011-07-07 15:08:58 +02:00
|
|
|
mb_adjustpos(win->w_buffer, &win->w_cursor);
|
2007-04-26 08:54:21 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2011-07-07 15:08:58 +02:00
|
|
|
else if (win->w_cursor.col < 0)
|
|
|
|
win->w_cursor.col = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// If virtual editing is on, we can leave the cursor on the old position,
|
|
|
|
// only we must set it to virtual. But don't do it when at the end of the
|
|
|
|
// line.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (oldcol == MAXCOL)
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.coladd = 0;
|
2021-07-26 22:19:10 +02:00
|
|
|
else if (cur_ve_flags == VE_ALL)
|
2009-03-11 16:29:20 +00:00
|
|
|
{
|
2011-07-07 15:08:58 +02:00
|
|
|
if (oldcoladd > win->w_cursor.col)
|
2017-08-19 15:05:32 +02:00
|
|
|
{
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
|
2017-08-30 17:01:35 +02:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Make sure that coladd is not more than the char width.
|
|
|
|
// Not for the last character, coladd is then used when the cursor
|
|
|
|
// is actually after the last character.
|
2022-03-22 20:42:12 +00:00
|
|
|
if (win->w_cursor.col + 1 < len)
|
2017-08-19 15:05:32 +02:00
|
|
|
{
|
|
|
|
int cs, ce;
|
|
|
|
|
|
|
|
getvcol(win, &win->w_cursor, &cs, NULL, &ce);
|
|
|
|
if (win->w_cursor.coladd > ce - cs)
|
|
|
|
win->w_cursor.coladd = ce - cs;
|
|
|
|
}
|
|
|
|
}
|
2009-03-11 16:29:20 +00:00
|
|
|
else
|
2019-12-21 18:25:54 +01:00
|
|
|
// avoid weird number when there is a miscalculation or overflow
|
2011-07-07 15:08:58 +02:00
|
|
|
win->w_cursor.coladd = 0;
|
2009-03-11 16:29:20 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* make sure curwin->w_cursor in on a valid character
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
check_cursor(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
check_cursor_lnum();
|
|
|
|
check_cursor_col();
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:40:59 +01:00
|
|
|
/*
|
|
|
|
* Check if VIsual position is valid, correct it if not.
|
|
|
|
* Can be called when in Visual mode and a change has been made.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
check_visual_pos(void)
|
|
|
|
{
|
|
|
|
if (VIsual.lnum > curbuf->b_ml.ml_line_count)
|
|
|
|
{
|
|
|
|
VIsual.lnum = curbuf->b_ml.ml_line_count;
|
|
|
|
VIsual.col = 0;
|
|
|
|
VIsual.coladd = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-03-12 21:50:32 +01:00
|
|
|
int len = ml_get_len(VIsual.lnum);
|
2022-05-16 19:40:59 +01:00
|
|
|
|
|
|
|
if (VIsual.col > len)
|
|
|
|
{
|
|
|
|
VIsual.col = len;
|
|
|
|
VIsual.coladd = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Make sure curwin->w_cursor is not on the NUL at the end of the line.
|
|
|
|
* Allow it when in Visual mode and 'selection' is not "old".
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
adjust_cursor_col(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (curwin->w_cursor.col > 0
|
|
|
|
&& (!VIsual_active || *p_sel == 'o')
|
|
|
|
&& gchar_cursor() == NUL)
|
|
|
|
--curwin->w_cursor.col;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-11-18 14:07:20 +00:00
|
|
|
* Set "curwin->w_leftcol" to "leftcol".
|
|
|
|
* Adjust the cursor position if needed.
|
2004-06-13 20:20:40 +00:00
|
|
|
* Return TRUE if the cursor was moved.
|
|
|
|
*/
|
|
|
|
int
|
2022-11-18 14:07:20 +00:00
|
|
|
set_leftcol(colnr_T leftcol)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int retval = FALSE;
|
2022-11-18 14:07:20 +00:00
|
|
|
|
|
|
|
// Return quickly when there is no change.
|
|
|
|
if (curwin->w_leftcol == leftcol)
|
|
|
|
return FALSE;
|
|
|
|
curwin->w_leftcol = leftcol;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
changed_cline_bef_curs();
|
2022-11-18 14:07:20 +00:00
|
|
|
long lastcol = curwin->w_leftcol + curwin->w_width - curwin_col_off() - 1;
|
2004-06-13 20:20:40 +00:00
|
|
|
validate_virtcol();
|
|
|
|
|
2022-11-18 14:07:20 +00:00
|
|
|
// If the cursor is right or left of the screen, move it to last or first
|
|
|
|
// visible character.
|
|
|
|
long siso = get_sidescrolloff_value();
|
2019-01-31 18:26:10 +01:00
|
|
|
if (curwin->w_virtcol > (colnr_T)(lastcol - siso))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
retval = TRUE;
|
2019-01-31 18:26:10 +01:00
|
|
|
coladvance((colnr_T)(lastcol - siso));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-01-31 18:26:10 +01:00
|
|
|
else if (curwin->w_virtcol < curwin->w_leftcol + siso)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
retval = TRUE;
|
2019-01-31 18:26:10 +01:00
|
|
|
(void)coladvance((colnr_T)(curwin->w_leftcol + siso));
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 14:07:20 +00:00
|
|
|
// If the start of the character under the cursor is not on the screen,
|
|
|
|
// advance the cursor one more char. If this fails (last char of the
|
|
|
|
// line) adjust the scrolling.
|
|
|
|
colnr_T s, e;
|
2004-06-13 20:20:40 +00:00
|
|
|
getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e);
|
|
|
|
if (e > (colnr_T)lastcol)
|
|
|
|
{
|
|
|
|
retval = TRUE;
|
|
|
|
coladvance(s - 1);
|
|
|
|
}
|
|
|
|
else if (s < curwin->w_leftcol)
|
|
|
|
{
|
|
|
|
retval = TRUE;
|
2019-12-21 18:25:54 +01:00
|
|
|
if (coladvance(e + 1) == FAIL) // there isn't another character
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
curwin->w_leftcol = s; // adjust w_leftcol instead
|
2004-06-13 20:20:40 +00:00
|
|
|
changed_cline_bef_curs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
curwin->w_set_curswant = TRUE;
|
2022-08-14 14:17:45 +01:00
|
|
|
redraw_later(UPD_NOT_VALID);
|
2004-06-13 20:20:40 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Isolate one part of a string option where parts are separated with
|
|
|
|
* "sep_chars".
|
2005-08-01 21:58:57 +00:00
|
|
|
* The part is copied into "buf[maxlen]".
|
2004-06-13 20:20:40 +00:00
|
|
|
* "*option" is advanced to the next part.
|
|
|
|
* The length is returned.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
copy_option_part(
|
|
|
|
char_u **option,
|
|
|
|
char_u *buf,
|
|
|
|
int maxlen,
|
|
|
|
char *sep_chars)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
char_u *p = *option;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// skip '.' at start of option part, for 'suffixes'
|
2004-06-13 20:20:40 +00:00
|
|
|
if (*p == '.')
|
|
|
|
buf[len++] = *p++;
|
|
|
|
while (*p != NUL && vim_strchr((char_u *)sep_chars, *p) == NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Skip backslash before a separator character and space.
|
|
|
|
*/
|
|
|
|
if (p[0] == '\\' && vim_strchr((char_u *)sep_chars, p[1]) != NULL)
|
|
|
|
++p;
|
|
|
|
if (len < maxlen - 1)
|
|
|
|
buf[len++] = *p;
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
buf[len] = NUL;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
if (*p != NUL && *p != ',') // skip non-standard separator
|
2004-06-13 20:20:40 +00:00
|
|
|
++p;
|
2019-12-21 18:25:54 +01:00
|
|
|
p = skip_to_option_part(p); // p points to next file name
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
*option = p;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef HAVE_MEMSET
|
|
|
|
void *
|
2016-01-30 19:39:49 +01:00
|
|
|
vim_memset(void *ptr, int c, size_t size)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char *p = ptr;
|
|
|
|
|
|
|
|
while (size-- > 0)
|
|
|
|
*p++ = c;
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Vim has its own isspace() function, because on some machines isspace()
|
|
|
|
* can't handle characters above 128.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
vim_isspace(int x)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
return ((x >= 9 && x <= 13) || x == ' ');
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************
|
|
|
|
* functions that use lookup tables for various things, generally to do with
|
|
|
|
* special key codes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some useful tables.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct modmasktable
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
short mod_mask; // Bit-mask for particular key modifier
|
|
|
|
short mod_flag; // Bit(s) for particular key modifier
|
|
|
|
char_u name; // Single letter name of modifier
|
2004-06-13 20:20:40 +00:00
|
|
|
} mod_mask_table[] =
|
|
|
|
{
|
|
|
|
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'M'},
|
2005-03-04 23:39:37 +00:00
|
|
|
{MOD_MASK_META, MOD_MASK_META, (char_u)'T'},
|
2004-06-13 20:20:40 +00:00
|
|
|
{MOD_MASK_CTRL, MOD_MASK_CTRL, (char_u)'C'},
|
|
|
|
{MOD_MASK_SHIFT, MOD_MASK_SHIFT, (char_u)'S'},
|
|
|
|
{MOD_MASK_MULTI_CLICK, MOD_MASK_2CLICK, (char_u)'2'},
|
|
|
|
{MOD_MASK_MULTI_CLICK, MOD_MASK_3CLICK, (char_u)'3'},
|
|
|
|
{MOD_MASK_MULTI_CLICK, MOD_MASK_4CLICK, (char_u)'4'},
|
2024-01-25 22:44:00 +01:00
|
|
|
#if defined(MACOS_X) || defined(FEAT_GUI_GTK)
|
2004-06-13 20:20:40 +00:00
|
|
|
{MOD_MASK_CMD, MOD_MASK_CMD, (char_u)'D'},
|
|
|
|
#endif
|
2019-12-21 18:25:54 +01:00
|
|
|
// 'A' must be the last one
|
2004-06-13 20:20:40 +00:00
|
|
|
{MOD_MASK_ALT, MOD_MASK_ALT, (char_u)'A'},
|
|
|
|
{0, 0, NUL}
|
2019-12-21 18:25:54 +01:00
|
|
|
// NOTE: when adding an entry, update MAX_KEY_NAME_LEN!
|
2004-06-13 20:20:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Shifted key terminal codes and their unshifted equivalent.
|
2007-05-10 18:00:30 +00:00
|
|
|
* Don't add mouse codes here, they are handled separately!
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
#define MOD_KEYS_ENTRY_SIZE 5
|
|
|
|
|
|
|
|
static char_u modifier_keys_table[] =
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// mod mask with modifier without modifier
|
|
|
|
MOD_MASK_SHIFT, '&', '9', '@', '1', // begin
|
|
|
|
MOD_MASK_SHIFT, '&', '0', '@', '2', // cancel
|
|
|
|
MOD_MASK_SHIFT, '*', '1', '@', '4', // command
|
|
|
|
MOD_MASK_SHIFT, '*', '2', '@', '5', // copy
|
|
|
|
MOD_MASK_SHIFT, '*', '3', '@', '6', // create
|
|
|
|
MOD_MASK_SHIFT, '*', '4', 'k', 'D', // delete char
|
|
|
|
MOD_MASK_SHIFT, '*', '5', 'k', 'L', // delete line
|
|
|
|
MOD_MASK_SHIFT, '*', '7', '@', '7', // end
|
|
|
|
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', // end
|
|
|
|
MOD_MASK_SHIFT, '*', '9', '@', '9', // exit
|
|
|
|
MOD_MASK_SHIFT, '*', '0', '@', '0', // find
|
|
|
|
MOD_MASK_SHIFT, '#', '1', '%', '1', // help
|
|
|
|
MOD_MASK_SHIFT, '#', '2', 'k', 'h', // home
|
|
|
|
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', // home
|
|
|
|
MOD_MASK_SHIFT, '#', '3', 'k', 'I', // insert
|
|
|
|
MOD_MASK_SHIFT, '#', '4', 'k', 'l', // left arrow
|
|
|
|
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', // left arrow
|
|
|
|
MOD_MASK_SHIFT, '%', 'a', '%', '3', // message
|
|
|
|
MOD_MASK_SHIFT, '%', 'b', '%', '4', // move
|
|
|
|
MOD_MASK_SHIFT, '%', 'c', '%', '5', // next
|
|
|
|
MOD_MASK_SHIFT, '%', 'd', '%', '7', // options
|
|
|
|
MOD_MASK_SHIFT, '%', 'e', '%', '8', // previous
|
|
|
|
MOD_MASK_SHIFT, '%', 'f', '%', '9', // print
|
|
|
|
MOD_MASK_SHIFT, '%', 'g', '%', '0', // redo
|
|
|
|
MOD_MASK_SHIFT, '%', 'h', '&', '3', // replace
|
|
|
|
MOD_MASK_SHIFT, '%', 'i', 'k', 'r', // right arr.
|
|
|
|
MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', // right arr.
|
|
|
|
MOD_MASK_SHIFT, '%', 'j', '&', '5', // resume
|
|
|
|
MOD_MASK_SHIFT, '!', '1', '&', '6', // save
|
|
|
|
MOD_MASK_SHIFT, '!', '2', '&', '7', // suspend
|
|
|
|
MOD_MASK_SHIFT, '!', '3', '&', '8', // undo
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', // up arrow
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', // down arrow
|
|
|
|
|
|
|
|
// vt100 F1
|
2004-06-13 20:20:40 +00:00
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1,
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2,
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3,
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4,
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', // F1
|
2004-06-13 20:20:40 +00:00
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F5, 'k', '5',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F6, 'k', '6',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9',
|
2019-12-21 18:25:54 +01:00
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', // F10
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F13, 'F', '3',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F14, 'F', '4',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F15, 'F', '5',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F16, 'F', '6',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F17, 'F', '7',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F18, 'F', '8',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F19, 'F', '9',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F20, 'F', 'A',
|
|
|
|
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F21, 'F', 'B',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F22, 'F', 'C',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F23, 'F', 'D',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F24, 'F', 'E',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F25, 'F', 'F',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F26, 'F', 'G',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F27, 'F', 'H',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F28, 'F', 'I',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F29, 'F', 'J',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F30, 'F', 'K',
|
|
|
|
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F31, 'F', 'L',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F32, 'F', 'M',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F33, 'F', 'N',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F34, 'F', 'O',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F35, 'F', 'P',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q',
|
|
|
|
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R',
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// TAB pseudo code
|
2004-06-13 20:20:40 +00:00
|
|
|
MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB,
|
|
|
|
|
|
|
|
NUL
|
|
|
|
};
|
|
|
|
|
2025-03-06 22:26:23 +01:00
|
|
|
// Indexes into the key_names_table array
|
|
|
|
// Must be kept in sync with the array!
|
|
|
|
#define IDX_KEYNAME_BS 2
|
|
|
|
#define IDX_KEYNAME_CAR 5
|
|
|
|
#define IDX_KEYNAME_DEL 9
|
|
|
|
#define IDX_KEYNAME_INS 59
|
|
|
|
#define IDX_KEYNAME_NL 101
|
|
|
|
#define IDX_KEYNAME_SWD 115
|
|
|
|
#define IDX_KEYNAME_SWU 118
|
|
|
|
|
|
|
|
#define STRING_INIT(s) \
|
|
|
|
{(char_u *)(s), STRLEN_LITERAL(s)}
|
2004-06-13 20:20:40 +00:00
|
|
|
static struct key_name_entry
|
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
int enabled; // is this entry available (TRUE/FALSE)?
|
|
|
|
int key; // special key code or ascii value
|
|
|
|
string_T name; // name of key
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
string_T *pref_name; // pointer to preferred key name
|
2025-03-06 22:26:23 +01:00
|
|
|
// (may be NULL or point to the name in another entry)
|
2004-06-13 20:20:40 +00:00
|
|
|
} key_names_table[] =
|
2025-03-06 22:26:23 +01:00
|
|
|
// Must be sorted by the 'name.string' field in ascending order because it is used by bsearch()!
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
{TRUE, K_BS, STRING_INIT("BackSpace"),
|
|
|
|
&key_names_table[IDX_KEYNAME_BS].name}, // Alternative name
|
|
|
|
{TRUE, '|', STRING_INIT("Bar"), NULL},
|
|
|
|
{TRUE, K_BS, STRING_INIT("BS"), NULL},
|
|
|
|
{TRUE, '\\', STRING_INIT("Bslash"), NULL},
|
|
|
|
{TRUE, K_COMMAND, STRING_INIT("Cmd"), NULL},
|
|
|
|
{TRUE, CAR, STRING_INIT("CR"), NULL},
|
|
|
|
{TRUE, CSI, STRING_INIT("CSI"), NULL},
|
|
|
|
{TRUE, K_CURSORHOLD, STRING_INIT("CursorHold"), NULL},
|
|
|
|
{
|
2012-01-20 17:15:51 +01:00
|
|
|
#ifdef FEAT_MOUSE_DEC
|
2025-03-06 22:26:23 +01:00
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
2012-01-20 17:15:51 +01:00
|
|
|
#endif
|
2025-03-06 22:26:23 +01:00
|
|
|
K_DEC_MOUSE, STRING_INIT("DecMouse"), NULL},
|
|
|
|
{TRUE, K_DEL, STRING_INIT("Del"), NULL},
|
|
|
|
{TRUE, K_DEL, STRING_INIT("Delete"),
|
|
|
|
&key_names_table[IDX_KEYNAME_DEL].name}, // Alternative name
|
|
|
|
{TRUE, K_DOWN, STRING_INIT("Down"), NULL},
|
|
|
|
{TRUE, K_DROP, STRING_INIT("Drop"), NULL},
|
|
|
|
{TRUE, K_END, STRING_INIT("End"), NULL},
|
|
|
|
{TRUE, CAR, STRING_INIT("Enter"),
|
|
|
|
&key_names_table[IDX_KEYNAME_CAR].name}, // Alternative name
|
|
|
|
{TRUE, ESC, STRING_INIT("Esc"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_F1, STRING_INIT("F1"), NULL},
|
|
|
|
{TRUE, K_F10, STRING_INIT("F10"), NULL},
|
|
|
|
{TRUE, K_F11, STRING_INIT("F11"), NULL},
|
|
|
|
{TRUE, K_F12, STRING_INIT("F12"), NULL},
|
|
|
|
{TRUE, K_F13, STRING_INIT("F13"), NULL},
|
|
|
|
{TRUE, K_F14, STRING_INIT("F14"), NULL},
|
|
|
|
{TRUE, K_F15, STRING_INIT("F15"), NULL},
|
|
|
|
{TRUE, K_F16, STRING_INIT("F16"), NULL},
|
|
|
|
{TRUE, K_F17, STRING_INIT("F17"), NULL},
|
|
|
|
{TRUE, K_F18, STRING_INIT("F18"), NULL},
|
|
|
|
{TRUE, K_F19, STRING_INIT("F19"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_F2, STRING_INIT("F2"), NULL},
|
|
|
|
{TRUE, K_F20, STRING_INIT("F20"), NULL},
|
|
|
|
{TRUE, K_F21, STRING_INIT("F21"), NULL},
|
|
|
|
{TRUE, K_F22, STRING_INIT("F22"), NULL},
|
|
|
|
{TRUE, K_F23, STRING_INIT("F23"), NULL},
|
|
|
|
{TRUE, K_F24, STRING_INIT("F24"), NULL},
|
|
|
|
{TRUE, K_F25, STRING_INIT("F25"), NULL},
|
|
|
|
{TRUE, K_F26, STRING_INIT("F26"), NULL},
|
|
|
|
{TRUE, K_F27, STRING_INIT("F27"), NULL},
|
|
|
|
{TRUE, K_F28, STRING_INIT("F28"), NULL},
|
|
|
|
{TRUE, K_F29, STRING_INIT("F29"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_F3, STRING_INIT("F3"), NULL},
|
|
|
|
{TRUE, K_F30, STRING_INIT("F30"), NULL},
|
|
|
|
{TRUE, K_F31, STRING_INIT("F31"), NULL},
|
|
|
|
{TRUE, K_F32, STRING_INIT("F32"), NULL},
|
|
|
|
{TRUE, K_F33, STRING_INIT("F33"), NULL},
|
|
|
|
{TRUE, K_F34, STRING_INIT("F34"), NULL},
|
|
|
|
{TRUE, K_F35, STRING_INIT("F35"), NULL},
|
|
|
|
{TRUE, K_F36, STRING_INIT("F36"), NULL},
|
|
|
|
{TRUE, K_F37, STRING_INIT("F37"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_F4, STRING_INIT("F4"), NULL},
|
|
|
|
{TRUE, K_F5, STRING_INIT("F5"), NULL},
|
|
|
|
{TRUE, K_F6, STRING_INIT("F6"), NULL},
|
|
|
|
{TRUE, K_F7, STRING_INIT("F7"), NULL},
|
|
|
|
{TRUE, K_F8, STRING_INIT("F8"), NULL},
|
|
|
|
{TRUE, K_F9, STRING_INIT("F9"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_FOCUSGAINED, STRING_INIT("FocusGained"), NULL},
|
|
|
|
{TRUE, K_FOCUSLOST, STRING_INIT("FocusLost"), NULL},
|
|
|
|
{TRUE, K_HELP, STRING_INIT("Help"), NULL},
|
|
|
|
{TRUE, K_HOME, STRING_INIT("Home"), NULL},
|
|
|
|
{TRUE, K_IGNORE, STRING_INIT("Ignore"), NULL},
|
|
|
|
{TRUE, K_INS, STRING_INIT("Ins"),
|
|
|
|
&key_names_table[IDX_KEYNAME_INS].name}, // Alternative name
|
|
|
|
{TRUE, K_INS, STRING_INIT("Insert"), NULL},
|
|
|
|
{
|
2012-01-20 17:15:51 +01:00
|
|
|
#ifdef FEAT_MOUSE_JSB
|
2025-03-06 22:26:23 +01:00
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
2012-01-20 17:15:51 +01:00
|
|
|
#endif
|
2025-03-06 22:26:23 +01:00
|
|
|
K_JSBTERM_MOUSE, STRING_INIT("JsbMouse"), NULL},
|
|
|
|
{TRUE, K_K0, STRING_INIT("k0"), NULL},
|
|
|
|
{TRUE, K_K1, STRING_INIT("k1"), NULL},
|
|
|
|
{TRUE, K_K2, STRING_INIT("k2"), NULL},
|
|
|
|
{TRUE, K_K3, STRING_INIT("k3"), NULL},
|
|
|
|
{TRUE, K_K4, STRING_INIT("k4"), NULL},
|
|
|
|
{TRUE, K_K5, STRING_INIT("k5"), NULL},
|
|
|
|
{TRUE, K_K6, STRING_INIT("k6"), NULL},
|
|
|
|
{TRUE, K_K7, STRING_INIT("k7"), NULL},
|
|
|
|
{TRUE, K_K8, STRING_INIT("k8"), NULL},
|
|
|
|
{TRUE, K_K9, STRING_INIT("k9"), NULL},
|
|
|
|
|
|
|
|
{TRUE, K_KDEL, STRING_INIT("kDel"), NULL},
|
|
|
|
{TRUE, K_KDIVIDE, STRING_INIT("kDivide"), NULL},
|
|
|
|
{TRUE, K_KEND, STRING_INIT("kEnd"), NULL},
|
|
|
|
{TRUE, K_KENTER, STRING_INIT("kEnter"), NULL},
|
|
|
|
{TRUE, K_KHOME, STRING_INIT("kHome"), NULL},
|
|
|
|
{TRUE, K_KINS, STRING_INIT("kInsert"), NULL},
|
|
|
|
{TRUE, K_KMINUS, STRING_INIT("kMinus"), NULL},
|
|
|
|
{TRUE, K_KMULTIPLY, STRING_INIT("kMultiply"), NULL},
|
|
|
|
{TRUE, K_KPAGEDOWN, STRING_INIT("kPageDown"), NULL},
|
|
|
|
{TRUE, K_KPAGEUP, STRING_INIT("kPageUp"), NULL},
|
|
|
|
{TRUE, K_KPLUS, STRING_INIT("kPlus"), NULL},
|
|
|
|
{TRUE, K_KPOINT, STRING_INIT("kPoint"), NULL},
|
|
|
|
{TRUE, K_LEFT, STRING_INIT("Left"), NULL},
|
|
|
|
{TRUE, K_LEFTDRAG, STRING_INIT("LeftDrag"), NULL},
|
|
|
|
{TRUE, K_LEFTMOUSE, STRING_INIT("LeftMouse"), NULL},
|
|
|
|
{TRUE, K_LEFTMOUSE_NM, STRING_INIT("LeftMouseNM"), NULL},
|
|
|
|
{TRUE, K_LEFTRELEASE, STRING_INIT("LeftRelease"), NULL},
|
|
|
|
{TRUE, K_LEFTRELEASE_NM, STRING_INIT("LeftReleaseNM"), NULL},
|
|
|
|
{TRUE, NL, STRING_INIT("LF"),
|
|
|
|
&key_names_table[IDX_KEYNAME_NL].name}, // Alternative name
|
|
|
|
{TRUE, NL, STRING_INIT("LineFeed"),
|
|
|
|
&key_names_table[IDX_KEYNAME_NL].name}, // Alternative name
|
|
|
|
{TRUE, '<', STRING_INIT("lt"), NULL},
|
|
|
|
{TRUE, K_MIDDLEDRAG, STRING_INIT("MiddleDrag"), NULL},
|
|
|
|
{TRUE, K_MIDDLEMOUSE, STRING_INIT("MiddleMouse"), NULL},
|
|
|
|
{TRUE, K_MIDDLERELEASE, STRING_INIT("MiddleRelease"), NULL},
|
|
|
|
{TRUE, K_MOUSE, STRING_INIT("Mouse"), NULL},
|
|
|
|
{TRUE, K_MOUSEDOWN, STRING_INIT("MouseDown"),
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
&key_names_table[IDX_KEYNAME_SWU].name}, // OBSOLETE: Use ScrollWheelUp instead
|
2025-03-06 22:26:23 +01:00
|
|
|
{TRUE, K_MOUSEMOVE, STRING_INIT("MouseMove"), NULL},
|
|
|
|
{TRUE, K_MOUSEUP, STRING_INIT("MouseUp"),
|
|
|
|
&key_names_table[IDX_KEYNAME_SWD].name}, // OBSELETE: Use ScrollWheelDown instead
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSE_NET
|
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
2012-01-20 17:15:51 +01:00
|
|
|
#endif
|
2025-03-06 22:26:23 +01:00
|
|
|
K_NETTERM_MOUSE, STRING_INIT("NetMouse"), NULL},
|
|
|
|
{TRUE, NL, STRING_INIT("NewLine"),
|
|
|
|
&key_names_table[IDX_KEYNAME_NL].name}, // Alternative name
|
|
|
|
{TRUE, NL, STRING_INIT("NL"), NULL},
|
|
|
|
{TRUE, K_ZERO, STRING_INIT("Nul"), NULL},
|
|
|
|
{TRUE, K_PAGEDOWN, STRING_INIT("PageDown"), NULL},
|
|
|
|
{TRUE, K_PAGEUP, STRING_INIT("PageUp"), NULL},
|
|
|
|
{TRUE, K_PE, STRING_INIT("PasteEnd"), NULL},
|
|
|
|
{TRUE, K_PS, STRING_INIT("PasteStart"), NULL},
|
|
|
|
{TRUE, K_PLUG, STRING_INIT("Plug"), NULL},
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSE_PTERM
|
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
2012-08-15 16:21:32 +02:00
|
|
|
#endif
|
2025-03-06 22:26:23 +01:00
|
|
|
K_PTERM_MOUSE, STRING_INIT("PtermMouse"), NULL},
|
|
|
|
{TRUE, CAR, STRING_INIT("Return"),
|
|
|
|
&key_names_table[IDX_KEYNAME_CAR].name}, // Alternative name
|
|
|
|
{TRUE, K_RIGHT, STRING_INIT("Right"), NULL},
|
|
|
|
{TRUE, K_RIGHTDRAG, STRING_INIT("RightDrag"), NULL},
|
|
|
|
{TRUE, K_RIGHTMOUSE, STRING_INIT("RightMouse"), NULL},
|
|
|
|
{TRUE, K_RIGHTRELEASE, STRING_INIT("RightRelease"), NULL},
|
|
|
|
{TRUE, K_SCRIPT_COMMAND, STRING_INIT("ScriptCmd"), NULL},
|
|
|
|
{TRUE, K_MOUSEUP, STRING_INIT("ScrollWheelDown"), NULL},
|
|
|
|
{TRUE, K_MOUSERIGHT, STRING_INIT("ScrollWheelLeft"), NULL},
|
|
|
|
{TRUE, K_MOUSELEFT, STRING_INIT("ScrollWheelRight"), NULL},
|
|
|
|
{TRUE, K_MOUSEDOWN, STRING_INIT("ScrollWheelUp"), NULL},
|
|
|
|
{TRUE, K_SGR_MOUSE, STRING_INIT("SgrMouse"), NULL},
|
|
|
|
{TRUE, K_SGR_MOUSERELEASE, STRING_INIT("SgrMouseRelease"), NULL},
|
|
|
|
{
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifdef FEAT_EVAL
|
2025-03-06 22:26:23 +01:00
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
2025-03-06 22:26:23 +01:00
|
|
|
K_SNR, STRING_INIT("SNR"), NULL},
|
|
|
|
{TRUE, ' ', STRING_INIT("Space"), NULL},
|
|
|
|
{TRUE, TAB, STRING_INIT("Tab"), NULL},
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
{TRUE, K_TAB, STRING_INIT("Tab"), NULL},
|
2025-03-06 22:26:23 +01:00
|
|
|
{TRUE, K_UNDO, STRING_INIT("Undo"), NULL},
|
|
|
|
{TRUE, K_UP, STRING_INIT("Up"), NULL},
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSE_URXVT
|
|
|
|
TRUE,
|
|
|
|
#else
|
|
|
|
FALSE,
|
|
|
|
#endif
|
|
|
|
K_URXVT_MOUSE, STRING_INIT("UrxvtMouse"), NULL},
|
|
|
|
{TRUE, K_X1DRAG, STRING_INIT("X1Drag"), NULL},
|
|
|
|
{TRUE, K_X1MOUSE, STRING_INIT("X1Mouse"), NULL},
|
|
|
|
{TRUE, K_X1RELEASE, STRING_INIT("X1Release"), NULL},
|
|
|
|
{TRUE, K_X2DRAG, STRING_INIT("X2Drag"), NULL},
|
|
|
|
{TRUE, K_X2MOUSE, STRING_INIT("X2Mouse"), NULL},
|
|
|
|
{TRUE, K_X2RELEASE, STRING_INIT("X2Release"), NULL},
|
|
|
|
{TRUE, K_CSI, STRING_INIT("xCSI"), NULL},
|
|
|
|
{TRUE, K_XDOWN, STRING_INIT("xDown"), NULL},
|
|
|
|
{TRUE, K_XEND, STRING_INIT("xEnd"), NULL},
|
|
|
|
{TRUE, K_XF1, STRING_INIT("xF1"), NULL},
|
|
|
|
{TRUE, K_XF2, STRING_INIT("xF2"), NULL},
|
|
|
|
{TRUE, K_XF3, STRING_INIT("xF3"), NULL},
|
|
|
|
{TRUE, K_XF4, STRING_INIT("xF4"), NULL},
|
|
|
|
{TRUE, K_XHOME, STRING_INIT("xHome"), NULL},
|
|
|
|
{TRUE, K_XLEFT, STRING_INIT("xLeft"), NULL},
|
|
|
|
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
|
|
|
|
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
|
|
|
|
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
|
|
|
|
{TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
|
2019-12-21 18:25:54 +01:00
|
|
|
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
|
2004-06-13 20:20:40 +00:00
|
|
|
};
|
2025-03-06 22:26:23 +01:00
|
|
|
#undef STRING_INIT
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the modifier mask bit (MOD_MASK_*) which corresponds to the given
|
|
|
|
* modifier name ('S' for Shift, 'C' for Ctrl etc).
|
|
|
|
*/
|
2019-08-20 20:13:45 +02:00
|
|
|
static int
|
2016-01-30 19:39:49 +01:00
|
|
|
name_to_mod_mask(int c)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
c = TOUPPER_ASC(c);
|
|
|
|
for (i = 0; mod_mask_table[i].mod_mask != 0; i++)
|
|
|
|
if (c == mod_mask_table[i].name)
|
|
|
|
return mod_mask_table[i].mod_flag;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if if there is a special key code for "key" that includes the
|
|
|
|
* modifiers specified.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
simplify_key(int key, int *modifiers)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int key0;
|
|
|
|
int key1;
|
|
|
|
|
2024-02-03 18:04:05 +01:00
|
|
|
if (!(*modifiers & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
|
2023-01-14 12:32:28 +00:00
|
|
|
return key;
|
|
|
|
|
|
|
|
// TAB is a special case
|
|
|
|
if (key == TAB && (*modifiers & MOD_MASK_SHIFT))
|
|
|
|
{
|
|
|
|
*modifiers &= ~MOD_MASK_SHIFT;
|
|
|
|
return K_S_TAB;
|
|
|
|
}
|
|
|
|
key0 = KEY2TERMCAP0(key);
|
|
|
|
key1 = KEY2TERMCAP1(key);
|
|
|
|
for (i = 0; modifier_keys_table[i] != NUL; i += MOD_KEYS_ENTRY_SIZE)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-14 12:32:28 +00:00
|
|
|
if (key0 == modifier_keys_table[i + 3]
|
|
|
|
&& key1 == modifier_keys_table[i + 4]
|
|
|
|
&& (*modifiers & modifier_keys_table[i]))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2023-01-14 12:32:28 +00:00
|
|
|
*modifiers &= ~modifier_keys_table[i];
|
|
|
|
return TERMCAP2KEY(modifier_keys_table[i + 1],
|
|
|
|
modifier_keys_table[i + 2]);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2005-03-06 23:38:09 +00:00
|
|
|
/*
|
|
|
|
* Change <xHome> to <Home>, <xUp> to <Up>, etc.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
handle_x_keys(int key)
|
2005-03-06 23:38:09 +00:00
|
|
|
{
|
|
|
|
switch (key)
|
|
|
|
{
|
|
|
|
case K_XUP: return K_UP;
|
|
|
|
case K_XDOWN: return K_DOWN;
|
|
|
|
case K_XLEFT: return K_LEFT;
|
|
|
|
case K_XRIGHT: return K_RIGHT;
|
|
|
|
case K_XHOME: return K_HOME;
|
2005-03-25 21:53:48 +00:00
|
|
|
case K_ZHOME: return K_HOME;
|
2005-03-06 23:38:09 +00:00
|
|
|
case K_XEND: return K_END;
|
2005-03-25 21:53:48 +00:00
|
|
|
case K_ZEND: return K_END;
|
2005-03-06 23:38:09 +00:00
|
|
|
case K_XF1: return K_F1;
|
|
|
|
case K_XF2: return K_F2;
|
|
|
|
case K_XF3: return K_F3;
|
|
|
|
case K_XF4: return K_F4;
|
|
|
|
case K_S_XF1: return K_S_F1;
|
|
|
|
case K_S_XF2: return K_S_F2;
|
|
|
|
case K_S_XF3: return K_S_F3;
|
|
|
|
case K_S_XF4: return K_S_F4;
|
|
|
|
}
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Return a string which contains the name of the given key when the given
|
|
|
|
* modifiers are down.
|
|
|
|
*/
|
|
|
|
char_u *
|
2016-01-30 19:39:49 +01:00
|
|
|
get_special_key_name(int c, int modifiers)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
static char_u string[MAX_KEY_NAME_LEN + 1];
|
|
|
|
int i, idx;
|
|
|
|
int table_idx;
|
|
|
|
|
|
|
|
string[0] = '<';
|
|
|
|
idx = 1;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Key that stands for a normal character.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
|
|
|
|
c = KEY2TERMCAP1(c);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Translate shifted special keys into unshifted keys and set modifier.
|
|
|
|
* Same for CTRL and ALT modifiers.
|
|
|
|
*/
|
|
|
|
if (IS_SPECIAL(c))
|
|
|
|
{
|
|
|
|
for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
|
|
|
|
if ( KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
|
|
|
|
&& (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2])
|
|
|
|
{
|
|
|
|
modifiers |= modifier_keys_table[i];
|
|
|
|
c = TERMCAP2KEY(modifier_keys_table[i + 3],
|
|
|
|
modifier_keys_table[i + 4]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// try to find the key in the special key table
|
2004-06-13 20:20:40 +00:00
|
|
|
table_idx = find_special_key_in_table(c);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When not a known special key, and not a printable character, try to
|
|
|
|
* extract modifiers.
|
|
|
|
*/
|
2019-01-24 15:54:21 +01:00
|
|
|
if (c > 0 && (*mb_char2len)(c) == 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (table_idx < 0
|
|
|
|
&& (!vim_isprintc(c) || (c & 0x7f) == ' ')
|
|
|
|
&& (c & 0x80))
|
|
|
|
{
|
|
|
|
c &= 0x7f;
|
|
|
|
modifiers |= MOD_MASK_ALT;
|
2019-12-21 18:25:54 +01:00
|
|
|
// try again, to find the un-alted key in the special key table
|
2004-06-13 20:20:40 +00:00
|
|
|
table_idx = find_special_key_in_table(c);
|
|
|
|
}
|
|
|
|
if (table_idx < 0 && !vim_isprintc(c) && c < ' ')
|
|
|
|
{
|
|
|
|
c += '@';
|
|
|
|
modifiers |= MOD_MASK_CTRL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// translate the modifier into a string
|
2004-06-13 20:20:40 +00:00
|
|
|
for (i = 0; mod_mask_table[i].name != 'A'; i++)
|
|
|
|
if ((modifiers & mod_mask_table[i].mod_mask)
|
|
|
|
== mod_mask_table[i].mod_flag)
|
|
|
|
{
|
|
|
|
string[idx++] = mod_mask_table[i].name;
|
|
|
|
string[idx++] = (char_u)'-';
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
if (table_idx < 0) // unknown special key, may output t_xx
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (IS_SPECIAL(c))
|
|
|
|
{
|
|
|
|
string[idx++] = 't';
|
|
|
|
string[idx++] = '_';
|
|
|
|
string[idx++] = KEY2TERMCAP0(c);
|
|
|
|
string[idx++] = KEY2TERMCAP1(c);
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
// Not a special key, only modifiers, output directly
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (has_mbyte && (*mb_char2len)(c) > 1)
|
|
|
|
idx += (*mb_char2bytes)(c, string + idx);
|
2019-01-24 15:54:21 +01:00
|
|
|
else if (vim_isprintc(c))
|
2004-06-13 20:20:40 +00:00
|
|
|
string[idx++] = c;
|
|
|
|
else
|
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
char_u *s = transchar(c);
|
2004-06-13 20:20:40 +00:00
|
|
|
while (*s)
|
|
|
|
string[idx++] = *s++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
else // use name of special key
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
string_T *s;
|
|
|
|
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
if (key_names_table[table_idx].pref_name != NULL)
|
|
|
|
s = key_names_table[table_idx].pref_name;
|
2025-03-06 22:26:23 +01:00
|
|
|
else
|
|
|
|
s = &key_names_table[table_idx].name;
|
2017-01-22 15:05:12 +01:00
|
|
|
|
2025-03-06 22:26:23 +01:00
|
|
|
if (s->length + idx + 2 <= MAX_KEY_NAME_LEN)
|
2017-01-22 15:05:12 +01:00
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
STRCPY(string + idx, s->string);
|
|
|
|
idx += (int)s->length;
|
2017-01-22 15:05:12 +01:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
string[idx++] = '>';
|
|
|
|
string[idx] = NUL;
|
2025-03-06 22:26:23 +01:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-01-13 18:46:57 +00:00
|
|
|
* Try translating a <> name at "(*srcp)[]" to "dst[]".
|
|
|
|
* Return the number of characters added to "dst[]", zero for no match.
|
|
|
|
* If there is a match, "srcp" is advanced to after the <> name.
|
|
|
|
* "dst[]" must be big enough to hold the result (up to six characters)!
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
trans_special(
|
|
|
|
char_u **srcp,
|
|
|
|
char_u *dst,
|
2020-05-30 21:52:54 +02:00
|
|
|
int flags, // FSK_ values
|
2022-05-02 22:53:45 +01:00
|
|
|
int escape_ks, // escape K_SPECIAL bytes in the character
|
2020-05-30 21:52:54 +02:00
|
|
|
int *did_simplify) // FSK_SIMPLIFY and found <C-H> or <A-x>
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int modifiers = 0;
|
|
|
|
int key;
|
|
|
|
|
2020-05-30 21:52:54 +02:00
|
|
|
key = find_special_key(srcp, &modifiers, flags, did_simplify);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (key == 0)
|
|
|
|
return 0;
|
|
|
|
|
2022-05-02 22:53:45 +01:00
|
|
|
return special_to_buf(key, modifiers, escape_ks, dst);
|
2019-06-01 17:13:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the character sequence for "key" with "modifiers" into "dst" and return
|
|
|
|
* the resulting length.
|
2022-05-02 22:53:45 +01:00
|
|
|
* When "escape_ks" is TRUE escape K_SPECIAL bytes in the character.
|
2019-06-01 17:13:36 +02:00
|
|
|
* The sequence is not NUL terminated.
|
|
|
|
* This is how characters in a string are encoded.
|
|
|
|
*/
|
|
|
|
int
|
2022-05-02 22:53:45 +01:00
|
|
|
special_to_buf(int key, int modifiers, int escape_ks, char_u *dst)
|
2019-06-01 17:13:36 +02:00
|
|
|
{
|
|
|
|
int dlen = 0;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Put the appropriate modifier in a string
|
2004-06-13 20:20:40 +00:00
|
|
|
if (modifiers != 0)
|
|
|
|
{
|
|
|
|
dst[dlen++] = K_SPECIAL;
|
|
|
|
dst[dlen++] = KS_MODIFIER;
|
|
|
|
dst[dlen++] = modifiers;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_SPECIAL(key))
|
|
|
|
{
|
|
|
|
dst[dlen++] = K_SPECIAL;
|
|
|
|
dst[dlen++] = KEY2TERMCAP0(key);
|
|
|
|
dst[dlen++] = KEY2TERMCAP1(key);
|
|
|
|
}
|
2022-05-02 22:53:45 +01:00
|
|
|
else if (escape_ks)
|
2004-06-13 20:20:40 +00:00
|
|
|
dlen = (int)(add_char2buf(key, dst + dlen) - dst);
|
2022-05-02 22:53:45 +01:00
|
|
|
else if (has_mbyte)
|
|
|
|
dlen += (*mb_char2bytes)(key, dst + dlen);
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
dst[dlen++] = key;
|
|
|
|
|
|
|
|
return dlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-01-13 18:46:57 +00:00
|
|
|
* Try translating a <> name at "(*srcp)[]", return the key and put modifiers
|
|
|
|
* in "modp".
|
|
|
|
* "srcp" is advanced to after the <> name.
|
2004-06-13 20:20:40 +00:00
|
|
|
* returns 0 if there is no match.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
find_special_key(
|
|
|
|
char_u **srcp,
|
|
|
|
int *modp,
|
2020-05-30 21:52:54 +02:00
|
|
|
int flags, // FSK_ values
|
2019-10-13 16:43:39 +02:00
|
|
|
int *did_simplify) // found <C-H> or <A-x>
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char_u *last_dash;
|
|
|
|
char_u *end_of_name;
|
|
|
|
char_u *src;
|
|
|
|
char_u *bp;
|
2020-05-30 21:52:54 +02:00
|
|
|
int in_string = flags & FSK_IN_STRING;
|
2004-06-13 20:20:40 +00:00
|
|
|
int modifiers;
|
|
|
|
int bit;
|
|
|
|
int key;
|
2016-07-01 18:17:26 +02:00
|
|
|
uvarnumber_T n;
|
2011-08-17 20:33:22 +02:00
|
|
|
int l;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
src = *srcp;
|
2020-05-31 22:06:51 +02:00
|
|
|
if (src[0] != '<')
|
2004-06-13 20:20:40 +00:00
|
|
|
return 0;
|
2020-05-31 22:06:51 +02:00
|
|
|
if (src[1] == '*') // <*xxx>: do not simplify
|
|
|
|
++src;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Find end of modifier list
|
2004-06-13 20:20:40 +00:00
|
|
|
last_dash = src;
|
2021-04-06 20:21:59 +02:00
|
|
|
for (bp = src + 1; *bp == '-' || vim_isNormalIDc(*bp); bp++)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (*bp == '-')
|
|
|
|
{
|
|
|
|
last_dash = bp;
|
2011-08-17 20:33:22 +02:00
|
|
|
if (bp[1] != NUL)
|
|
|
|
{
|
|
|
|
if (has_mbyte)
|
|
|
|
l = mb_ptr2len(bp + 1);
|
|
|
|
else
|
|
|
|
l = 1;
|
2019-08-16 20:33:05 +02:00
|
|
|
// Anything accepted, like <C-?>.
|
|
|
|
// <C-"> or <M-"> are not special in strings as " is
|
|
|
|
// the string delimiter. With a backslash it works: <M-\">
|
2020-05-31 22:06:51 +02:00
|
|
|
if (!(in_string && bp[1] == '"') && bp[l + 1] == '>')
|
2016-07-01 11:59:47 +02:00
|
|
|
bp += l;
|
2016-08-14 16:07:48 +02:00
|
|
|
else if (in_string && bp[1] == '\\' && bp[2] == '"'
|
2020-05-31 22:06:51 +02:00
|
|
|
&& bp[3] == '>')
|
2016-08-14 16:07:48 +02:00
|
|
|
bp += 2;
|
2011-08-17 20:33:22 +02:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
|
2020-05-31 22:06:51 +02:00
|
|
|
bp += 3; // skip t_xx, xx may be '-' or '>'
|
2011-08-19 22:29:02 +02:00
|
|
|
else if (STRNICMP(bp, "char-", 5) == 0)
|
|
|
|
{
|
2023-03-04 20:47:39 +00:00
|
|
|
vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE, NULL);
|
2019-05-19 19:59:35 +02:00
|
|
|
if (l == 0)
|
|
|
|
{
|
2021-12-31 22:49:24 +00:00
|
|
|
emsg(_(e_invalid_argument));
|
2019-05-19 19:59:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2011-08-19 22:29:02 +02:00
|
|
|
bp += l + 5;
|
|
|
|
break;
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
2020-05-31 22:06:51 +02:00
|
|
|
if (*bp == '>') // found matching '>'
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
end_of_name = bp + 1;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Which modifiers are given?
|
2004-06-13 20:20:40 +00:00
|
|
|
modifiers = 0x0;
|
|
|
|
for (bp = src + 1; bp < last_dash; bp++)
|
|
|
|
{
|
|
|
|
if (*bp != '-')
|
|
|
|
{
|
|
|
|
bit = name_to_mod_mask(*bp);
|
|
|
|
if (bit == 0x0)
|
2019-12-21 18:25:54 +01:00
|
|
|
break; // Illegal modifier name
|
2004-06-13 20:20:40 +00:00
|
|
|
modifiers |= bit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Legal modifier name.
|
|
|
|
*/
|
|
|
|
if (bp >= last_dash)
|
|
|
|
{
|
2011-08-17 20:33:22 +02:00
|
|
|
if (STRNICMP(last_dash + 1, "char-", 5) == 0
|
|
|
|
&& VIM_ISDIGIT(last_dash[6]))
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// <Char-123> or <Char-033> or <Char-0x33>
|
2019-10-13 16:43:39 +02:00
|
|
|
vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
|
2023-03-04 20:47:39 +00:00
|
|
|
&n, 0, TRUE, NULL);
|
2019-05-19 19:59:35 +02:00
|
|
|
if (l == 0)
|
|
|
|
{
|
2021-12-31 22:49:24 +00:00
|
|
|
emsg(_(e_invalid_argument));
|
2019-05-19 19:59:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2011-08-19 22:29:02 +02:00
|
|
|
key = (int)n;
|
2011-08-17 20:33:22 +02:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
2005-03-06 23:38:09 +00:00
|
|
|
{
|
2016-08-14 16:07:48 +02:00
|
|
|
int off = 1;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Modifier with single letter, or special key name.
|
2016-08-14 16:07:48 +02:00
|
|
|
if (in_string && last_dash[1] == '\\' && last_dash[2] == '"')
|
|
|
|
off = 2;
|
2011-08-19 22:29:02 +02:00
|
|
|
if (has_mbyte)
|
2016-08-14 16:07:48 +02:00
|
|
|
l = mb_ptr2len(last_dash + off);
|
2011-08-19 22:29:02 +02:00
|
|
|
else
|
|
|
|
l = 1;
|
2020-05-31 22:06:51 +02:00
|
|
|
if (modifiers != 0 && last_dash[l + off] == '>')
|
2016-08-14 16:07:48 +02:00
|
|
|
key = PTR2CHAR(last_dash + off);
|
2011-08-19 22:29:02 +02:00
|
|
|
else
|
|
|
|
{
|
2016-08-14 16:07:48 +02:00
|
|
|
key = get_special_key_code(last_dash + off);
|
2020-05-30 21:52:54 +02:00
|
|
|
if (!(flags & FSK_KEEP_X_KEY))
|
2011-08-19 22:29:02 +02:00
|
|
|
key = handle_x_keys(key);
|
|
|
|
}
|
2005-03-06 23:38:09 +00:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
key = simplify_key(key, &modifiers);
|
|
|
|
|
2023-01-13 18:46:57 +00:00
|
|
|
if ((flags & FSK_KEYCODE) == 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// don't want keycode, use single byte code
|
2004-06-13 20:20:40 +00:00
|
|
|
if (key == K_BS)
|
|
|
|
key = BS;
|
|
|
|
else if (key == K_DEL || key == K_KDEL)
|
|
|
|
key = DEL;
|
|
|
|
}
|
2023-01-13 18:46:57 +00:00
|
|
|
else if (key == 27
|
2023-01-14 21:07:07 +00:00
|
|
|
&& (flags & FSK_FROM_PART) != 0
|
2023-01-13 18:46:57 +00:00
|
|
|
&& (kitty_protocol_state == KKPS_ENABLED
|
|
|
|
|| kitty_protocol_state == KKPS_DISABLED))
|
|
|
|
{
|
|
|
|
// Using the Kitty key protocol, which uses K_ESC for an
|
|
|
|
// Esc character. For the simplified keys use the Esc
|
|
|
|
// character and set did_simplify, then in the
|
|
|
|
// non-simplified keys use K_ESC.
|
|
|
|
if ((flags & FSK_SIMPLIFY) != 0)
|
2023-01-14 21:07:07 +00:00
|
|
|
{
|
|
|
|
if (did_simplify != NULL)
|
|
|
|
*did_simplify = TRUE;
|
|
|
|
}
|
2023-01-13 18:46:57 +00:00
|
|
|
else
|
|
|
|
key = K_ESC;
|
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-10-13 16:43:39 +02:00
|
|
|
// Normal Key with modifier: Try to make a single byte code.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!IS_SPECIAL(key))
|
2019-10-13 16:43:39 +02:00
|
|
|
key = extract_modifiers(key, &modifiers,
|
2020-05-30 21:52:54 +02:00
|
|
|
flags & FSK_SIMPLIFY, did_simplify);
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
*modp = modifiers;
|
|
|
|
*srcp = end_of_name;
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-20 14:43:23 +02:00
|
|
|
|
2020-10-07 16:12:37 +02:00
|
|
|
/*
|
|
|
|
* Some keys are used with Ctrl without Shift and are still expected to be
|
|
|
|
* mapped as if Shift was pressed:
|
|
|
|
* CTRL-2 is CTRL-@
|
|
|
|
* CTRL-6 is CTRL-^
|
|
|
|
* CTRL-- is CTRL-_
|
2022-11-19 19:02:40 +00:00
|
|
|
* Also, unless no_reduce_keys is set then <C-H> and <C-h> mean the same thing,
|
|
|
|
* use "H".
|
2020-10-07 16:12:37 +02:00
|
|
|
* Returns the possibly adjusted key.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
may_adjust_key_for_ctrl(int modifiers, int key)
|
|
|
|
{
|
2023-02-11 16:15:50 +00:00
|
|
|
if ((modifiers & MOD_MASK_CTRL) == 0)
|
2023-01-14 12:32:28 +00:00
|
|
|
return key;
|
|
|
|
|
|
|
|
if (ASCII_ISALPHA(key))
|
2020-10-07 16:12:37 +02:00
|
|
|
{
|
2022-11-19 19:02:40 +00:00
|
|
|
#ifdef FEAT_TERMINAL
|
2023-01-14 12:32:28 +00:00
|
|
|
check_no_reduce_keys(); // may update the no_reduce_keys flag
|
2022-11-19 19:02:40 +00:00
|
|
|
#endif
|
2023-01-14 12:32:28 +00:00
|
|
|
return no_reduce_keys == 0 ? TOUPPER_ASC(key) : key;
|
2020-10-07 16:12:37 +02:00
|
|
|
}
|
2023-01-14 12:32:28 +00:00
|
|
|
if (key == '2')
|
|
|
|
return '@';
|
|
|
|
if (key == '6')
|
|
|
|
return '^';
|
|
|
|
if (key == '-')
|
|
|
|
return '_';
|
2023-02-11 16:15:50 +00:00
|
|
|
|
|
|
|
// On a Belgian keyboard AltGr $ is ']', on other keyboards '$' can only be
|
|
|
|
// obtained with Shift. Assume that '$' without shift implies a Belgian
|
|
|
|
// keyboard, where CTRL-$ means CTRL-].
|
|
|
|
if (key == '$' && (modifiers & MOD_MASK_SHIFT) == 0)
|
|
|
|
return ']';
|
|
|
|
|
2020-10-07 16:12:37 +02:00
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2020-06-20 14:43:23 +02:00
|
|
|
/*
|
|
|
|
* Some keys already have Shift included, pass them as normal keys.
|
2020-10-07 17:29:48 +02:00
|
|
|
* When Ctrl is also used <C-H> and <C-S-H> are different, but <C-S-{> should
|
|
|
|
* be <C-{>. Same for <C-S-}> and <C-S-|>.
|
2020-06-20 14:43:23 +02:00
|
|
|
* Also for <A-S-a> and <M-S-a>.
|
2022-09-12 20:35:28 +01:00
|
|
|
* This includes all printable ASCII characters except a-z.
|
|
|
|
* Digits are included because with AZERTY the Shift key is used to get them.
|
2020-06-20 14:43:23 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
may_remove_shift_modifier(int modifiers, int key)
|
|
|
|
{
|
|
|
|
if ((modifiers == MOD_MASK_SHIFT
|
|
|
|
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
|
2024-01-25 22:44:00 +01:00
|
|
|
#ifdef FEAT_GUI_GTK
|
|
|
|
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_CMD)
|
|
|
|
#endif
|
2020-06-20 14:43:23 +02:00
|
|
|
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
|
2020-09-27 13:16:46 +02:00
|
|
|
&& ((key >= '!' && key <= '/')
|
|
|
|
|| (key >= ':' && key <= 'Z')
|
2022-09-12 20:35:28 +01:00
|
|
|
|| vim_isdigit(key)
|
2020-09-27 13:16:46 +02:00
|
|
|
|| (key >= '[' && key <= '`')
|
2020-06-20 14:43:23 +02:00
|
|
|
|| (key >= '{' && key <= '~')))
|
|
|
|
return modifiers & ~MOD_MASK_SHIFT;
|
2020-10-07 17:29:48 +02:00
|
|
|
|
|
|
|
if (modifiers == (MOD_MASK_SHIFT | MOD_MASK_CTRL)
|
|
|
|
&& (key == '{' || key == '}' || key == '|'))
|
|
|
|
return modifiers & ~MOD_MASK_SHIFT;
|
|
|
|
|
2020-06-20 14:43:23 +02:00
|
|
|
return modifiers;
|
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Try to include modifiers in the key.
|
|
|
|
* Changes "Shift-a" to 'A', "Alt-A" to 0xc0, etc.
|
2019-10-13 16:43:39 +02:00
|
|
|
* When "simplify" is FALSE don't do Ctrl and Alt.
|
|
|
|
* When "simplify" is TRUE and Ctrl or Alt is removed from modifiers set
|
|
|
|
* "did_simplify" when it's not NULL.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
int
|
2019-10-13 16:43:39 +02:00
|
|
|
extract_modifiers(int key, int *modp, int simplify, int *did_simplify)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int modifiers = *modp;
|
|
|
|
|
2017-10-28 21:11:06 +02:00
|
|
|
#ifdef MACOS_X
|
2019-10-13 16:43:39 +02:00
|
|
|
// Command-key really special, no fancynest
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!(modifiers & MOD_MASK_CMD))
|
|
|
|
#endif
|
|
|
|
if ((modifiers & MOD_MASK_SHIFT) && ASCII_ISALPHA(key))
|
|
|
|
{
|
|
|
|
key = TOUPPER_ASC(key);
|
2020-06-19 21:46:52 +02:00
|
|
|
// With <C-S-a> we keep the shift modifier.
|
|
|
|
// With <S-a>, <A-S-a> and <S-A> we don't keep the shift modifier.
|
|
|
|
if (simplify || modifiers == MOD_MASK_SHIFT
|
|
|
|
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_ALT)
|
|
|
|
|| modifiers == (MOD_MASK_SHIFT | MOD_MASK_META))
|
2019-10-13 16:43:39 +02:00
|
|
|
modifiers &= ~MOD_MASK_SHIFT;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-10-13 16:43:39 +02:00
|
|
|
|
|
|
|
// <C-H> and <C-h> mean the same thing, always use "H"
|
|
|
|
if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
|
|
|
|
key = TOUPPER_ASC(key);
|
|
|
|
|
|
|
|
if (simplify && (modifiers & MOD_MASK_CTRL)
|
2022-01-31 14:59:41 +00:00
|
|
|
&& ((key >= '?' && key <= '_') || ASCII_ISALPHA(key)))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
key = Ctrl_chr(key);
|
|
|
|
modifiers &= ~MOD_MASK_CTRL;
|
2019-12-21 18:25:54 +01:00
|
|
|
// <C-@> is <Nul>
|
2022-04-26 12:51:07 +01:00
|
|
|
if (key == NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
key = K_ZERO;
|
2019-10-13 16:43:39 +02:00
|
|
|
if (did_simplify != NULL)
|
|
|
|
*did_simplify = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
2019-10-13 16:43:39 +02:00
|
|
|
|
2017-10-28 21:11:06 +02:00
|
|
|
#ifdef MACOS_X
|
2019-12-21 18:25:54 +01:00
|
|
|
// Command-key really special, no fancynest
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!(modifiers & MOD_MASK_CMD))
|
|
|
|
#endif
|
2019-10-13 16:43:39 +02:00
|
|
|
if (simplify && (modifiers & MOD_MASK_ALT) && key < 0x80
|
2019-01-24 15:54:21 +01:00
|
|
|
&& !enc_dbcs) // avoid creating a lead byte
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
key |= 0x80;
|
2019-12-21 18:25:54 +01:00
|
|
|
modifiers &= ~MOD_MASK_ALT; // remove the META modifier
|
2019-10-13 16:43:39 +02:00
|
|
|
if (did_simplify != NULL)
|
|
|
|
*did_simplify = TRUE;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*modp = modifiers;
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to find key "c" in the special key table.
|
|
|
|
* Return the index when found, -1 when not found.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
find_special_key_in_table(int c)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2025-03-06 22:26:23 +01:00
|
|
|
for (i = 0; i < (int)ARRAY_LENGTH(key_names_table); i++)
|
2004-06-13 20:20:40 +00:00
|
|
|
if (c == key_names_table[i].key)
|
2025-03-06 22:26:23 +01:00
|
|
|
return key_names_table[i].enabled ? i : -1;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compare two 'struct key_name_entry' structures.
|
|
|
|
* Note that the target string (p1) may contain additional trailing characters
|
|
|
|
* that should not factor into the comparison. Example:
|
|
|
|
* 'LeftMouse>", "<LeftMouse>"] ...'
|
|
|
|
* should match with
|
|
|
|
* 'LeftMouse'.
|
|
|
|
* These characters are identified by vim_isNormalIDc().
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
cmp_key_name_entry(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
char_u *p1 = ((struct key_name_entry *)a)->name.string;
|
|
|
|
char_u *p2 = ((struct key_name_entry *)b)->name.string;
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
if (p1 == p2)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (vim_isNormalIDc(*p1) && *p2 != NUL)
|
|
|
|
{
|
|
|
|
if ((result = TOLOWER_ASC(*p1) - TOLOWER_ASC(*p2)) != 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
break;
|
2025-03-06 22:26:23 +01:00
|
|
|
++p1;
|
|
|
|
++p2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
{
|
|
|
|
if (*p2 == NUL)
|
|
|
|
{
|
|
|
|
if (vim_isNormalIDc(*p1))
|
|
|
|
result = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the special key with the given name (the given string does not have to
|
|
|
|
* end with NUL, the name is assumed to end before the first non-idchar).
|
|
|
|
* If the name starts with "t_" the next two characters are interpreted as a
|
|
|
|
* termcap name.
|
|
|
|
* Return the key code, or 0 if not found.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_special_key_code(char_u *name)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If it's <t_xx> we get the code for xx from the termcap
|
|
|
|
*/
|
|
|
|
if (name[0] == 't' && name[1] == '_' && name[2] != NUL && name[3] != NUL)
|
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
char_u string[3];
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
string[0] = name[2];
|
|
|
|
string[1] = name[3];
|
|
|
|
string[2] = NUL;
|
|
|
|
if (add_termcap_entry(string, FALSE) == OK)
|
|
|
|
return TERMCAP2KEY(name[2], name[3]);
|
|
|
|
}
|
|
|
|
else
|
2025-03-06 22:26:23 +01:00
|
|
|
{
|
|
|
|
struct key_name_entry target;
|
|
|
|
struct key_name_entry *entry;
|
|
|
|
|
|
|
|
target.enabled = TRUE;
|
|
|
|
target.key = 0;
|
|
|
|
target.name.string = name;
|
|
|
|
target.name.length = 0;
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
target.pref_name = NULL;
|
2025-03-06 22:26:23 +01:00
|
|
|
|
|
|
|
entry = (struct key_name_entry *)bsearch(
|
|
|
|
&target,
|
|
|
|
&key_names_table,
|
|
|
|
ARRAY_LENGTH(key_names_table),
|
|
|
|
sizeof(key_names_table[0]),
|
|
|
|
cmp_key_name_entry);
|
|
|
|
if (entry != NULL && entry->enabled)
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
{
|
|
|
|
int key = entry->key;
|
|
|
|
// Both TAB and K_TAB have name "Tab", and it's unspecified which
|
|
|
|
// one bsearch() will return. TAB is the expected one.
|
|
|
|
return key == K_TAB ? TAB : key;
|
|
|
|
}
|
2025-03-06 22:26:23 +01:00
|
|
|
}
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char_u *
|
2016-01-30 19:39:49 +01:00
|
|
|
get_key_name(int i)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
if (i < 0 || i >= (int)ARRAY_LENGTH(key_names_table))
|
2004-06-13 20:20:40 +00:00
|
|
|
return NULL;
|
2025-03-06 22:26:23 +01:00
|
|
|
|
patch 9.1.1180: short-description
Problem: The meaning of <Tab> depends on unspecified behavior
(after 9.1.1179).
Solution: Return TAB in case bsearch() finds K_TAB. Rename alt_name to
pref_name as that's closer to it meaning (zeertzjq).
The man page of bsearch() says:
The bsearch() function returns a pointer to a matching member of the
array, or NULL if no match is found. If there are multiple elements
that match the key, the element returned is unspecified.
So it's possible that bsearch() finds K_TAB instead of TAB when trying
to get the key code for <Tab>. Actually, it can happen when adding a
single key to end of the table:
closes: #16821
Signed-off-by: zeertzjq <zeertzjq@outlook.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/misc2.c b/src/misc2.c
index 151745ca2..90f108a24 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1141,7 +1141,8 @@ static struct key_name_entry
{TRUE, K_XRIGHT, STRING_INIT("xRight"), NULL},
{TRUE, K_XUP, STRING_INIT("xUp"), NULL},
{TRUE, K_ZEND, STRING_INIT("zEnd"), NULL},
- {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL}
+ {TRUE, K_ZHOME, STRING_INIT("zHome"), NULL},
+ {TRUE, -1, STRING_INIT("zzDummyKey"), NULL}
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
#undef STRING_INIT
Meanwhile IDX_KEYNAME_TAB doesn't do anything, as TAB and K_TAB have the
same name.
Signed-off-by: Christian Brabandt <cb@256bit.org>
2025-03-07 18:51:40 +01:00
|
|
|
return (key_names_table[i].pref_name != NULL) ?
|
|
|
|
key_names_table[i].pref_name->string :
|
2025-03-06 22:26:23 +01:00
|
|
|
key_names_table[i].name.string;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_fileformat(buf_T *buf)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int c = *buf->b_p_ff;
|
|
|
|
|
|
|
|
if (buf->b_p_bin || c == 'u')
|
|
|
|
return EOL_UNIX;
|
|
|
|
if (c == 'm')
|
|
|
|
return EOL_MAC;
|
|
|
|
return EOL_DOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Like get_fileformat(), but override 'fileformat' with "p" for "++opt=val"
|
|
|
|
* argument.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_fileformat_force(
|
|
|
|
buf_T *buf,
|
2019-12-21 18:25:54 +01:00
|
|
|
exarg_T *eap) // can be NULL!
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
if (eap != NULL && eap->force_ff != 0)
|
2018-04-04 22:57:29 +02:00
|
|
|
c = eap->force_ff;
|
2004-06-13 20:20:40 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((eap != NULL && eap->force_bin != 0)
|
|
|
|
? (eap->force_bin == FORCE_BIN) : buf->b_p_bin)
|
|
|
|
return EOL_UNIX;
|
|
|
|
c = *buf->b_p_ff;
|
|
|
|
}
|
|
|
|
if (c == 'u')
|
|
|
|
return EOL_UNIX;
|
|
|
|
if (c == 'm')
|
|
|
|
return EOL_MAC;
|
|
|
|
return EOL_DOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the current end-of-line type to EOL_DOS, EOL_UNIX or EOL_MAC.
|
|
|
|
* Sets both 'textmode' and 'fileformat'.
|
|
|
|
* Note: Does _not_ set global value of 'textmode'!
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
set_fileformat(
|
|
|
|
int t,
|
2019-12-21 18:25:54 +01:00
|
|
|
int opt_flags) // OPT_LOCAL and/or OPT_GLOBAL
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char *p = NULL;
|
|
|
|
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case EOL_DOS:
|
|
|
|
p = FF_DOS;
|
|
|
|
curbuf->b_p_tx = TRUE;
|
|
|
|
break;
|
|
|
|
case EOL_UNIX:
|
|
|
|
p = FF_UNIX;
|
|
|
|
curbuf->b_p_tx = FALSE;
|
|
|
|
break;
|
|
|
|
case EOL_MAC:
|
|
|
|
p = FF_MAC;
|
|
|
|
curbuf->b_p_tx = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p != NULL)
|
|
|
|
set_string_option_direct((char_u *)"ff", -1, (char_u *)p,
|
2006-02-27 23:58:35 +00:00
|
|
|
OPT_FREE | opt_flags, 0);
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// This may cause the buffer to become (un)modified.
|
2004-06-13 20:20:40 +00:00
|
|
|
check_status(curbuf);
|
2006-02-17 21:53:23 +00:00
|
|
|
redraw_tabline = TRUE;
|
2019-12-21 18:25:54 +01:00
|
|
|
need_maketitle = TRUE; // set window title later
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the default fileformat from 'fileformats'.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
default_fileformat(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
switch (*p_ffs)
|
|
|
|
{
|
|
|
|
case 'm': return EOL_MAC;
|
|
|
|
case 'd': return EOL_DOS;
|
|
|
|
}
|
|
|
|
return EOL_UNIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Call shell. Calls mch_call_shell, with 'shellxquote' added.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
call_shell(char_u *cmd, int opt)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int retval;
|
2005-02-26 23:04:13 +00:00
|
|
|
#ifdef FEAT_PROFILE
|
|
|
|
proftime_T wait_time;
|
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
if (p_verbose > 3)
|
|
|
|
{
|
2005-05-31 22:14:58 +00:00
|
|
|
verbose_enter();
|
2020-05-12 23:45:16 +02:00
|
|
|
smsg(_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd);
|
2022-09-26 19:50:44 +01:00
|
|
|
msg_putchar_attr('\n', 0);
|
2004-06-13 20:20:40 +00:00
|
|
|
cursor_on();
|
2005-05-31 22:14:58 +00:00
|
|
|
verbose_leave();
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
|
2005-02-26 23:04:13 +00:00
|
|
|
#ifdef FEAT_PROFILE
|
2006-03-20 21:50:15 +00:00
|
|
|
if (do_profiling == PROF_YES)
|
2005-02-26 23:04:13 +00:00
|
|
|
prof_child_enter(&wait_time);
|
|
|
|
#endif
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (*p_sh == NUL)
|
|
|
|
{
|
2021-12-16 20:56:57 +00:00
|
|
|
emsg(_(e_shell_option_is_empty));
|
2004-06-13 20:20:40 +00:00
|
|
|
retval = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef FEAT_GUI_MSWIN
|
2019-12-21 18:25:54 +01:00
|
|
|
// Don't hide the pointer while executing a shell command.
|
2004-06-13 20:20:40 +00:00
|
|
|
gui_mch_mousehide(FALSE);
|
|
|
|
#endif
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
++hold_gui_events;
|
|
|
|
#endif
|
2019-12-21 18:25:54 +01:00
|
|
|
// The external command may update a tags file, clear cached tags.
|
2004-06-13 20:20:40 +00:00
|
|
|
tag_freematch();
|
|
|
|
|
2019-06-10 14:46:04 +02:00
|
|
|
if (cmd == NULL || *p_sxq == NUL)
|
2004-06-13 20:20:40 +00:00
|
|
|
retval = mch_call_shell(cmd, opt);
|
|
|
|
else
|
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
char_u *ncmd;
|
|
|
|
size_t ncmdsize;
|
|
|
|
char_u *ecmd = cmd;
|
2012-02-20 22:18:30 +01:00
|
|
|
|
2019-09-28 15:51:37 +02:00
|
|
|
if (*p_sxe != NUL && *p_sxq == '(')
|
2012-02-20 22:18:30 +01:00
|
|
|
{
|
|
|
|
ecmd = vim_strsave_escaped_ext(cmd, p_sxe, '^', FALSE);
|
|
|
|
if (ecmd == NULL)
|
|
|
|
ecmd = cmd;
|
|
|
|
}
|
2025-03-06 22:26:23 +01:00
|
|
|
ncmdsize = STRLEN(ecmd) + STRLEN(p_sxq) * 2 + 1;
|
|
|
|
ncmd = alloc(ncmdsize);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (ncmd != NULL)
|
|
|
|
{
|
2019-09-28 15:51:37 +02:00
|
|
|
// When 'shellxquote' is ( append ).
|
|
|
|
// When 'shellxquote' is "( append )".
|
2025-03-06 22:26:23 +01:00
|
|
|
vim_snprintf((char *)ncmd, ncmdsize, "%s%s%s", p_sxq, ecmd, *p_sxq == '(' ? (char_u *)")"
|
2019-09-28 15:51:37 +02:00
|
|
|
: *p_sxq == '"' && *(p_sxq+1) == '(' ? (char_u *)")\""
|
|
|
|
: p_sxq);
|
2004-06-13 20:20:40 +00:00
|
|
|
retval = mch_call_shell(ncmd, opt);
|
|
|
|
vim_free(ncmd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
retval = -1;
|
2012-02-20 22:18:30 +01:00
|
|
|
if (ecmd != cmd)
|
|
|
|
vim_free(ecmd);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
#ifdef FEAT_GUI
|
|
|
|
--hold_gui_events;
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Check the window size, in case it changed while executing the
|
|
|
|
* external command.
|
|
|
|
*/
|
|
|
|
shell_resized_check();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FEAT_EVAL
|
|
|
|
set_vim_var_nr(VV_SHELL_ERROR, (long)retval);
|
2005-02-26 23:04:13 +00:00
|
|
|
# ifdef FEAT_PROFILE
|
2006-03-20 21:50:15 +00:00
|
|
|
if (do_profiling == PROF_YES)
|
2005-02-26 23:04:13 +00:00
|
|
|
prof_child_exit(&wait_time);
|
|
|
|
# endif
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2022-05-07 20:01:16 +01:00
|
|
|
* MODE_VISUAL, MODE_SELECT and MODE_OP_PENDING State are never set, they are
|
|
|
|
* equal to MODE_NORMAL State with a condition. This function returns the real
|
|
|
|
* State.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_real_state(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2022-05-07 20:01:16 +01:00
|
|
|
if (State & MODE_NORMAL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (VIsual_active)
|
2006-03-20 21:50:15 +00:00
|
|
|
{
|
|
|
|
if (VIsual_select)
|
2022-05-07 20:01:16 +01:00
|
|
|
return MODE_SELECT;
|
|
|
|
return MODE_VISUAL;
|
2006-03-20 21:50:15 +00:00
|
|
|
}
|
2014-03-23 15:13:05 +01:00
|
|
|
else if (finish_op)
|
2022-05-07 20:01:16 +01:00
|
|
|
return MODE_OP_PENDING;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
return State;
|
|
|
|
}
|
|
|
|
|
2004-12-19 22:46:22 +00:00
|
|
|
/*
|
|
|
|
* Return TRUE if "p" points to just after a path separator.
|
2011-07-07 17:15:33 +02:00
|
|
|
* Takes care of multi-byte characters.
|
2004-12-19 22:46:22 +00:00
|
|
|
* "b" must point to the start of the file name
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
after_pathsep(char_u *b, char_u *p)
|
2004-12-19 22:46:22 +00:00
|
|
|
{
|
2011-07-07 17:15:33 +02:00
|
|
|
return p > b && vim_ispathsep(p[-1])
|
2004-12-19 22:46:22 +00:00
|
|
|
&& (!has_mbyte || (*mb_head_off)(b, p - 1) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return TRUE if file names "f1" and "f2" are in the same directory.
|
|
|
|
* "f1" may be a short name, "f2" must be a full path.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
same_directory(char_u *f1, char_u *f2)
|
2004-12-19 22:46:22 +00:00
|
|
|
{
|
|
|
|
char_u ffname[MAXPATHL];
|
|
|
|
char_u *t1;
|
|
|
|
char_u *t2;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// safety check
|
2004-12-19 22:46:22 +00:00
|
|
|
if (f1 == NULL || f2 == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
(void)vim_FullName(f1, ffname, MAXPATHL, FALSE);
|
|
|
|
t1 = gettail_sep(ffname);
|
|
|
|
t2 = gettail_sep(f2);
|
|
|
|
return (t1 - ffname == t2 - f2
|
|
|
|
&& pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0);
|
|
|
|
}
|
|
|
|
|
2018-06-29 20:28:31 +02:00
|
|
|
#if defined(FEAT_SESSION) || defined(FEAT_AUTOCHDIR) \
|
2020-08-11 21:58:20 +02:00
|
|
|
|| defined(MSWIN) || defined(FEAT_GUI_GTK) \
|
2019-01-17 15:45:25 +01:00
|
|
|
|| defined(FEAT_NETBEANS_INTG) \
|
2004-06-13 20:20:40 +00:00
|
|
|
|| defined(PROTO)
|
|
|
|
/*
|
|
|
|
* Change to a file's directory.
|
|
|
|
* Caller must call shorten_fnames()!
|
|
|
|
* Return OK or FAIL.
|
|
|
|
*/
|
|
|
|
int
|
2018-12-16 15:38:02 +01:00
|
|
|
vim_chdirfile(char_u *fname, char *trigger_autocmd)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2018-12-16 15:38:02 +01:00
|
|
|
char_u old_dir[MAXPATHL];
|
|
|
|
char_u new_dir[MAXPATHL];
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2018-12-16 15:38:02 +01:00
|
|
|
if (mch_dirname(old_dir, MAXPATHL) != OK)
|
|
|
|
*old_dir = NUL;
|
|
|
|
|
|
|
|
vim_strncpy(new_dir, fname, MAXPATHL - 1);
|
|
|
|
*gettail_sep(new_dir) = NUL;
|
|
|
|
|
2018-12-16 16:30:21 +01:00
|
|
|
if (pathcmp((char *)old_dir, (char *)new_dir, -1) == 0)
|
2018-12-16 15:38:02 +01:00
|
|
|
// nothing to do
|
2022-02-02 13:16:37 +00:00
|
|
|
return OK;
|
|
|
|
|
2022-02-09 12:58:20 +00:00
|
|
|
if (trigger_autocmd != NULL)
|
|
|
|
trigger_DirChangedPre((char_u *)trigger_autocmd, new_dir);
|
|
|
|
|
2022-02-02 13:16:37 +00:00
|
|
|
if (mch_chdir((char *)new_dir) != 0)
|
|
|
|
return FAIL;
|
2018-12-16 15:38:02 +01:00
|
|
|
|
2022-02-02 13:16:37 +00:00
|
|
|
if (trigger_autocmd != NULL)
|
|
|
|
apply_autocmds(EVENT_DIRCHANGED, (char_u *)trigger_autocmd,
|
2018-12-16 15:38:02 +01:00
|
|
|
new_dir, FALSE, curbuf);
|
2022-02-02 13:16:37 +00:00
|
|
|
return OK;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(STAT_IGNORES_SLASH) || defined(PROTO)
|
|
|
|
/*
|
|
|
|
* Check if "name" ends in a slash and is not a directory.
|
|
|
|
* Used for systems where stat() ignores a trailing slash on a file name.
|
|
|
|
* The Vim code assumes a trailing slash is only ignored for a directory.
|
|
|
|
*/
|
2017-03-12 19:22:36 +01:00
|
|
|
static int
|
2017-03-16 12:22:38 +01:00
|
|
|
illegal_slash(const char *name)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (name[0] == NUL)
|
2019-12-21 18:25:54 +01:00
|
|
|
return FALSE; // no file name is not illegal
|
2004-06-13 20:20:40 +00:00
|
|
|
if (name[strlen(name) - 1] != '/')
|
2019-12-21 18:25:54 +01:00
|
|
|
return FALSE; // no trailing slash
|
2004-06-13 20:20:40 +00:00
|
|
|
if (mch_isdir((char_u *)name))
|
2019-12-21 18:25:54 +01:00
|
|
|
return FALSE; // trailing slash for a directory
|
2004-06-13 20:20:40 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2017-03-12 19:22:36 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Special implementation of mch_stat() for Solaris.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
vim_stat(const char *name, stat_T *stp)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// On Solaris stat() accepts "file/" as if it was "file". Return -1 if
|
|
|
|
// the name ends in "/" and it's not a directory.
|
2017-03-16 12:22:38 +01:00
|
|
|
return illegal_slash(name) ? -1 : stat(name, stp);
|
2017-03-12 19:22:36 +01:00
|
|
|
}
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CURSOR_SHAPE) || defined(PROTO)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handling of cursor and mouse pointer shapes in various modes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
cursorentry_T shape_table[SHAPE_IDX_COUNT] =
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// The values will be filled in from the 'guicursor' and 'mouseshape'
|
|
|
|
// defaults when Vim starts.
|
|
|
|
// Adjust the SHAPE_IDX_ defines when making changes!
|
2004-06-13 20:20:40 +00:00
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE},
|
|
|
|
{0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
|
|
|
|
};
|
|
|
|
|
2022-11-14 19:49:15 +00:00
|
|
|
# ifdef FEAT_MOUSESHAPE
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Table with names for mouse shapes. Keep in sync with all the tables for
|
|
|
|
* mch_set_mouse_shape()!.
|
|
|
|
*/
|
2025-03-06 22:26:23 +01:00
|
|
|
#define STRING_INIT(s) \
|
|
|
|
{(char_u *)(s), STRLEN_LITERAL(s)}
|
|
|
|
static string_T mshape_names[] =
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
STRING_INIT("arrow"), // default, must be the first one
|
|
|
|
STRING_INIT("blank"), // hidden
|
|
|
|
STRING_INIT("beam"),
|
|
|
|
STRING_INIT("updown"),
|
|
|
|
STRING_INIT("udsizing"),
|
|
|
|
STRING_INIT("leftright"),
|
|
|
|
STRING_INIT("lrsizing"),
|
|
|
|
STRING_INIT("busy"),
|
|
|
|
STRING_INIT("no"),
|
|
|
|
STRING_INIT("crosshair"),
|
|
|
|
STRING_INIT("hand1"),
|
|
|
|
STRING_INIT("hand2"),
|
|
|
|
STRING_INIT("pencil"),
|
|
|
|
STRING_INIT("question"),
|
|
|
|
STRING_INIT("rightup-arrow"),
|
|
|
|
STRING_INIT("up-arrow"),
|
|
|
|
{NULL, 0}
|
2004-06-13 20:20:40 +00:00
|
|
|
};
|
2025-03-06 22:26:23 +01:00
|
|
|
#undef STRING_INIT
|
2022-11-14 19:49:15 +00:00
|
|
|
|
|
|
|
# define MSHAPE_NAMES_COUNT (ARRAY_LENGTH(mshape_names) - 1)
|
|
|
|
# endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
|
|
|
|
* ("what" is SHAPE_MOUSE).
|
|
|
|
* Returns error message for an illegal option, NULL otherwise.
|
|
|
|
*/
|
2019-01-13 23:38:42 +01:00
|
|
|
char *
|
2016-01-30 19:39:49 +01:00
|
|
|
parse_shape_opt(int what)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char_u *modep;
|
|
|
|
char_u *colonp;
|
|
|
|
char_u *commap;
|
|
|
|
char_u *slashp;
|
|
|
|
char_u *p, *endp;
|
2019-12-21 18:25:54 +01:00
|
|
|
int idx = 0; // init for GCC
|
2004-06-13 20:20:40 +00:00
|
|
|
int all_idx;
|
|
|
|
int len;
|
|
|
|
int i;
|
|
|
|
long n;
|
2019-12-21 18:25:54 +01:00
|
|
|
int found_ve = FALSE; // found "ve" flag
|
2004-06-13 20:20:40 +00:00
|
|
|
int round;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First round: check for errors; second round: do it for real.
|
|
|
|
*/
|
|
|
|
for (round = 1; round <= 2; ++round)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Repeat for all comma separated parts.
|
|
|
|
*/
|
|
|
|
#ifdef FEAT_MOUSESHAPE
|
|
|
|
if (what == SHAPE_MOUSE)
|
|
|
|
modep = p_mouseshape;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
modep = p_guicursor;
|
|
|
|
while (*modep != NUL)
|
|
|
|
{
|
|
|
|
colonp = vim_strchr(modep, ':');
|
2017-02-23 17:59:22 +01:00
|
|
|
commap = vim_strchr(modep, ',');
|
|
|
|
|
|
|
|
if (colonp == NULL || (commap != NULL && commap < colonp))
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_missing_colon_2;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (colonp == modep)
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_illegal_mode;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Repeat for all mode's before the colon.
|
|
|
|
* For the 'a' mode, we loop to handle all the modes.
|
|
|
|
*/
|
|
|
|
all_idx = -1;
|
|
|
|
while (modep < colonp || all_idx >= 0)
|
|
|
|
{
|
|
|
|
if (all_idx < 0)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Find the mode.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (modep[1] == '-' || modep[1] == ':')
|
|
|
|
len = 1;
|
|
|
|
else
|
|
|
|
len = 2;
|
|
|
|
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a')
|
|
|
|
all_idx = SHAPE_IDX_COUNT - 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
|
|
|
|
if (STRNICMP(modep, shape_table[idx].name, len)
|
|
|
|
== 0)
|
|
|
|
break;
|
|
|
|
if (idx == SHAPE_IDX_COUNT
|
|
|
|
|| (shape_table[idx].used_for & what) == 0)
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_illegal_mode;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
|
|
|
|
found_ve = TRUE;
|
|
|
|
}
|
|
|
|
modep += len + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (all_idx >= 0)
|
|
|
|
idx = all_idx--;
|
|
|
|
else if (round == 2)
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSESHAPE
|
|
|
|
if (what == SHAPE_MOUSE)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Set the default, for the missing parts
|
2004-06-13 20:20:40 +00:00
|
|
|
shape_table[idx].mshape = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Set the defaults, for the missing parts
|
2004-06-13 20:20:40 +00:00
|
|
|
shape_table[idx].shape = SHAPE_BLOCK;
|
|
|
|
shape_table[idx].blinkwait = 700L;
|
|
|
|
shape_table[idx].blinkon = 400L;
|
|
|
|
shape_table[idx].blinkoff = 250L;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Parse the part after the colon
|
2004-06-13 20:20:40 +00:00
|
|
|
for (p = colonp + 1; *p && *p != ','; )
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSESHAPE
|
|
|
|
if (what == SHAPE_MOUSE)
|
|
|
|
{
|
|
|
|
for (i = 0; ; ++i)
|
|
|
|
{
|
2025-03-06 22:26:23 +01:00
|
|
|
if (mshape_names[i].string == NULL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (!VIM_ISDIGIT(*p))
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_illegal_mouseshape;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (round == 2)
|
|
|
|
shape_table[idx].mshape =
|
|
|
|
getdigits(&p) + MSHAPE_NUMBERED;
|
|
|
|
else
|
|
|
|
(void)getdigits(&p);
|
|
|
|
break;
|
|
|
|
}
|
2025-03-06 22:26:23 +01:00
|
|
|
if (STRNICMP(p, mshape_names[i].string, mshape_names[i].length) == 0)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (round == 2)
|
|
|
|
shape_table[idx].mshape = i;
|
2025-03-06 22:26:23 +01:00
|
|
|
p += mshape_names[i].length;
|
2004-06-13 20:20:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
else // if (what == SHAPE_MOUSE)
|
2004-06-13 20:20:40 +00:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* First handle the ones with a number argument.
|
|
|
|
*/
|
|
|
|
i = *p;
|
|
|
|
len = 0;
|
|
|
|
if (STRNICMP(p, "ver", 3) == 0)
|
|
|
|
len = 3;
|
|
|
|
else if (STRNICMP(p, "hor", 3) == 0)
|
|
|
|
len = 3;
|
|
|
|
else if (STRNICMP(p, "blinkwait", 9) == 0)
|
|
|
|
len = 9;
|
|
|
|
else if (STRNICMP(p, "blinkon", 7) == 0)
|
|
|
|
len = 7;
|
|
|
|
else if (STRNICMP(p, "blinkoff", 8) == 0)
|
|
|
|
len = 8;
|
|
|
|
if (len != 0)
|
|
|
|
{
|
|
|
|
p += len;
|
|
|
|
if (!VIM_ISDIGIT(*p))
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_digit_expected;
|
2004-06-13 20:20:40 +00:00
|
|
|
n = getdigits(&p);
|
2019-12-21 18:25:54 +01:00
|
|
|
if (len == 3) // "ver" or "hor"
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (n == 0)
|
2022-01-02 21:26:16 +00:00
|
|
|
return e_illegal_percentage;
|
2004-06-13 20:20:40 +00:00
|
|
|
if (round == 2)
|
|
|
|
{
|
|
|
|
if (TOLOWER_ASC(i) == 'v')
|
|
|
|
shape_table[idx].shape = SHAPE_VER;
|
|
|
|
else
|
|
|
|
shape_table[idx].shape = SHAPE_HOR;
|
|
|
|
shape_table[idx].percentage = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (round == 2)
|
|
|
|
{
|
|
|
|
if (len == 9)
|
|
|
|
shape_table[idx].blinkwait = n;
|
|
|
|
else if (len == 7)
|
|
|
|
shape_table[idx].blinkon = n;
|
|
|
|
else
|
|
|
|
shape_table[idx].blinkoff = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (STRNICMP(p, "block", 5) == 0)
|
|
|
|
{
|
|
|
|
if (round == 2)
|
|
|
|
shape_table[idx].shape = SHAPE_BLOCK;
|
|
|
|
p += 5;
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
else // must be a highlight group name then
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
endp = vim_strchr(p, '-');
|
2019-12-21 18:25:54 +01:00
|
|
|
if (commap == NULL) // last part
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (endp == NULL)
|
2019-12-21 18:25:54 +01:00
|
|
|
endp = p + STRLEN(p); // find end of part
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
else if (endp > commap || endp == NULL)
|
|
|
|
endp = commap;
|
|
|
|
slashp = vim_strchr(p, '/');
|
|
|
|
if (slashp != NULL && slashp < endp)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// "group/langmap_group"
|
2004-06-13 20:20:40 +00:00
|
|
|
i = syn_check_group(p, (int)(slashp - p));
|
|
|
|
p = slashp + 1;
|
|
|
|
}
|
|
|
|
if (round == 2)
|
|
|
|
{
|
|
|
|
shape_table[idx].id = syn_check_group(p,
|
|
|
|
(int)(endp - p));
|
|
|
|
shape_table[idx].id_lm = shape_table[idx].id;
|
|
|
|
if (slashp != NULL && slashp < endp)
|
|
|
|
shape_table[idx].id = i;
|
|
|
|
}
|
|
|
|
p = endp;
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
} // if (what != SHAPE_MOUSE)
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
if (*p == '-')
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
modep = p;
|
|
|
|
if (*modep == ',')
|
|
|
|
++modep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// If the 's' flag is not given, use the 'v' cursor for 's'
|
2004-06-13 20:20:40 +00:00
|
|
|
if (!found_ve)
|
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSESHAPE
|
|
|
|
if (what == SHAPE_MOUSE)
|
|
|
|
{
|
|
|
|
shape_table[SHAPE_IDX_VE].mshape = shape_table[SHAPE_IDX_V].mshape;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
|
|
|
|
shape_table[SHAPE_IDX_VE].percentage =
|
|
|
|
shape_table[SHAPE_IDX_V].percentage;
|
|
|
|
shape_table[SHAPE_IDX_VE].blinkwait =
|
|
|
|
shape_table[SHAPE_IDX_V].blinkwait;
|
|
|
|
shape_table[SHAPE_IDX_VE].blinkon =
|
|
|
|
shape_table[SHAPE_IDX_V].blinkon;
|
|
|
|
shape_table[SHAPE_IDX_VE].blinkoff =
|
|
|
|
shape_table[SHAPE_IDX_V].blinkoff;
|
|
|
|
shape_table[SHAPE_IDX_VE].id = shape_table[SHAPE_IDX_V].id;
|
|
|
|
shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2005-08-29 22:25:38 +00:00
|
|
|
# if defined(MCH_CURSOR_SHAPE) || defined(FEAT_GUI) \
|
|
|
|
|| defined(FEAT_MOUSESHAPE) || defined(PROTO)
|
2004-06-13 20:20:40 +00:00
|
|
|
/*
|
|
|
|
* Return the index into shape_table[] for the current mode.
|
|
|
|
* When "mouse" is TRUE, consider indexes valid for the mouse pointer.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_shape_idx(int mouse)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
#ifdef FEAT_MOUSESHAPE
|
2022-05-07 20:01:16 +01:00
|
|
|
if (mouse && (State == MODE_HITRETURN || State == MODE_ASKMORE))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
# ifdef FEAT_GUI
|
2005-01-08 21:45:39 +00:00
|
|
|
int x, y;
|
|
|
|
gui_mch_getmouse(&x, &y);
|
|
|
|
if (Y_2_ROW(y) == Rows - 1)
|
2004-06-13 20:20:40 +00:00
|
|
|
return SHAPE_IDX_MOREL;
|
|
|
|
# endif
|
|
|
|
return SHAPE_IDX_MORE;
|
|
|
|
}
|
|
|
|
if (mouse && drag_status_line)
|
|
|
|
return SHAPE_IDX_SDRAG;
|
|
|
|
if (mouse && drag_sep_line)
|
|
|
|
return SHAPE_IDX_VDRAG;
|
|
|
|
#endif
|
2022-05-07 20:01:16 +01:00
|
|
|
if (!mouse && State == MODE_SHOWMATCH)
|
2004-06-13 20:20:40 +00:00
|
|
|
return SHAPE_IDX_SM;
|
|
|
|
if (State & VREPLACE_FLAG)
|
|
|
|
return SHAPE_IDX_R;
|
|
|
|
if (State & REPLACE_FLAG)
|
|
|
|
return SHAPE_IDX_R;
|
2022-05-07 20:01:16 +01:00
|
|
|
if (State & MODE_INSERT)
|
2004-06-13 20:20:40 +00:00
|
|
|
return SHAPE_IDX_I;
|
2022-05-07 20:01:16 +01:00
|
|
|
if (State & MODE_CMDLINE)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (cmdline_at_end())
|
|
|
|
return SHAPE_IDX_C;
|
|
|
|
if (cmdline_overstrike())
|
|
|
|
return SHAPE_IDX_CR;
|
|
|
|
return SHAPE_IDX_CI;
|
|
|
|
}
|
|
|
|
if (finish_op)
|
|
|
|
return SHAPE_IDX_O;
|
|
|
|
if (VIsual_active)
|
|
|
|
{
|
|
|
|
if (*p_sel == 'e')
|
|
|
|
return SHAPE_IDX_VE;
|
|
|
|
else
|
|
|
|
return SHAPE_IDX_V;
|
|
|
|
}
|
|
|
|
return SHAPE_IDX_N;
|
|
|
|
}
|
2005-08-29 22:25:38 +00:00
|
|
|
#endif
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
# if defined(FEAT_MOUSESHAPE) || defined(PROTO)
|
2022-11-14 19:49:15 +00:00
|
|
|
static int current_mouse_shape = 0;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the mouse shape:
|
|
|
|
* If "shape" is -1, use shape depending on the current mode,
|
|
|
|
* depending on the current state.
|
|
|
|
* If "shape" is -2, only update the shape when it's CLINE or STATUS (used
|
|
|
|
* when the mouse moves off the status or command line).
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
update_mouseshape(int shape_idx)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int new_mouse_shape;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Only works in GUI mode.
|
2005-03-22 23:03:44 +00:00
|
|
|
if (!gui.in_use || gui.starting)
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Postpone the updating when more is to come. Speeds up executing of
|
|
|
|
// mappings.
|
2004-06-13 20:20:40 +00:00
|
|
|
if (shape_idx == -1 && char_avail())
|
|
|
|
{
|
|
|
|
postponed_mouseshape = TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// When ignoring the mouse don't change shape on the statusline.
|
2006-05-04 21:54:08 +00:00
|
|
|
if (*p_mouse == NUL
|
|
|
|
&& (shape_idx == SHAPE_IDX_CLINE
|
|
|
|
|| shape_idx == SHAPE_IDX_STATUS
|
|
|
|
|| shape_idx == SHAPE_IDX_VSEP))
|
|
|
|
shape_idx = -2;
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
if (shape_idx == -2
|
2022-11-14 19:49:15 +00:00
|
|
|
&& current_mouse_shape != shape_table[SHAPE_IDX_CLINE].mshape
|
|
|
|
&& current_mouse_shape != shape_table[SHAPE_IDX_STATUS].mshape
|
|
|
|
&& current_mouse_shape != shape_table[SHAPE_IDX_VSEP].mshape)
|
2004-06-13 20:20:40 +00:00
|
|
|
return;
|
|
|
|
if (shape_idx < 0)
|
|
|
|
new_mouse_shape = shape_table[get_shape_idx(TRUE)].mshape;
|
|
|
|
else
|
|
|
|
new_mouse_shape = shape_table[shape_idx].mshape;
|
2022-11-14 19:49:15 +00:00
|
|
|
if (new_mouse_shape != current_mouse_shape)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
mch_set_mouse_shape(new_mouse_shape);
|
2022-11-14 19:49:15 +00:00
|
|
|
current_mouse_shape = new_mouse_shape;
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
postponed_mouseshape = FALSE;
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
#endif // CURSOR_SHAPE
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2022-11-14 19:49:15 +00:00
|
|
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
|
|
|
/*
|
|
|
|
* Mainly for tests: get the name of the current mouse shape.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
f_getmouseshape(typval_T *argvars UNUSED, typval_T *rettv)
|
|
|
|
{
|
|
|
|
rettv->v_type = VAR_STRING;
|
|
|
|
rettv->vval.v_string = NULL;
|
|
|
|
# if defined(FEAT_MOUSESHAPE) || defined(PROTO)
|
|
|
|
if (current_mouse_shape >= 0
|
|
|
|
&& current_mouse_shape < (int)MSHAPE_NAMES_COUNT)
|
2025-03-06 22:26:23 +01:00
|
|
|
rettv->vval.v_string = vim_strnsave(
|
|
|
|
mshape_names[current_mouse_shape].string,
|
|
|
|
mshape_names[current_mouse_shape].length);
|
2022-11-14 19:49:15 +00:00
|
|
|
# endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
/*
|
2022-08-25 16:02:23 +01:00
|
|
|
* Change directory to "new_dir". Search 'cdpath' for relative directory
|
2022-09-10 20:00:56 +01:00
|
|
|
* names.
|
2004-06-13 20:20:40 +00:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
vim_chdir(char_u *new_dir)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char_u *dir_name;
|
|
|
|
int r;
|
2023-03-11 13:55:53 +00:00
|
|
|
char_u *file_to_find = NULL;
|
|
|
|
char *search_ctx = NULL;
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
dir_name = find_directory_in_path(new_dir, (int)STRLEN(new_dir),
|
2023-03-11 13:55:53 +00:00
|
|
|
FNAME_MESS, curbuf->b_ffname, &file_to_find, &search_ctx);
|
|
|
|
vim_free(file_to_find);
|
|
|
|
vim_findfile_cleanup(search_ctx);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (dir_name == NULL)
|
|
|
|
return -1;
|
|
|
|
r = mch_chdir((char *)dir_name);
|
|
|
|
vim_free(dir_name);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-07-18 21:47:53 +00:00
|
|
|
* Get user name from machine-specific function.
|
2004-06-13 20:20:40 +00:00
|
|
|
* Returns the user name in "buf[len]".
|
2005-07-18 21:47:53 +00:00
|
|
|
* Some systems are quite slow in obtaining the user name (Windows NT), thus
|
|
|
|
* cache the result.
|
2004-06-13 20:20:40 +00:00
|
|
|
* Returns OK or FAIL.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get_user_name(char_u *buf, int len)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
2005-06-25 23:04:51 +00:00
|
|
|
if (username == NULL)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
if (mch_get_user_name(buf, len) == FAIL)
|
|
|
|
return FAIL;
|
2005-06-25 23:04:51 +00:00
|
|
|
username = vim_strsave(buf);
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
else
|
2005-07-18 21:47:53 +00:00
|
|
|
vim_strncpy(buf, username, len - 1);
|
2004-06-13 20:20:40 +00:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2022-05-16 19:40:59 +01:00
|
|
|
#if defined(EXITFREE) || defined(PROTO)
|
2021-08-06 21:51:55 +02:00
|
|
|
/*
|
|
|
|
* Free the memory allocated by get_user_name()
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
free_username(void)
|
|
|
|
{
|
|
|
|
vim_free(username);
|
|
|
|
}
|
2022-01-08 12:41:16 +00:00
|
|
|
#endif
|
2021-08-06 21:51:55 +02:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
#ifndef HAVE_QSORT
|
|
|
|
/*
|
|
|
|
* Our own qsort(), for systems that don't have it.
|
|
|
|
* It's simple and slow. From the K&R C book.
|
|
|
|
*/
|
|
|
|
void
|
2016-01-30 19:39:49 +01:00
|
|
|
qsort(
|
|
|
|
void *base,
|
|
|
|
size_t elm_count,
|
|
|
|
size_t elm_size,
|
|
|
|
int (*cmp)(const void *, const void *))
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char_u *buf;
|
|
|
|
char_u *p1;
|
|
|
|
char_u *p2;
|
|
|
|
int i, j;
|
|
|
|
int gap;
|
|
|
|
|
2019-05-24 18:54:09 +02:00
|
|
|
buf = alloc(elm_size);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (buf == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (gap = elm_count / 2; gap > 0; gap /= 2)
|
|
|
|
for (i = gap; i < elm_count; ++i)
|
|
|
|
for (j = i - gap; j >= 0; j -= gap)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Compare the elements.
|
2004-06-13 20:20:40 +00:00
|
|
|
p1 = (char_u *)base + j * elm_size;
|
|
|
|
p2 = (char_u *)base + (j + gap) * elm_size;
|
|
|
|
if ((*cmp)((void *)p1, (void *)p2) <= 0)
|
|
|
|
break;
|
2019-12-21 18:25:54 +01:00
|
|
|
// Exchange the elements.
|
2004-06-13 20:20:40 +00:00
|
|
|
mch_memmove(buf, p1, elm_size);
|
|
|
|
mch_memmove(p1, p2, elm_size);
|
|
|
|
mch_memmove(p2, buf, elm_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
vim_free(buf);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The putenv() implementation below comes from the "screen" program.
|
|
|
|
* Included with permission from Juergen Weigert.
|
|
|
|
* See pty.c for the copyright notice.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* putenv -- put value into environment
|
|
|
|
*
|
|
|
|
* Usage: i = putenv (string)
|
|
|
|
* int i;
|
|
|
|
* char *string;
|
|
|
|
*
|
|
|
|
* where string is of the form <name>=<value>.
|
|
|
|
* Putenv returns 0 normally, -1 on error (not enough core for malloc).
|
|
|
|
*
|
|
|
|
* Putenv may need to add a new name into the environment, or to
|
|
|
|
* associate a value longer than the current value with a particular
|
|
|
|
* name. So, to make life simpler, putenv() copies your entire
|
|
|
|
* environment into the heap (i.e. malloc()) from the stack
|
|
|
|
* (i.e. where it resides when your process is initiated) the first
|
|
|
|
* time you call it.
|
|
|
|
*
|
|
|
|
* (history removed, not very interesting. See the "screen" sources.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
#define EXTRASIZE 5 // increment to add to env. size
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
static int envsize = -1; // current size of environment
|
|
|
|
extern char **environ; // the global which is your env.
|
2004-06-13 20:20:40 +00:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
static int findenv(char *name); // look for a name in the env.
|
|
|
|
static int newenv(void); // copy env. from stack to heap
|
|
|
|
static int moreenv(void); // incr. size of env.
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
putenv(const char *string)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (envsize < 0)
|
2019-12-21 18:25:54 +01:00
|
|
|
{ // first time putenv called
|
|
|
|
if (newenv() < 0) // copy env. to heap
|
2004-06-13 20:20:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
i = findenv((char *)string); // look for name in environment
|
2004-06-13 20:20:40 +00:00
|
|
|
|
|
|
|
if (i < 0)
|
2019-12-21 18:25:54 +01:00
|
|
|
{ // name must be added
|
2004-06-13 20:20:40 +00:00
|
|
|
for (i = 0; environ[i]; i++);
|
|
|
|
if (i >= (envsize - 1))
|
2019-12-21 18:25:54 +01:00
|
|
|
{ // need new slot
|
2004-06-13 20:20:40 +00:00
|
|
|
if (moreenv() < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
2019-05-28 23:08:19 +02:00
|
|
|
p = alloc(strlen(string) + 1);
|
2019-12-21 18:25:54 +01:00
|
|
|
if (p == NULL) // not enough core
|
2004-06-13 20:20:40 +00:00
|
|
|
return -1;
|
2019-12-21 18:25:54 +01:00
|
|
|
environ[i + 1] = 0; // new end of env.
|
2004-06-13 20:20:40 +00:00
|
|
|
}
|
|
|
|
else
|
2019-12-21 18:25:54 +01:00
|
|
|
{ // name already in env.
|
2004-06-13 20:20:40 +00:00
|
|
|
p = vim_realloc(environ[i], strlen(string) + 1);
|
|
|
|
if (p == NULL)
|
|
|
|
return -1;
|
|
|
|
}
|
2019-12-21 18:25:54 +01:00
|
|
|
sprintf(p, "%s", string); // copy into env.
|
2004-06-13 20:20:40 +00:00
|
|
|
environ[i] = p;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-01-30 19:39:49 +01:00
|
|
|
findenv(char *name)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char *namechar, *envchar;
|
|
|
|
int i, found;
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
for (i = 0; environ[i] && !found; i++)
|
|
|
|
{
|
|
|
|
envchar = environ[i];
|
|
|
|
namechar = name;
|
|
|
|
while (*namechar && *namechar != '=' && (*namechar == *envchar))
|
|
|
|
{
|
|
|
|
namechar++;
|
|
|
|
envchar++;
|
|
|
|
}
|
|
|
|
found = ((*namechar == '\0' || *namechar == '=') && *envchar == '=');
|
|
|
|
}
|
|
|
|
return found ? i - 1 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-01-30 19:39:49 +01:00
|
|
|
newenv(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
char **env, *elem;
|
|
|
|
int i, esize;
|
|
|
|
|
|
|
|
for (i = 0; environ[i]; i++)
|
|
|
|
;
|
2017-10-28 21:11:06 +02:00
|
|
|
|
2004-06-13 20:20:40 +00:00
|
|
|
esize = i + EXTRASIZE + 1;
|
2019-05-28 23:08:19 +02:00
|
|
|
env = ALLOC_MULT(char *, esize);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (env == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; environ[i]; i++)
|
|
|
|
{
|
2019-05-28 23:08:19 +02:00
|
|
|
elem = alloc(strlen(environ[i]) + 1);
|
2004-06-13 20:20:40 +00:00
|
|
|
if (elem == NULL)
|
|
|
|
return -1;
|
|
|
|
env[i] = elem;
|
|
|
|
strcpy(elem, environ[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
env[i] = 0;
|
|
|
|
environ = env;
|
|
|
|
envsize = esize;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-01-30 19:39:49 +01:00
|
|
|
moreenv(void)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int esize;
|
|
|
|
char **env;
|
|
|
|
|
|
|
|
esize = envsize + EXTRASIZE;
|
2019-05-28 23:08:19 +02:00
|
|
|
env = vim_realloc((char *)environ, esize * sizeof (*env));
|
2004-06-13 20:20:40 +00:00
|
|
|
if (env == 0)
|
|
|
|
return -1;
|
|
|
|
environ = env;
|
|
|
|
envsize = esize;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
# ifdef USE_VIMPTY_GETENV
|
2017-07-22 21:11:53 +02:00
|
|
|
/*
|
|
|
|
* Used for mch_getenv() for Mac.
|
|
|
|
*/
|
2004-06-13 20:20:40 +00:00
|
|
|
char_u *
|
2016-01-30 19:39:49 +01:00
|
|
|
vimpty_getenv(const char_u *string)
|
2004-06-13 20:20:40 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char_u *p;
|
|
|
|
|
|
|
|
if (envsize < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
i = findenv((char *)string);
|
|
|
|
|
|
|
|
if (i < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p = vim_strchr((char_u *)environ[i], '=');
|
|
|
|
return (p + 1);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
#endif // !defined(HAVE_SETENV) && !defined(HAVE_PUTENV)
|
2005-06-07 21:04:49 +00:00
|
|
|
|
2006-03-12 21:58:43 +00:00
|
|
|
#if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
|
2005-06-07 21:04:49 +00:00
|
|
|
/*
|
|
|
|
* Return 0 for not writable, 1 for writable file, 2 for a dir which we have
|
|
|
|
* rights to write into.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
filewritable(char_u *fname)
|
2005-06-07 21:04:49 +00:00
|
|
|
{
|
|
|
|
int retval = 0;
|
|
|
|
#if defined(UNIX) || defined(VMS)
|
|
|
|
int perm = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(UNIX) || defined(VMS)
|
|
|
|
perm = mch_getperm(fname);
|
|
|
|
#endif
|
|
|
|
if (
|
2019-02-17 17:44:42 +01:00
|
|
|
# ifdef MSWIN
|
2005-06-07 21:04:49 +00:00
|
|
|
mch_writable(fname) &&
|
|
|
|
# else
|
|
|
|
# if defined(UNIX) || defined(VMS)
|
|
|
|
(perm & 0222) &&
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
mch_access((char *)fname, W_OK) == 0
|
|
|
|
)
|
|
|
|
{
|
|
|
|
++retval;
|
|
|
|
if (mch_isdir(fname))
|
|
|
|
++retval;
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
2005-06-16 21:53:56 +00:00
|
|
|
|
2010-05-29 15:11:47 +02:00
|
|
|
#if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
|
|
|
|
/*
|
|
|
|
* Read 2 bytes from "fd" and turn them into an int, MSB first.
|
2018-03-20 12:34:04 +01:00
|
|
|
* Returns -1 when encountering EOF.
|
2010-05-29 15:11:47 +02:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get2c(FILE *fd)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
2018-03-20 12:34:04 +01:00
|
|
|
int c, n;
|
2010-05-29 15:11:47 +02:00
|
|
|
|
|
|
|
n = getc(fd);
|
2018-03-20 12:34:04 +01:00
|
|
|
if (n == EOF) return -1;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
return (n << 8) + c;
|
2010-05-29 15:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read 3 bytes from "fd" and turn them into an int, MSB first.
|
2018-03-20 12:34:04 +01:00
|
|
|
* Returns -1 when encountering EOF.
|
2010-05-29 15:11:47 +02:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get3c(FILE *fd)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
2018-03-20 12:34:04 +01:00
|
|
|
int c, n;
|
2010-05-29 15:11:47 +02:00
|
|
|
|
|
|
|
n = getc(fd);
|
2018-03-20 12:34:04 +01:00
|
|
|
if (n == EOF) return -1;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
n = (n << 8) + c;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
return (n << 8) + c;
|
2010-05-29 15:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read 4 bytes from "fd" and turn them into an int, MSB first.
|
2018-03-20 12:34:04 +01:00
|
|
|
* Returns -1 when encountering EOF.
|
2010-05-29 15:11:47 +02:00
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
get4c(FILE *fd)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
2018-03-20 12:34:04 +01:00
|
|
|
int c;
|
2019-12-21 18:25:54 +01:00
|
|
|
// Use unsigned rather than int otherwise result is undefined
|
|
|
|
// when left-shift sets the MSB.
|
2013-09-08 16:07:07 +02:00
|
|
|
unsigned n;
|
|
|
|
|
2018-03-20 12:34:04 +01:00
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
n = (unsigned)c;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
n = (n << 8) + (unsigned)c;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
n = (n << 8) + (unsigned)c;
|
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF) return -1;
|
|
|
|
n = (n << 8) + (unsigned)c;
|
2013-09-08 16:07:07 +02:00
|
|
|
return (int)n;
|
2010-05-29 15:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a string of length "cnt" from "fd" into allocated memory.
|
|
|
|
* Returns NULL when out of memory or unable to read that many bytes.
|
|
|
|
*/
|
|
|
|
char_u *
|
2016-01-30 19:39:49 +01:00
|
|
|
read_string(FILE *fd, int cnt)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
|
|
|
char_u *str;
|
|
|
|
int i;
|
|
|
|
int c;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// allocate memory
|
2019-05-24 18:54:09 +02:00
|
|
|
str = alloc(cnt + 1);
|
2023-01-14 12:32:28 +00:00
|
|
|
if (str == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
// Read the string. Quit when running into the EOF.
|
|
|
|
for (i = 0; i < cnt; ++i)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
2023-01-14 12:32:28 +00:00
|
|
|
c = getc(fd);
|
|
|
|
if (c == EOF)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
2023-01-14 12:32:28 +00:00
|
|
|
vim_free(str);
|
|
|
|
return NULL;
|
2010-05-29 15:11:47 +02:00
|
|
|
}
|
2023-01-14 12:32:28 +00:00
|
|
|
str[i] = c;
|
2010-05-29 15:11:47 +02:00
|
|
|
}
|
2023-01-14 12:32:28 +00:00
|
|
|
str[i] = NUL;
|
2010-05-29 15:11:47 +02:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a number to file "fd", MSB first, in "len" bytes.
|
|
|
|
*/
|
|
|
|
int
|
2016-01-30 19:39:49 +01:00
|
|
|
put_bytes(FILE *fd, long_u nr, int len)
|
2010-05-29 15:11:47 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = len - 1; i >= 0; --i)
|
|
|
|
if (putc((int)(nr >> (i * 8)), fd) == EOF)
|
|
|
|
return FAIL;
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2012-01-10 16:28:45 +01:00
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
#ifndef PROTO // proto is defined in vim.h
|
2016-12-01 23:03:28 +01:00
|
|
|
# ifdef ELAPSED_TIMEVAL
|
2016-11-24 17:22:50 +01:00
|
|
|
/*
|
|
|
|
* Return time in msec since "start_tv".
|
|
|
|
*/
|
|
|
|
long
|
|
|
|
elapsed(struct timeval *start_tv)
|
|
|
|
{
|
|
|
|
struct timeval now_tv;
|
|
|
|
|
|
|
|
gettimeofday(&now_tv, NULL);
|
|
|
|
return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
|
|
|
|
+ (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
|
|
|
|
}
|
2016-12-01 23:03:28 +01:00
|
|
|
# endif
|
2016-11-24 17:22:50 +01:00
|
|
|
|
2016-12-01 23:03:28 +01:00
|
|
|
# ifdef ELAPSED_TICKCOUNT
|
2016-11-24 17:22:50 +01:00
|
|
|
/*
|
|
|
|
* Return time in msec since "start_tick".
|
|
|
|
*/
|
|
|
|
long
|
|
|
|
elapsed(DWORD start_tick)
|
|
|
|
{
|
|
|
|
DWORD now = GetTickCount();
|
|
|
|
|
|
|
|
return (long)now - (long)start_tick;
|
|
|
|
}
|
2016-12-01 23:03:28 +01:00
|
|
|
# endif
|
2016-11-24 17:22:50 +01:00
|
|
|
#endif
|
2018-04-21 22:30:08 +02:00
|
|
|
|
|
|
|
#if defined(FEAT_JOB_CHANNEL) \
|
|
|
|
|| (defined(UNIX) && (!defined(USE_SYSTEM) \
|
|
|
|
|| (defined(FEAT_GUI) && defined(FEAT_TERMINAL)))) \
|
|
|
|
|| defined(PROTO)
|
|
|
|
/*
|
|
|
|
* Parse "cmd" and put the white-separated parts in "argv".
|
|
|
|
* "argv" is an allocated array with "argc" entries and room for 4 more.
|
|
|
|
* Returns FAIL when out of memory.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char_u *p, *d;
|
|
|
|
int inquote;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do this loop twice:
|
|
|
|
* 1: find number of arguments
|
|
|
|
* 2: separate them and build argv[]
|
|
|
|
*/
|
2020-03-26 16:27:38 +01:00
|
|
|
for (i = 1; i <= 2; ++i)
|
2018-04-21 22:30:08 +02:00
|
|
|
{
|
|
|
|
p = skipwhite(cmd);
|
|
|
|
inquote = FALSE;
|
|
|
|
*argc = 0;
|
2020-03-26 16:27:38 +01:00
|
|
|
while (*p != NUL)
|
2018-04-21 22:30:08 +02:00
|
|
|
{
|
2020-03-26 16:27:38 +01:00
|
|
|
if (i == 2)
|
2018-04-21 22:30:08 +02:00
|
|
|
(*argv)[*argc] = (char *)p;
|
|
|
|
++*argc;
|
|
|
|
d = p;
|
|
|
|
while (*p != NUL && (inquote || (*p != ' ' && *p != TAB)))
|
|
|
|
{
|
|
|
|
if (p[0] == '"')
|
2018-10-07 21:36:11 +02:00
|
|
|
// quotes surrounding an argument and are dropped
|
2018-04-21 22:30:08 +02:00
|
|
|
inquote = !inquote;
|
|
|
|
else
|
|
|
|
{
|
2018-10-07 21:36:11 +02:00
|
|
|
if (rem_backslash(p))
|
2018-04-21 22:30:08 +02:00
|
|
|
{
|
2018-10-07 21:36:11 +02:00
|
|
|
// First pass: skip over "\ " and "\"".
|
|
|
|
// Second pass: Remove the backslash.
|
2018-04-21 22:30:08 +02:00
|
|
|
++p;
|
|
|
|
}
|
2020-03-26 16:27:38 +01:00
|
|
|
if (i == 2)
|
2018-04-21 22:30:08 +02:00
|
|
|
*d++ = *p;
|
|
|
|
}
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
if (*p == NUL)
|
|
|
|
{
|
2020-03-26 16:27:38 +01:00
|
|
|
if (i == 2)
|
2018-04-21 22:30:08 +02:00
|
|
|
*d++ = NUL;
|
|
|
|
break;
|
|
|
|
}
|
2020-03-26 16:27:38 +01:00
|
|
|
if (i == 2)
|
2018-04-21 22:30:08 +02:00
|
|
|
*d++ = NUL;
|
|
|
|
p = skipwhite(p + 1);
|
|
|
|
}
|
|
|
|
if (*argv == NULL)
|
|
|
|
{
|
|
|
|
if (use_shcf)
|
|
|
|
{
|
2019-12-21 18:25:54 +01:00
|
|
|
// Account for possible multiple args in p_shcf.
|
2018-04-21 22:30:08 +02:00
|
|
|
p = p_shcf;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
p = skiptowhite(p);
|
|
|
|
if (*p == NUL)
|
|
|
|
break;
|
|
|
|
++*argc;
|
|
|
|
p = skipwhite(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 23:08:19 +02:00
|
|
|
*argv = ALLOC_MULT(char *, *argc + 4);
|
2019-12-21 18:25:54 +01:00
|
|
|
if (*argv == NULL) // out of memory
|
2018-04-21 22:30:08 +02:00
|
|
|
return FAIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
2018-04-21 23:34:43 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Build "argv[argc]" from the string "cmd".
|
|
|
|
* "argv[argc]" is set to NULL;
|
|
|
|
* Return FAIL when out of memory.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
build_argv_from_string(char_u *cmd, char ***argv, int *argc)
|
|
|
|
{
|
|
|
|
char_u *cmd_copy;
|
|
|
|
int i;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Make a copy, parsing will modify "cmd".
|
2018-04-21 23:34:43 +02:00
|
|
|
cmd_copy = vim_strsave(cmd);
|
|
|
|
if (cmd_copy == NULL
|
|
|
|
|| mch_parse_cmd(cmd_copy, FALSE, argv, argc) == FAIL)
|
|
|
|
{
|
|
|
|
vim_free(cmd_copy);
|
|
|
|
return FAIL;
|
|
|
|
}
|
|
|
|
for (i = 0; i < *argc; i++)
|
|
|
|
(*argv)[i] = (char *)vim_strsave((char_u *)(*argv)[i]);
|
|
|
|
(*argv)[*argc] = NULL;
|
|
|
|
vim_free(cmd_copy);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2022-01-17 11:23:45 +00:00
|
|
|
# if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
|
2018-04-21 23:34:43 +02:00
|
|
|
/*
|
|
|
|
* Build "argv[argc]" from the list "l".
|
|
|
|
* "argv[argc]" is set to NULL;
|
|
|
|
* Return FAIL when out of memory.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
build_argv_from_list(list_T *l, char ***argv, int *argc)
|
|
|
|
{
|
|
|
|
listitem_T *li;
|
|
|
|
char_u *s;
|
|
|
|
|
2019-12-21 18:25:54 +01:00
|
|
|
// Pass argv[] to mch_call_shell().
|
2019-05-28 23:08:19 +02:00
|
|
|
*argv = ALLOC_MULT(char *, l->lv_len + 1);
|
2018-04-21 23:34:43 +02:00
|
|
|
if (*argv == NULL)
|
|
|
|
return FAIL;
|
|
|
|
*argc = 0;
|
2020-04-02 18:50:46 +02:00
|
|
|
FOR_ALL_LIST_ITEMS(l, li)
|
2018-04-21 23:34:43 +02:00
|
|
|
{
|
2018-12-21 16:04:21 +01:00
|
|
|
s = tv_get_string_chk(&li->li_tv);
|
2018-04-21 23:34:43 +02:00
|
|
|
if (s == NULL)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < *argc; ++i)
|
2020-04-13 18:13:33 +02:00
|
|
|
VIM_CLEAR((*argv)[i]);
|
2021-10-05 19:19:35 +01:00
|
|
|
(*argv)[0] = NULL;
|
2018-04-21 23:34:43 +02:00
|
|
|
return FAIL;
|
|
|
|
}
|
|
|
|
(*argv)[*argc] = (char *)vim_strsave(s);
|
|
|
|
*argc += 1;
|
|
|
|
}
|
|
|
|
(*argv)[*argc] = NULL;
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
# endif
|
2018-04-21 22:30:08 +02:00
|
|
|
#endif
|
2019-09-13 22:30:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Change the behavior of vterm.
|
|
|
|
* 0: As usual.
|
|
|
|
* 1: Windows 10 version 1809
|
|
|
|
* The bug causes unstable handling of ambiguous width character.
|
2019-11-13 21:49:24 +01:00
|
|
|
* 2: Windows 10 version 1903 & 1909
|
2019-09-13 22:30:11 +02:00
|
|
|
* Use the wrong result because each result is different.
|
|
|
|
* 3: Windows 10 insider preview (current latest logic)
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
get_special_pty_type(void)
|
|
|
|
{
|
|
|
|
#ifdef MSWIN
|
|
|
|
return get_conpty_type();
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
2024-04-02 20:26:01 +02:00
|
|
|
|
|
|
|
// compare two keyvalue_T structs by case sensitive value
|
|
|
|
int
|
|
|
|
cmp_keyvalue_value(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
keyvalue_T *kv1 = (keyvalue_T *)a;
|
|
|
|
keyvalue_T *kv2 = (keyvalue_T *)b;
|
|
|
|
|
2024-11-02 15:59:01 +01:00
|
|
|
return STRCMP(kv1->value.string, kv2->value.string);
|
2024-04-02 20:26:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// compare two keyvalue_T structs by value with length
|
|
|
|
int
|
|
|
|
cmp_keyvalue_value_n(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
keyvalue_T *kv1 = (keyvalue_T *)a;
|
|
|
|
keyvalue_T *kv2 = (keyvalue_T *)b;
|
|
|
|
|
2024-11-02 15:59:01 +01:00
|
|
|
return STRNCMP(kv1->value.string, kv2->value.string, MAX(kv1->value.length,
|
|
|
|
kv2->value.length));
|
2024-04-02 20:26:01 +02:00
|
|
|
}
|
|
|
|
|
2024-09-04 22:10:34 +02:00
|
|
|
// compare two keyvalue_T structs by case insensitive value
|
|
|
|
int
|
|
|
|
cmp_keyvalue_value_i(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
keyvalue_T *kv1 = (keyvalue_T *)a;
|
|
|
|
keyvalue_T *kv2 = (keyvalue_T *)b;
|
|
|
|
|
2024-11-02 15:59:01 +01:00
|
|
|
return STRICMP(kv1->value.string, kv2->value.string);
|
2024-09-04 22:10:34 +02:00
|
|
|
}
|
|
|
|
|
2024-09-02 09:59:18 +02:00
|
|
|
// compare two keyvalue_T structs by case insensitive ASCII value
|
2024-11-02 15:59:01 +01:00
|
|
|
// with value.length
|
2024-04-02 20:26:01 +02:00
|
|
|
int
|
|
|
|
cmp_keyvalue_value_ni(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
keyvalue_T *kv1 = (keyvalue_T *)a;
|
|
|
|
keyvalue_T *kv2 = (keyvalue_T *)b;
|
|
|
|
|
2024-11-02 15:59:01 +01:00
|
|
|
return vim_strnicmp_asc((char *)kv1->value.string,
|
|
|
|
(char *)kv2->value.string, MAX(kv1->value.length,
|
|
|
|
kv2->value.length));
|
2024-04-02 20:26:01 +02:00
|
|
|
}
|
|
|
|
|