Subject: Re: > toggle binary/text mode of current buffer

From: Don Erway <[email-masked]>
Date: Wed, 26 Mar 1997 09:07:47 -0800

>>>>> "db" == David Biesack <[email-masked]> writes:

 db> suggested:

 db> (defvar binary-mode-distance 500
 db>       "Number of characters to search for CR/LF when looking for a binary file.")

 db> (defun check-buffer-file-type (filename)
 db>   (if (and (looking-at ".*\r\n") ;; It has CR-LF sequence
 db>            ;; and has no LF w/o CR within sight
 db>            (not (re-search-forward "[^\r]\n]" binary-mode-distance t)))
 db>       nil ;; so use text mode
 db>     t))   ;; else use binary mode

This works fine.  However, auto detection still does not work under unix.  I
am running 19.32 on NT, and 19.33 on Solaris.  In the 19.33 solaris version,
there is no file-name-buffer-file-type-alist defined.  So without this
alist, and some code to process it, there is no surprise that it doesn't work.

Is the idea to use winnt.el even when running on unix?

If I load winnt.el into the unix version, it complains that the
set-message-beep function doesn't exist.  But I can always work around that if
this is even the right approach.

Don

---

From: David Biesack <[email-masked]>
Date: Wed, 26 Mar 1997 08:20:33 -0500

> ;;; This examines the actual contents of the loaded file to see if 
> ;;;  it should use text mode or binary:
> (defun check-buffer-file-type (filename)
>   (if (and (looking-at ".*\r\n")		    ;; It has CR-LF sequence
>            (not (search-forward "[^\r]\n]" nil t))) ;; and has no LF w/o CR
>       nil					    ;; so use text mode
>     t))						    ;; else use binary mode

Someone else pointed out that the search-forward should be a
re-search-forward. However, also note that passing nil to the search
will cause inspection of the entire buffer, which is not always
negligible. It might be better to make this a variable as is done in
dos-mode.el

;;;    LCD Archive Entry:
;;;    dos-mode|Andy [email-masked]
;;;    |MSDOS minor mode for GNU Emacs
;;;    |$Date: 93/06/01 19:54:29 $|$Revision: 1.12 $|

which passes (min (point-max) dos-mode-distance) to re-search-forward
where 

    (defvar dos-mode-distance 200
      "Number of characters to search for RETURN when looking for a DOS file.")

to determine if a file is in DOS CR/LF mode.  You can change
dos-mode-distance to 1000 or some other reasonable value in your .emacs

suggested:

(defvar binary-mode-distance 500
      "Number of characters to search for CR/LF when looking for a binary file.")

(defun check-buffer-file-type (filename)
  (if (and (looking-at ".*\r\n") ;; It has CR-LF sequence
           ;; and has no LF w/o CR within sight
           (not (re-search-forward "[^\r]\n]" binary-mode-distance t)))
      nil ;; so use text mode
    t))   ;; else use binary mode

---

From: Kin Cho <[email-masked]>
Date: Tue, 25 Mar 1997 14:29:49 -0800

Thanks, this is good!

A real solution as compared to the workarounds that came before.
If only this works in UNIX as well!

Please put it in the FAQ, or even better, integrate it with main line code.

-kin

p.s., this is my mod:
	      (list (cons "" 'check-buffer-file-type))))

;;; Associate the universal match regexp "" with the
;;; function check-buffer-file-type, so any file will be
;;; examined to automatically select the appropriate mode.
;;; Add this check only after known filename patterns are
;;; treated the way they should be.  (That's why we append
;;; to the list, instead of replacing it).  You might want
;;; to use more more restrictive pattern(s) for doing this
;;; check.
(setq file-name-buffer-file-type-alist
      (append file-name-buffer-file-type-alist
	      (list (cons "" 'check-buffer-file-type))))
;;; This examines the actual contents of the loaded file to see if 
;;;  it should use text mode or binary:
(defun check-buffer-file-type (filename)
  (if (and (looking-at ".*\r\n")		    ;; It has CR-LF sequence
	   (not (search-forward "[^\r]\n]" nil t))) ;; and has no LF w/o CR
      nil					    ;; so use text mode
    t))						    ;; else use binary mode

---

From: Geoff Odhner <[email-masked]>
Date: Sun, 23 Mar 1997 11:34:55 -0500

Don Erway wrote:
> Finally, it needs an auto option, to make it possible to
> automatically go into text mode if the content is strictly
> text and crlfs are already present in a file.  This should
> not be based on file name extensions or file systems, but
> only on file content.

I have written a few more bits of code that help automate
binary/text mode selection.  This approach is possible due
to the Geoff Voelker's foresight in designing the
infrastructure to be configurable in this way.  Thanks,
Geoff.

	      (cons "" 'check-buffer-file-type)))

---

From: Don Erway <[email-masked]>
Date: Sat, 22 Mar 1997 12:55:31 -0800

This is good.

I can now happily make everything binary by default, and use your toggle
funciton for the few cases it is really needed.  This is better than using
crypt's DOS mode, because it is faster.

Now, if only it would work in unix emacs, we could completely share files
either way.

Finally, it needs an auto option, to make it possible to automatically go into
text mode if the content is strictly text and crlfs are already present in a
file.  This should not be based on file name extensions or file systems, but
only on file content.

Thanks for the useful hack.

Don

	Don Erway			[email-masked]
	NDC Systems			818-939-3847
	5314 N. Irwindale Ave		Fax:939-3870
	Irwindale, CA, 91706

---

From: Geoff Odhner <[email-masked]>
Date: Sat, 22 Mar 1997 15:22:48 -0500

Kin Cho wrote:
> 
> Is that a function that does this?
> Trying to work around yet another PC<->UNIX integration problem.
> 
> Thanks.
> 
> -kin

I have yet another version of my toggle-buffer-file-type function.
This one updates the status bar, which is necessary if you bind it 
to a key.  

-Geoff

;;;  If you have loaded a file as binary that actually has the ^M's in it,
;;;  then switching to text mode will remove them in the buffer.  Of course
;;;  now that it's in text mode, it will save with the ^M's inserted.
;;;  Switching to binary mode does NOT have a reverse effect.  If you want
;;;  to disable that change on entering text mode, then use a negative
;;;  prefix argument, as described below.

;;;  A prefix argument will force the mode change in a particular
;;;  direction.  A positive prefix argument forces it to binary.  A zero
;;;  prefix argument forces text mode allowing the removal of ^M's (only
;;;  preceding ^J's).  A negative prefix argument forces text mode
;;;  disallowing the removal of ^M's.  

;;;  When the mode is changed the state of modification of the buffer is
;;;  preserved, even if the ^M's are removed.

(defun toggle-buffer-file-type (arg)
  "Alternate value of buffer-file-type"
  (interactive "P")
  (let ((old buffer-file-type)
	(mod (buffer-modified-p)))
    (setq buffer-file-type
	  (if arg (>= arg 1)
	    (not buffer-file-type)))
    (if (and old
	     (not buffer-file-type)
	     (or (not arg)
		 (> arg -2)))
	(save-excursion
	  (beginning-of-buffer)
	  (while (search-forward "\r\n" nil t)
	    (replace-match "\n" nil t))
	  (set-buffer-modified-p mod))))
  (force-mode-line-update))

;;;  Here's my personal selection for a key binding for this function:
(global-set-key [?\A-t]		'toggle-buffer-file-type)