3
(defun tmp:interactive (&optional scope pos-style)
  "POS-STYLE has no effect when SCOPE is `directory'."
  (interactive
   (list
    (cdr (assoc (read-char-choice
                 "Copy (f)ull name, (d)irectory, or just the (b)asename? "
                 '(?f ?d ?b))
                '((?f . full)
                  (?d . directory)
                  (?b . basename))))
    (when (and (not (equal scope 'directory)) current-prefix-arg)
      (cdr (assoc (read-char-choice
                   "Style: (n)one, (l)ine, (c)olumn, or (p)oint? "
                   '(?n ?l ?c ?p))
                  '((?n . nil)
                    (?l . line)
                    (?c . line-column)
                    (?p . point)))))))
  (message "%S %S" scope pos-style))

Above is a skeleton of a function that copies the appropriate file name for the current buffer. However, it doesn't really make sense to include position information when the user is copying the directory name.

Is there a way to ignore a prefix argument within the (interactive ...) form based on previous input?

(An alternative solution to this end would be to test called-interactively-p and leave the optional argument as nil to test in the body of the defun, but that's very fragmented.

1

1 Answer 1

3

You cannot refer to SCOPE within the interactive form, because it is that form that defines SCOPE.

What you can do is use let to save the result of read-char-choice and then test that in the rest of the interactive spec.

(defun tmp:interactive (&optional scope pos-style)
  "POS-STYLE has no effect when SCOPE is `directory'."
  (interactive
   (let ((scop  (cdr (assoc (read-char-choice
                             "Copy (f)ull name, (d)irectory, or just the (b)asename? "
                             '(?f ?d ?b))
                            '((?f . full)
                              (?d . directory)
                              (?b . basename))))))

     (list scop (and (not (equal scop 'directory))
                     current-prefix-arg
                     (cdr (assoc (read-char-choice
                                  "Style: (n)one, (l)ine, (c)olumn, or (p)oint? "
                                  '(?n ?l ?c ?p))
                                 '((?n . nil)
                                   (?l . line)
                                   (?c . line-column)
                                   (?p . point))))))))
  (message "%S %S" scope pos-style))
17
  • That's why I figured it didn't work. I did think of doing something like that (naïvely using setq, though), but I couldn't figure a way to get around the scoping issue. Can you provide an example using a let-binding? Commented Dec 7, 2014 at 19:18
  • 1
    See above. Also, you don't need when here; it is extra. What's more, many people (me too) prefer to not use when when the return value is important. We use when and until only for side effects. This makes it easier for humans to understand the code (the intent).
    – Drew
    Commented Dec 7, 2014 at 19:22
  • Good points about side-effects; I'll keep that in mind for future development. And ah!! It seems so simple now that you laid it out! Thanks :) Commented Dec 7, 2014 at 19:24
  • By the way, you don't need to use scop rather than scope here – is that another style choice? Commented Dec 7, 2014 at 19:27
  • Yes, it just makes it easier to read (IMO). You saw how easy it was to confuse the input parameter with using it inside `interactive'. This helps human readers realize that this local variable is not the same thing. It is true that a function parameter cannot be a dynamic variable in Emacs Lisp, but it's best to help readers avoid any confusion here (IMO).
    – Drew
    Commented Dec 7, 2014 at 21:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.