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