all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Moving between headers in message-mode
@ 2013-06-15  4:00 Emanuel Berg
  2013-06-15 12:58 ` Pascal J. Bourguignon
  2013-06-19 15:02 ` Stefan Monnier
  0 siblings, 2 replies; 10+ messages in thread
From: Emanuel Berg @ 2013-06-15  4:00 UTC (permalink / raw)
  To: help-gnu-emacs

Hello all. I wrote this tonight. The purpose is defined in the
docstring. It is supposed to be used in message-mode. I haven't
done much testing but it seems to work. If you have any
suggestions how to make it better, please tell me. Cheers.

;; separator
(setq mail-header-separator "---")
(set-face-attribute 'message-separator nil :foreground "black")

(defun do-nothing () "Do nothing." () )
(defun iterate-header (back)
  "Unless BACK, go to the next header input field:
either on the same line as the present point,
or the next header below.
If the field has a string, put point to the string's right;
if the field is empty, put point so that typing will set the header,
without any prior cursor movement.
If you move from a header which has data, that data is expanded if
found to be an `abbrev-mode' abbreviation (possibly setup in
~/.mailrc), without need for a whitespace.
If there are no headers left, `message-goto-body';
if already in the body, goto the topmost header.
If BACK, do the same, only in reverse direction."
  (interactive)
    (let ((position (point)))
      (goto-char (point-min))
      (search-forward mail-header-separator)
      (let ((separator-pos (point))
            (search-fun)
            (start-pos)
            (end-pos)
            (chars-forward-after-hit)
            (maybe-beginning-of-line))
        (if back
            (progn
              (setq search-fun 'search-backward)
              (setq start-pos separator-pos)
              (setq end-pos (point-min))
              (setq chars-forward-after-hit 2)
              (setq maybe-beginning-of-line 'beginning-of-line) )
            (progn
              (setq search-fun 'search-forward)
              (setq start-pos (point-min))
              (setq end-pos separator-pos)
              (setq chars-forward-after-hit 1)
              (setq maybe-beginning-of-line 'do-nothing) ))
        (if (< position separator-pos)
            (progn
              (goto-char position)
              (expand-abbrev) )
          (goto-char start-pos) )
        (funcall maybe-beginning-of-line)
        (if (not (funcall search-fun ":" end-pos t))
            (message-goto-body)
          (progn
            (forward-char chars-forward-after-hit)
            (end-of-line) )))))

(defun iterate-header-back ()
  "See `iterate-header'."
  (interactive)
  (iterate-header t) ) ; t = back (or up)

(defun iterate-header-next ()
  "See `iterate-header'."
  (interactive)
  (iterate-header nil) ) ; nil = forward (or down)

(define-key message-mode-map (kbd "TAB") 'iterate-header-next)
(define-key message-mode-map (kbd "<backtab>") 'iterate-header-back)

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-15  4:00 Moving between headers in message-mode Emanuel Berg
@ 2013-06-15 12:58 ` Pascal J. Bourguignon
  2013-06-15 17:02   ` Emanuel Berg
  2013-06-19 15:02 ` Stefan Monnier
  1 sibling, 1 reply; 10+ messages in thread
From: Pascal J. Bourguignon @ 2013-06-15 12:58 UTC (permalink / raw)
  To: help-gnu-emacs

Emanuel Berg <embe8573@student.uu.se> writes:

> Hello all. I wrote this tonight. The purpose is defined in the
> docstring. It is supposed to be used in message-mode. I haven't
> done much testing but it seems to work. If you have any
> suggestions how to make it better, please tell me. Cheers.
>
> ;; separator
> (setq mail-header-separator "---")
> (set-face-attribute 'message-separator nil :foreground "black")
>
> (defun do-nothing () "Do nothing." () )
> (defun iterate-header (back)
>   "Unless BACK, go to the next header input field:
> either on the same line as the present point,
> or the next header below.
> If the field has a string, put point to the string's right;
> if the field is empty, put point so that typing will set the header,
> without any prior cursor movement.
> If you move from a header which has data, that data is expanded if
> found to be an `abbrev-mode' abbreviation (possibly setup in
> ~/.mailrc), without need for a whitespace.
> If there are no headers left, `message-goto-body';
> if already in the body, goto the topmost header.
> If BACK, do the same, only in reverse direction."
>   (interactive)
>     (let ((position (point)))
>       (goto-char (point-min))
>       (search-forward mail-header-separator)
>       (let ((separator-pos (point))
>             (search-fun)
>             (start-pos)
>             (end-pos)
>             (chars-forward-after-hit)
>             (maybe-beginning-of-line))
>         (if back
>             (progn
>               (setq search-fun 'search-backward)
>               (setq start-pos separator-pos)
>               (setq end-pos (point-min))
>               (setq chars-forward-after-hit 2)
>               (setq maybe-beginning-of-line 'beginning-of-line) )
>             (progn
>               (setq search-fun 'search-forward)
>               (setq start-pos (point-min))
>               (setq end-pos separator-pos)
>               (setq chars-forward-after-hit 1)
>               (setq maybe-beginning-of-line 'do-nothing) ))
>         (if (< position separator-pos)
>             (progn
>               (goto-char position)
>               (expand-abbrev) )
>           (goto-char start-pos) )
>         (funcall maybe-beginning-of-line)
>         (if (not (funcall search-fun ":" end-pos t))
>             (message-goto-body)
>           (progn
>             (forward-char chars-forward-after-hit)
>             (end-of-line) )))))

I would factorize out the body:

(require 'cl)
(defun iterate-header (back)
  "Unless BACK, go to the next header input field:
either on the same line as the present point,
or the next header below.
If the field has a string, put point to the string's right;
if the field is empty, put point so that typing will set the header,
without any prior cursor movement.
If you move from a header which has data, that data is expanded if
found to be an `abbrev-mode' abbreviation (possibly setup in
~/.mailrc), without need for a whitespace.
If there are no headers left, `message-goto-body';
if already in the body, goto the topmost header.
If BACK, do the same, only in reverse direction."
  (interactive)
  (let ((position (point)))
    (goto-char (point-min))
    (search-forward mail-header-separator)
    (let ((separator-pos (point)))
      (flet ((goto-to-header (search-fun start-pos end-pos chars-forward-after-hit maybe-beginning-of-line)
               (if (< position separator-pos)
                   (progn
                     (goto-char position)
                     (expand-abbrev))
                   (goto-char start-pos))
               (funcall maybe-beginning-of-line)
               (if (funcall search-fun ":" end-pos t)
                   (progn
                     (forward-char chars-forward-after-hit)
                     (end-of-line))
                   (message-goto-body))))
        (if back
            (goto-to-header 'search-backward separator-pos (point-min) 2 'beginning-of-line)
            (goto-to-header 'search-forward (point-min) separator-pos 1 'do-nothing))))))


Don't put spaces between openning or closing parentheses (you may put a
space between a closing and an opening one).  In general use paredit to
edit lisp code.

In general, try to avoid setq, you can only write better code if you can
avoid setq or setf.  Of course, setf is often needed and useful too, you
have to know when ;-)  But a (let (var) (setq var expr)) is almost never
a good expression.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.  
You know you've been lisping too long when you see a recent picture of George 
Lucas and think "Wait, I thought John McCarthy was dead!" -- Dalek_Baldwin


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-15 12:58 ` Pascal J. Bourguignon
@ 2013-06-15 17:02   ` Emanuel Berg
  2013-06-15 18:22     ` Pascal J. Bourguignon
  0 siblings, 1 reply; 10+ messages in thread
From: Emanuel Berg @ 2013-06-15 17:02 UTC (permalink / raw)
  To: help-gnu-emacs

"Pascal J. Bourguignon" <pjb@informatimago.com> writes:

First, thanks *a lot*, however, your feedback is above me, I must
admit. Perhaps, you can elaborate the four points below a bit? Or
perhaps point me to related material?

> I would factorize out the body ...
>
> Don't put spaces between openning or closing parentheses (you
> may put a space between a closing and an opening one).
>
> In general use paredit ...
>
> In general, try to avoid setq, you can only write better code if
> you can avoid setq or setf.  Of course, setf is often needed and
> useful too, you have to know when ;-) But a (let (var) (setq var
> expr)) is almost never a good expression.

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-15 17:02   ` Emanuel Berg
@ 2013-06-15 18:22     ` Pascal J. Bourguignon
  2013-06-18 22:17       ` Emanuel Berg
  0 siblings, 1 reply; 10+ messages in thread
From: Pascal J. Bourguignon @ 2013-06-15 18:22 UTC (permalink / raw)
  To: help-gnu-emacs

Emanuel Berg <embe8573@student.uu.se> writes:

> "Pascal J. Bourguignon" <pjb@informatimago.com> writes:
>
> First, thanks *a lot*, however, your feedback is above me, I must
> admit. Perhaps, you can elaborate the four points below a bit? Or
> perhaps point me to related material?
>
>> I would factorize out the body ...

This is what I've done in the code I included in my message.  Now, at
first the local function was named body, but then it's good also to try
to give more meaningful names to functions, even if they are local
functions.

Now, the first thing is that in simple cases, you could just use let:


Instead of:

    (let (color)
      (if prefixp
          (setf color "red")
          (setf color "blue"))
      (set-foreground-color color)
      (set-cursor-color color))

write:
    
    (let ((color (if prefixp "red" "blue")))
      (set-foreground-color color)
      (set-cursor-color color))

but in your case, you have a lot of variables that depend on the same
condition, so it would be awkward to repeat it in all initialization
expressions.


Now one thing is that let is equivalent to an anonymous function call
(see: http://home.pipeline.com/~hbaker1/MetaCircular.html )


    (let ((a e1)
          (b e2)
          (c e3))
       (do-something-with a b c)
       (and-something-with b c))

<=>

    ((lambda (a b c)
       (do-something-with a b c)
       (and-something-with b c))
     e1 e2 e3)


Of course, we could just give a name to the function, and call it:

    (defun body (a b c)
       (do-something-with a b c)
       (and-something-with b c))

    (body e1 e2 e3)


or:

    (if conditionp
       (body e11 e21 e31)
       (body e12 e22 e32))

But since your 'body' function is quite specific, there's no reason to
give it a global name.  Hence using flet, to give it a local name.


>> Don't put spaces between openning or closing parentheses (you
>> may put a space between a closing and an opening one).

Have a look at:

http://labs.ariel-networks.com/cl-style-guide.html
http://mumble.net/~campbell/scheme/style.txt
http://google-styleguide.googlecode.com/svn/trunk/lispguide.xml


>> In general use paredit ...

It lets you mostly ignore those style questions, since emacs does almost
all the work for you.

http://www.emacswiki.org/emacs/ParEdit
http://www.emacswiki.org/emacs/PareditCheatsheet
http://mumble.net/~campbell/emacs/paredit.el



>> In general, try to avoid setq, you can only write better code if
>> you can avoid setq or setf.  Of course, setf is often needed and
>> useful too, you have to know when ;-) But a (let (var) (setq var
>> expr)) is almost never a good expression.

setf does all that setq does, so you can just always use setf.

and you cannot do that with setq:

    (let ((x (cons 1 2)))
       (setf (car x) 42) 
       x)
    --> (42 . 2)

this is equivalent to:

    (let ((x (cons 1 2)))
       (rplaca x 42) 
       x)
    --> (42 . 2)


But setf is an operator that mutates variables or data objects.  Of
course, the purpose of an editor is to mutate the state of a buffer, so
we're quite far from functional programming.  Nonetheless, if you write
your emacs lisp code with a mostly functional programming style, it will
be good, since this has a lot of advantages:

http://www.emacswiki.org/emacs/FunctionalProgramming
http://c2.com/cgi/wiki?AdvantagesOfFunctionalProgramming
http://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.  
You know you've been lisping too long when you see a recent picture of George 
Lucas and think "Wait, I thought John McCarthy was dead!" -- Dalek_Baldwin


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-15 18:22     ` Pascal J. Bourguignon
@ 2013-06-18 22:17       ` Emanuel Berg
  2013-06-19  0:30         ` Emanuel Berg
  0 siblings, 1 reply; 10+ messages in thread
From: Emanuel Berg @ 2013-06-18 22:17 UTC (permalink / raw)
  To: help-gnu-emacs

Did I correctly boil it down to:

1) Don't use setq
2) Don't use let let unless you complete the name-value
association (i.e., don't set it up to be assigned later)

(As for style, I haven't got around to that, will do. I *think* I
picked up mine mostly from a book called "The Land of Lisp".)

What do you think of:

;; separator
(set-variable 'mail-header-separator "---")
(set-face-attribute 'message-separator nil :foreground "black")

(defun do-nothing () "Do nothing." () )
(defun iterate-header (separator-pos
                       search-fun
                       start-pos end-pos
                       chars-forward-after-hit
                       maybe-beginning-of-line)
  "Unless BACK, go to the next header input field:
either on the same line as the present point,
or the next header below.
If the field has a string, put point to the string's right;
if the field is empty, put point so that typing will set the header,
without any prior cursor movement.
If you move from a header which has data, that data is expanded if
found to be an `abbrev-mode' abbreviation (possibly setup in
~/.mailrc), without need for a whitespace.
If there are no headers left, `message-goto-body';
if already in the body, goto the topmost header."
  (interactive)
  (let ((position (point)))
    (if (< position separator-pos)
        (progn
          (goto-char position)
          (expand-abbrev) )
      (goto-char start-pos) )
    (funcall maybe-beginning-of-line)
    (if (not (funcall search-fun ":" end-pos t))
        (message-goto-body)
      (progn
        (forward-char chars-forward-after-hit)
        (end-of-line) ))))

(defun get-separator-pos ()
  "Get the position of `mail-header-separator'."
  (save-excursion
    (goto-char (point-min))
    (search-forward mail-header-separator)
    (point) ))

(defun iterate-header-back ()
  "See `iterate-header'."
  (interactive)
  (let ((separator-pos (get-separator-pos)))
    (iterate-header
     separator-pos
     'search-backward
     separator-pos (point-min)
     2
     'beginning-of-line) ))
(defun iterate-header-next ()
  "See `iterate-header'."
  (interactive)
  (let ((separator-pos (get-separator-pos)))
    (iterate-header
     separator-pos
     'search-forward
     (point-min) separator-pos
     1
     'do-nothing) ))

(define-key message-mode-map (kbd "TAB") 'iterate-header-next)
(define-key message-mode-map (kbd "<backtab>") 'iterate-header-back)

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-18 22:17       ` Emanuel Berg
@ 2013-06-19  0:30         ` Emanuel Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Emanuel Berg @ 2013-06-19  0:30 UTC (permalink / raw)
  To: help-gnu-emacs

Wow, I found a huge bug!

The whole search-and-skip is based on the position of the
separator - but it doesn't take into account, that when you type
(fill in the headers), that position changes! How embarrassing...

I guess I have to determine the position of "---" before every new
search, unless the buffer hasn't been changed.

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-15  4:00 Moving between headers in message-mode Emanuel Berg
  2013-06-15 12:58 ` Pascal J. Bourguignon
@ 2013-06-19 15:02 ` Stefan Monnier
  2013-06-20  9:32   ` Emanuel Berg
  1 sibling, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2013-06-19 15:02 UTC (permalink / raw)
  To: help-gnu-emacs

> (setq mail-header-separator "---")

Other than Pascal's recommendations, I'd recommend you simply use
`rfc822-goto-eoh' to find the end of the header.


        Stefan


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-19 15:02 ` Stefan Monnier
@ 2013-06-20  9:32   ` Emanuel Berg
  2013-06-20 13:16     ` Stefan Monnier
       [not found]     ` <mailman.2075.1371734198.22516.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 10+ messages in thread
From: Emanuel Berg @ 2013-06-20  9:32 UTC (permalink / raw)
  To: help-gnu-emacs

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Other than Pascal's recommendations, I'd recommend you simply
> use `rfc822-goto-eoh' to find the end of the header.

Hihi, "simply" this, "simply" that - clearly, I didn't know about
that function. But thanks, that's a huge improvement!

But, the prefix - rfc822 - and the help section

    "This function obeys RFC822."

- why did they think this to be so important, they actually filed
a RFC, and not only that, the implementers (the writers of
`simple.el') found it equally important, so they even put it as a
prefix in the function *name*?

Can I browse those RFCs somehow from Emacs?

Does the numbering follow some system (like "e-mail stuff between
700 and 900") or is it just a unique identifier?

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
  2013-06-20  9:32   ` Emanuel Berg
@ 2013-06-20 13:16     ` Stefan Monnier
       [not found]     ` <mailman.2075.1371734198.22516.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 10+ messages in thread
From: Stefan Monnier @ 2013-06-20 13:16 UTC (permalink / raw)
  To: help-gnu-emacs

> - why did they think this to be so important, they actually filed
> a RFC, and not only that, the implementers (the writers of
> `simple.el') found it equally important, so they even put it as a
> prefix in the function *name*?

https://www.ietf.org/rfc.html

> Can I browse those RFCs somehow from Emacs?

http://www.emacswiki.org/emacs/RFC


        Stefan




^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: Moving between headers in message-mode
       [not found]     ` <mailman.2075.1371734198.22516.help-gnu-emacs@gnu.org>
@ 2013-06-20 18:17       ` Emanuel Berg
  0 siblings, 0 replies; 10+ messages in thread
From: Emanuel Berg @ 2013-06-20 18:17 UTC (permalink / raw)
  To: help-gnu-emacs

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> - why did they think this to be so important, they actually
>> filed a RFC, and not only that, the implementers (the writers
>> of `simple.el') found it equally important, so they even put it
>> as a prefix in the function *name*?
>
> https://www.ietf.org/rfc.html

"Standard for the Format of ARPA Internet Text Messages"
- 1982 (obsoleted by RFC 2822)

:)

-- 
Emanuel Berg - programmer (hire me! CV below)
computer projects: http://user.it.uu.se/~embe8573
internet activity: http://home.student.uu.se/embe8573


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-06-20 18:17 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-15  4:00 Moving between headers in message-mode Emanuel Berg
2013-06-15 12:58 ` Pascal J. Bourguignon
2013-06-15 17:02   ` Emanuel Berg
2013-06-15 18:22     ` Pascal J. Bourguignon
2013-06-18 22:17       ` Emanuel Berg
2013-06-19  0:30         ` Emanuel Berg
2013-06-19 15:02 ` Stefan Monnier
2013-06-20  9:32   ` Emanuel Berg
2013-06-20 13:16     ` Stefan Monnier
     [not found]     ` <mailman.2075.1371734198.22516.help-gnu-emacs@gnu.org>
2013-06-20 18:17       ` Emanuel Berg

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.