0

In the (amateurish, convoluted) code below, I am trying create an environment where there may be multiple serial-term buffers/windows at the same time. I am doing everything I can think of (and just random desperate things) to make the variables local to the buffer running the terminal to which they pertain. For instance, there may be a buffer "serial-1a2b-buffer" with the terminal "serial-1a2b-term" running in it while at the same time there's a buffer "serial-3c4d-buffer" with the terminal "serial-3crd-term" running in it.

I can get the buffers/terminals setup and running with defun setupserial, but defun killserial and defun resetserial don't get the right value for "termname" and "buffname". It might be the values in the other buffer or it may be past values for buffers and terminals that no longer exist.

(In case anyone is wondering, I do a lot of work with microcontrollers. If the serial connection to them is interrupted, like with a hardware reset, then the serial process dies. The idea was to have a quick way to reset the connection - like with a function bound to a key sequence.)

(defvar serialspeed "115200")
(defvar serialport "/dev/ttyACM0")
(defvar serialbasename "serial")
(require 'term)


(defun setupserial (serialport serialspeed)
  (interactive
   (list
    (read-string
     (format "Serial Port (%s): "
         serialport)
     nil nil
     serialport)
    (read-string
     (format "Speed (%s): "
         serialspeed)
     nil nil
     serialspeed)))
  (setq uniqueid (format "%04x" (random (expt 16 4))))
  (setq serialid (concat serialbasename "-" uniqueid))
  (setq buffname (concat serialid "-buffer"))
  (setq termname (concat serialid "-term"))
  (setq bufferid (get-buffer-create buffname))
  (setq procid (make-serial-process
   :speed (string-to-number serialspeed)
   :port serialport
   :name termname
   :buffer buffname))
  (switch-to-buffer bufferid)
  (make-local-variable 'serialid)
  (make-local-variable 'buffname)
  (make-local-variable 'bufferid)
  (make-local-variable 'termname)
  (make-local-variable 'procid)
  (make-local-variable 'serialspeed)
  (make-local-variable 'serialport)
  (term-mode)
  (term-char-mode)
  (local-set-key (kbd "M-r") #'resetserial)
  (local-set-key (kbd "M-k") #'killserial)
  (local-set-key (kbd "M-x") #'execute-extended-command)
  (local-set-key (kbd "M-o") #'ace-window)
  (message "Started Serial Terminal"))

(defun resetserial ()
  (interactive)
  (make-serial-process
   :speed (string-to-number serialspeed)
   :port serialport
   :name termname
   :buffer bufferid)
  (message "Restarted Serial Terminal"))


(defun killserial ()
  (interactive)
  (delete-process termname))

(global-set-key (kbd "C-c s") #'setupserial)

(provide 'setup-serial)
nelsonov
  • 60
  • 6
  • I've tried both "buffname" and "bufferid" in resetserial. Both should work, but neither gives the value from the proper scope. – nelsonov Dec 09 '21 at 08:48

1 Answers1

1

Your problems are sequential. Having created all of your buffer-local variables, you are then destroying them all by calling a new major mode.

The section on "Derived modes, and mode hooks" in this answer might be useful reading, but the key point is that the first thing that happens when you call a major mode is kill-all-local-variables.

Because you are setting global values too, in the absence of local values your other commands will end up using whatever the most-recent global value happened to be.

Set the major mode first.

phils
  • 71,335
  • 11
  • 153
  • 198
  • Thank you so much. I read at least a half a dozen times that the first thing that happens after changing modes is `kill-all-local-variables` but for some reason it just didn't embed itself in my brain. I was suffering tunnel vision thinking it was some sort of issue with scope. – nelsonov Dec 10 '21 at 01:53
  • You're welcome. I'll add that I'm unsure whether you had a reason for assigning global values as well as buffer-local ones, but if not then you might consider declaring them all with `defvar-local` and then in your function you can simply `setq` them after changing the major mode, and you will automatically be setting a buffer-local value. There's also `setq-local` which is a more concise way to set a buffer-local value regardless of how the variable was defined. – phils Dec 10 '21 at 03:13