Skip to content

Commit 269c166

Browse files
author
Phil Sainty
committed
Add compose buffer history search commands bound to M-r and C-M-r
Isearch through `ement-room-message-history'. New commands: - ement-room-compose-history-isearch-backward - ement-room-compose-history-isearch-backward-regexp (ement-room-init-compose-buffer) Update key bindings and set up isearch support (which is derived from comint.el).
1 parent cf105d7 commit 269c166

File tree

1 file changed

+147
-18
lines changed

1 file changed

+147
-18
lines changed

ement-room.el

+147-18
Original file line numberDiff line numberDiff line change
@@ -4255,6 +4255,7 @@ a copy of the local keymap, and sets `header-line-format'."
42554255
(setq-local yank-excluded-properties
42564256
(append '(line-prefix wrap-prefix)
42574257
(default-value 'yank-excluded-properties)))
4258+
(add-hook 'isearch-mode-hook 'ement-room-compose-history-isearch-setup nil t)
42584259
;; FIXME: Compose with local map?
42594260
(use-local-map (if (current-local-map)
42604261
(copy-keymap (current-local-map))
@@ -4270,8 +4271,10 @@ a copy of the local keymap, and sets `header-line-format'."
42704271
cmd))))
42714272
(local-set-key [remap save-buffer] #'ement-room-dispatch-send-message)
42724273
(local-set-key (kbd "C-c C-k") #'ement-room-compose-abort)
4273-
(local-set-key (kbd "M-n") #'ement-room-compose-history-next-message)
42744274
(local-set-key (kbd "M-p") #'ement-room-compose-history-prev-message)
4275+
(local-set-key (kbd "M-n") #'ement-room-compose-history-next-message)
4276+
(local-set-key (kbd "M-r") #'ement-room-compose-history-isearch-backward)
4277+
(local-set-key (kbd "C-M-r") #'ement-room-compose-history-isearch-backward-regexp)
42754278
(setq header-line-format
42764279
(concat (substitute-command-keys
42774280
(format " Press \\[save-buffer] to send message to room (%s), or \\[ement-room-compose-abort] to cancel."
@@ -4358,16 +4361,35 @@ Used with `dabbrev-friend-buffer-function'."
43584361
(with-current-buffer buffer
43594362
(derived-mode-p 'ement-room-mode)))
43604363

4361-
;;; Message history for compose buffers.
4364+
;;; Message history for compose buffers. Isearch code is derived from comint.el.
43624365

43634366
(defvar-local ement-room--compose-message-history-index -1)
43644367
(defvar-local ement-room--compose-message-history-initial "")
4368+
(defvar-local ement-room--compose-history-isearch nil)
4369+
4370+
(defun ement-room-compose-message-history-insert (pos)
4371+
"Insert text of the absolute history position POS."
4372+
;; Store the not-from-history buffer message.
4373+
(when (< ement-room--compose-message-history-index 0)
4374+
(setq ement-room--compose-message-history-initial
4375+
(ement-room-compose-buffer-string-trimmed)))
4376+
;; Update the index.
4377+
(setq ement-room--compose-message-history-index (or pos -1))
4378+
;; Update the buffer.
4379+
(erase-buffer)
4380+
(insert (if (< ement-room--compose-message-history-index 0)
4381+
ement-room--compose-message-history-initial
4382+
(or (nth ement-room--compose-message-history-index
4383+
ement-room-message-history)
4384+
(format "[invalid ement message history element %d]"
4385+
ement-room--compose-message-history-index)))))
43654386

43664387
(defun ement-room-compose-history-prev-message (arg)
43674388
"Cycle backward through message history, after saving current message.
43684389
With a numeric prefix ARG, go back ARG messages."
43694390
(interactive "*p")
43704391
(let ((len (length ement-room-message-history)))
4392+
;; Valid index values: -1 <= idx < len.
43714393
(cond ((<= len 0)
43724394
(user-error "Empty message history"))
43734395
((eql arg 0)) ;; No-op.
@@ -4376,29 +4398,136 @@ With a numeric prefix ARG, go back ARG messages."
43764398
((and (< arg 0) (< ement-room--compose-message-history-index 0))
43774399
(user-error "End of history; no next item"))
43784400
(t
4379-
;; Store the not-from-history buffer message.
4380-
(when (< ement-room--compose-message-history-index 0)
4381-
(setq ement-room--compose-message-history-initial
4382-
(ement-room-compose-buffer-string-trimmed)))
4383-
;; Update the index.
4384-
(setq ement-room--compose-message-history-index
4385-
(let ((newidx (+ arg ement-room--compose-message-history-index)))
4386-
(cond ((>= newidx len) (1- len))
4387-
((< newidx -1) -1)
4388-
(t newidx))))
4389-
;; Update the buffer.
4390-
(erase-buffer)
4391-
(insert (if (< ement-room--compose-message-history-index 0)
4392-
ement-room--compose-message-history-initial
4393-
(nth ement-room--compose-message-history-index
4394-
ement-room-message-history)))))))
4401+
;; It's still possible to move in the specified direction.
4402+
(ement-room-compose-message-history-insert
4403+
(let ((pos (+ arg ement-room--compose-message-history-index)))
4404+
(cond ((>= pos len) (1- len))
4405+
((< pos -1) -1)
4406+
(t pos))))))))
43954407

43964408
(defun ement-room-compose-history-next-message (arg)
43974409
"Cycle forward through message history, after saving current message.
43984410
With a numeric prefix ARG, go forward ARG messages."
43994411
(interactive "*p")
44004412
(ement-room-compose-history-prev-message (- arg)))
44014413

4414+
(defun ement-room-compose-history-isearch-backward ()
4415+
"Search for a string in the message history using Isearch.
4416+
Use \\[isearch-backward] and \\[isearch-forward] to continue searching."
4417+
(interactive)
4418+
(setq ement-room--compose-history-isearch t)
4419+
(isearch-backward nil t))
4420+
4421+
(defun ement-room-compose-history-isearch-backward-regexp ()
4422+
"Search for a regular expression in the message history using Isearch.
4423+
Use \\[isearch-backward] and \\[isearch-forward] to continue searching."
4424+
(interactive)
4425+
(setq ement-room--compose-history-isearch t)
4426+
(isearch-backward-regexp nil t))
4427+
4428+
(defun ement-room-compose-history-isearch-setup ()
4429+
"Set up Isearch to search `ement-room-message-history'.
4430+
Intended to be added to `isearch-mode-hook' in an ement compose buffer."
4431+
(when (eq ement-room--compose-history-isearch t)
4432+
(setq isearch-message-prefix-add "history ")
4433+
(setq-local isearch-search-fun-function
4434+
#'ement-room-compose-history-isearch-search)
4435+
(setq-local isearch-message-function
4436+
#'ement-room-compose-history-isearch-message)
4437+
(setq-local isearch-wrap-function
4438+
#'ement-room-compose-history-isearch-wrap)
4439+
(setq-local isearch-push-state-function
4440+
#'ement-room-compose-history-isearch-push-state)
4441+
(setq-local isearch-lazy-count nil)
4442+
(add-hook 'isearch-mode-end-hook 'ement-room-compose-history-isearch-end nil t)))
4443+
4444+
(defun ement-room-compose-history-isearch-end ()
4445+
"Clean up the buffer after terminating Isearch."
4446+
(setq isearch-message-prefix-add nil)
4447+
(setq isearch-search-fun-function 'isearch-search-fun-default)
4448+
(setq isearch-wrap-function nil)
4449+
(setq isearch-push-state-function nil)
4450+
;; Force isearch to not change mark.
4451+
(setq isearch-opoint (point))
4452+
(kill-local-variable 'isearch-lazy-count)
4453+
(remove-hook 'isearch-mode-end-hook 'ement-room-compose-history-isearch-end t)
4454+
(unless isearch-suspended
4455+
(setq ement-room--compose-history-isearch nil)))
4456+
4457+
(defun ement-room-compose-history-isearch-search ()
4458+
"Return the search function for Isearch in message history."
4459+
#'ement-room-compose-history-isearch-function)
4460+
4461+
(defun ement-room-compose-history-isearch-function (string bound noerror)
4462+
"Isearch in message history."
4463+
(let ((search-fun
4464+
;; Use standard functions to search within message text
4465+
(isearch-search-fun-default))
4466+
found)
4467+
(or
4468+
;; 1. First try searching in the initial message
4469+
(funcall search-fun string nil noerror)
4470+
;; 2. If the above search fails, start putting next/prev history elements in the
4471+
;; buffer successively, and search the string in them. Do this only when bound is
4472+
;; nil (i.e. not while lazy-highlighting search strings in the current message).
4473+
(unless bound
4474+
(condition-case nil
4475+
(progn
4476+
(while (not found)
4477+
(if isearch-forward
4478+
(ement-room-compose-history-next-message 1)
4479+
(ement-room-compose-history-prev-message 1))
4480+
(goto-char (if isearch-forward (point-min) (point-max)))
4481+
(setq isearch-barrier (point)
4482+
isearch-opoint (point))
4483+
;; After putting the next/prev history element, search the string in
4484+
;; them again, until `ement-room-compose-history-next-message' or
4485+
;; `ement-room-compose-history-prev-message' raises an error at the
4486+
;; beginning/end of history.
4487+
(setq found (funcall search-fun string nil noerror)))
4488+
;; Return point of the new search result.
4489+
(point))
4490+
;; Return nil on any isearch errors, including the "no next/preceding item"
4491+
;; user-errors signalled from `ement-room-compose-history-prev-message'.
4492+
(error nil))))))
4493+
4494+
(defun ement-room-compose-history-isearch-message (&optional c-q-hack ellipsis)
4495+
"Display the isearch message."
4496+
(setq isearch-message-prefix-add
4497+
(if (and isearch-success
4498+
(not isearch-error)
4499+
(>= ement-room--compose-message-history-index 0))
4500+
(format "history item %d: "
4501+
ement-room--compose-message-history-index)
4502+
"history "))
4503+
(isearch-message c-q-hack ellipsis))
4504+
4505+
(defun ement-room-compose-history-isearch-wrap ()
4506+
"Wrap the history search when search fails.
4507+
Move point to the first history element for a forward search,
4508+
or to the last history element for a backward search."
4509+
;; When `ement-room-compose-history-isearch-search' fails on reaching the
4510+
;; beginning/end of the history, wrap the search to the first/last
4511+
;; input history element.
4512+
(ement-room-compose-message-history-insert
4513+
(if isearch-forward
4514+
(1- (length ement-room-message-history))
4515+
-1))
4516+
(goto-char (if isearch-forward (point-min) (point-max))))
4517+
4518+
(defun ement-room-compose-history-isearch-push-state ()
4519+
"Save a function restoring the state of input history search.
4520+
Save `ement-room--compose-message-history-index' to the additional state parameter
4521+
in the search status stack."
4522+
(let ((index ement-room--compose-message-history-index))
4523+
(lambda (cmd)
4524+
(ement-room-compose-history-isearch-pop-state cmd index))))
4525+
4526+
(defun ement-room-compose-history-isearch-pop-state (_cmd hist-pos)
4527+
"Restore the input history search state.
4528+
Go to the history element by the absolute history position HIST-POS."
4529+
(ement-room-compose-message-history-insert hist-pos))
4530+
44024531
;;;;; Widgets
44034532

44044533
(require 'widget)

0 commit comments

Comments
 (0)