blob: b3c644b14b247087242a713bbcd4ed80e8a8d9b7 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * mark.c: functions for setting marks and jumping to them
12 */
13
14#include "vim.h"
15
16/*
17 * This file contains routines to maintain and manipulate marks.
18 */
19
20/*
21 * If a named file mark's lnum is non-zero, it is valid.
22 * If a named file mark's fnum is non-zero, it is for an existing buffer,
23 * otherwise it is from .viminfo and namedfm[n].fname is the file name.
24 * There are marks 'A - 'Z (set by user) and '0 to '9 (set when writing
25 * viminfo).
26 */
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010027static xfmark_T namedfm[NMARKS + EXTRA_MARKS]; // marks with file nr
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
Bram Moolenaar5843f5f2019-08-20 20:13:45 +020029static void fname2fnum(xfmark_T *fm);
Bram Moolenaar92b8b2d2016-01-29 22:36:45 +010030static void fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf);
31static char_u *mark_line(pos_T *mp, int lead_len);
32static void show_one_mark(int, char_u *, pos_T *, char_u *, int current);
Bram Moolenaar88d298a2017-03-14 21:53:58 +010033static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount,
34 long amount_after, int adjust_folds);
Bram Moolenaar071d4272004-06-13 20:20:40 +000035
36/*
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000037 * Set named mark "c" at current cursor position.
Bram Moolenaar071d4272004-06-13 20:20:40 +000038 * Returns OK on success, FAIL if bad name given.
39 */
40 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +010041setmark(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +000042{
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000043 return setmark_pos(c, &curwin->w_cursor, curbuf->b_fnum);
44}
45
46/*
47 * Set named mark "c" to position "pos".
48 * When "c" is upper case use file "fnum".
49 * Returns OK on success, FAIL if bad name given.
50 */
51 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +010052setmark_pos(int c, pos_T *pos, int fnum)
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000053{
Bram Moolenaar071d4272004-06-13 20:20:40 +000054 int i;
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010055 buf_T *buf;
Bram Moolenaar071d4272004-06-13 20:20:40 +000056
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010057 // Check for a special key (may cause islower() to crash).
Bram Moolenaar071d4272004-06-13 20:20:40 +000058 if (c < 0)
59 return FAIL;
60
61 if (c == '\'' || c == '`')
62 {
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000063 if (pos == &curwin->w_cursor)
64 {
65 setpcmark();
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010066 // keep it even when the cursor doesn't move
Bram Moolenaarbfb2d402006-03-03 22:50:42 +000067 curwin->w_prev_pcmark = curwin->w_pcmark;
68 }
69 else
70 curwin->w_pcmark = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000071 return OK;
72 }
73
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010074 buf = buflist_findnr(fnum);
75 if (buf == NULL)
76 return FAIL;
77
Bram Moolenaar08250432008-02-13 11:42:46 +000078 if (c == '"')
79 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010080 buf->b_last_cursor = *pos;
Bram Moolenaar08250432008-02-13 11:42:46 +000081 return OK;
82 }
83
Bram Moolenaar4ba37b52019-12-04 21:57:43 +010084 // Allow setting '[ and '] for an autocommand that simulates reading a
85 // file.
Bram Moolenaar071d4272004-06-13 20:20:40 +000086 if (c == '[')
87 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010088 buf->b_op_start = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000089 return OK;
90 }
91 if (c == ']')
92 {
Bram Moolenaarf13e00b2017-01-28 18:23:54 +010093 buf->b_op_end = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +000094 return OK;
95 }
96
Bram Moolenaarbc88a272013-08-02 17:22:23 +020097 if (c == '<' || c == '>')
Bram Moolenaar0306ac32012-07-06 17:51:28 +020098 {
Bram Moolenaarbc88a272013-08-02 17:22:23 +020099 if (c == '<')
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100100 buf->b_visual.vi_start = *pos;
Bram Moolenaarbc88a272013-08-02 17:22:23 +0200101 else
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100102 buf->b_visual.vi_end = *pos;
103 if (buf->b_visual.vi_mode == NUL)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100104 // Visual_mode has not yet been set, use a sane default.
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100105 buf->b_visual.vi_mode = 'v';
Bram Moolenaar0306ac32012-07-06 17:51:28 +0200106 return OK;
107 }
Bram Moolenaar0306ac32012-07-06 17:51:28 +0200108
Bram Moolenaar2d358992016-06-12 21:20:54 +0200109 if (ASCII_ISLOWER(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110 {
111 i = c - 'a';
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100112 buf->b_namedm[i] = *pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113 return OK;
114 }
Bram Moolenaar2d358992016-06-12 21:20:54 +0200115 if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116 {
Bram Moolenaar2d358992016-06-12 21:20:54 +0200117 if (VIM_ISDIGIT(c))
118 i = c - '0' + NMARKS;
119 else
120 i = c - 'A';
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000121 namedfm[i].fmark.mark = *pos;
122 namedfm[i].fmark.fnum = fnum;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100123 VIM_CLEAR(namedfm[i].fname);
Bram Moolenaar2d358992016-06-12 21:20:54 +0200124#ifdef FEAT_VIMINFO
125 namedfm[i].time_set = vim_time();
126#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000127 return OK;
128 }
129 return FAIL;
130}
131
132/*
133 * Set the previous context mark to the current position and add it to the
134 * jump list.
135 */
136 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100137setpcmark(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139 int i;
140 xfmark_T *fm;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100142 // for :global the mark is set only once
Bram Moolenaare1004402020-10-24 20:49:43 +0200143 if (global_busy || listcmd_busy || (cmdmod.cmod_flags & CMOD_KEEPJUMPS))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144 return;
145
146 curwin->w_prev_pcmark = curwin->w_pcmark;
147 curwin->w_pcmark = curwin->w_cursor;
148
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100149 // If jumplist is full: remove oldest entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150 if (++curwin->w_jumplistlen > JUMPLISTSIZE)
151 {
152 curwin->w_jumplistlen = JUMPLISTSIZE;
153 vim_free(curwin->w_jumplist[0].fname);
154 for (i = 1; i < JUMPLISTSIZE; ++i)
155 curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
156 }
157 curwin->w_jumplistidx = curwin->w_jumplistlen;
158 fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
159
160 fm->fmark.mark = curwin->w_pcmark;
161 fm->fmark.fnum = curbuf->b_fnum;
162 fm->fname = NULL;
Bram Moolenaar739f13a2021-12-13 13:12:53 +0000163#ifdef FEAT_VIMINFO
Bram Moolenaar2d358992016-06-12 21:20:54 +0200164 fm->time_set = vim_time();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165#endif
166}
167
168/*
169 * To change context, call setpcmark(), then move the current position to
170 * where ever, then call checkpcmark(). This ensures that the previous
171 * context will only be changed if the cursor moved to a different line.
172 * If pcmark was deleted (with "dG") the previous mark is restored.
173 */
174 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100175checkpcmark(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000176{
177 if (curwin->w_prev_pcmark.lnum != 0
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100178 && (EQUAL_POS(curwin->w_pcmark, curwin->w_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179 || curwin->w_pcmark.lnum == 0))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180 curwin->w_pcmark = curwin->w_prev_pcmark;
Bram Moolenaare08aee62021-10-17 21:53:58 +0100181 curwin->w_prev_pcmark.lnum = 0; // it has been checked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182}
183
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184/*
185 * move "count" positions in the jump list (count may be negative)
186 */
187 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100188movemark(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189{
190 pos_T *pos;
191 xfmark_T *jmp;
192
Bram Moolenaar48679742018-02-13 13:33:29 +0100193 cleanup_jumplist(curwin, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100195 if (curwin->w_jumplistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196 return (pos_T *)NULL;
197
198 for (;;)
199 {
200 if (curwin->w_jumplistidx + count < 0
201 || curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
202 return (pos_T *)NULL;
203
204 /*
205 * if first CTRL-O or CTRL-I command after a jump, add cursor position
Bram Moolenaarf711faf2007-05-10 16:48:19 +0000206 * to list. Careful: If there are duplicates (CTRL-O immediately after
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207 * starting Vim on a file), another entry may have been removed.
208 */
209 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
210 {
211 setpcmark();
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100212 --curwin->w_jumplistidx; // skip the new entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000213 if (curwin->w_jumplistidx + count < 0)
214 return (pos_T *)NULL;
215 }
216
217 curwin->w_jumplistidx += count;
218
219 jmp = curwin->w_jumplist + curwin->w_jumplistidx;
220 if (jmp->fmark.fnum == 0)
221 fname2fnum(jmp);
222 if (jmp->fmark.fnum != curbuf->b_fnum)
223 {
Bram Moolenaar8ecfa2c2022-09-21 13:07:22 +0100224 // Make a copy, an autocommand may make "jmp" invalid.
225 fmark_T fmark = jmp->fmark;
226
227 // jump to the file with the mark
228 if (buflist_findnr(fmark.fnum) == NULL)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100229 { // Skip this one ..
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230 count += count < 0 ? -1 : 1;
231 continue;
232 }
Bram Moolenaar8ecfa2c2022-09-21 13:07:22 +0100233 if (buflist_getfile(fmark.fnum, fmark.mark.lnum, 0, FALSE) == FAIL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 return (pos_T *)NULL;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100235 // Set lnum again, autocommands my have changed it
Bram Moolenaar8ecfa2c2022-09-21 13:07:22 +0100236 curwin->w_cursor = fmark.mark;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237 pos = (pos_T *)-1;
238 }
239 else
240 pos = &(jmp->fmark.mark);
241 return pos;
242 }
243}
244
245/*
246 * Move "count" positions in the changelist (count may be negative).
247 */
248 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100249movechangelist(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000250{
251 int n;
252
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100253 if (curbuf->b_changelistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254 return (pos_T *)NULL;
255
256 n = curwin->w_changelistidx;
257 if (n + count < 0)
258 {
259 if (n == 0)
260 return (pos_T *)NULL;
261 n = 0;
262 }
263 else if (n + count >= curbuf->b_changelistlen)
264 {
265 if (n == curbuf->b_changelistlen - 1)
266 return (pos_T *)NULL;
267 n = curbuf->b_changelistlen - 1;
268 }
269 else
270 n += count;
271 curwin->w_changelistidx = n;
272 return curbuf->b_changelist + n;
273}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274
275/*
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100276 * Find mark "c" in buffer pointed to by "buf".
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000277 * If "changefile" is TRUE it's allowed to edit another file for '0, 'A, etc.
278 * If "fnum" is not NULL store the fnum there for '0, 'A etc., don't edit
279 * another file.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 * Returns:
281 * - pointer to pos_T if found. lnum is 0 when mark not set, -1 when mark is
282 * in another file which can't be gotten. (caller needs to check lnum!)
283 * - NULL if there is no mark called 'c'.
284 * - -1 if mark is in other file and jumped there (only if changefile is TRUE)
285 */
286 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100287getmark_buf(buf_T *buf, int c, int changefile)
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100288{
289 return getmark_buf_fnum(buf, c, changefile, NULL);
290}
291
292 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100293getmark(int c, int changefile)
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000294{
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100295 return getmark_buf_fnum(curbuf, c, changefile, NULL);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000296}
297
298 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100299getmark_buf_fnum(
300 buf_T *buf,
301 int c,
302 int changefile,
303 int *fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000304{
305 pos_T *posp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 pos_T *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 static pos_T pos_copy;
308
309 posp = NULL;
310
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100311 // Check for special key, can't be a mark name and might cause islower()
312 // to crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313 if (c < 0)
314 return posp;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100315 if (c > '~') // check for islower()/isupper()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316 ;
Bram Moolenaar424bcae2022-01-31 14:59:41 +0000317 else if (c == '\'' || c == '`') // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100319 pos_copy = curwin->w_pcmark; // need to make a copy because
320 posp = &pos_copy; // w_pcmark may be changed soon
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100322 else if (c == '"') // to pos when leaving buffer
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100323 posp = &(buf->b_last_cursor);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100324 else if (c == '^') // to where Insert mode stopped
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100325 posp = &(buf->b_last_insert);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100326 else if (c == '.') // to where last change was made
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100327 posp = &(buf->b_last_change);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100328 else if (c == '[') // to start of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100329 posp = &(buf->b_op_start);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100330 else if (c == ']') // to end of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100331 posp = &(buf->b_op_end);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100332 else if (c == '{' || c == '}') // to previous/next paragraph
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333 {
334 pos_T pos;
335 oparg_T oa;
336 int slcb = listcmd_busy;
337
338 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100339 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar8b96d642005-09-05 22:05:30 +0000340 if (findpar(&oa.inclusive,
341 c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 {
343 pos_copy = curwin->w_cursor;
344 posp = &pos_copy;
345 }
346 curwin->w_cursor = pos;
347 listcmd_busy = slcb;
348 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100349 else if (c == '(' || c == ')') // to previous/next sentence
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 {
351 pos_T pos;
352 int slcb = listcmd_busy;
353
354 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100355 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 if (findsent(c == ')' ? FORWARD : BACKWARD, 1L))
357 {
358 pos_copy = curwin->w_cursor;
359 posp = &pos_copy;
360 }
361 curwin->w_cursor = pos;
362 listcmd_busy = slcb;
363 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100364 else if (c == '<' || c == '>') // start/end of visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100366 startp = &buf->b_visual.vi_start;
367 endp = &buf->b_visual.vi_end;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100368 if (((c == '<') == LT_POS(*startp, *endp) || endp->lnum == 0)
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100369 && startp->lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 posp = startp;
371 else
372 posp = endp;
373 /*
374 * For Visual line mode, set mark at begin or end of line
375 */
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100376 if (buf->b_visual.vi_mode == 'V')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 {
378 pos_copy = *posp;
379 posp = &pos_copy;
380 if (c == '<')
381 pos_copy.col = 0;
382 else
383 pos_copy.col = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 pos_copy.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 }
386 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100387 else if (ASCII_ISLOWER(c)) // normal named mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100389 posp = &(buf->b_namedm[c - 'a']);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100391 else if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c)) // named file mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 {
393 if (VIM_ISDIGIT(c))
394 c = c - '0' + NMARKS;
395 else
396 c -= 'A';
397 posp = &(namedfm[c].fmark.mark);
398
399 if (namedfm[c].fmark.fnum == 0)
400 fname2fnum(&namedfm[c]);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000401
402 if (fnum != NULL)
403 *fnum = namedfm[c].fmark.fnum;
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100404 else if (namedfm[c].fmark.fnum != buf->b_fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100406 // mark is in another file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 posp = &pos_copy;
408
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409 if (namedfm[c].fmark.mark.lnum != 0
410 && changefile && namedfm[c].fmark.fnum)
411 {
412 if (buflist_getfile(namedfm[c].fmark.fnum,
413 (linenr_T)1, GETF_SETMARK, FALSE) == OK)
414 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100415 // Set the lnum now, autocommands could have changed it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 curwin->w_cursor = namedfm[c].fmark.mark;
417 return (pos_T *)-1;
418 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100419 pos_copy.lnum = -1; // can't get file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 }
421 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100422 pos_copy.lnum = 0; // mark exists, but is not valid in
423 // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 }
425 }
426
427 return posp;
428}
429
430/*
431 * Search for the next named mark in the current file.
432 *
433 * Returns pointer to pos_T of the next mark or NULL if no mark is found.
434 */
435 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100436getnextmark(
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100437 pos_T *startpos, // where to start
438 int dir, // direction for search
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100439 int begin_line)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440{
441 int i;
442 pos_T *result = NULL;
443 pos_T pos;
444
445 pos = *startpos;
446
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100447 // When searching backward and leaving the cursor on the first non-blank,
448 // position must be in a previous line.
449 // When searching forward and leaving the cursor on the first non-blank,
450 // position must be in a next line.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451 if (dir == BACKWARD && begin_line)
452 pos.col = 0;
453 else if (dir == FORWARD && begin_line)
454 pos.col = MAXCOL;
455
456 for (i = 0; i < NMARKS; i++)
457 {
458 if (curbuf->b_namedm[i].lnum > 0)
459 {
460 if (dir == FORWARD)
461 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100462 if ((result == NULL || LT_POS(curbuf->b_namedm[i], *result))
463 && LT_POS(pos, curbuf->b_namedm[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464 result = &curbuf->b_namedm[i];
465 }
466 else
467 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100468 if ((result == NULL || LT_POS(*result, curbuf->b_namedm[i]))
469 && LT_POS(curbuf->b_namedm[i], pos))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 result = &curbuf->b_namedm[i];
471 }
472 }
473 }
474
475 return result;
476}
477
478/*
479 * For an xtended filemark: set the fnum from the fname.
480 * This is used for marks obtained from the .viminfo file. It's postponed
481 * until the mark is used to avoid a long startup delay.
482 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +0200483 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100484fname2fnum(xfmark_T *fm)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485{
486 char_u *p;
487
Yegappan Lakshmanane8575982023-01-14 12:32:28 +0000488 if (fm->fname == NULL)
489 return;
490
491 /*
492 * First expand "~/" in the file name to the home directory.
493 * Don't expand the whole name, it may contain other '~' chars.
494 */
495 if (fm->fname[0] == '~' && (fm->fname[1] == '/'
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000496#ifdef BACKSLASH_IN_FILENAME
Yegappan Lakshmanane8575982023-01-14 12:32:28 +0000497 || fm->fname[1] == '\\'
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000498#endif
Yegappan Lakshmanane8575982023-01-14 12:32:28 +0000499 ))
500 {
501 int len;
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000502
Yegappan Lakshmanane8575982023-01-14 12:32:28 +0000503 expand_env((char_u *)"~/", NameBuff, MAXPATHL);
504 len = (int)STRLEN(NameBuff);
505 vim_strncpy(NameBuff + len, fm->fname + 2, MAXPATHL - len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 }
Yegappan Lakshmanane8575982023-01-14 12:32:28 +0000507 else
508 vim_strncpy(NameBuff, fm->fname, MAXPATHL - 1);
509
510 // Try to shorten the file name.
511 mch_dirname(IObuff, IOSIZE);
512 p = shorten_fname(NameBuff, IObuff);
513
514 // buflist_new() will call fmarks_check_names()
515 (void)buflist_new(NameBuff, p, (linenr_T)1, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516}
517
518/*
519 * Check all file marks for a name that matches the file name in buf.
520 * May replace the name with an fnum.
521 * Used for marks that come from the .viminfo file.
522 */
523 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100524fmarks_check_names(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525{
526 char_u *name;
527 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528 win_T *wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529
530 if (buf->b_ffname == NULL)
531 return;
532
533 name = home_replace_save(buf, buf->b_ffname);
534 if (name == NULL)
535 return;
536
537 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
538 fmarks_check_one(&namedfm[i], name, buf);
539
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540 FOR_ALL_WINDOWS(wp)
541 {
542 for (i = 0; i < wp->w_jumplistlen; ++i)
543 fmarks_check_one(&wp->w_jumplist[i], name, buf);
544 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545
546 vim_free(name);
547}
548
549 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100550fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551{
552 if (fm->fmark.fnum == 0
553 && fm->fname != NULL
554 && fnamecmp(name, fm->fname) == 0)
555 {
556 fm->fmark.fnum = buf->b_fnum;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100557 VIM_CLEAR(fm->fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 }
559}
560
561/*
562 * Check a if a position from a mark is valid.
563 * Give and error message and return FAIL if not.
564 */
565 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100566check_mark(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567{
568 if (pos == NULL)
569 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000570 emsg(_(e_unknown_mark));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 return FAIL;
572 }
573 if (pos->lnum <= 0)
574 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100575 // lnum is negative if mark is in another file can can't get that
576 // file, error message already give then.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577 if (pos->lnum == 0)
Bram Moolenaar108010a2021-06-27 22:03:33 +0200578 emsg(_(e_mark_not_set));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 return FAIL;
580 }
581 if (pos->lnum > curbuf->b_ml.ml_line_count)
582 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200583 emsg(_(e_mark_has_invalid_line_number));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 return FAIL;
585 }
586 return OK;
587}
588
589/*
590 * clrallmarks() - clear all marks in the buffer 'buf'
591 *
592 * Used mainly when trashing the entire buffer during ":e" type commands
593 */
594 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100595clrallmarks(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596{
597 static int i = -1;
598
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100599 if (i == -1) // first call ever: initialize
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 for (i = 0; i < NMARKS + 1; i++)
601 {
602 namedfm[i].fmark.mark.lnum = 0;
603 namedfm[i].fname = NULL;
Bram Moolenaar2d358992016-06-12 21:20:54 +0200604#ifdef FEAT_VIMINFO
605 namedfm[i].time_set = 0;
606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 }
608
609 for (i = 0; i < NMARKS; i++)
610 buf->b_namedm[i].lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100611 buf->b_op_start.lnum = 0; // start/end op mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 buf->b_op_end.lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100613 buf->b_last_cursor.lnum = 1; // '" mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614 buf->b_last_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 buf->b_last_cursor.coladd = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100616 buf->b_last_insert.lnum = 0; // '^ mark cleared
617 buf->b_last_change.lnum = 0; // '. mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 buf->b_changelistlen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619}
620
621/*
622 * Get name of file from a filemark.
623 * When it's in the current buffer, return the text at the mark.
624 * Returns an allocated string.
625 */
626 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100627fm_getname(fmark_T *fmark, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628{
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100629 if (fmark->fnum == curbuf->b_fnum) // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 return mark_line(&(fmark->mark), lead_len);
631 return buflist_nr2name(fmark->fnum, FALSE, TRUE);
632}
633
634/*
635 * Return the line at mark "mp". Truncate to fit in window.
636 * The returned string has been allocated.
637 */
638 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100639mark_line(pos_T *mp, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640{
641 char_u *s, *p;
642 int len;
643
644 if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
645 return vim_strsave((char_u *)"-invalid-");
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200646 // Allow for up to 5 bytes per character.
Bram Moolenaar71ccd032020-06-12 22:59:11 +0200647 s = vim_strnsave(skipwhite(ml_get(mp->lnum)), Columns * 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648 if (s == NULL)
649 return NULL;
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200650 // Truncate the line to fit it in the window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 len = 0;
Bram Moolenaar91acfff2017-03-12 19:22:36 +0100652 for (p = s; *p != NUL; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653 {
654 len += ptr2cells(p);
655 if (len >= Columns - lead_len)
656 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657 }
658 *p = NUL;
659 return s;
660}
661
662/*
663 * print the marks
664 */
665 void
Bram Moolenaar4bd78232019-09-19 23:21:55 +0200666ex_marks(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000667{
668 char_u *arg = eap->arg;
669 int i;
670 char_u *name;
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200671 pos_T *posp, *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672
673 if (arg != NULL && *arg == NUL)
674 arg = NULL;
675
676 show_one_mark('\'', arg, &curwin->w_pcmark, NULL, TRUE);
677 for (i = 0; i < NMARKS; ++i)
678 show_one_mark(i + 'a', arg, &curbuf->b_namedm[i], NULL, TRUE);
679 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
680 {
681 if (namedfm[i].fmark.fnum != 0)
682 name = fm_getname(&namedfm[i].fmark, 15);
683 else
684 name = namedfm[i].fname;
685 if (name != NULL)
686 {
687 show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
688 arg, &namedfm[i].fmark.mark, name,
689 namedfm[i].fmark.fnum == curbuf->b_fnum);
690 if (namedfm[i].fmark.fnum != 0)
691 vim_free(name);
692 }
693 }
694 show_one_mark('"', arg, &curbuf->b_last_cursor, NULL, TRUE);
695 show_one_mark('[', arg, &curbuf->b_op_start, NULL, TRUE);
696 show_one_mark(']', arg, &curbuf->b_op_end, NULL, TRUE);
697 show_one_mark('^', arg, &curbuf->b_last_insert, NULL, TRUE);
698 show_one_mark('.', arg, &curbuf->b_last_change, NULL, TRUE);
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200699
700 // Show the marks as where they will jump to.
701 startp = &curbuf->b_visual.vi_start;
702 endp = &curbuf->b_visual.vi_end;
703 if ((LT_POS(*startp, *endp) || endp->lnum == 0) && startp->lnum != 0)
704 posp = startp;
705 else
706 posp = endp;
707 show_one_mark('<', arg, posp, NULL, TRUE);
708 show_one_mark('>', arg, posp == startp ? endp : startp, NULL, TRUE);
709
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 show_one_mark(-1, arg, NULL, NULL, FALSE);
711}
712
713 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100714show_one_mark(
715 int c,
716 char_u *arg,
717 pos_T *p,
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200718 char_u *name_arg,
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100719 int current) // in current file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720{
721 static int did_title = FALSE;
722 int mustfree = FALSE;
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200723 char_u *name = name_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100725 if (c == -1) // finish up
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 {
727 if (did_title)
728 did_title = FALSE;
729 else
730 {
731 if (arg == NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100732 msg(_("No marks set"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 else
Bram Moolenaar9a846fb2022-01-01 21:59:18 +0000734 semsg(_(e_no_marks_matching_str), arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 }
736 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200737 // don't output anything if 'q' typed at --more-- prompt
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738 else if (!got_int
739 && (arg == NULL || vim_strchr(arg, c) != NULL)
740 && p->lnum != 0)
741 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200742 if (name == NULL && current)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200744 name = mark_line(p, 15);
745 mustfree = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200747 if (!message_filtered(name))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200749 if (!did_title)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200751 // Highlight title
752 msg_puts_title(_("\nmark line col file/text"));
753 did_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200755 msg_putchar('\n');
756 if (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200758 sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
759 msg_outtrans(IObuff);
760 if (name != NULL)
761 {
762 msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
763 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200765 out_flush(); // show one line at a time
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200767 if (mustfree)
768 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 }
770}
771
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000772/*
773 * ":delmarks[!] [marks]"
774 */
775 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100776ex_delmarks(exarg_T *eap)
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000777{
778 char_u *p;
779 int from, to;
780 int i;
781 int lower;
782 int digit;
783 int n;
784
785 if (*eap->arg == NUL && eap->forceit)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100786 // clear all marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000787 clrallmarks(curbuf);
788 else if (eap->forceit)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000789 emsg(_(e_invalid_argument));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000790 else if (*eap->arg == NUL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000791 emsg(_(e_argument_required));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000792 else
793 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100794 // clear specified marks only
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000795 for (p = eap->arg; *p != NUL; ++p)
796 {
797 lower = ASCII_ISLOWER(*p);
798 digit = VIM_ISDIGIT(*p);
799 if (lower || digit || ASCII_ISUPPER(*p))
800 {
801 if (p[1] == '-')
802 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100803 // clear range of marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000804 from = *p;
805 to = p[2];
806 if (!(lower ? ASCII_ISLOWER(p[2])
807 : (digit ? VIM_ISDIGIT(p[2])
808 : ASCII_ISUPPER(p[2])))
809 || to < from)
810 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000811 semsg(_(e_invalid_argument_str), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000812 return;
813 }
814 p += 2;
815 }
816 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100817 // clear one lower case mark
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000818 from = to = *p;
819
820 for (i = from; i <= to; ++i)
821 {
822 if (lower)
823 curbuf->b_namedm[i - 'a'].lnum = 0;
824 else
825 {
826 if (digit)
827 n = i - '0' + NMARKS;
828 else
829 n = i - 'A';
830 namedfm[n].fmark.mark.lnum = 0;
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100831 namedfm[n].fmark.fnum = 0;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100832 VIM_CLEAR(namedfm[n].fname);
Bram Moolenaar2d358992016-06-12 21:20:54 +0200833#ifdef FEAT_VIMINFO
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100834 namedfm[n].time_set = digit ? 0 : vim_time();
Bram Moolenaar2d358992016-06-12 21:20:54 +0200835#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000836 }
837 }
838 }
839 else
840 switch (*p)
841 {
842 case '"': curbuf->b_last_cursor.lnum = 0; break;
843 case '^': curbuf->b_last_insert.lnum = 0; break;
844 case '.': curbuf->b_last_change.lnum = 0; break;
845 case '[': curbuf->b_op_start.lnum = 0; break;
846 case ']': curbuf->b_op_end.lnum = 0; break;
Bram Moolenaara226a6d2006-02-26 23:59:20 +0000847 case '<': curbuf->b_visual.vi_start.lnum = 0; break;
848 case '>': curbuf->b_visual.vi_end.lnum = 0; break;
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000849 case ' ': break;
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000850 default: semsg(_(e_invalid_argument_str), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000851 return;
852 }
853 }
854 }
855}
856
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857/*
858 * print the jumplist
859 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100861ex_jumps(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862{
863 int i;
864 char_u *name;
865
Bram Moolenaar48679742018-02-13 13:33:29 +0100866 cleanup_jumplist(curwin, TRUE);
Bram Moolenaara7e18d22018-02-11 14:29:49 +0100867
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100868 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100869 msg_puts_title(_("\n jump line col file/text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i)
871 {
872 if (curwin->w_jumplist[i].fmark.mark.lnum != 0)
873 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
Bram Moolenaarf86db782018-10-25 13:31:37 +0200875
Christian Brabandta0f659c2022-04-09 13:35:00 +0100876 // Make sure to output the current indicator, even when on an wiped
877 // out buffer. ":filter" may still skip it.
878 if (name == NULL && i == curwin->w_jumplistidx)
879 name = vim_strsave((char_u *)"-invalid-");
Bram Moolenaarf86db782018-10-25 13:31:37 +0200880 // apply :filter /pat/ or file name not available
881 if (name == NULL || message_filtered(name))
Bram Moolenaard93090f2019-01-27 15:07:39 +0100882 {
883 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 continue;
Bram Moolenaard93090f2019-01-27 15:07:39 +0100885 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886
887 msg_putchar('\n');
888 if (got_int)
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000889 {
890 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891 break;
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000892 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 sprintf((char *)IObuff, "%c %2d %5ld %4d ",
894 i == curwin->w_jumplistidx ? '>' : ' ',
895 i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
896 : curwin->w_jumplistidx - i,
897 curwin->w_jumplist[i].fmark.mark.lnum,
898 curwin->w_jumplist[i].fmark.mark.col);
899 msg_outtrans(IObuff);
900 msg_outtrans_attr(name,
901 curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum
Bram Moolenaar8820b482017-03-16 17:23:31 +0100902 ? HL_ATTR(HLF_D) : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 vim_free(name);
904 ui_breakcheck();
905 }
906 out_flush();
907 }
908 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100909 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000910}
911
Bram Moolenaar2d358992016-06-12 21:20:54 +0200912 void
913ex_clearjumps(exarg_T *eap UNUSED)
914{
915 free_jumplist(curwin);
916 curwin->w_jumplistlen = 0;
917 curwin->w_jumplistidx = 0;
918}
919
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920/*
921 * print the changelist
922 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000923 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100924ex_changes(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925{
926 int i;
927 char_u *name;
928
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100929 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100930 msg_puts_title(_("\nchange line col text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931
932 for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i)
933 {
934 if (curbuf->b_changelist[i].lnum != 0)
935 {
936 msg_putchar('\n');
937 if (got_int)
938 break;
939 sprintf((char *)IObuff, "%c %3d %5ld %4d ",
940 i == curwin->w_changelistidx ? '>' : ' ',
941 i > curwin->w_changelistidx ? i - curwin->w_changelistidx
942 : curwin->w_changelistidx - i,
943 (long)curbuf->b_changelist[i].lnum,
944 curbuf->b_changelist[i].col);
945 msg_outtrans(IObuff);
946 name = mark_line(&curbuf->b_changelist[i], 17);
947 if (name == NULL)
948 break;
Bram Moolenaar8820b482017-03-16 17:23:31 +0100949 msg_outtrans_attr(name, HL_ATTR(HLF_D));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000950 vim_free(name);
951 ui_breakcheck();
952 }
953 out_flush();
954 }
955 if (curwin->w_changelistidx == curbuf->b_changelistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100956 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000957}
Bram Moolenaar071d4272004-06-13 20:20:40 +0000958
959#define one_adjust(add) \
960 { \
961 lp = add; \
962 if (*lp >= line1 && *lp <= line2) \
963 { \
964 if (amount == MAXLNUM) \
965 *lp = 0; \
966 else \
967 *lp += amount; \
968 } \
969 else if (amount_after && *lp > line2) \
970 *lp += amount_after; \
971 }
972
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100973// don't delete the line, just put at first deleted line
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974#define one_adjust_nodel(add) \
975 { \
976 lp = add; \
977 if (*lp >= line1 && *lp <= line2) \
978 { \
979 if (amount == MAXLNUM) \
980 *lp = line1; \
981 else \
982 *lp += amount; \
983 } \
984 else if (amount_after && *lp > line2) \
985 *lp += amount_after; \
986 }
987
988/*
Bram Moolenaare7f05a82023-04-22 15:35:28 +0100989 * Adjust marks between "line1" and "line2" (inclusive) to move "amount" lines.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990 * Must be called before changed_*(), appended_lines() or deleted_lines().
991 * May be called before or after changing the text.
Bram Moolenaare7f05a82023-04-22 15:35:28 +0100992 * When deleting lines "line1" to "line2", use an "amount" of MAXLNUM: The
993 * marks within this range are made invalid.
994 * If "amount_after" is non-zero adjust marks after "line2".
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 * Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2);
996 * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
997 * or: mark_adjust(56, 55, MAXLNUM, 2);
998 */
999 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001000mark_adjust(
1001 linenr_T line1,
1002 linenr_T line2,
1003 long amount,
1004 long amount_after)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005{
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001006 mark_adjust_internal(line1, line2, amount, amount_after, TRUE);
1007}
1008
1009 void
1010mark_adjust_nofold(
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01001011 linenr_T line1,
1012 linenr_T line2,
1013 long amount,
1014 long amount_after)
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001015{
1016 mark_adjust_internal(line1, line2, amount, amount_after, FALSE);
1017}
1018
1019 static void
1020mark_adjust_internal(
Bram Moolenaarb4ad3b02022-03-30 10:57:45 +01001021 linenr_T line1,
1022 linenr_T line2,
1023 long amount,
1024 long amount_after,
1025 int adjust_folds UNUSED)
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001026{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027 int i;
1028 int fnum = curbuf->b_fnum;
1029 linenr_T *lp;
1030 win_T *win;
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001031 tabpage_T *tab;
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001032 static pos_T initpos = {1, 0, 0};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001034 if (line2 < line1 && amount_after == 0L) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 return;
1036
Bram Moolenaare1004402020-10-24 20:49:43 +02001037 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001039 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 for (i = 0; i < NMARKS; i++)
1041 {
1042 one_adjust(&(curbuf->b_namedm[i].lnum));
1043 if (namedfm[i].fmark.fnum == fnum)
1044 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1045 }
1046 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1047 {
1048 if (namedfm[i].fmark.fnum == fnum)
1049 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1050 }
1051
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001052 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 one_adjust(&(curbuf->b_last_insert.lnum));
1054
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001055 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 one_adjust(&(curbuf->b_last_change.lnum));
1057
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001058 // last cursor position, if it was set
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01001059 if (!EQUAL_POS(curbuf->b_last_cursor, initpos))
Bram Moolenaarb6a76ff2013-02-06 12:33:21 +01001060 one_adjust(&(curbuf->b_last_cursor.lnum));
1061
1062
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001063 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 for (i = 0; i < curbuf->b_changelistlen; ++i)
1065 one_adjust_nodel(&(curbuf->b_changelist[i].lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001067 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001068 one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum));
1069 one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070
1071#ifdef FEAT_QUICKFIX
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001072 // quickfix marks
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001073 qf_mark_adjust(NULL, line1, line2, amount, amount_after);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001074 // location lists
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001075 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001076 qf_mark_adjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077#endif
1078
1079#ifdef FEAT_SIGNS
1080 sign_mark_adjust(line1, line2, amount, amount_after);
1081#endif
1082 }
1083
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001084 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 one_adjust(&(curwin->w_pcmark.lnum));
1086
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001087 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 one_adjust(&(curwin->w_prev_pcmark.lnum));
1089
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001090 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 if (saved_cursor.lnum != 0)
1092 one_adjust_nodel(&(saved_cursor.lnum));
1093
1094 /*
1095 * Adjust items in all windows related to the current buffer.
1096 */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001097 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 {
Bram Moolenaare1004402020-10-24 20:49:43 +02001099 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001100 // Marks in the jumplist. When deleting lines, this may create
1101 // duplicate marks in the jumplist, they will be removed later.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 for (i = 0; i < win->w_jumplistlen; ++i)
1103 if (win->w_jumplist[i].fmark.fnum == fnum)
1104 one_adjust_nodel(&(win->w_jumplist[i].fmark.mark.lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105
1106 if (win->w_buffer == curbuf)
1107 {
Bram Moolenaare1004402020-10-24 20:49:43 +02001108 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001109 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110 for (i = 0; i < win->w_tagstacklen; i++)
1111 if (win->w_tagstack[i].fmark.fnum == fnum)
1112 one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
1113
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001114 // the displayed Visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115 if (win->w_old_cursor_lnum != 0)
1116 {
1117 one_adjust_nodel(&(win->w_old_cursor_lnum));
1118 one_adjust_nodel(&(win->w_old_visual_lnum));
1119 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001121 // topline and cursor position for windows with the same buffer
1122 // other than the current window
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123 if (win != curwin)
1124 {
1125 if (win->w_topline >= line1 && win->w_topline <= line2)
1126 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001127 if (amount == MAXLNUM) // topline is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128 {
1129 if (line1 <= 1)
1130 win->w_topline = 1;
1131 else
1132 win->w_topline = line1 - 1;
1133 }
Bram Moolenaare7f05a82023-04-22 15:35:28 +01001134 else if (win->w_topline > line1)
1135 // keep topline on the same line, unless inserting just
1136 // above it (we probably want to see that line then)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 win->w_topline += amount;
1138#ifdef FEAT_DIFF
1139 win->w_topfill = 0;
1140#endif
1141 }
1142 else if (amount_after && win->w_topline > line2)
1143 {
1144 win->w_topline += amount_after;
1145#ifdef FEAT_DIFF
1146 win->w_topfill = 0;
1147#endif
1148 }
1149 if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
1150 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001151 if (amount == MAXLNUM) // line with cursor is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 {
1153 if (line1 <= 1)
1154 win->w_cursor.lnum = 1;
1155 else
1156 win->w_cursor.lnum = line1 - 1;
1157 win->w_cursor.col = 0;
1158 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001159 else // keep cursor on the same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 win->w_cursor.lnum += amount;
1161 }
1162 else if (amount_after && win->w_cursor.lnum > line2)
1163 win->w_cursor.lnum += amount_after;
1164 }
1165
1166#ifdef FEAT_FOLDING
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001167 // adjust folds
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001168 if (adjust_folds)
1169 foldMarkAdjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170#endif
1171 }
1172 }
1173
1174#ifdef FEAT_DIFF
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001175 // adjust diffs
Bram Moolenaar071d4272004-06-13 20:20:40 +00001176 diff_mark_adjust(line1, line2, amount, amount_after);
1177#endif
1178}
1179
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001180// This code is used often, needs to be fast.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181#define col_adjust(pp) \
1182 { \
1183 posp = pp; \
1184 if (posp->lnum == lnum && posp->col >= mincol) \
1185 { \
1186 posp->lnum += lnum_amount; \
1187 if (col_amount < 0 && posp->col <= (colnr_T)-col_amount) \
1188 posp->col = 0; \
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001189 else if (posp->col < spaces_removed) \
1190 posp->col = col_amount + spaces_removed; \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191 else \
1192 posp->col += col_amount; \
1193 } \
1194 }
1195
1196/*
1197 * Adjust marks in line "lnum" at column "mincol" and further: add
1198 * "lnum_amount" to the line number and add "col_amount" to the column
1199 * position.
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001200 * "spaces_removed" is the number of spaces that were removed, matters when the
1201 * cursor is inside them.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 */
1203 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001204mark_col_adjust(
1205 linenr_T lnum,
1206 colnr_T mincol,
1207 long lnum_amount,
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001208 long col_amount,
1209 int spaces_removed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210{
1211 int i;
1212 int fnum = curbuf->b_fnum;
1213 win_T *win;
1214 pos_T *posp;
1215
Bram Moolenaare1004402020-10-24 20:49:43 +02001216 if ((col_amount == 0L && lnum_amount == 0L)
1217 || (cmdmod.cmod_flags & CMOD_LOCKMARKS))
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001218 return; // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001220 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221 for (i = 0; i < NMARKS; i++)
1222 {
1223 col_adjust(&(curbuf->b_namedm[i]));
1224 if (namedfm[i].fmark.fnum == fnum)
1225 col_adjust(&(namedfm[i].fmark.mark));
1226 }
1227 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1228 {
1229 if (namedfm[i].fmark.fnum == fnum)
1230 col_adjust(&(namedfm[i].fmark.mark));
1231 }
1232
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001233 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234 col_adjust(&(curbuf->b_last_insert));
1235
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001236 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001237 col_adjust(&(curbuf->b_last_change));
1238
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001239 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 for (i = 0; i < curbuf->b_changelistlen; ++i)
1241 col_adjust(&(curbuf->b_changelist[i]));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001243 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001244 col_adjust(&(curbuf->b_visual.vi_start));
1245 col_adjust(&(curbuf->b_visual.vi_end));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001247 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248 col_adjust(&(curwin->w_pcmark));
1249
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001250 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001251 col_adjust(&(curwin->w_prev_pcmark));
1252
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001253 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 col_adjust(&saved_cursor);
1255
1256 /*
1257 * Adjust items in all windows related to the current buffer.
1258 */
1259 FOR_ALL_WINDOWS(win)
1260 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001261 // marks in the jumplist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262 for (i = 0; i < win->w_jumplistlen; ++i)
1263 if (win->w_jumplist[i].fmark.fnum == fnum)
1264 col_adjust(&(win->w_jumplist[i].fmark.mark));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265
1266 if (win->w_buffer == curbuf)
1267 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001268 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001269 for (i = 0; i < win->w_tagstacklen; i++)
1270 if (win->w_tagstack[i].fmark.fnum == fnum)
1271 col_adjust(&(win->w_tagstack[i].fmark.mark));
1272
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001273 // cursor position for other windows with the same buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274 if (win != curwin)
1275 col_adjust(&win->w_cursor);
1276 }
1277 }
1278}
1279
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280/*
1281 * When deleting lines, this may create duplicate marks in the
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001282 * jumplist. They will be removed here for the specified window.
Bram Moolenaar48679742018-02-13 13:33:29 +01001283 * When "loadfiles" is TRUE first ensure entries have the "fnum" field set
1284 * (this may be a bit slow).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285 */
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001286 void
Bram Moolenaar48679742018-02-13 13:33:29 +01001287cleanup_jumplist(win_T *wp, int loadfiles)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288{
1289 int i;
1290 int from, to;
1291
Bram Moolenaar48679742018-02-13 13:33:29 +01001292 if (loadfiles)
1293 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001294 // If specified, load all the files from the jump list. This is
1295 // needed to properly clean up duplicate entries, but will take some
1296 // time.
Bram Moolenaar48679742018-02-13 13:33:29 +01001297 for (i = 0; i < wp->w_jumplistlen; ++i)
1298 {
1299 if ((wp->w_jumplist[i].fmark.fnum == 0) &&
1300 (wp->w_jumplist[i].fmark.mark.lnum != 0))
1301 fname2fnum(&wp->w_jumplist[i]);
1302 }
1303 }
1304
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 to = 0;
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001306 for (from = 0; from < wp->w_jumplistlen; ++from)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001308 if (wp->w_jumplistidx == from)
1309 wp->w_jumplistidx = to;
1310 for (i = from + 1; i < wp->w_jumplistlen; ++i)
1311 if (wp->w_jumplist[i].fmark.fnum
1312 == wp->w_jumplist[from].fmark.fnum
1313 && wp->w_jumplist[from].fmark.fnum != 0
1314 && wp->w_jumplist[i].fmark.mark.lnum
1315 == wp->w_jumplist[from].fmark.mark.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001316 break;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001317 if (i >= wp->w_jumplistlen) // no duplicate
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001318 wp->w_jumplist[to++] = wp->w_jumplist[from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319 else
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001320 vim_free(wp->w_jumplist[from].fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 }
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001322 if (wp->w_jumplistidx == wp->w_jumplistlen)
1323 wp->w_jumplistidx = to;
1324 wp->w_jumplistlen = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325}
1326
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327/*
1328 * Copy the jumplist from window "from" to window "to".
1329 */
1330 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001331copy_jumplist(win_T *from, win_T *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332{
1333 int i;
1334
1335 for (i = 0; i < from->w_jumplistlen; ++i)
1336 {
1337 to->w_jumplist[i] = from->w_jumplist[i];
1338 if (from->w_jumplist[i].fname != NULL)
1339 to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
1340 }
1341 to->w_jumplistlen = from->w_jumplistlen;
1342 to->w_jumplistidx = from->w_jumplistidx;
1343}
1344
1345/*
1346 * Free items in the jumplist of window "wp".
1347 */
1348 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001349free_jumplist(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350{
1351 int i;
1352
1353 for (i = 0; i < wp->w_jumplistlen; ++i)
1354 vim_free(wp->w_jumplist[i].fname);
1355}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356
1357 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001358set_last_cursor(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359{
Bram Moolenaar9db12932013-11-03 00:20:52 +01001360 if (win->w_buffer != NULL)
1361 win->w_buffer->b_last_cursor = win->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362}
1363
Bram Moolenaarea408852005-06-25 22:49:46 +00001364#if defined(EXITFREE) || defined(PROTO)
1365 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001366free_all_marks(void)
Bram Moolenaarea408852005-06-25 22:49:46 +00001367{
1368 int i;
1369
1370 for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
1371 if (namedfm[i].fmark.mark.lnum != 0)
1372 vim_free(namedfm[i].fname);
1373}
1374#endif
1375
Dominique Pelle748b3082022-01-08 12:41:16 +00001376#if defined(FEAT_VIMINFO) || defined(PROTO)
Bram Moolenaar2d358992016-06-12 21:20:54 +02001377/*
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001378 * Return a pointer to the named file marks.
Bram Moolenaar2d358992016-06-12 21:20:54 +02001379 */
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001380 xfmark_T *
1381get_namedfm(void)
Bram Moolenaar2d358992016-06-12 21:20:54 +02001382{
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001383 return namedfm;
Bram Moolenaar2d358992016-06-12 21:20:54 +02001384}
Dominique Pelle748b3082022-01-08 12:41:16 +00001385#endif
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001386
1387#if defined(FEAT_EVAL) || defined(PROTO)
1388/*
1389 * Add information about mark 'mname' to list 'l'
1390 */
1391 static int
1392add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr, char_u *fname)
1393{
1394 dict_T *d;
1395 list_T *lpos;
1396
1397 if (pos->lnum <= 0)
1398 return OK;
1399
1400 d = dict_alloc();
1401 if (d == NULL)
1402 return FAIL;
1403
1404 if (list_append_dict(l, d) == FAIL)
1405 {
1406 dict_unref(d);
1407 return FAIL;
1408 }
1409
1410 lpos = list_alloc();
1411 if (lpos == NULL)
1412 return FAIL;
1413
1414 list_append_number(lpos, bufnr);
1415 list_append_number(lpos, pos->lnum);
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +02001416 list_append_number(lpos, pos->col + 1);
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001417 list_append_number(lpos, pos->coladd);
1418
1419 if (dict_add_string(d, "mark", mname) == FAIL
1420 || dict_add_list(d, "pos", lpos) == FAIL
1421 || (fname != NULL && dict_add_string(d, "file", fname) == FAIL))
1422 return FAIL;
1423
1424 return OK;
1425}
1426
1427/*
1428 * Get information about marks local to a buffer.
1429 */
1430 static void
1431get_buf_local_marks(buf_T *buf, list_T *l)
1432{
1433 char_u mname[3] = "' ";
1434 int i;
1435
1436 // Marks 'a' to 'z'
1437 for (i = 0; i < NMARKS; ++i)
1438 {
1439 mname[1] = 'a' + i;
1440 add_mark(l, mname, &buf->b_namedm[i], buf->b_fnum, NULL);
1441 }
1442
1443 // Mark '' is a window local mark and not a buffer local mark
1444 add_mark(l, (char_u *)"''", &curwin->w_pcmark, curbuf->b_fnum, NULL);
1445
1446 add_mark(l, (char_u *)"'\"", &buf->b_last_cursor, buf->b_fnum, NULL);
1447 add_mark(l, (char_u *)"'[", &buf->b_op_start, buf->b_fnum, NULL);
1448 add_mark(l, (char_u *)"']", &buf->b_op_end, buf->b_fnum, NULL);
1449 add_mark(l, (char_u *)"'^", &buf->b_last_insert, buf->b_fnum, NULL);
1450 add_mark(l, (char_u *)"'.", &buf->b_last_change, buf->b_fnum, NULL);
1451 add_mark(l, (char_u *)"'<", &buf->b_visual.vi_start, buf->b_fnum, NULL);
1452 add_mark(l, (char_u *)"'>", &buf->b_visual.vi_end, buf->b_fnum, NULL);
1453}
1454
1455/*
1456 * Get information about global marks ('A' to 'Z' and '0' to '9')
1457 */
1458 static void
1459get_global_marks(list_T *l)
1460{
1461 char_u mname[3] = "' ";
1462 int i;
1463 char_u *name;
1464
1465 // Marks 'A' to 'Z' and '0' to '9'
1466 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
1467 {
1468 if (namedfm[i].fmark.fnum != 0)
1469 name = buflist_nr2name(namedfm[i].fmark.fnum, TRUE, TRUE);
1470 else
1471 name = namedfm[i].fname;
1472 if (name != NULL)
1473 {
1474 mname[1] = i >= NMARKS ? i - NMARKS + '0' : i + 'A';
1475 add_mark(l, mname, &namedfm[i].fmark.mark,
1476 namedfm[i].fmark.fnum, name);
1477 if (namedfm[i].fmark.fnum != 0)
1478 vim_free(name);
1479 }
1480 }
1481}
1482
1483/*
1484 * getmarklist() function
1485 */
1486 void
1487f_getmarklist(typval_T *argvars, typval_T *rettv)
1488{
1489 buf_T *buf = NULL;
1490
Bram Moolenaar8088ae92022-06-20 11:38:17 +01001491 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001492 return;
1493
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02001494 if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL)
1495 return;
1496
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001497 if (argvars[0].v_type == VAR_UNKNOWN)
1498 {
1499 get_global_marks(rettv->vval.v_list);
1500 return;
1501 }
1502
1503 buf = tv_get_buf(&argvars[0], FALSE);
1504 if (buf == NULL)
1505 return;
1506
1507 get_buf_local_marks(buf, rettv->vval.v_list);
1508}
1509#endif