comparison src/viminfo.c @ 17460:e43f0c0c491c v8.1.1728

patch 8.1.1728: wrong place for command line history viminfo support commit https://github.com/vim/vim/commit/5f32ece459d1f310b1b48b72e07dcd77d3261a76 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 21 21:51:59 2019 +0200 patch 8.1.1728: wrong place for command line history viminfo support Problem: Wrong place for command line history viminfo support. Solution: Move it to viminfo.c.
author Bram Moolenaar <Bram@vim.org>
date Sun, 21 Jul 2019 22:00:05 +0200
parents cfdef48743ed
children 3e708b5c0509
comparison
equal deleted inserted replaced
17459:02dc4260ddbb 17460:e43f0c0c491c
166 buf->b_last_cursor.col); 166 buf->b_last_cursor.col);
167 viminfo_writestring(fp, line); 167 viminfo_writestring(fp, line);
168 } 168 }
169 vim_free(line); 169 vim_free(line);
170 } 170 }
171
172 #if defined(FEAT_CMDHIST) || defined(PROTO)
173 /*
174 * Buffers for history read from a viminfo file. Only valid while reading.
175 */
176 static histentry_T *viminfo_history[HIST_COUNT] =
177 {NULL, NULL, NULL, NULL, NULL};
178 static int viminfo_hisidx[HIST_COUNT] = {0, 0, 0, 0, 0};
179 static int viminfo_hislen[HIST_COUNT] = {0, 0, 0, 0, 0};
180 static int viminfo_add_at_front = FALSE;
181
182 /*
183 * Translate a history type number to the associated character.
184 */
185 static int
186 hist_type2char(
187 int type,
188 int use_question) // use '?' instead of '/'
189 {
190 if (type == HIST_CMD)
191 return ':';
192 if (type == HIST_SEARCH)
193 {
194 if (use_question)
195 return '?';
196 else
197 return '/';
198 }
199 if (type == HIST_EXPR)
200 return '=';
201 return '@';
202 }
203
204 /*
205 * Prepare for reading the history from the viminfo file.
206 * This allocates history arrays to store the read history lines.
207 */
208 static void
209 prepare_viminfo_history(int asklen, int writing)
210 {
211 int i;
212 int num;
213 int type;
214 int len;
215 int hislen = get_hislen();
216
217 init_history();
218 viminfo_add_at_front = (asklen != 0 && !writing);
219 if (asklen > hislen)
220 asklen = hislen;
221
222 for (type = 0; type < HIST_COUNT; ++type)
223 {
224 histentry_T *histentry = get_histentry(type);
225
226 // Count the number of empty spaces in the history list. Entries read
227 // from viminfo previously are also considered empty. If there are
228 // more spaces available than we request, then fill them up.
229 for (i = 0, num = 0; i < hislen; i++)
230 if (histentry[i].hisstr == NULL || histentry[i].viminfo)
231 num++;
232 len = asklen;
233 if (num > len)
234 len = num;
235 if (len <= 0)
236 viminfo_history[type] = NULL;
237 else
238 viminfo_history[type] = LALLOC_MULT(histentry_T, len);
239 if (viminfo_history[type] == NULL)
240 len = 0;
241 viminfo_hislen[type] = len;
242 viminfo_hisidx[type] = 0;
243 }
244 }
245
246 /*
247 * Accept a line from the viminfo, store it in the history array when it's
248 * new.
249 */
250 static int
251 read_viminfo_history(vir_T *virp, int writing)
252 {
253 int type;
254 long_u len;
255 char_u *val;
256 char_u *p;
257
258 type = hist_char2type(virp->vir_line[0]);
259 if (viminfo_hisidx[type] < viminfo_hislen[type])
260 {
261 val = viminfo_readstring(virp, 1, TRUE);
262 if (val != NULL && *val != NUL)
263 {
264 int sep = (*val == ' ' ? NUL : *val);
265
266 if (!in_history(type, val + (type == HIST_SEARCH),
267 viminfo_add_at_front, sep, writing))
268 {
269 // Need to re-allocate to append the separator byte.
270 len = STRLEN(val);
271 p = alloc(len + 2);
272 if (p != NULL)
273 {
274 if (type == HIST_SEARCH)
275 {
276 // Search entry: Move the separator from the first
277 // column to after the NUL.
278 mch_memmove(p, val + 1, (size_t)len);
279 p[len] = sep;
280 }
281 else
282 {
283 // Not a search entry: No separator in the viminfo
284 // file, add a NUL separator.
285 mch_memmove(p, val, (size_t)len + 1);
286 p[len + 1] = NUL;
287 }
288 viminfo_history[type][viminfo_hisidx[type]].hisstr = p;
289 viminfo_history[type][viminfo_hisidx[type]].time_set = 0;
290 viminfo_history[type][viminfo_hisidx[type]].viminfo = TRUE;
291 viminfo_history[type][viminfo_hisidx[type]].hisnum = 0;
292 viminfo_hisidx[type]++;
293 }
294 }
295 }
296 vim_free(val);
297 }
298 return viminfo_readline(virp);
299 }
300
301 /*
302 * Accept a new style history line from the viminfo, store it in the history
303 * array when it's new.
304 */
305 static void
306 handle_viminfo_history(
307 garray_T *values,
308 int writing)
309 {
310 int type;
311 long_u len;
312 char_u *val;
313 char_u *p;
314 bval_T *vp = (bval_T *)values->ga_data;
315
316 // Check the format:
317 // |{bartype},{histtype},{timestamp},{separator},"text"
318 if (values->ga_len < 4
319 || vp[0].bv_type != BVAL_NR
320 || vp[1].bv_type != BVAL_NR
321 || (vp[2].bv_type != BVAL_NR && vp[2].bv_type != BVAL_EMPTY)
322 || vp[3].bv_type != BVAL_STRING)
323 return;
324
325 type = vp[0].bv_nr;
326 if (type >= HIST_COUNT)
327 return;
328 if (viminfo_hisidx[type] < viminfo_hislen[type])
329 {
330 val = vp[3].bv_string;
331 if (val != NULL && *val != NUL)
332 {
333 int sep = type == HIST_SEARCH && vp[2].bv_type == BVAL_NR
334 ? vp[2].bv_nr : NUL;
335 int idx;
336 int overwrite = FALSE;
337
338 if (!in_history(type, val, viminfo_add_at_front, sep, writing))
339 {
340 // If lines were written by an older Vim we need to avoid
341 // getting duplicates. See if the entry already exists.
342 for (idx = 0; idx < viminfo_hisidx[type]; ++idx)
343 {
344 p = viminfo_history[type][idx].hisstr;
345 if (STRCMP(val, p) == 0
346 && (type != HIST_SEARCH || sep == p[STRLEN(p) + 1]))
347 {
348 overwrite = TRUE;
349 break;
350 }
351 }
352
353 if (!overwrite)
354 {
355 // Need to re-allocate to append the separator byte.
356 len = vp[3].bv_len;
357 p = alloc(len + 2);
358 }
359 else
360 len = 0; // for picky compilers
361 if (p != NULL)
362 {
363 viminfo_history[type][idx].time_set = vp[1].bv_nr;
364 if (!overwrite)
365 {
366 mch_memmove(p, val, (size_t)len + 1);
367 // Put the separator after the NUL.
368 p[len + 1] = sep;
369 viminfo_history[type][idx].hisstr = p;
370 viminfo_history[type][idx].hisnum = 0;
371 viminfo_history[type][idx].viminfo = TRUE;
372 viminfo_hisidx[type]++;
373 }
374 }
375 }
376 }
377 }
378 }
379
380 /*
381 * Concatenate history lines from viminfo after the lines typed in this Vim.
382 */
383 static void
384 concat_history(int type)
385 {
386 int idx;
387 int i;
388 int hislen = get_hislen();
389 histentry_T *histentry = get_histentry(type);
390 int *hisidx = get_hisidx(type);
391 int *hisnum = get_hisnum(type);
392
393 idx = *hisidx + viminfo_hisidx[type];
394 if (idx >= hislen)
395 idx -= hislen;
396 else if (idx < 0)
397 idx = hislen - 1;
398 if (viminfo_add_at_front)
399 *hisidx = idx;
400 else
401 {
402 if (*hisidx == -1)
403 *hisidx = hislen - 1;
404 do
405 {
406 if (histentry[idx].hisstr != NULL || histentry[idx].viminfo)
407 break;
408 if (++idx == hislen)
409 idx = 0;
410 } while (idx != *hisidx);
411 if (idx != *hisidx && --idx < 0)
412 idx = hislen - 1;
413 }
414 for (i = 0; i < viminfo_hisidx[type]; i++)
415 {
416 vim_free(histentry[idx].hisstr);
417 histentry[idx].hisstr = viminfo_history[type][i].hisstr;
418 histentry[idx].viminfo = TRUE;
419 histentry[idx].time_set = viminfo_history[type][i].time_set;
420 if (--idx < 0)
421 idx = hislen - 1;
422 }
423 idx += 1;
424 idx %= hislen;
425 for (i = 0; i < viminfo_hisidx[type]; i++)
426 {
427 histentry[idx++].hisnum = ++*hisnum;
428 idx %= hislen;
429 }
430 }
431
432 static int
433 sort_hist(const void *s1, const void *s2)
434 {
435 histentry_T *p1 = *(histentry_T **)s1;
436 histentry_T *p2 = *(histentry_T **)s2;
437
438 if (p1->time_set < p2->time_set) return -1;
439 if (p1->time_set > p2->time_set) return 1;
440 return 0;
441 }
442
443 /*
444 * Merge history lines from viminfo and lines typed in this Vim based on the
445 * timestamp;
446 */
447 static void
448 merge_history(int type)
449 {
450 int max_len;
451 histentry_T **tot_hist;
452 histentry_T *new_hist;
453 int i;
454 int len;
455 int hislen = get_hislen();
456 histentry_T *histentry = get_histentry(type);
457 int *hisidx = get_hisidx(type);
458 int *hisnum = get_hisnum(type);
459
460 // Make one long list with all entries.
461 max_len = hislen + viminfo_hisidx[type];
462 tot_hist = ALLOC_MULT(histentry_T *, max_len);
463 new_hist = ALLOC_MULT(histentry_T, hislen );
464 if (tot_hist == NULL || new_hist == NULL)
465 {
466 vim_free(tot_hist);
467 vim_free(new_hist);
468 return;
469 }
470 for (i = 0; i < viminfo_hisidx[type]; i++)
471 tot_hist[i] = &viminfo_history[type][i];
472 len = i;
473 for (i = 0; i < hislen; i++)
474 if (histentry[i].hisstr != NULL)
475 tot_hist[len++] = &histentry[i];
476
477 // Sort the list on timestamp.
478 qsort((void *)tot_hist, (size_t)len, sizeof(histentry_T *), sort_hist);
479
480 // Keep the newest ones.
481 for (i = 0; i < hislen; i++)
482 {
483 if (i < len)
484 {
485 new_hist[i] = *tot_hist[i];
486 tot_hist[i]->hisstr = NULL;
487 if (new_hist[i].hisnum == 0)
488 new_hist[i].hisnum = ++*hisnum;
489 }
490 else
491 clear_hist_entry(&new_hist[i]);
492 }
493 *hisidx = (i < len ? i : len) - 1;
494
495 // Free what is not kept.
496 for (i = 0; i < viminfo_hisidx[type]; i++)
497 vim_free(viminfo_history[type][i].hisstr);
498 for (i = 0; i < hislen; i++)
499 vim_free(histentry[i].hisstr);
500 vim_free(histentry);
501 set_histentry(type, new_hist);
502 vim_free(tot_hist);
503 }
504
505 /*
506 * Finish reading history lines from viminfo. Not used when writing viminfo.
507 */
508 static void
509 finish_viminfo_history(vir_T *virp)
510 {
511 int type;
512 int merge = virp->vir_version >= VIMINFO_VERSION_WITH_HISTORY;
513
514 for (type = 0; type < HIST_COUNT; ++type)
515 {
516 if (get_histentry(type) == NULL)
517 continue;
518
519 if (merge)
520 merge_history(type);
521 else
522 concat_history(type);
523
524 VIM_CLEAR(viminfo_history[type]);
525 viminfo_hisidx[type] = 0;
526 }
527 }
528
529 /*
530 * Write history to viminfo file in "fp".
531 * When "merge" is TRUE merge history lines with a previously read viminfo
532 * file, data is in viminfo_history[].
533 * When "merge" is FALSE just write all history lines. Used for ":wviminfo!".
534 */
535 static void
536 write_viminfo_history(FILE *fp, int merge)
537 {
538 int i;
539 int type;
540 int num_saved;
541 int round;
542 int hislen;
543
544 init_history();
545 hislen = get_hislen();
546 if (hislen == 0)
547 return;
548 for (type = 0; type < HIST_COUNT; ++type)
549 {
550 histentry_T *histentry = get_histentry(type);
551 int *hisidx = get_hisidx(type);
552
553 num_saved = get_viminfo_parameter(hist_type2char(type, FALSE));
554 if (num_saved == 0)
555 continue;
556 if (num_saved < 0) // Use default
557 num_saved = hislen;
558 fprintf(fp, _("\n# %s History (newest to oldest):\n"),
559 type == HIST_CMD ? _("Command Line") :
560 type == HIST_SEARCH ? _("Search String") :
561 type == HIST_EXPR ? _("Expression") :
562 type == HIST_INPUT ? _("Input Line") :
563 _("Debug Line"));
564 if (num_saved > hislen)
565 num_saved = hislen;
566
567 /*
568 * Merge typed and viminfo history:
569 * round 1: history of typed commands.
570 * round 2: history from recently read viminfo.
571 */
572 for (round = 1; round <= 2; ++round)
573 {
574 if (round == 1)
575 // start at newest entry, somewhere in the list
576 i = *hisidx;
577 else if (viminfo_hisidx[type] > 0)
578 // start at newest entry, first in the list
579 i = 0;
580 else
581 // empty list
582 i = -1;
583 if (i >= 0)
584 while (num_saved > 0
585 && !(round == 2 && i >= viminfo_hisidx[type]))
586 {
587 char_u *p;
588 time_t timestamp;
589 int c = NUL;
590
591 if (round == 1)
592 {
593 p = histentry[i].hisstr;
594 timestamp = histentry[i].time_set;
595 }
596 else
597 {
598 p = viminfo_history[type] == NULL ? NULL
599 : viminfo_history[type][i].hisstr;
600 timestamp = viminfo_history[type] == NULL ? 0
601 : viminfo_history[type][i].time_set;
602 }
603
604 if (p != NULL && (round == 2
605 || !merge
606 || !histentry[i].viminfo))
607 {
608 --num_saved;
609 fputc(hist_type2char(type, TRUE), fp);
610 // For the search history: put the separator in the
611 // second column; use a space if there isn't one.
612 if (type == HIST_SEARCH)
613 {
614 c = p[STRLEN(p) + 1];
615 putc(c == NUL ? ' ' : c, fp);
616 }
617 viminfo_writestring(fp, p);
618
619 {
620 char cbuf[NUMBUFLEN];
621
622 // New style history with a bar line. Format:
623 // |{bartype},{histtype},{timestamp},{separator},"text"
624 if (c == NUL)
625 cbuf[0] = NUL;
626 else
627 sprintf(cbuf, "%d", c);
628 fprintf(fp, "|%d,%d,%ld,%s,", BARTYPE_HISTORY,
629 type, (long)timestamp, cbuf);
630 barline_writestring(fp, p, LSIZE - 20);
631 putc('\n', fp);
632 }
633 }
634 if (round == 1)
635 {
636 // Decrement index, loop around and stop when back at
637 // the start.
638 if (--i < 0)
639 i = hislen - 1;
640 if (i == *hisidx)
641 break;
642 }
643 else
644 {
645 // Increment index. Stop at the end in the while.
646 ++i;
647 }
648 }
649 }
650 for (i = 0; i < viminfo_hisidx[type]; ++i)
651 if (viminfo_history[type] != NULL)
652 vim_free(viminfo_history[type][i].hisstr);
653 VIM_CLEAR(viminfo_history[type]);
654 viminfo_hisidx[type] = 0;
655 }
656 }
657 #endif // FEAT_VIMINFO
171 658
172 static void 659 static void
173 write_viminfo_barlines(vir_T *virp, FILE *fp_out) 660 write_viminfo_barlines(vir_T *virp, FILE *fp_out)
174 { 661 {
175 int i; 662 int i;