Wednesday, April 22, 2026

How I got into Emacs (and Free Software)

This is a long tale, not confined to Emacs alone. This is, indeed, a story about why I am a confirmed Free Software advocate. This has been a rocky road. For this chapter, I'll try my best to restrict my discussion to Emacs; but that's impossible. In the late 80s and early 90s, I was living in Chuuk Lagoon, Micronesia. Graduate work at the University of Guam (UOG) marine lab had been interrupted, at the outset of my third year; in Chuuk, my wife was preparing to give birth to our first son.

In my letter of intent for my application to the graduate program at UOG Marine Lab, in 1984, I had written that my first order of business was to learn the marine fauna  of Micronesia, to prepare for future study of traditional marine biological knowledge. A lexicon of marine life would be required. After  two years of classwork, with a working  knowledge of the fauna, in late 1986 I hit the ground running, collecting notes on the names and knowledge of marine animals. 


As  notes piled up, I would obviously need a PC to compile, sort, and analyze the burgeoning information. I had a working knowledge of computers, and had used some of the earliest PCs---IBM XT and IBM AT--- at the Marine Lab. Somehow I acquired a PC, and started messing around with typing in  names, and organizing the data.  I  purchased a copy of SNOBOL4, and began to study it, and SPITBOL, hopeful it would be helpful for string manipulation.   I tried Borland Paradox.   Progress was minimal. 

 

In 1990 and 1991, my life in turmoil I moved to another island, nearby. My Mother came to the rescue, gifting me a Toshiba laptop. I soon  realized it came with no software, not even a word processor.  I made do for a while.  I remember using 4Dos.  

 In  1991, I had remarried, moved again, and had a new teaching job. With a 10W solar panel, the laptop could be used,  and I tried various editors to develop a simple database---a list of animal names with descriptive text.   I needed a programmer's editor that did not mangle the text with control codes.  A linguist from the University of Hawaii sent a demonstration copy of MultiEdit, which did some of what I wanted. But to learn how to type diacritics, I would need to purchase the manual, for over 300.00. On my teacher's salary, this was impossible.  

 At the time, I had been reading Infoworld, and , ran across  a short article buried a few pages in, about the Free Software Foundation. I knew nothing about this, or about Free Software, but the name said it all. I wrote a letter to the FSF explaining my project, and asking for help for an editor. A few weeks later, I received a package with about 13 3-1/2" diskettes, a package that would change my life.  (Whom should I thank?)  On one disk was "Demacs," an implementation of Emacs for the Windows ecosystem, in addition to a number of Unix text tools ported to Windows, by Cygwin, and Unix Text Tools---sort, ptx, grep, find, and other---ported for Windows 3.0.   

 Demacs was a well-functioning port of Emacs to Windows. One of the first things I noticed was the existence of a Tutorial, a genius introduction.  And this was the "self documenting text editor."  Within minutes I was sufficiently able to navigate the interface and to work with text.  I developed a crude understanding of Emacs Lisp, and wrote several low level helper functions for my needs. This software was beyond any dream. 

  Shockingly, in this age of continual modernization, most of the tweaks I developed to my first emacs files still function on today's Emacs 30+, in 2026, not the case for files written on early windows Word versions.  Happily, over the next couple of years, the Gnus Bull, the bulletin of the Free Software Foundation arrived every so often in my post office box. In one of these bulletins, fascinating reading for me at the time, was an article about Unix work-alike operating systems, Linux and FreeBSD.  Later on, on an extended medical visit to Guam, I was able, through generous assistance of the owners of the ISP Kuentos Communications, I was enabled to download Slackware and install it on my Toshiba Laptop.

This meant I could install Emacs directly. The Unix text tools were available directly as well.  My needs are simple, compared to many---if not most---Emacs users, many of whom are programmers comfortable with generating elaborate and extensive code. As my project grew, Emacs was the essential ingredient. Later on I learned of the existence of LaTeX. Eventually, my lexicon was published from camera ready copy generated by LaTeX in the journal Micronesica.  With the help of a programmer at the University of Hawaii Linguistics Department, an Emacs guru, I was able to write an emacs lisp program to "alphabetize" Chuukese in an arbitrary order.  Many other scholars and programmers have helped along the way, on mailing lists, or through lengthy correspondences.   Early on, Professor Hsu at UH mentioned the Band Format---a free form database used by linguists for lexical data.  I could not afford the tools he offered, but I was able to mimic some of the needed facility using Emacs lisp.  

 I was able to implement a tool to convert each record of the band format database into LaTeX code for a single entry, that was typeset as camera ready copy for the ultimate publication.   

 For this carnival, the take home messages for Newbies and scholars was that the Tutorial can provide, in an hour or two, a tremendous introduction to the keyboard use for Emacs.  And secondly, I think it's important to recognize the number of Emacs experts who are willing to assist in such an endeavor as mine.  I have not resorted to a starter kit.   

Wednesday, April 8, 2026

Setting file times in Emacs from Time-stamps in file, or "Created " at start of a file: Generated through Google AI Summary

AI is problematic, but the sheer convenience of it has grabbed my attention.  For tweaking my GNU/Linux system, AI summaries of Google searches come in a few seconds, and they sometimes save hours of research.  It is helpful that low grade links to sources are often provided.  I balk, however, at the damaging infrastructure involved.   

 A recent adventure has been developing a useful emacs lisp tool to change the metadata time stamps of a file from emacs' Time-stamps, when they exist.   

