Emacs for programming


#1

I’ve been using emacs to write my code and send it to the board using the emacs built in serial terminal. Emacs being lisp smart (among many other things) gives code color high lighting and parenthesis matching.
The terminal has cut and pasting as well as all the other editing features (in line mode). It takes a bit to get use too but once you establish a work flow its far supperior to the arduino serial terminal.


#2

That sounds like a great way of working with uLisp. Would you consider writing up a bit more detail? How to get and install emacs, set it up, and what platforms it supports?


#3

Is there a way to copy the lisp expression from the source file to the serial-term? (I mean by not using M-c, C-x o, C-y)?
I think it exists a emacs-mode which uses C-c e or something like this to evaluate the expression where the cursor is.
Do you know if it is possible to use something like this?


#4

Emacs is an extensible (you can add to it) text editor that has been around since the dark ages of unix.
Its written in C and a dialect of lisp (elisp).

I believe emacs is cross platform, but I have no understanding of windoze or mackos so you’re on you’re own on how to install it here. On Linux its available either already installed or available in your distros repository.

Once installed I recommend doing the tutorial which is available holding down the control and h key then pressing t. Also, the resource that got me over the hump and on the road to using emacs for everything was the excellent podcasts done by Klaatu for hackerpublicradio, the links are as follows:

http://hackerpublicradio.org/eps.php?id=0852
https://hackerpublicradio.org/eps.php?id=0856
https://hackerpublicradio.org/eps.php?id=0861

listen to those and you’ll be well on your way to using emacs for all of your computing needs.

As far as using emacs for ulisp, I usually split the screen and have the serial terminal in one buffer (meta-x serial-term) and the scratch buffer in the other. I compose my code in the scratch buffer then cut and paste to the terminal there. You must be in line mode (C-c C-j) for this to work, and char mode (C-c C-k) sends the text to the device. If that doesn’t make sense, you haven’t listened to the podcasts ;) Anyway, I haven’t yet explored all the serial terminal can do or customized it in anyway but it is much more functional than the arduino terminal. Hope this helps.

In response to Kaef:

I don’t know of a way to push the code to the buffer with the the serial terminal in it, but that doesn’t mean its not possible.


#5

Thanks for the information! There are several Mac versions of Emacs; for a good review see:


#6

I’m use emacs serial-term too. But instead of copy the code by hand,
i have the following snippet in my init.el (emac’s config file):

(setq ulisp-term-buffer-name "/dev/ttyUSB0")

(defun ulisp-eval-last-expression-in-term ()
  (interactive)
  (let ((expr (buffer-substring-no-properties  
                     (save-excursion (backward-sexp) (point))
                     (point))))
      (with-current-buffer ulisp-term-buffer-name
          (insert expr)
          (term-send-input))))

(global-set-key (kbd "C-x e") 'ulisp-eval-last-expression-in-term)

With this snippet, i can place my cursor at the end of a expression (after the last closing “)”)
and hit Ctrl-x e to evaluate it (copy it in the serial-term buffer and send it to the esp).

To test it yourself, you can copy this snippet in your *scratch* buffer, evaluate each
expression per Ctrl-x Ctrl-e or type M-x eval-buffer to evaluate the whole buffer.

Maybe you need to adjust the variable ulisp-term-buffer-name. Use the name
of your serial-term buffer. I use Linux (so it’s /dev/ttyUSB0) and FreeBSD (so it’s /dev/ttyU0).
For other platforms, i have no idea.

If something is unclear, feel free to ask.


#7

That’s great! I was playing around last night to try to do just that. Awesome!


#8

Great, that’s what I was looking for – thank you very much!


#9

Hi,
does anyone knows how to save an emacs session including the serial-term config?
On emacs start I do:

  • Ctrl-x 3 to get two buffers
  • Ctrl-x o (switch to second (right) buffer)
  • Meta-x serial-term (and enter device and baudrate)
  • switch serial-term to line mode
  • Ctrl-x o (go to left buffer)
  • Ctrl-x-f (open source file)

I’d like to save the settings (I tried ‘save-desktop’ but it doesn’t seems to work) – any suggestions?

Regards,
Kaef


#10

Hey,
put the following snippet in your init.el (or to test it first, in your *scratch* buffer and evaluate it per Meta-x eval-buffer).

quick and dirty:

(defun setup-ulisp-workspace ()
  (interactive)

  (split-window-right)
  (other-window 1)

  (serial-term "/dev/ttyUSB0" 9600)
  (term-line-mode)

  (other-window 1)
  (find-file "my-source-file"))

Then you can execute it per M-x setup-ulisp-workspace.

The (find-file "my-source-file") opens a predefined source-file - remove this if
you don’t want to open a predefined file.


You can “ask” emacs how you can code it yourself.
To map your described key functions to elisp functions simply type Ctrl-h k before your keys.

Example:

  • Ctrl-x 3 to get two buffer

in emacs, hit Ctrl-h k Ctrl-x 3 and you get split-window-right

  • Ctrl-x o (switch to second (right) buffer)

in emacs, hit Ctrl-h k Ctr-x o and you get other-window COUNT

and so on.

