tags:

views:

270

answers:

4

I use emacs to edit everything. On some of my LateX documents I would like to automatically disable auto-fill mode when I am editing tables and code. Basically, I'd like to have two tags, like:

   %%% BEGIN NO FILL
   %%% END NO FILL

and nothing between them will be autofilled.

Can anybody think of a way to do this? I would need to figure out whether or not the cursor is inside the region and then have to toggle the mode, and would need to do that every time the cursor moved. Or is there a better way to do it?

+1  A: 

If you are using AUCTeX (you should be) then you may want to check out LaTeX-indent-environment-list. Adding an environment to this variable will make it so that (among other things) M-q doesn't refill the paragraph. Unfortunately it doesn't seem work for auto-fill-mode. The following largely untested code added to LaTeX-mode-hook might do what you want.

(setq auto-fill-function
  (lambda ()
    (unless (> (save-excursion (or (search-backward "%%% BEGIN NO FILL" (point-min) t) 0))
               (save-excursion (or (search-backward "%%% END NO FILL"   (point-min) t) 0)))
      (do-auto-fill))))

It's very stupid and inefficient, but seems to be fast enough on my machine. It doesn't allow nesting, and requires that you manually mark up all sections that you don't want filled. What I am thinking of adding to my .emacs (until I read your question I didn't realize how much this bugged me) is below which keys off of the current environment so there is no need for special markup (though it only looks at the innermost environment (I'm not sure how much of a problem that will cause in practice)). Combining the two is left as an exercise to the interested reader.

;; You can use the following to unset the variables and play around with them
;; (makunbound 'auto-fill-ignore-environments)
;; (makunbound 'auto-fill-ignore-environments-regexp)
(defcustom auto-fill-ignore-environments
  (mapcar 'car LaTeX-indent-environment-list)
  "List of environments for which `auto-fill-mode' should be
disabled.  Used to generate `auto-fill-ignore-environments-regexp'."
  :type '(sexp)
  )
(defcustom auto-fill-ignore-environments-regexp
  (regexp-opt auto-fill-ignore-environments)
  "Regexp matching LaTeX environments for which `auto-fill-mode'
should be disabled.  If not set, automatically generated from
`auto-fill-ignore-environments'"
  :type '(string)
  :set-after '(auto-fill-ignore-environments)
  )
(add-hook 'LaTeX-mode-hook
          (lambda ()
            (setq auto-fill-function
                  (lambda ()
                    (unless (string-match auto-fill-ignore-environments-regexp
                                          (LaTeX-current-environment))
                      (do-auto-fill))))))

I have never used defcustom before so I'm sure that part could be improved quite a bit.

Ivan Andrus
Thanks. I'm just using the tex.el mode that's built into MacOS. I guess I'll need to find out about AUCtex. Your system is inefficient but seems clever. Nesting is not important. I bet we could have it toggle auto-fill on and off with cursor up and down...
vy32
Yes, you could probably parse the file and add text properties or overlays with point-left and point-entered properties. One difficulty with this is that you have to keep the text properties in sync which can be a pain. I know some folding modes do something like this.Or you could advise the motion commands, but there are tons of them, and I think it would end up being run more often then when you type an autofill character e.g. space. Perhaps you could get by with advising only certain motion commands.
Ivan Andrus
Is there a general way to advise on the motion commands, or on motion? I came up with a solution that just rebinds ^p and ^n.
vy32
There doesn't appear to be. For example table.el uses overlays to trigger table-point-entered-cell-hook. If forward and backward-line are the only things you use then it's probably fine.
Ivan Andrus
A: 

Alternately, you can turn off auto-fill-mode and use M-q to format paragraphs. I don't love auto-fill's jumpiness so I use this in every mode.

rgiar
A: 

Got it. Check this out:

(defun in-no-auto-fill-region ()
  (> (save-excursion (or (search-backward "%%% BEGIN NO FILL" (point-min) t) 0))
     (save-excursion (or (search-backward "%%% END NO FILL"   (point-min) t) 0))
     ))

(defun previous-line-checking-auto-fill (arg)
  (interactive "P")
  (previous-line arg)
  (if (in-no-auto-fill-region)
      (turn-off-auto-fill)
    (turn-on-auto-fill)))

(defun next-line-checking-auto-fill (arg)
  (interactive "P")
  (next-line arg)
  (if (in-no-auto-fill-region)
      (turn-off-auto-fill)
    (turn-on-auto-fill)))

(add-hook 'LaTeX-mode-hook
      '(lambda nil
     (local-set-key "C-p" 'previous-line-checking-auto-fill)
     (local-set-key "C-n" 'next-line-checking-auto-fill)
     (auto-fill-mode 1)
     ))
vy32
A: 

If you want to go the route of advising/redefining all the movement functions, this should help:

(defmacro movement-advice (func)
  `(defadvice ,func (after ; run this after the original function is done (and point has moved)
                     ;; Give it a unique name
                     ,(intern (concat (symbol-name func) "-auto-fill-auto-off"))
                     ;; Hopefully this satisfies the arguments of any function we can throw at it
                     (&rest args)
                     ;; turn it on
                     activate
                     )
     "Turn auto-fill-mode on or off automatically."
     (auto-fill-mode (not (in-no-auto-fill-region)))))

(dolist (func '(next-line
                previous-line
                forward-paragraph
                backward-paragraph
                mouse-drag-region
                ;; Whatever you use
                ))
  (eval `(movement-advice ,func)))
Ivan Andrus
Huh. I need to learn about this advice stuff. Thanks.
vy32
Hm. Anyway to restrict that to LaTeX mode, and not every mode?
vy32
Strangely, this doesn't work: (auto-fill-mode (not (in-no-auto-fill-region)))You need this: (if (in-no-auto-fill-region) (turn-off-auto-fill) (turn-on-auto-fill)))I have no idea why.
vy32
Hmm. I don't know of anyway to turn on advice only for a given mode. I guess it might be easier to rebind everything in LaTeX-mode. You can use `where-is-internal` to override a command wherever it might be bound. I thought there was a function to do that, but I can't find it now.And that is weird that auto-fill-mode doesn't work like that. Sorry to mislead you. I guess this is why you should always test things :)
Ivan Andrus