Today I realized I had copied files from another system without specifying to save file metadata.  Could I set the file times of files with timestamps using the "Time-stamp: < >" utility in Emacs?   I searched, and, I must freely admit, I asked for more info from the AI helper of Google Search.  After about 7 or more rounds of providing feedback about  a regular expression that did not work, these functions were provided.  Wow.   The last two of these is probably sufficient for my needs.  I will change the names.

 

(defun my/set-file-time-final ()
  "Sets file time by finding 'Time-stamp' and extracting only the date/time.  From Google AI."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    ;; 1. Find the literal word "Time-stamp" anywhere (ignores #, brackets, etc.)
    (if (re-search-forward "Time-stamp" nil t)
        ;; 2. Look for the first date pattern (YYYY-MM-DD HH:MM:SS) that follows it
        (if (re-search-forward "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}[ T][0-9]\\{2\\}:[0-9]\\{2\\}:[0-9]\\{2\\}\\)" nil t)
            (let* ((ts-string (match-string 1))
                   (parsed (parse-time-string ts-string))
                   (lisp-time (when parsed (encode-time parsed))))
              (if (and (buffer-file-name) lisp-time)
                  (progn
                    (set-file-times (buffer-file-name) lisp-time)
                    (message "Success! Mtime set to %s (Username ignored)" ts-string))
                (error "Parsed '%s' but system couldn't use it" ts-string)))
          (error "Found 'Time-stamp' but no YYYY-MM-DD HH:MM:SS format found after it"))
      (error "The word 'Time-stamp' is missing from this file"))))

(defun my/dired-set-times-from-stamps ()
  "In Dired, run 'my/set-file-time-final' on all marked files. From Google AI."
  (interactive)
  (let ((files (dired-get-marked-files)))
    (dolist (file files)
      (with-current-buffer (find-file-noselect file)
        (condition-case err
            (progn
              (my/set-file-time-final)
              (save-buffer))
          (error (message "Skipping %s: %s" file (error-message-string err))))))
    (revert-buffer) ; Refresh the Dired buffer to show the new times
    (message "Done processing marked files.")))

(defun my/dired-set-times-from-stamps ()
  "In Dired, sync system times for marked files. Files without stamps are ignored."
  (interactive)
  (let ((files (dired-get-marked-files))
        (skipped 0)
        (updated 0))
    (dolist (file files)
      (with-current-buffer (find-file-noselect file)
        ;; Use condition-case to catch files that don't have the stamp
        (condition-case nil
            (progn
              (my/set-file-time-final)
              (save-buffer)
              (setq updated (1+ updated)))
          (error (setq skipped (1+ skipped))))))
    (revert-buffer)
    (message "Done! Updated: %d | Skipped (no stamp): %d" updated skipped)))

(defun my/set-file-time-final ()
  "From Google AI summary session after Google search.  Sets file time from header. Handles: Created YYYY-MM-DD Day HH:MM:"
  (interactive)
  (save-excursion
    (goto-char (point-min))
    ;; 1. Search for 'Time-stamp' or 'Created'
    (if (re-search-forward "\\(Time-stamp\\|Created\\):?" nil t)
        ;; 2. Match the date (YYYY-MM-DD) 
        ;;    Then skip any day-of-week (like Tue)
        ;;    Then grab the time (HH:MM or HH:MM:SS)
        (if (re-search-forward "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\)[^0-9]*\\([0-9]\\{2\\}:[0-9]\\{2\\}\\(?::[0-9]\\{2\\}\\)?\\)" nil t)
            (let* ((date-part (match-string 1))
                   (time-part (match-string 2))
                   (ts-string (concat date-part " " time-part))
                   (parsed (parse-time-string ts-string))
                   (lisp-time (when parsed (encode-time parsed))))
              (if (and (buffer-file-name) lisp-time)
                  (progn
                    (set-file-times (buffer-file-name) lisp-time)
                    (message "Success! Mtime set to %s" ts-string))
                (error "Parsed '%s' but couldn't use it" ts-string)))
          (error "Found keyword but date/time format was unexpected"))
      (error "No 'Time-stamp' or 'Created' header found"))))

(defun my/dired-set-times-from-stamps ()
  "From Google AI summary session.  This calls the function my/set-file-time-final.  In Dired, sync system modification times for all marked files
based on the 'Created' or 'Time-stamp' lines inside them."
  (interactive)
  (let ((files (dired-get-marked-files))
        (updated 0)
        (skipped 0))
    (dolist (file files)
      ;; Open the file in a buffer without switching to it
      (with-current-buffer (find-file-noselect file)
        (condition-case nil
            (progn
              ;; Call your working 'within-the-file' function
              (my/set-file-time-final)
              ;; Save the buffer to ensure metadata is flushed to disk
              (save-buffer)
              (setq updated (1+ updated)))
          (error 
           (setq skipped (1+ skipped))))))
    ;; Refresh the Dired buffer so you see the new dates immediately
    (revert-buffer)
    (message "Batch complete: %d updated, %d skipped (no stamp found)." updated skipped)))

(with-eval-after-load 'dired
  (define-key dired-mode-map (kbd "T") 'my/dired-set-times-from-stamps))

How I got into Emacs (and Free Software)

This is a long tale, not confined to Emacs alone. This is, indeed, a story about why I am a confirmed Free Software advocate. This has been...