If you need some help for a function, type Ctrl-h f <function-name> (or put your coursor under an lisp function and only type Ctrl-h f <RETURN>.

If something is unclear, feel free to ask.

Regards, Jürgen


#11

Hi Jürgen,

great! This is what I wanted to have, thank you very much.

emacs coding

What do you think is a good way learning emacs and elisp? What in your oppinion would be a good starting point?
I’m using emacs a while ago (a few years) but till now I’m just using basic (editing-) functions. Now I think it’s time to go deeper…

Kindly Regards,
Kaef


#12

Hey,

sadly, i can’t recommend any specific resource.
I learned emacs by using it. And i can’t say from me, that i am an lisp hacker.

One important lesson for me was to understand, that i can ask emacs, which function, key-sequence, …
i need for my current task (type Ctrl-h ? for help). And then simply using it - learning by doing.

I was often frustated by the complicated (for me) key-sequences. But now i use emacs
as mail client, notes, programming - so for all my tasks.

Keep using it, and with the time, the key-sequences / concepts are in your finger / brain muscle.

Regards, Jürgen


#13

Hello, I use Emacs too, and I use inferior-lisp and lisp-mode with ulisp, it works well!

Put those code in ulisp.lisp, and load it in emacs, then you can connect to ulisp via M-x connect-to-ulisp (or C-u M-x connect-to-ulisp if you want to change the default serial device). And connect in a lisp-mode file buffer will make that buffer talk to ulisp (via C-x C-e). Hope this is useful for other :)

(defvar ulisp-port-name "/dev/ttyUSB0"
  "Serial port name for uLisp.")
(defvar ulisp-port-speed 9600
  "Serial port speed for uLisp.")

(defun connect-to-ulisp (port speed)
  "Run a uLisp serial process, input and output via buffer *ulisp*."
  (interactive
   (if current-prefix-arg
       (list
        (read-file-name "Serial port: " "/dev" ulisp-port-name)
        ulisp-port-speed)
     (list ulisp-port-name ulisp-port-speed)))
  (with-current-buffer (make-comint-in-buffer "ulisp" "*ulisp*" nil)
    (setq-local inferior-lisp-buffer "*ulisp*")
    (inferior-lisp-mode))
  (when (not (string-equal
              "serial"
              (process-type (get-buffer-process "*ulisp*"))))
    (make-serial-process
     :buffer "*ulisp*"
     :port port
     :speed speed
     :noquery t))
  (setq-local inferior-lisp-buffer "*ulisp*")
  (pop-to-buffer "*ulisp*"))

Working around serial buffer overflow with Emacs
#14

Thank you for this, it works well for me.

Using Emacs 28.2 on macOS 12.6, I got the error message
Symbol’s function definition is void: inferior-lisp-mode

So I had to add the following before it to make it work:
(require 'inf-lisp)

(I also had to remove SLIME, which probably interferes with inferior-lisp-mode in many ways.)


#15

On my Linux Mint 22 system with Emacs 29.3 I set up the above Lisp code as indicated. Connecting to uLisp and using it works, but in the Emacs buffer a ^M is appended to the end of every uLisp output line like this:

emacs-ulisp

How can I get rid of the extra ^M?


Working around serial buffer overflow with Emacs
#16

^M is just caret notation for #\Return. I guess Emacs is expecting only #\Newline for end-of-line, instead of #\Return#\Newline which is what uLisp uses. There is probably some way to change this.


#17

Right thanks, I’ll add a call to comint-strip-ctrl-m inside connect-to-ulisp.


#18

I tried adding comint-strip-ctrl-m inside connect-to-ulisp, either just after the call to inferior-lisp-mode or as the very last expression of connect-to-ulisp, but Emacs still prints the ^Ms. Interactively executing M-x comint-strip-ctrl-m has no effect either.


#19

Adding (add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m) to my ~/.emacs did suppress the extra ^Ms. But it worked only once and now I always get ^Ms in the inferior Lisp buffer.

In addition, copying to the inferior Lisp some code longer than the serial buffer (preceeded by a line with one or more semicolons) and evaluating it locks the inferior Lisp Emacs buffer and uLisp, in that text typed on either is echoed but no evaluation takes place.

So far the full code in my ~/.emacs is:

;;; uLisp

(require 'inf-lisp)

(defvar ulisp-port-name "/dev/ttyACM0"
  "Serial port name for uLisp.")

(defvar ulisp-port-speed 9600
  "Serial port speed for uLisp.")

(add-hook 'comint-output-filter-functions #'comint-strip-ctrl-m)

(defun connect-to-ulisp (port speed)
  "Run a uLisp serial process, input and output via buffer *ulisp*."
  (interactive
   (if current-prefix-arg
       (list
        (read-file-name "Serial port: " "/dev" ulisp-port-name)
        ulisp-port-speed)
     (list ulisp-port-name ulisp-port-speed)))
  (with-current-buffer (make-comint-in-buffer "ulisp" "*ulisp*" nil)
    (setq-local inferior-lisp-buffer "*ulisp*")
    (inferior-lisp-mode))
  (when (not (string-equal
              "serial"
              (process-type (get-buffer-process "*ulisp*"))))
    (make-serial-process
     :buffer "*ulisp*"
     :port port
     :speed speed
     :noquery t))
  (setq-local inferior-lisp-buffer "*ulisp*")
  (pop-to-buffer "*ulisp*"))

I use Emacs 29.3 on Linux Mint 22 Cinnamon.


Working around serial buffer overflow with Emacs