1

I am switching from VIM to Emacs for just a couple weeks and trying to write some Elisp. Having difficulties to adapt, I am exploring different options to do marking and reached this function.

(defun mark-word (&optional arg allow-extend)                          
  "Set mark ARG words away from point.                                 
The place mark goes is the same place \\[forward-word] would           
move to with the same argument.                                        
Interactively, if this command is repeated                             
or (in Transient Mark mode) if the mark is active,                     
it marks the next ARG words after the ones already marked."            
  (interactive "P\np")                                                 
  (cond ((and allow-extend                                             
              (or (and (eq last-command this-command) (mark t))        
                  (region-active-p)))                                  
         (setq arg (if arg (prefix-numeric-value arg)                  
                     (if (< (mark) (point)) -1 1)))                    
         (set-mark                                                     
          (save-excursion                                              
            (goto-char (mark))                                         
            (forward-word arg)                                         
            (point))))                                                 
        (t                                                             
         (push-mark                                                    
          (save-excursion                                              
            (forward-word (prefix-numeric-value arg))                  
            (point))                                                   
          nil t))))                                                    

it's pretty straight forward except allow-extend. It seems to me for this function to work, allow-extend needs to be empty. But when we do interaction, we don't really provide any prefix key to it.

So why would allow-extend be non nil in this case? Also how does "P\np" work here?

2 Answers 2

1

As @db48x pointed out, indeed C-u passes in 2 arguments down to the function if it's pressed, but it wouldn't be the case if it's not pressed in the first place.

The trick here is the second argument is p, lower case. That converts the second argument to a number when called by call-interactively regardless, which has no chance to be nil.

Examination,

M-: (defun try-it (&optional a b) (interactive "P\np") (message "a is %s and b is %s" a b))

then

M-x try-it

gives

a is nil and b is 1

while

C-u M-x try-it 

gives

a is (4) and b is 4  
1

The interactive declaration specifies that the function wants two arguments. The code letters for the arguments are P and p. If we examine the help for interactive (by typing C-h f interactive <RET>), we can see what these mean:

p -- Prefix arg converted to number.  Does not do I/O.
P -- Prefix arg in raw form.  Does not do I/O.

This means that the single prefix arg is passed to mark-word twice; first in raw form (it's a list of numbers, as I recall), then in the form of an integer.

Edit: of course, a non-interactive caller can provide any args they want, so while this command always gets a number (which is always a true value) when called interactively, there might be non-interactive callers that pass in nil to turn off that behavior. I did not consider, when I wrote this answer, that this might be not be obvious.

8
  • This is in fact not a complete answer, I will answer this myself.
    – Jason Hu
    Commented Jul 27, 2017 at 22:14
  • @HuStmpHrrr: What do you think is missing from this answer? It does mention that p converts the prefix argument to a number. The only thing I see in your answer that's not here are some (unnecessary, I'd say) examples.
    – Omar
    Commented Jul 29, 2017 at 1:41
  • I'm sorry but after reading you answer, I'm still confused about why the second argument is not nil, thinking it should be as nobody pass it. My question is about why the second argument is not nil, I don't see you answered that.
    – Jason Hu
    Commented Jul 29, 2017 at 1:44
  • When Emacs calls an interactive function, it first builds an argument list. It uses the code letters from the interactive declaration to decide what arguments to pass. This function asks for two arguments, and both of them come from the prefix arg. Thus the single prefix argument that the user created with C-u becomes two arguments that are passed to this function.
    – db48x
    Commented Jul 29, 2017 at 18:31
  • you haven't got it yet. I understand what happens when C-u is pressed. my question is about why the second argument isn't nil even if C-u is not pressed. as I said, you didn't really explain this part as it's stated in my original question as the most confusing part.
    – Jason Hu
    Commented Jul 29, 2017 at 23:02

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.