blob: b5f2a7e80a0bbf0c3724b27bfc6b82d36aafe343 [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{
139#ifdef FEAT_JUMPLIST
140 int i;
141 xfmark_T *fm;
142#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100144 // for :global the mark is set only once
Bram Moolenaare1004402020-10-24 20:49:43 +0200145 if (global_busy || listcmd_busy || (cmdmod.cmod_flags & CMOD_KEEPJUMPS))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146 return;
147
148 curwin->w_prev_pcmark = curwin->w_pcmark;
149 curwin->w_pcmark = curwin->w_cursor;
150
151#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100152 // If jumplist is full: remove oldest entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153 if (++curwin->w_jumplistlen > JUMPLISTSIZE)
154 {
155 curwin->w_jumplistlen = JUMPLISTSIZE;
156 vim_free(curwin->w_jumplist[0].fname);
157 for (i = 1; i < JUMPLISTSIZE; ++i)
158 curwin->w_jumplist[i - 1] = curwin->w_jumplist[i];
159 }
160 curwin->w_jumplistidx = curwin->w_jumplistlen;
161 fm = &curwin->w_jumplist[curwin->w_jumplistlen - 1];
162
163 fm->fmark.mark = curwin->w_pcmark;
164 fm->fmark.fnum = curbuf->b_fnum;
165 fm->fname = NULL;
Bram Moolenaar2d358992016-06-12 21:20:54 +0200166# ifdef FEAT_VIMINFO
167 fm->time_set = vim_time();
168# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169#endif
170}
171
172/*
173 * To change context, call setpcmark(), then move the current position to
174 * where ever, then call checkpcmark(). This ensures that the previous
175 * context will only be changed if the cursor moved to a different line.
176 * If pcmark was deleted (with "dG") the previous mark is restored.
177 */
178 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100179checkpcmark(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180{
181 if (curwin->w_prev_pcmark.lnum != 0
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100182 && (EQUAL_POS(curwin->w_pcmark, curwin->w_cursor)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183 || curwin->w_pcmark.lnum == 0))
184 {
185 curwin->w_pcmark = curwin->w_prev_pcmark;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100186 curwin->w_prev_pcmark.lnum = 0; // Show it has been checked
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187 }
188}
189
190#if defined(FEAT_JUMPLIST) || defined(PROTO)
191/*
192 * move "count" positions in the jump list (count may be negative)
193 */
194 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100195movemark(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196{
197 pos_T *pos;
198 xfmark_T *jmp;
199
Bram Moolenaar48679742018-02-13 13:33:29 +0100200 cleanup_jumplist(curwin, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100202 if (curwin->w_jumplistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203 return (pos_T *)NULL;
204
205 for (;;)
206 {
207 if (curwin->w_jumplistidx + count < 0
208 || curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
209 return (pos_T *)NULL;
210
211 /*
212 * if first CTRL-O or CTRL-I command after a jump, add cursor position
Bram Moolenaarf711faf2007-05-10 16:48:19 +0000213 * to list. Careful: If there are duplicates (CTRL-O immediately after
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214 * starting Vim on a file), another entry may have been removed.
215 */
216 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
217 {
218 setpcmark();
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100219 --curwin->w_jumplistidx; // skip the new entry
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220 if (curwin->w_jumplistidx + count < 0)
221 return (pos_T *)NULL;
222 }
223
224 curwin->w_jumplistidx += count;
225
226 jmp = curwin->w_jumplist + curwin->w_jumplistidx;
227 if (jmp->fmark.fnum == 0)
228 fname2fnum(jmp);
229 if (jmp->fmark.fnum != curbuf->b_fnum)
230 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100231 // jump to other file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 if (buflist_findnr(jmp->fmark.fnum) == NULL)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100233 { // Skip this one ..
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234 count += count < 0 ? -1 : 1;
235 continue;
236 }
237 if (buflist_getfile(jmp->fmark.fnum, jmp->fmark.mark.lnum,
238 0, FALSE) == FAIL)
239 return (pos_T *)NULL;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100240 // Set lnum again, autocommands my have changed it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 curwin->w_cursor = jmp->fmark.mark;
242 pos = (pos_T *)-1;
243 }
244 else
245 pos = &(jmp->fmark.mark);
246 return pos;
247 }
248}
249
250/*
251 * Move "count" positions in the changelist (count may be negative).
252 */
253 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100254movechangelist(int count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255{
256 int n;
257
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100258 if (curbuf->b_changelistlen == 0) // nothing to jump to
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 return (pos_T *)NULL;
260
261 n = curwin->w_changelistidx;
262 if (n + count < 0)
263 {
264 if (n == 0)
265 return (pos_T *)NULL;
266 n = 0;
267 }
268 else if (n + count >= curbuf->b_changelistlen)
269 {
270 if (n == curbuf->b_changelistlen - 1)
271 return (pos_T *)NULL;
272 n = curbuf->b_changelistlen - 1;
273 }
274 else
275 n += count;
276 curwin->w_changelistidx = n;
277 return curbuf->b_changelist + n;
278}
279#endif
280
281/*
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100282 * Find mark "c" in buffer pointed to by "buf".
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000283 * If "changefile" is TRUE it's allowed to edit another file for '0, 'A, etc.
284 * If "fnum" is not NULL store the fnum there for '0, 'A etc., don't edit
285 * another file.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286 * Returns:
287 * - pointer to pos_T if found. lnum is 0 when mark not set, -1 when mark is
288 * in another file which can't be gotten. (caller needs to check lnum!)
289 * - NULL if there is no mark called 'c'.
290 * - -1 if mark is in other file and jumped there (only if changefile is TRUE)
291 */
292 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100293getmark_buf(buf_T *buf, int c, int changefile)
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100294{
295 return getmark_buf_fnum(buf, c, changefile, NULL);
296}
297
298 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100299getmark(int c, int changefile)
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000300{
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100301 return getmark_buf_fnum(curbuf, c, changefile, NULL);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000302}
303
304 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100305getmark_buf_fnum(
306 buf_T *buf,
307 int c,
308 int changefile,
309 int *fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310{
311 pos_T *posp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 pos_T *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000313 static pos_T pos_copy;
314
315 posp = NULL;
316
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100317 // Check for special key, can't be a mark name and might cause islower()
318 // to crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 if (c < 0)
320 return posp;
321#ifndef EBCDIC
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100322 if (c > '~') // check for islower()/isupper()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000323 ;
324 else
325#endif
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100326 if (c == '\'' || c == '`') // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100328 pos_copy = curwin->w_pcmark; // need to make a copy because
329 posp = &pos_copy; // w_pcmark may be changed soon
Bram Moolenaar071d4272004-06-13 20:20:40 +0000330 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100331 else if (c == '"') // to pos when leaving buffer
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100332 posp = &(buf->b_last_cursor);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100333 else if (c == '^') // to where Insert mode stopped
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100334 posp = &(buf->b_last_insert);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100335 else if (c == '.') // to where last change was made
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100336 posp = &(buf->b_last_change);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100337 else if (c == '[') // to start of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100338 posp = &(buf->b_op_start);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100339 else if (c == ']') // to end of previous operator
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100340 posp = &(buf->b_op_end);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100341 else if (c == '{' || c == '}') // to previous/next paragraph
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 {
343 pos_T pos;
344 oparg_T oa;
345 int slcb = listcmd_busy;
346
347 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100348 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar8b96d642005-09-05 22:05:30 +0000349 if (findpar(&oa.inclusive,
350 c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000351 {
352 pos_copy = curwin->w_cursor;
353 posp = &pos_copy;
354 }
355 curwin->w_cursor = pos;
356 listcmd_busy = slcb;
357 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100358 else if (c == '(' || c == ')') // to previous/next sentence
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 {
360 pos_T pos;
361 int slcb = listcmd_busy;
362
363 pos = curwin->w_cursor;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100364 listcmd_busy = TRUE; // avoid that '' is changed
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 if (findsent(c == ')' ? FORWARD : BACKWARD, 1L))
366 {
367 pos_copy = curwin->w_cursor;
368 posp = &pos_copy;
369 }
370 curwin->w_cursor = pos;
371 listcmd_busy = slcb;
372 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100373 else if (c == '<' || c == '>') // start/end of visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100375 startp = &buf->b_visual.vi_start;
376 endp = &buf->b_visual.vi_end;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100377 if (((c == '<') == LT_POS(*startp, *endp) || endp->lnum == 0)
Bram Moolenaarf13e00b2017-01-28 18:23:54 +0100378 && startp->lnum != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379 posp = startp;
380 else
381 posp = endp;
382 /*
383 * For Visual line mode, set mark at begin or end of line
384 */
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100385 if (buf->b_visual.vi_mode == 'V')
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 {
387 pos_copy = *posp;
388 posp = &pos_copy;
389 if (c == '<')
390 pos_copy.col = 0;
391 else
392 pos_copy.col = MAXCOL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393 pos_copy.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394 }
395 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100396 else if (ASCII_ISLOWER(c)) // normal named mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 {
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100398 posp = &(buf->b_namedm[c - 'a']);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100400 else if (ASCII_ISUPPER(c) || VIM_ISDIGIT(c)) // named file mark
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401 {
402 if (VIM_ISDIGIT(c))
403 c = c - '0' + NMARKS;
404 else
405 c -= 'A';
406 posp = &(namedfm[c].fmark.mark);
407
408 if (namedfm[c].fmark.fnum == 0)
409 fname2fnum(&namedfm[c]);
Bram Moolenaarbfb2d402006-03-03 22:50:42 +0000410
411 if (fnum != NULL)
412 *fnum = namedfm[c].fmark.fnum;
Bram Moolenaar9d182dd2013-01-23 15:53:15 +0100413 else if (namedfm[c].fmark.fnum != buf->b_fnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100415 // mark is in another file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 posp = &pos_copy;
417
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 if (namedfm[c].fmark.mark.lnum != 0
419 && changefile && namedfm[c].fmark.fnum)
420 {
421 if (buflist_getfile(namedfm[c].fmark.fnum,
422 (linenr_T)1, GETF_SETMARK, FALSE) == OK)
423 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100424 // Set the lnum now, autocommands could have changed it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425 curwin->w_cursor = namedfm[c].fmark.mark;
426 return (pos_T *)-1;
427 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100428 pos_copy.lnum = -1; // can't get file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 }
430 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100431 pos_copy.lnum = 0; // mark exists, but is not valid in
432 // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433 }
434 }
435
436 return posp;
437}
438
439/*
440 * Search for the next named mark in the current file.
441 *
442 * Returns pointer to pos_T of the next mark or NULL if no mark is found.
443 */
444 pos_T *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100445getnextmark(
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100446 pos_T *startpos, // where to start
447 int dir, // direction for search
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100448 int begin_line)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449{
450 int i;
451 pos_T *result = NULL;
452 pos_T pos;
453
454 pos = *startpos;
455
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100456 // When searching backward and leaving the cursor on the first non-blank,
457 // position must be in a previous line.
458 // When searching forward and leaving the cursor on the first non-blank,
459 // position must be in a next line.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460 if (dir == BACKWARD && begin_line)
461 pos.col = 0;
462 else if (dir == FORWARD && begin_line)
463 pos.col = MAXCOL;
464
465 for (i = 0; i < NMARKS; i++)
466 {
467 if (curbuf->b_namedm[i].lnum > 0)
468 {
469 if (dir == FORWARD)
470 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100471 if ((result == NULL || LT_POS(curbuf->b_namedm[i], *result))
472 && LT_POS(pos, curbuf->b_namedm[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000473 result = &curbuf->b_namedm[i];
474 }
475 else
476 {
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100477 if ((result == NULL || LT_POS(*result, curbuf->b_namedm[i]))
478 && LT_POS(curbuf->b_namedm[i], pos))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 result = &curbuf->b_namedm[i];
480 }
481 }
482 }
483
484 return result;
485}
486
487/*
488 * For an xtended filemark: set the fnum from the fname.
489 * This is used for marks obtained from the .viminfo file. It's postponed
490 * until the mark is used to avoid a long startup delay.
491 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +0200492 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100493fname2fnum(xfmark_T *fm)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494{
495 char_u *p;
496
497 if (fm->fname != NULL)
498 {
499 /*
500 * First expand "~/" in the file name to the home directory.
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000501 * Don't expand the whole name, it may contain other '~' chars.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 */
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000503 if (fm->fname[0] == '~' && (fm->fname[1] == '/'
504#ifdef BACKSLASH_IN_FILENAME
505 || fm->fname[1] == '\\'
506#endif
507 ))
508 {
509 int len;
510
511 expand_env((char_u *)"~/", NameBuff, MAXPATHL);
Bram Moolenaarcb4cef22008-03-16 15:04:34 +0000512 len = (int)STRLEN(NameBuff);
Bram Moolenaar525ad4d2008-01-03 19:22:13 +0000513 vim_strncpy(NameBuff + len, fm->fname + 2, MAXPATHL - len - 1);
514 }
515 else
516 vim_strncpy(NameBuff, fm->fname, MAXPATHL - 1);
517
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100518 // Try to shorten the file name.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 mch_dirname(IObuff, IOSIZE);
520 p = shorten_fname(NameBuff, IObuff);
521
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100522 // buflist_new() will call fmarks_check_names()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 (void)buflist_new(NameBuff, p, (linenr_T)1, 0);
524 }
525}
526
527/*
528 * Check all file marks for a name that matches the file name in buf.
529 * May replace the name with an fnum.
530 * Used for marks that come from the .viminfo file.
531 */
532 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100533fmarks_check_names(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534{
535 char_u *name;
536 int i;
537#ifdef FEAT_JUMPLIST
538 win_T *wp;
539#endif
540
541 if (buf->b_ffname == NULL)
542 return;
543
544 name = home_replace_save(buf, buf->b_ffname);
545 if (name == NULL)
546 return;
547
548 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
549 fmarks_check_one(&namedfm[i], name, buf);
550
551#ifdef FEAT_JUMPLIST
552 FOR_ALL_WINDOWS(wp)
553 {
554 for (i = 0; i < wp->w_jumplistlen; ++i)
555 fmarks_check_one(&wp->w_jumplist[i], name, buf);
556 }
557#endif
558
559 vim_free(name);
560}
561
562 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100563fmarks_check_one(xfmark_T *fm, char_u *name, buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000564{
565 if (fm->fmark.fnum == 0
566 && fm->fname != NULL
567 && fnamecmp(name, fm->fname) == 0)
568 {
569 fm->fmark.fnum = buf->b_fnum;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100570 VIM_CLEAR(fm->fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 }
572}
573
574/*
575 * Check a if a position from a mark is valid.
576 * Give and error message and return FAIL if not.
577 */
578 int
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100579check_mark(pos_T *pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000580{
581 if (pos == NULL)
582 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100583 emsg(_(e_umark));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 return FAIL;
585 }
586 if (pos->lnum <= 0)
587 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100588 // lnum is negative if mark is in another file can can't get that
589 // file, error message already give then.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 if (pos->lnum == 0)
Bram Moolenaar108010a2021-06-27 22:03:33 +0200591 emsg(_(e_mark_not_set));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 return FAIL;
593 }
594 if (pos->lnum > curbuf->b_ml.ml_line_count)
595 {
Bram Moolenaar108010a2021-06-27 22:03:33 +0200596 emsg(_(e_mark_has_invalid_line_number));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 return FAIL;
598 }
599 return OK;
600}
601
602/*
603 * clrallmarks() - clear all marks in the buffer 'buf'
604 *
605 * Used mainly when trashing the entire buffer during ":e" type commands
606 */
607 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100608clrallmarks(buf_T *buf)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609{
610 static int i = -1;
611
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100612 if (i == -1) // first call ever: initialize
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 for (i = 0; i < NMARKS + 1; i++)
614 {
615 namedfm[i].fmark.mark.lnum = 0;
616 namedfm[i].fname = NULL;
Bram Moolenaar2d358992016-06-12 21:20:54 +0200617#ifdef FEAT_VIMINFO
618 namedfm[i].time_set = 0;
619#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 }
621
622 for (i = 0; i < NMARKS; i++)
623 buf->b_namedm[i].lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100624 buf->b_op_start.lnum = 0; // start/end op mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 buf->b_op_end.lnum = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100626 buf->b_last_cursor.lnum = 1; // '" mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 buf->b_last_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 buf->b_last_cursor.coladd = 0;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100629 buf->b_last_insert.lnum = 0; // '^ mark cleared
630 buf->b_last_change.lnum = 0; // '. mark cleared
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631#ifdef FEAT_JUMPLIST
632 buf->b_changelistlen = 0;
633#endif
634}
635
636/*
637 * Get name of file from a filemark.
638 * When it's in the current buffer, return the text at the mark.
639 * Returns an allocated string.
640 */
641 char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100642fm_getname(fmark_T *fmark, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643{
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100644 if (fmark->fnum == curbuf->b_fnum) // current buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 return mark_line(&(fmark->mark), lead_len);
646 return buflist_nr2name(fmark->fnum, FALSE, TRUE);
647}
648
649/*
650 * Return the line at mark "mp". Truncate to fit in window.
651 * The returned string has been allocated.
652 */
653 static char_u *
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100654mark_line(pos_T *mp, int lead_len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655{
656 char_u *s, *p;
657 int len;
658
659 if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
660 return vim_strsave((char_u *)"-invalid-");
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200661 // Allow for up to 5 bytes per character.
Bram Moolenaar71ccd032020-06-12 22:59:11 +0200662 s = vim_strnsave(skipwhite(ml_get(mp->lnum)), Columns * 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663 if (s == NULL)
664 return NULL;
Bram Moolenaar9d5185b2018-07-08 17:57:34 +0200665 // Truncate the line to fit it in the window.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666 len = 0;
Bram Moolenaar91acfff2017-03-12 19:22:36 +0100667 for (p = s; *p != NUL; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 {
669 len += ptr2cells(p);
670 if (len >= Columns - lead_len)
671 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672 }
673 *p = NUL;
674 return s;
675}
676
677/*
678 * print the marks
679 */
680 void
Bram Moolenaar4bd78232019-09-19 23:21:55 +0200681ex_marks(exarg_T *eap)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682{
683 char_u *arg = eap->arg;
684 int i;
685 char_u *name;
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200686 pos_T *posp, *startp, *endp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687
688 if (arg != NULL && *arg == NUL)
689 arg = NULL;
690
691 show_one_mark('\'', arg, &curwin->w_pcmark, NULL, TRUE);
692 for (i = 0; i < NMARKS; ++i)
693 show_one_mark(i + 'a', arg, &curbuf->b_namedm[i], NULL, TRUE);
694 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
695 {
696 if (namedfm[i].fmark.fnum != 0)
697 name = fm_getname(&namedfm[i].fmark, 15);
698 else
699 name = namedfm[i].fname;
700 if (name != NULL)
701 {
702 show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
703 arg, &namedfm[i].fmark.mark, name,
704 namedfm[i].fmark.fnum == curbuf->b_fnum);
705 if (namedfm[i].fmark.fnum != 0)
706 vim_free(name);
707 }
708 }
709 show_one_mark('"', arg, &curbuf->b_last_cursor, NULL, TRUE);
710 show_one_mark('[', arg, &curbuf->b_op_start, NULL, TRUE);
711 show_one_mark(']', arg, &curbuf->b_op_end, NULL, TRUE);
712 show_one_mark('^', arg, &curbuf->b_last_insert, NULL, TRUE);
713 show_one_mark('.', arg, &curbuf->b_last_change, NULL, TRUE);
Bram Moolenaar54c3fcd2020-07-19 22:09:06 +0200714
715 // Show the marks as where they will jump to.
716 startp = &curbuf->b_visual.vi_start;
717 endp = &curbuf->b_visual.vi_end;
718 if ((LT_POS(*startp, *endp) || endp->lnum == 0) && startp->lnum != 0)
719 posp = startp;
720 else
721 posp = endp;
722 show_one_mark('<', arg, posp, NULL, TRUE);
723 show_one_mark('>', arg, posp == startp ? endp : startp, NULL, TRUE);
724
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 show_one_mark(-1, arg, NULL, NULL, FALSE);
726}
727
728 static void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100729show_one_mark(
730 int c,
731 char_u *arg,
732 pos_T *p,
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200733 char_u *name_arg,
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100734 int current) // in current file
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735{
736 static int did_title = FALSE;
737 int mustfree = FALSE;
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200738 char_u *name = name_arg;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100740 if (c == -1) // finish up
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 {
742 if (did_title)
743 did_title = FALSE;
744 else
745 {
746 if (arg == NULL)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100747 msg(_("No marks set"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100749 semsg(_("E283: No marks matching \"%s\""), arg);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 }
751 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200752 // don't output anything if 'q' typed at --more-- prompt
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 else if (!got_int
754 && (arg == NULL || vim_strchr(arg, c) != NULL)
755 && p->lnum != 0)
756 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200757 if (name == NULL && current)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200759 name = mark_line(p, 15);
760 mustfree = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200762 if (!message_filtered(name))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200764 if (!did_title)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200766 // Highlight title
767 msg_puts_title(_("\nmark line col file/text"));
768 did_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200770 msg_putchar('\n');
771 if (!got_int)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 {
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200773 sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
774 msg_outtrans(IObuff);
775 if (name != NULL)
776 {
777 msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
778 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200780 out_flush(); // show one line at a time
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 }
Bram Moolenaarad6dc492019-04-27 22:40:08 +0200782 if (mustfree)
783 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 }
785}
786
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000787/*
788 * ":delmarks[!] [marks]"
789 */
790 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100791ex_delmarks(exarg_T *eap)
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000792{
793 char_u *p;
794 int from, to;
795 int i;
796 int lower;
797 int digit;
798 int n;
799
800 if (*eap->arg == NUL && eap->forceit)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100801 // clear all marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000802 clrallmarks(curbuf);
803 else if (eap->forceit)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100804 emsg(_(e_invarg));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000805 else if (*eap->arg == NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100806 emsg(_(e_argreq));
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000807 else
808 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100809 // clear specified marks only
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000810 for (p = eap->arg; *p != NUL; ++p)
811 {
812 lower = ASCII_ISLOWER(*p);
813 digit = VIM_ISDIGIT(*p);
814 if (lower || digit || ASCII_ISUPPER(*p))
815 {
816 if (p[1] == '-')
817 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100818 // clear range of marks
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000819 from = *p;
820 to = p[2];
821 if (!(lower ? ASCII_ISLOWER(p[2])
822 : (digit ? VIM_ISDIGIT(p[2])
823 : ASCII_ISUPPER(p[2])))
824 || to < from)
825 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100826 semsg(_(e_invarg2), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000827 return;
828 }
829 p += 2;
830 }
831 else
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100832 // clear one lower case mark
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000833 from = to = *p;
834
835 for (i = from; i <= to; ++i)
836 {
837 if (lower)
838 curbuf->b_namedm[i - 'a'].lnum = 0;
839 else
840 {
841 if (digit)
842 n = i - '0' + NMARKS;
843 else
844 n = i - 'A';
845 namedfm[n].fmark.mark.lnum = 0;
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100846 namedfm[n].fmark.fnum = 0;
Bram Moolenaard23a8232018-02-10 18:45:26 +0100847 VIM_CLEAR(namedfm[n].fname);
Bram Moolenaar2d358992016-06-12 21:20:54 +0200848#ifdef FEAT_VIMINFO
Bram Moolenaar8cd6cd82019-12-27 17:33:26 +0100849 namedfm[n].time_set = digit ? 0 : vim_time();
Bram Moolenaar2d358992016-06-12 21:20:54 +0200850#endif
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000851 }
852 }
853 }
854 else
855 switch (*p)
856 {
857 case '"': curbuf->b_last_cursor.lnum = 0; break;
858 case '^': curbuf->b_last_insert.lnum = 0; break;
859 case '.': curbuf->b_last_change.lnum = 0; break;
860 case '[': curbuf->b_op_start.lnum = 0; break;
861 case ']': curbuf->b_op_end.lnum = 0; break;
Bram Moolenaara226a6d2006-02-26 23:59:20 +0000862 case '<': curbuf->b_visual.vi_start.lnum = 0; break;
863 case '>': curbuf->b_visual.vi_end.lnum = 0; break;
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000864 case ' ': break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100865 default: semsg(_(e_invarg2), p);
Bram Moolenaarc0197e22004-09-13 20:26:32 +0000866 return;
867 }
868 }
869 }
870}
871
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872#if defined(FEAT_JUMPLIST) || defined(PROTO)
873/*
874 * print the jumplist
875 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100877ex_jumps(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878{
879 int i;
880 char_u *name;
881
Bram Moolenaar48679742018-02-13 13:33:29 +0100882 cleanup_jumplist(curwin, TRUE);
Bram Moolenaara7e18d22018-02-11 14:29:49 +0100883
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100884 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100885 msg_puts_title(_("\n jump line col file/text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i)
887 {
888 if (curwin->w_jumplist[i].fmark.mark.lnum != 0)
889 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000890 name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
Bram Moolenaarf86db782018-10-25 13:31:37 +0200891
892 // apply :filter /pat/ or file name not available
893 if (name == NULL || message_filtered(name))
Bram Moolenaard93090f2019-01-27 15:07:39 +0100894 {
895 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 continue;
Bram Moolenaard93090f2019-01-27 15:07:39 +0100897 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898
899 msg_putchar('\n');
900 if (got_int)
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000901 {
902 vim_free(name);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 break;
Bram Moolenaared39e1d2008-08-09 17:55:22 +0000904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905 sprintf((char *)IObuff, "%c %2d %5ld %4d ",
906 i == curwin->w_jumplistidx ? '>' : ' ',
907 i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
908 : curwin->w_jumplistidx - i,
909 curwin->w_jumplist[i].fmark.mark.lnum,
910 curwin->w_jumplist[i].fmark.mark.col);
911 msg_outtrans(IObuff);
912 msg_outtrans_attr(name,
913 curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum
Bram Moolenaar8820b482017-03-16 17:23:31 +0100914 ? HL_ATTR(HLF_D) : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 vim_free(name);
916 ui_breakcheck();
917 }
918 out_flush();
919 }
920 if (curwin->w_jumplistidx == curwin->w_jumplistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100921 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922}
923
Bram Moolenaar2d358992016-06-12 21:20:54 +0200924 void
925ex_clearjumps(exarg_T *eap UNUSED)
926{
927 free_jumplist(curwin);
928 curwin->w_jumplistlen = 0;
929 curwin->w_jumplistidx = 0;
930}
931
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932/*
933 * print the changelist
934 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000935 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +0100936ex_changes(exarg_T *eap UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937{
938 int i;
939 char_u *name;
940
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100941 // Highlight title
Bram Moolenaar32526b32019-01-19 17:43:09 +0100942 msg_puts_title(_("\nchange line col text"));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943
944 for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i)
945 {
946 if (curbuf->b_changelist[i].lnum != 0)
947 {
948 msg_putchar('\n');
949 if (got_int)
950 break;
951 sprintf((char *)IObuff, "%c %3d %5ld %4d ",
952 i == curwin->w_changelistidx ? '>' : ' ',
953 i > curwin->w_changelistidx ? i - curwin->w_changelistidx
954 : curwin->w_changelistidx - i,
955 (long)curbuf->b_changelist[i].lnum,
956 curbuf->b_changelist[i].col);
957 msg_outtrans(IObuff);
958 name = mark_line(&curbuf->b_changelist[i], 17);
959 if (name == NULL)
960 break;
Bram Moolenaar8820b482017-03-16 17:23:31 +0100961 msg_outtrans_attr(name, HL_ATTR(HLF_D));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962 vim_free(name);
963 ui_breakcheck();
964 }
965 out_flush();
966 }
967 if (curwin->w_changelistidx == curbuf->b_changelistlen)
Bram Moolenaar32526b32019-01-19 17:43:09 +0100968 msg_puts("\n>");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000969}
970#endif
971
972#define one_adjust(add) \
973 { \
974 lp = add; \
975 if (*lp >= line1 && *lp <= line2) \
976 { \
977 if (amount == MAXLNUM) \
978 *lp = 0; \
979 else \
980 *lp += amount; \
981 } \
982 else if (amount_after && *lp > line2) \
983 *lp += amount_after; \
984 }
985
Bram Moolenaar4ba37b52019-12-04 21:57:43 +0100986// don't delete the line, just put at first deleted line
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987#define one_adjust_nodel(add) \
988 { \
989 lp = add; \
990 if (*lp >= line1 && *lp <= line2) \
991 { \
992 if (amount == MAXLNUM) \
993 *lp = line1; \
994 else \
995 *lp += amount; \
996 } \
997 else if (amount_after && *lp > line2) \
998 *lp += amount_after; \
999 }
1000
1001/*
1002 * Adjust marks between line1 and line2 (inclusive) to move 'amount' lines.
1003 * Must be called before changed_*(), appended_lines() or deleted_lines().
1004 * May be called before or after changing the text.
1005 * When deleting lines line1 to line2, use an 'amount' of MAXLNUM: The marks
1006 * within this range are made invalid.
1007 * If 'amount_after' is non-zero adjust marks after line2.
1008 * Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2);
1009 * Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
1010 * or: mark_adjust(56, 55, MAXLNUM, 2);
1011 */
1012 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001013mark_adjust(
1014 linenr_T line1,
1015 linenr_T line2,
1016 long amount,
1017 long amount_after)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018{
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001019 mark_adjust_internal(line1, line2, amount, amount_after, TRUE);
1020}
1021
1022 void
1023mark_adjust_nofold(
1024 linenr_T line1,
1025 linenr_T line2,
1026 long amount,
1027 long amount_after)
1028{
1029 mark_adjust_internal(line1, line2, amount, amount_after, FALSE);
1030}
1031
1032 static void
1033mark_adjust_internal(
1034 linenr_T line1,
1035 linenr_T line2,
1036 long amount,
1037 long amount_after,
1038 int adjust_folds UNUSED)
1039{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 int i;
1041 int fnum = curbuf->b_fnum;
1042 linenr_T *lp;
1043 win_T *win;
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001044 tabpage_T *tab;
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001045 static pos_T initpos = {1, 0, 0};
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001047 if (line2 < line1 && amount_after == 0L) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001048 return;
1049
Bram Moolenaare1004402020-10-24 20:49:43 +02001050 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001052 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 for (i = 0; i < NMARKS; i++)
1054 {
1055 one_adjust(&(curbuf->b_namedm[i].lnum));
1056 if (namedfm[i].fmark.fnum == fnum)
1057 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1058 }
1059 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1060 {
1061 if (namedfm[i].fmark.fnum == fnum)
1062 one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
1063 }
1064
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001065 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 one_adjust(&(curbuf->b_last_insert.lnum));
1067
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001068 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 one_adjust(&(curbuf->b_last_change.lnum));
1070
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001071 // last cursor position, if it was set
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01001072 if (!EQUAL_POS(curbuf->b_last_cursor, initpos))
Bram Moolenaarb6a76ff2013-02-06 12:33:21 +01001073 one_adjust(&(curbuf->b_last_cursor.lnum));
1074
1075
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001077 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 for (i = 0; i < curbuf->b_changelistlen; ++i)
1079 one_adjust_nodel(&(curbuf->b_changelist[i].lnum));
1080#endif
1081
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001082 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001083 one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum));
1084 one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085
1086#ifdef FEAT_QUICKFIX
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001087 // quickfix marks
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001088 qf_mark_adjust(NULL, line1, line2, amount, amount_after);
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001089 // location lists
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001090 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar28c258f2006-01-25 22:02:51 +00001091 qf_mark_adjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092#endif
1093
1094#ifdef FEAT_SIGNS
1095 sign_mark_adjust(line1, line2, amount, amount_after);
1096#endif
1097 }
1098
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001099 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 one_adjust(&(curwin->w_pcmark.lnum));
1101
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001102 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001103 one_adjust(&(curwin->w_prev_pcmark.lnum));
1104
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001105 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 if (saved_cursor.lnum != 0)
1107 one_adjust_nodel(&(saved_cursor.lnum));
1108
1109 /*
1110 * Adjust items in all windows related to the current buffer.
1111 */
Bram Moolenaarbd1e5d22009-04-29 09:02:44 +00001112 FOR_ALL_TAB_WINDOWS(tab, win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001113 {
1114#ifdef FEAT_JUMPLIST
Bram Moolenaare1004402020-10-24 20:49:43 +02001115 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001116 // Marks in the jumplist. When deleting lines, this may create
1117 // duplicate marks in the jumplist, they will be removed later.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 for (i = 0; i < win->w_jumplistlen; ++i)
1119 if (win->w_jumplist[i].fmark.fnum == fnum)
1120 one_adjust_nodel(&(win->w_jumplist[i].fmark.mark.lnum));
1121#endif
1122
1123 if (win->w_buffer == curbuf)
1124 {
Bram Moolenaare1004402020-10-24 20:49:43 +02001125 if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001126 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127 for (i = 0; i < win->w_tagstacklen; i++)
1128 if (win->w_tagstack[i].fmark.fnum == fnum)
1129 one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
1130
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001131 // the displayed Visual area
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 if (win->w_old_cursor_lnum != 0)
1133 {
1134 one_adjust_nodel(&(win->w_old_cursor_lnum));
1135 one_adjust_nodel(&(win->w_old_visual_lnum));
1136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001138 // topline and cursor position for windows with the same buffer
1139 // other than the current window
Bram Moolenaar071d4272004-06-13 20:20:40 +00001140 if (win != curwin)
1141 {
1142 if (win->w_topline >= line1 && win->w_topline <= line2)
1143 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001144 if (amount == MAXLNUM) // topline is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145 {
1146 if (line1 <= 1)
1147 win->w_topline = 1;
1148 else
1149 win->w_topline = line1 - 1;
1150 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001151 else // keep topline on the same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 win->w_topline += amount;
1153#ifdef FEAT_DIFF
1154 win->w_topfill = 0;
1155#endif
1156 }
1157 else if (amount_after && win->w_topline > line2)
1158 {
1159 win->w_topline += amount_after;
1160#ifdef FEAT_DIFF
1161 win->w_topfill = 0;
1162#endif
1163 }
1164 if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2)
1165 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001166 if (amount == MAXLNUM) // line with cursor is deleted
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 {
1168 if (line1 <= 1)
1169 win->w_cursor.lnum = 1;
1170 else
1171 win->w_cursor.lnum = line1 - 1;
1172 win->w_cursor.col = 0;
1173 }
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001174 else // keep cursor on the same line
Bram Moolenaar071d4272004-06-13 20:20:40 +00001175 win->w_cursor.lnum += amount;
1176 }
1177 else if (amount_after && win->w_cursor.lnum > line2)
1178 win->w_cursor.lnum += amount_after;
1179 }
1180
1181#ifdef FEAT_FOLDING
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001182 // adjust folds
Bram Moolenaar88d298a2017-03-14 21:53:58 +01001183 if (adjust_folds)
1184 foldMarkAdjust(win, line1, line2, amount, amount_after);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185#endif
1186 }
1187 }
1188
1189#ifdef FEAT_DIFF
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001190 // adjust diffs
Bram Moolenaar071d4272004-06-13 20:20:40 +00001191 diff_mark_adjust(line1, line2, amount, amount_after);
1192#endif
1193}
1194
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001195// This code is used often, needs to be fast.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196#define col_adjust(pp) \
1197 { \
1198 posp = pp; \
1199 if (posp->lnum == lnum && posp->col >= mincol) \
1200 { \
1201 posp->lnum += lnum_amount; \
1202 if (col_amount < 0 && posp->col <= (colnr_T)-col_amount) \
1203 posp->col = 0; \
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001204 else if (posp->col < spaces_removed) \
1205 posp->col = col_amount + spaces_removed; \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001206 else \
1207 posp->col += col_amount; \
1208 } \
1209 }
1210
1211/*
1212 * Adjust marks in line "lnum" at column "mincol" and further: add
1213 * "lnum_amount" to the line number and add "col_amount" to the column
1214 * position.
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001215 * "spaces_removed" is the number of spaces that were removed, matters when the
1216 * cursor is inside them.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217 */
1218 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001219mark_col_adjust(
1220 linenr_T lnum,
1221 colnr_T mincol,
1222 long lnum_amount,
Bram Moolenaare1e714e2018-12-31 23:58:24 +01001223 long col_amount,
1224 int spaces_removed)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001225{
1226 int i;
1227 int fnum = curbuf->b_fnum;
1228 win_T *win;
1229 pos_T *posp;
1230
Bram Moolenaare1004402020-10-24 20:49:43 +02001231 if ((col_amount == 0L && lnum_amount == 0L)
1232 || (cmdmod.cmod_flags & CMOD_LOCKMARKS))
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001233 return; // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001235 // named marks, lower case and upper case
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 for (i = 0; i < NMARKS; i++)
1237 {
1238 col_adjust(&(curbuf->b_namedm[i]));
1239 if (namedfm[i].fmark.fnum == fnum)
1240 col_adjust(&(namedfm[i].fmark.mark));
1241 }
1242 for (i = NMARKS; i < NMARKS + EXTRA_MARKS; i++)
1243 {
1244 if (namedfm[i].fmark.fnum == fnum)
1245 col_adjust(&(namedfm[i].fmark.mark));
1246 }
1247
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001248 // last Insert position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249 col_adjust(&(curbuf->b_last_insert));
1250
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001251 // last change position
Bram Moolenaar071d4272004-06-13 20:20:40 +00001252 col_adjust(&(curbuf->b_last_change));
1253
1254#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001255 // list of change positions
Bram Moolenaar071d4272004-06-13 20:20:40 +00001256 for (i = 0; i < curbuf->b_changelistlen; ++i)
1257 col_adjust(&(curbuf->b_changelist[i]));
1258#endif
1259
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001260 // Visual area
Bram Moolenaara226a6d2006-02-26 23:59:20 +00001261 col_adjust(&(curbuf->b_visual.vi_start));
1262 col_adjust(&(curbuf->b_visual.vi_end));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001263
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001264 // previous context mark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001265 col_adjust(&(curwin->w_pcmark));
1266
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001267 // previous pcmark
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 col_adjust(&(curwin->w_prev_pcmark));
1269
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001270 // saved cursor for formatting
Bram Moolenaar071d4272004-06-13 20:20:40 +00001271 col_adjust(&saved_cursor);
1272
1273 /*
1274 * Adjust items in all windows related to the current buffer.
1275 */
1276 FOR_ALL_WINDOWS(win)
1277 {
1278#ifdef FEAT_JUMPLIST
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001279 // marks in the jumplist
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280 for (i = 0; i < win->w_jumplistlen; ++i)
1281 if (win->w_jumplist[i].fmark.fnum == fnum)
1282 col_adjust(&(win->w_jumplist[i].fmark.mark));
1283#endif
1284
1285 if (win->w_buffer == curbuf)
1286 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001287 // marks in the tag stack
Bram Moolenaar071d4272004-06-13 20:20:40 +00001288 for (i = 0; i < win->w_tagstacklen; i++)
1289 if (win->w_tagstack[i].fmark.fnum == fnum)
1290 col_adjust(&(win->w_tagstack[i].fmark.mark));
1291
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001292 // cursor position for other windows with the same buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00001293 if (win != curwin)
1294 col_adjust(&win->w_cursor);
1295 }
1296 }
1297}
1298
1299#ifdef FEAT_JUMPLIST
1300/*
1301 * When deleting lines, this may create duplicate marks in the
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001302 * jumplist. They will be removed here for the specified window.
Bram Moolenaar48679742018-02-13 13:33:29 +01001303 * When "loadfiles" is TRUE first ensure entries have the "fnum" field set
1304 * (this may be a bit slow).
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 */
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001306 void
Bram Moolenaar48679742018-02-13 13:33:29 +01001307cleanup_jumplist(win_T *wp, int loadfiles)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308{
1309 int i;
1310 int from, to;
1311
Bram Moolenaar48679742018-02-13 13:33:29 +01001312 if (loadfiles)
1313 {
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001314 // If specified, load all the files from the jump list. This is
1315 // needed to properly clean up duplicate entries, but will take some
1316 // time.
Bram Moolenaar48679742018-02-13 13:33:29 +01001317 for (i = 0; i < wp->w_jumplistlen; ++i)
1318 {
1319 if ((wp->w_jumplist[i].fmark.fnum == 0) &&
1320 (wp->w_jumplist[i].fmark.mark.lnum != 0))
1321 fname2fnum(&wp->w_jumplist[i]);
1322 }
1323 }
1324
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325 to = 0;
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001326 for (from = 0; from < wp->w_jumplistlen; ++from)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001327 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001328 if (wp->w_jumplistidx == from)
1329 wp->w_jumplistidx = to;
1330 for (i = from + 1; i < wp->w_jumplistlen; ++i)
1331 if (wp->w_jumplist[i].fmark.fnum
1332 == wp->w_jumplist[from].fmark.fnum
1333 && wp->w_jumplist[from].fmark.fnum != 0
1334 && wp->w_jumplist[i].fmark.mark.lnum
1335 == wp->w_jumplist[from].fmark.mark.lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336 break;
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001337 if (i >= wp->w_jumplistlen) // no duplicate
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001338 wp->w_jumplist[to++] = wp->w_jumplist[from];
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339 else
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001340 vim_free(wp->w_jumplist[from].fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341 }
Bram Moolenaara7e18d22018-02-11 14:29:49 +01001342 if (wp->w_jumplistidx == wp->w_jumplistlen)
1343 wp->w_jumplistidx = to;
1344 wp->w_jumplistlen = to;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345}
1346
Bram Moolenaar071d4272004-06-13 20:20:40 +00001347/*
1348 * Copy the jumplist from window "from" to window "to".
1349 */
1350 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001351copy_jumplist(win_T *from, win_T *to)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001352{
1353 int i;
1354
1355 for (i = 0; i < from->w_jumplistlen; ++i)
1356 {
1357 to->w_jumplist[i] = from->w_jumplist[i];
1358 if (from->w_jumplist[i].fname != NULL)
1359 to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
1360 }
1361 to->w_jumplistlen = from->w_jumplistlen;
1362 to->w_jumplistidx = from->w_jumplistidx;
1363}
1364
1365/*
1366 * Free items in the jumplist of window "wp".
1367 */
1368 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001369free_jumplist(win_T *wp)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370{
1371 int i;
1372
1373 for (i = 0; i < wp->w_jumplistlen; ++i)
1374 vim_free(wp->w_jumplist[i].fname);
1375}
Bram Moolenaar4ba37b52019-12-04 21:57:43 +01001376#endif // FEAT_JUMPLIST
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377
1378 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001379set_last_cursor(win_T *win)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001380{
Bram Moolenaar9db12932013-11-03 00:20:52 +01001381 if (win->w_buffer != NULL)
1382 win->w_buffer->b_last_cursor = win->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383}
1384
Bram Moolenaarea408852005-06-25 22:49:46 +00001385#if defined(EXITFREE) || defined(PROTO)
1386 void
Bram Moolenaar52ea13d2016-01-30 18:51:09 +01001387free_all_marks(void)
Bram Moolenaarea408852005-06-25 22:49:46 +00001388{
1389 int i;
1390
1391 for (i = 0; i < NMARKS + EXTRA_MARKS; i++)
1392 if (namedfm[i].fmark.mark.lnum != 0)
1393 vim_free(namedfm[i].fname);
1394}
1395#endif
1396
Bram Moolenaar2d358992016-06-12 21:20:54 +02001397/*
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001398 * Return a pointer to the named file marks.
Bram Moolenaar2d358992016-06-12 21:20:54 +02001399 */
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001400 xfmark_T *
1401get_namedfm(void)
Bram Moolenaar2d358992016-06-12 21:20:54 +02001402{
Bram Moolenaar1e78e692019-07-22 20:18:27 +02001403 return namedfm;
Bram Moolenaar2d358992016-06-12 21:20:54 +02001404}
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001405
1406#if defined(FEAT_EVAL) || defined(PROTO)
1407/*
1408 * Add information about mark 'mname' to list 'l'
1409 */
1410 static int
1411add_mark(list_T *l, char_u *mname, pos_T *pos, int bufnr, char_u *fname)
1412{
1413 dict_T *d;
1414 list_T *lpos;
1415
1416 if (pos->lnum <= 0)
1417 return OK;
1418
1419 d = dict_alloc();
1420 if (d == NULL)
1421 return FAIL;
1422
1423 if (list_append_dict(l, d) == FAIL)
1424 {
1425 dict_unref(d);
1426 return FAIL;
1427 }
1428
1429 lpos = list_alloc();
1430 if (lpos == NULL)
1431 return FAIL;
1432
1433 list_append_number(lpos, bufnr);
1434 list_append_number(lpos, pos->lnum);
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +02001435 list_append_number(lpos, pos->col + 1);
Bram Moolenaarcfb4b472020-05-31 15:41:57 +02001436 list_append_number(lpos, pos->coladd);
1437
1438 if (dict_add_string(d, "mark", mname) == FAIL
1439 || dict_add_list(d, "pos", lpos) == FAIL
1440 || (fname != NULL && dict_add_string(d, "file", fname) == FAIL))
1441 return FAIL;
1442
1443 return OK;
1444}
1445
1446/*
1447 * Get information about marks local to a buffer.
1448 */
1449 static void
1450get_buf_local_marks(buf_T *buf, list_T *l)
1451{
1452 char_u mname[3] = "' ";
1453 int i;
1454
1455 // Marks 'a' to 'z'
1456 for (i = 0; i < NMARKS; ++i)
1457 {
1458 mname[1] = 'a' + i;
1459 add_mark(l, mname, &buf->b_namedm[i], buf->b_fnum, NULL);
1460 }
1461
1462 // Mark '' is a window local mark and not a buffer local mark
1463 add_mark(l, (char_u *)"''", &curwin->w_pcmark, curbuf->b_fnum, NULL);
1464
1465 add_mark(l, (char_u *)"'\"", &buf->b_last_cursor, buf->b_fnum, NULL);
1466 add_mark(l, (char_u *)"'[", &buf->b_op_start, buf->b_fnum, NULL);
1467 add_mark(l, (char_u *)"']", &buf->b_op_end, buf->b_fnum, NULL);
1468 add_mark(l, (char_u *)"'^", &buf->b_last_insert, buf->b_fnum, NULL);
1469 add_mark(l, (char_u *)"'.", &buf->b_last_change, buf->b_fnum, NULL);
1470 add_mark(l, (char_u *)"'<", &buf->b_visual.vi_start, buf->b_fnum, NULL);
1471 add_mark(l, (char_u *)"'>", &buf->b_visual.vi_end, buf->b_fnum, NULL);
1472}
1473
1474/*
1475 * Get information about global marks ('A' to 'Z' and '0' to '9')
1476 */
1477 static void
1478get_global_marks(list_T *l)
1479{
1480 char_u mname[3] = "' ";
1481 int i;
1482 char_u *name;
1483
1484 // Marks 'A' to 'Z' and '0' to '9'
1485 for (i = 0; i < NMARKS + EXTRA_MARKS; ++i)
1486 {
1487 if (namedfm[i].fmark.fnum != 0)
1488 name = buflist_nr2name(namedfm[i].fmark.fnum, TRUE, TRUE);
1489 else
1490 name = namedfm[i].fname;
1491 if (name != NULL)
1492 {
1493 mname[1] = i >= NMARKS ? i - NMARKS + '0' : i + 'A';
1494 add_mark(l, mname, &namedfm[i].fmark.mark,
1495 namedfm[i].fmark.fnum, name);
1496 if (namedfm[i].fmark.fnum != 0)
1497 vim_free(name);
1498 }
1499 }
1500}
1501
1502/*
1503 * getmarklist() function
1504 */
1505 void
1506f_getmarklist(typval_T *argvars, typval_T *rettv)
1507{
1508 buf_T *buf = NULL;
1509
1510 if (rettv_list_alloc(rettv) != OK)
1511 return;
1512
1513 if (argvars[0].v_type == VAR_UNKNOWN)
1514 {
1515 get_global_marks(rettv->vval.v_list);
1516 return;
1517 }
1518
1519 buf = tv_get_buf(&argvars[0], FALSE);
1520 if (buf == NULL)
1521 return;
1522
1523 get_buf_local_marks(buf, rettv->vval.v_list);
1524}
1525#endif