+(defvar lurk-history-index nil)
+
+(defun lurk-history-cycle (delta)
+ (when lurk-history
+ (with-current-buffer "*lurk*"
+ (if lurk-history-index
+ (setq lurk-history-index
+ (max 0
+ (min (- (length lurk-history) 1)
+ (+ delta lurk-history-index))))
+ (setq lurk-history-index 0))
+ (delete-region lurk-input-marker (point-max))
+ (insert (elt lurk-history lurk-history-index)))))
+
+(defun lurk-history-next ()
+ (interactive)
+ (lurk-history-cycle -1))
+
+(defun lurk-history-prev ()
+ (interactive)
+ (lurk-history-cycle +1))
+
+;;; Interactive functions
+;;
+
+(defun lurk-cycle-contexts-forward ()
+ (interactive)
+ (lurk-cycle-contexts))
+
+(defun lurk-cycle-contexts-reverse ()
+ (interactive)
+ (lurk-cycle-contexts t))
+
+(defvar lurk-zoomed nil
+ "Keeps track of zoom status.")
+
+(defun lurk-toggle-zoom ()
+ (interactive)
+ (if lurk-zoomed
+ (lurk-zoom-out)
+ (lurk-zoom-in lurk-current-context))
+ (setq lurk-zoomed (not lurk-zoomed)))
+
+(defun lurk-complete-input ()
+ (interactive)
+ (when (and (>= (point) lurk-input-marker))
+ (pcase (buffer-substring lurk-input-marker (point))
+ ((rx (: "/connect" (+ " ") (* (not whitespace)) string-end))
+ (let ((space-idx (save-excursion
+ (re-search-backward " " lurk-input-marker t))))
+ (completion-in-region (+ 1 space-idx)
+ (point)
+ (mapcar (lambda (row) (car row)) lurk-networks))))
+ ((rx (: "/" (* (not whitespace)) string-end))
+ (message (buffer-substring lurk-input-marker (point)))
+ (completion-in-region lurk-input-marker (point)
+ '("/connect"
+ "/join"
+ "/part"
+ "/quit")))
+ (_
+ (let* ((end (max lurk-input-marker (point)))
+ (space-idx (save-excursion
+ (re-search-backward " " lurk-input-marker t)))
+ (start (if space-idx (+ 1 space-idx) lurk-input-marker))
+ (completion-ignore-case t))
+ (unless (string-prefix-p "/" (buffer-substring start end))
+ (completion-in-region start end (lurk-get-context-users lurk-current-context))))))))
+