Function: hyrolo-add

hyrolo-add is an autoloaded, interactive and byte-compiled function defined in hyrolo.el.

Signature

(hyrolo-add NAME &optional FILE)

Documentation

Add a new entry for NAME in the first file from hyrolo-file-list.

Last name first is best, e.g. "Smith, John". With prefix argument, prompts for optional FILE to add entry within. NAME may be of the form: parent/child to insert child below a parent entry which begins with the parent string.

Key Bindings

Source Code

;; Defined in ~/.emacs.d/elpa/hyperbole-20260414.325/hyrolo.el
;;; ************************************************************************
;;; Commands
;;; ************************************************************************

;;;###autoload
(defun hyrolo-add (name &optional file)
  "Add a new entry for NAME in the first file from `hyrolo-file-list'.
Last name first is best, e.g. \"Smith, John\".
With prefix argument, prompts for optional FILE to add entry within.
NAME may be of the form: parent/child to insert child below a parent
entry which begins with the parent string."
  (interactive
   (let* ((lst (hyrolo-name-and-email))
	  (name (car lst))
	  (email (car (cdr lst)))
	  (entry (read-string "Name to add to rolo: "
			      (or name email))))
     (list (if (and email name
		    (string-match (concat "\\`" (regexp-quote entry)) name))
	       (format hyrolo-email-format entry email)
	     entry)
	   current-prefix-arg)))
  (when (or (not (stringp name)) (string-equal name ""))
    (error "(hyrolo-add): Invalid name: `%s'" name))
  (when (and (called-interactively-p 'interactive) file)
    (setq file (completing-read "File to add to: "
				(mapcar #'list (hyrolo-get-file-list)))))
  (unless file
    (setq file (car (hyrolo-get-file-list))))
  (cond ((and file (or (not (stringp file)) (string-equal file "")))
	 (error "(hyrolo-add): Invalid file: `%s'" file))
	((and (file-exists-p file) (not (file-readable-p file)))
	 (error "(hyrolo-add): File not readable: `%s'" file))
	((not (file-writable-p file))
	 (error "(hyrolo-add): File not writable: `%s'" file)))
  (set-buffer (or (get-file-buffer file)
		  (hyrolo-find-file-noselect file)))
  (when (called-interactively-p 'interactive)
    (message "Locating insertion point for `%s'..." name))
  (let ((parent "")
	(level "")
	(entry-regexp hyrolo-entry-regexp)
	end)
    (hyrolo-widen)
    (goto-char (point-min))
    ;; If name includes slash level separator character, walk down
    ;; existing matching tree of entries to find insertion point.
    (while (string-match "\\`[^\]\[/<>{}\"]*/" name)
      (setq end (1- (match-end 0))
	    parent (substring name 0 end)
	    name (substring name (min (1+ end) (length name))))
      (if (re-search-forward
	   (concat entry-regexp (regexp-quote parent) "\\s-") nil t)
	  (progn (setq level (match-string-no-properties hyrolo-entry-group-number))
		 (goto-char (match-beginning 0)))
	(error "(hyrolo-add): Insertion failed, `%s' parent entry not found in \"%s\""
	       parent file)))
    (when (looking-at hyrolo-entry-regexp)
      (narrow-to-region (point) (progn (hyrolo-to-entry-end t) (point))))
    (let* ((name-level (concat level "*"))
	   (level-len (length name-level))
	   (first-char (aref name 0))
	   (entry "")
	   (entry-spc "")
	   (entry-level-len)
	   (match)
	   (again t))
      ;; Speed up entry insertion point location if this is a first-level
      ;; entry by moving to an entry with the same (or nearest) first character
      ;; to that of `name'.
      (if (and (= level-len 1)
	       (equal entry-regexp hyrolo-entry-regexp))
	  (let ((case-fold-search))
	    (goto-char (point-min))
	    (if (re-search-forward (concat entry-regexp
					   (regexp-quote (char-to-string first-char)))
				   nil t)
		(goto-char (match-beginning 0))
	      (goto-char (point-max))
	      (when (and (> first-char ?0)
			 (re-search-backward
			  (concat "^\\*[ \t]+["
				  (substring
				   "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz"
				   0 (min (- first-char ?0) 62))
				  "])")
			  nil t))
		(goto-char (match-end 0))
		(hyrolo-to-entry-end t)
		;; Now at the insertion point, immediately after
		;; the last existing entry whose first character
		;; is less than that of `name'.  Setting `again'
		;; to nil prevents further searching for an
		;; insertion point.
		(setq again nil))))
	(goto-char (point-min)))

      (when again
	(goto-char (point-min)))
      (while (and again (re-search-forward entry-regexp nil 'end))
	(setq entry-level-len (length (match-string-no-properties hyrolo-entry-group-number)))
	(if (/= entry-level-len level-len)
	    (hyrolo-to-entry-end t)
	  (setq entry-spc (match-string-no-properties hyrolo-entry-trailing-space-group-number)
		entry (buffer-substring-no-properties (point)
						      (save-excursion
							(re-search-forward hyrolo-entry-name-regexp nil t)
							(point))))
	  (when (and (derived-mode-p 'markdown-mode)
		     (string-match "\\`[^#]*#+" entry-spc))
	    (setq entry-spc (substring entry-spc (length (match-string 0 entry-spc)))))
	  (cond ((string-lessp entry name)
		 (hyrolo-to-entry-end t))
		((string-lessp name entry)
		 (setq again nil) (beginning-of-line))
		(t ;; found existing entry matching name
		 (setq again nil match t)))))
      (setq buffer-read-only nil)
      (unless match
	(unless (zerop (current-column))
	  (insert "\n"))
	(insert (concat level "*")
		(if (string-equal entry-spc "") "   " entry-spc)
		name "\n")
	(backward-char 1))
      ;; hyrolo-to-buffer may move point from its desired location, so
      ;; restore it.
      (let ((opoint (point)))
	(hyrolo-widen)
	(hyrolo-to-buffer (current-buffer))
	(goto-char opoint))
      (when (derived-mode-p 'kotl-mode)
	(kotl-mode:to-valid-position))
      (set-auto-mode t)
      (run-hooks 'hyrolo-add-hook)
      (when (called-interactively-p 'interactive)
	(message "Edit entry at point.")))))