2023-03-01	Emacs widget for my literature list

  This is an update to my phlog post "AWK replaces LibreCalc"[1] where
  I describe how I use Awk to view, sort and filter my literature list
  (a basic csv-file).  This works great but manually  adding new books
  to the list is a bit cumbersome.  I always wanted to make use of the
  Emacs widget library[2]  and this was the perfect  opportunity. So I
  created   a   simple   widget   containing   editable-input   fields
  corresponding to the column header of the csv-file. Then I added one
  button to append the data row to the file and one to reset the form.

  This was fun because

  - I learned how to use the widget library

  - I learned about buffer-local variables[3]

  - I came up with an elegant way to check if a list of variables is
    defined (look for boundp in the source)

  - I could use a macro to refactor the code


Code
~~~~

(require 'widget)

(defmacro sulaco/generate-field-widget (VAR LENGTH)
  `(progn (widget-insert (format "%s:\n" ,(capitalize VAR)))
	  (widget-create 'editable-field
			 :size ,LENGTH
			 :notify (lambda (this &rest ignore)
				   (setq-local ,(intern VAR)
					       (widget-value this))))
	  (widget-insert "\n")))

(defun sulaco/add-book ()
  "Create a widget to append a new entry to literaturliste.csv."
  (interactive)

  (if (not (get-buffer "*Add Book Form*"))
      (progn      
       (switch-to-buffer "*Add Book Form*")
       (kill-all-local-variables)
       (let ((inhibit-read-only t))
	 (erase-buffer))

       (sulaco/generate-field-widget "author" 60)
       (sulaco/generate-field-widget "title" 60)
       (sulaco/generate-field-widget "year" 5)
       (sulaco/generate-field-widget "language" 20)
       (sulaco/generate-field-widget "epoch" 20)
       (sulaco/generate-field-widget "type" 20)
       (sulaco/generate-field-widget "date-read" 20)
       (sulaco/generate-field-widget "annotation" 60)
       (widget-insert "\n")
       (widget-create
	'push-button
	:notify (lambda (&rest ignore)
		  (let ((output-line (mapconcat
				      (lambda (x)
					(if (boundp x) (symbol-value x) ""))
        			      '(author title year language epoch type
	        			       date-read annotation)
				      "\t")))
		    (append-to-file
		     (concat output-line "\n")
		     nil "~/Dokumente/literaturliste.csv")))
	"Add book")

       (widget-create 'push-button
		      :notify (lambda (&rest ignore)
				(progn
				 (kill-buffer (current-buffer))
				 (sulaco/add-book)))
		      "Reset Form")

       (use-local-map widget-keymap)
       (widget-setup)
       (goto-char 9))
      ;; else
      (switch-to-buffer "*Add Book Form*")))


Screenshot
~~~~~~~~~~

   Author:
   ____________________________________
   Title:
   ____________________________________
   Year:
   _____
   Language:
   ______________________
   Epoch:
   ______________________
   Type:
   ______________________
   Date-Read:
   ______________________
   Annotation:
   ____________________________________

   [Add book][Reset Form]



   U:@**-  *Add Book Form*  All (2,0)     (Fundamental)




Footnotes
~~~~~~~~~

[1] gopher://tilde.club/0/~sulaco/phlog/9993-2023-02-12-AWK_replaces_LibreCalc

[2] https://www.gnu.org/software/emacs/manual/html_mono/widget.html
    or C-h i s widget RET RET

[3] https://www.gnu.org/software/emacs/manual/html_node/elisp/Buffer_002dLocal-Variables.html
    or C-h i s elisp RET RET s buffer-local RET RET