help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Making a function than can only be used interactively


From: Emanuel Berg
Subject: Re: Making a function than can only be used interactively
Date: Fri, 08 Jul 2022 08:30:04 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux)

Yuri Khan wrote:

> It does not matter for interactive use. [...] ‘&optional’
> comes into play if you use this function non-interactively,
> from Lisp

No, it matters. One example how it matters is that optional
arguments defaults to nil.

Check out this file and in particular example 4 which doesn't
make sense to me?

;;; -*- lexical-binding: t -*-
;;
;; this file:
;;   https://dataswamp.org/~incal/emacs-init/dwim.el

;; DWIM example 1, from Lisp ignore region if set

(defun test-dwim (&optional beg end)
  (interactive (when (use-region-p)
                 (list (region-beginning) (region-end)) ))
  (or beg (setq beg (point-min))) ; or (point)
  (or end (setq end (point-max)))
  ;; insert code here
  ;; now let's just make a list to do something
  (list beg end) )

;; example 2, use the region if available from Lisp as well

(defun test-dwim-2 (&optional beg end)
  (interactive (when (use-region-p)
                 (list (region-beginning) (region-end)) ))
  (or beg (setq beg (if (use-region-p) (region-beginning) (point-min))))
  (or end (setq end (if (use-region-p) (region-end)       (point-max))))
  (list beg end) )

;; example 3, one call to `use-region-p' is enough

(defun test-dwim-3 (re &optional beg end)
  (interactive `(,(read-regexp "re: ")
                 ,@(when (use-region-p)
                     (list (region-beginning) (region-end)) )))
  (or beg (setq beg (point-min)))
  (or end (setq end (point-max)))
  (message "%s" (list re beg end)) )

;; example 4, let's do that with the `interactive' spec
;; string. but without `use-region-p' it doesn't reset after
;; I clear the region, or that's what I thought happened
;; anyway :) so this doesn't work as intended, which
;; `test-dwim-3' does, supposedly the worse one.

(defun test-dwim-4 (re &optional beg end)
  (interactive "sre: \nr")
  (or beg (setq beg (point-min)))
  (or end (setq end (point-max)))
  (message "%s" (list re beg end)) )

;; test the interface

(when nil
  (save-excursion
    (set-mark   10)
    (goto-char 500)
    (call-interactively #'test-dwim) ) ; (10  500)
  (call-interactively #'test-dwim)     ; ( 1 2867)
  (test-dwim 30 90)                    ; (30   90)
  (test-dwim)                          ; ( 1 2867)
)

;; example function

(defun count-chars (&optional beg end)
  (interactive (when (use-region-p)
                 (list (region-beginning) (region-end)) ))
  (let*((bg (or beg (point-min)))
        (ed (or end (point-max)))
        (df (- ed bg)) )
    (prog1
        df
      (message "%d" df) )))

;; Test the example function:
;;
:;   [try these with and without a region]
;;
;;   (call-interactively #'count-chars)
;;   (count-chars)
;;
;;   [this will always be the same tho]
;;
;;   (count-chars 10 40)
;;
;; Note:
;;   A common mistake in Elisp is that optional formal
;;   parameters aren't sent as arguments when called from
;;   Lisp, they are then nil but are used as for example an
;;   integer, as in:
;;
;;     (when (and (<= 0 width) (<= width 648)) ... ) ; DNC
;;
;; The test method is to call the function every way possible:
;;   1. interactively with a region
;;   2. ditto w/o
;;   3. From Lisp with arguments
;;   4. ditto w/o
;;   .. ..

-- 
underground experts united
https://dataswamp.org/~incal




reply via email to

[Prev in Thread] Current Thread [Next in Thread]