diff options
| author | Basil L. Contovounesios | 2018-04-29 15:37:45 +0100 |
|---|---|---|
| committer | Noam Postavsky | 2018-05-02 20:18:07 -0400 |
| commit | f2c74543edc7e8d07655b459ba8898eec9b6d4e8 (patch) | |
| tree | b6612a1370f9c20399e8fa32ff50be643a0ecabd /src | |
| parent | 05e9477ab5d5dba1b960415d60b9957caa90da48 (diff) | |
| download | emacs-f2c74543edc7e8d07655b459ba8898eec9b6d4e8.tar.gz emacs-f2c74543edc7e8d07655b459ba8898eec9b6d4e8.zip | |
Fix off-by-one history pruning (bug#31211)
* lisp/subr.el (add-to-history): Clarify docstring.
Protect against negative history-length and unnecessary variable
modification, as per read_minibuf.
* lisp/ido.el (ido-record-command):
* lisp/international/mule-cmds.el (deactivate-input-method):
(set-language-environment-input-method):
* lisp/isearch.el (isearch-done):
* lisp/minibuffer.el (read-file-name-default):
* lisp/net/eww.el (eww-save-history):
* lisp/simple.el (edit-and-eval-command, repeat-complex-command):
(command-execute, kill-new, push-mark):
* src/callint.c (Fcall_interactively):
* src/minibuf.c (read_minibuf): Delegate to add-to-history.
* test/lisp/simple-tests.el (command-execute-prune-command-history):
* test/src/callint-tests.el
(call-interactively-prune-command-history): New tests.
Diffstat (limited to 'src')
| -rw-r--r-- | src/callint.c | 27 | ||||
| -rw-r--r-- | src/minibuf.c | 40 |
2 files changed, 7 insertions, 60 deletions
diff --git a/src/callint.c b/src/callint.c index 08a8bba4646..fd44494cfee 100644 --- a/src/callint.c +++ b/src/callint.c | |||
| @@ -262,7 +262,7 @@ to the function `interactive' at the top level of the function body. | |||
| 262 | See `interactive'. | 262 | See `interactive'. |
| 263 | 263 | ||
| 264 | Optional second arg RECORD-FLAG non-nil | 264 | Optional second arg RECORD-FLAG non-nil |
| 265 | means unconditionally put this command in the command-history. | 265 | means unconditionally put this command in the variable `command-history'. |
| 266 | Otherwise, this is done only if an arg is read using the minibuffer. | 266 | Otherwise, this is done only if an arg is read using the minibuffer. |
| 267 | 267 | ||
| 268 | Optional third arg KEYS, if given, specifies the sequence of events to | 268 | Optional third arg KEYS, if given, specifies the sequence of events to |
| @@ -328,18 +328,8 @@ invoke it. If KEYS is omitted or nil, the return value of | |||
| 328 | and turn them into things we can eval. */ | 328 | and turn them into things we can eval. */ |
| 329 | Lisp_Object values = quotify_args (Fcopy_sequence (specs)); | 329 | Lisp_Object values = quotify_args (Fcopy_sequence (specs)); |
| 330 | fix_command (input, values); | 330 | fix_command (input, values); |
| 331 | Lisp_Object this_cmd = Fcons (function, values); | 331 | call4 (intern ("add-to-history"), intern ("command-history"), |
| 332 | if (history_delete_duplicates) | 332 | Fcons (function, values), Qnil, Qt); |
| 333 | Vcommand_history = Fdelete (this_cmd, Vcommand_history); | ||
| 334 | Vcommand_history = Fcons (this_cmd, Vcommand_history); | ||
| 335 | |||
| 336 | /* Don't keep command history around forever. */ | ||
| 337 | if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0) | ||
| 338 | { | ||
| 339 | Lisp_Object teml = Fnthcdr (Vhistory_length, Vcommand_history); | ||
| 340 | if (CONSP (teml)) | ||
| 341 | XSETCDR (teml, Qnil); | ||
| 342 | } | ||
| 343 | } | 333 | } |
| 344 | 334 | ||
| 345 | Vthis_command = save_this_command; | 335 | Vthis_command = save_this_command; |
| @@ -768,15 +758,8 @@ invoke it. If KEYS is omitted or nil, the return value of | |||
| 768 | visargs[i] = (varies[i] > 0 | 758 | visargs[i] = (varies[i] > 0 |
| 769 | ? list1 (intern (callint_argfuns[varies[i]])) | 759 | ? list1 (intern (callint_argfuns[varies[i]])) |
| 770 | : quotify_arg (args[i])); | 760 | : quotify_arg (args[i])); |
| 771 | Vcommand_history = Fcons (Flist (nargs - 1, visargs + 1), | 761 | call4 (intern ("add-to-history"), intern ("command-history"), |
| 772 | Vcommand_history); | 762 | Flist (nargs - 1, visargs + 1), Qnil, Qt); |
| 773 | /* Don't keep command history around forever. */ | ||
| 774 | if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0) | ||
| 775 | { | ||
| 776 | Lisp_Object teml = Fnthcdr (Vhistory_length, Vcommand_history); | ||
| 777 | if (CONSP (teml)) | ||
| 778 | XSETCDR (teml, Qnil); | ||
| 779 | } | ||
| 780 | } | 763 | } |
| 781 | 764 | ||
| 782 | /* If we used a marker to hold point, mark, or an end of the region, | 765 | /* If we used a marker to hold point, mark, or an end of the region, |
diff --git a/src/minibuf.c b/src/minibuf.c index c41958d85f9..e18c99bef28 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -702,44 +702,8 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, | |||
| 702 | histstring = Qnil; | 702 | histstring = Qnil; |
| 703 | 703 | ||
| 704 | /* Add the value to the appropriate history list, if any. */ | 704 | /* Add the value to the appropriate history list, if any. */ |
| 705 | if (!NILP (Vhistory_add_new_input) | 705 | if (! (NILP (Vhistory_add_new_input) || NILP (histstring))) |
| 706 | && SYMBOLP (Vminibuffer_history_variable) | 706 | call2 (intern ("add-to-history"), Vminibuffer_history_variable, histstring); |
| 707 | && !NILP (histstring)) | ||
| 708 | { | ||
| 709 | /* If the caller wanted to save the value read on a history list, | ||
| 710 | then do so if the value is not already the front of the list. */ | ||
| 711 | |||
| 712 | /* The value of the history variable must be a cons or nil. Other | ||
| 713 | values are unacceptable. We silently ignore these values. */ | ||
| 714 | |||
| 715 | if (NILP (histval) | ||
| 716 | || (CONSP (histval) | ||
| 717 | /* Don't duplicate the most recent entry in the history. */ | ||
| 718 | && (NILP (Fequal (histstring, Fcar (histval)))))) | ||
| 719 | { | ||
| 720 | Lisp_Object length; | ||
| 721 | |||
| 722 | if (history_delete_duplicates) Fdelete (histstring, histval); | ||
| 723 | histval = Fcons (histstring, histval); | ||
| 724 | Fset (Vminibuffer_history_variable, histval); | ||
| 725 | |||
| 726 | /* Truncate if requested. */ | ||
| 727 | length = Fget (Vminibuffer_history_variable, Qhistory_length); | ||
| 728 | if (NILP (length)) length = Vhistory_length; | ||
| 729 | if (INTEGERP (length)) | ||
| 730 | { | ||
| 731 | if (XINT (length) <= 0) | ||
| 732 | Fset (Vminibuffer_history_variable, Qnil); | ||
| 733 | else | ||
| 734 | { | ||
| 735 | Lisp_Object temp; | ||
| 736 | |||
| 737 | temp = Fnthcdr (Fsub1 (length), histval); | ||
| 738 | if (CONSP (temp)) Fsetcdr (temp, Qnil); | ||
| 739 | } | ||
| 740 | } | ||
| 741 | } | ||
| 742 | } | ||
| 743 | 707 | ||
| 744 | /* If Lisp form desired instead of string, parse it. */ | 708 | /* If Lisp form desired instead of string, parse it. */ |
| 745 | if (expflag) | 709 | if (expflag) |