From: nj104@cus.cam.ac.uk (Neil Jerram)
Newsgroups: gnu.emacs.sources
Subject: linenumbers.el compatible with mode-line-format.el
Date: 7 Jan 93 18:02:41 GMT
Distribution: gnu
Organization: U of Cambridge, England

Yet another revision of linenumbers.el, I'm afraid, prompted by
incompatibility with mode-line-format.el (which does horrible things
to the variable mode-line-buffer-identification).  It now works by
inserting a new entry in mode-line-format itself.

Hope it's useful for you.

Neil.

;----------------------------------------------------------------------
; linenumbers.el
;
; A mix'n'match of linenumbers.el by Ajay Shekhawat
;              and hscroll.el by Wayne Mesard
;
; OR...
;
; ``If it's acceptable to have 1 second polling for horizontal scroll
;   checking, then why not do line numbers the easy way ?''
;
; Mished and mashed by Neil Jerram <nj104@cus.cam.ac.uk>,
; Monday 21 December 1992.
;
; Wednesday 6 January 1993:
; * Modified considerably so that the claim about
;      (setq-default ln-mode t)
;   is true.
; * Added a new public variable ln-format to allow customisation of
;   the line number display.
; * Renamed most variables and internal functions so they begin
;   with "ln-" rather than "linenumber-".
; * Improved mode-line modification so as to interfere minimally with
;   the representation before linenumbers are switched on.
;   (Try linenumbers in *info* for an example of this.)
; * Improved linenumbers-shutdown so that it switches off linenumbering
;   in all exisiting buffers.  Otherwise you are left with a lingering
;   but meaningless number in your mode-line.
; * Generally tidied up, split isolated bits of functionality
;   (like starting the external process) into their own functions, etc.
;
; Thursday 7 January 1993:
; * Modified to reduce clashing with mode-line-format.el.  The line
;   number string is now inserted as part of the list mode-line-format
;   rather than as part of mode-line-buffer-identification, since the
;   latter tends to get shaken about by, e.g., mode-line-format.el
;   (a package for abbreviating long path-names) and info.el.
;     Another possibility would have been to use the variable
;   global-mode-string (which already exists in mode-line-format for
;   the purposes of customisation), in the same way as time.el does
;   to display the time, load, Mail, etc; but I feel that this moves
;   the line number too far away from the buffer name.
; * Linenumbers mode is now disabled by setting ln-string to ""
;   rather than by redefining the mode-line-format.  This is simpler
;   and cleaner.

;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 1, or (at your option)
;;; any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; The GNU General Public License is available by anonymouse ftp from
;;; prep.ai.mit.edu in pub/gnu/COPYING.  Alternately, you can write to
;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
;;; USA.

(provide 'linenumbers)

; ----------------
; Public variables
; ----------------

(defvar ln-poll-period "1"
  "*Interval between checking the current line number (in seconds).
If nil, it will test continuously (but this is not recommended, 
since it will slow down your machine and annoy Emacs).")

(defvar ln-mode nil 
  "*Whether ln-mode is enabled for the current buffer.
Ordinarily set indirectly (via \\[linenumbers]).  However,
   (setq-default ln-mode t)
will put buffers in linenumbers mode by default.
Automatically becomes local when set.")

(defvar ln-format " l.%d"
  "*A format string describing the presentation of the line number.
The \"%d\" should be included somewhere in this string: it stands for 
the line number itself.")

; As an example of alternative formats, you might write
;  (setq ln-format "-= line %d =-")
; in your `.emacs' file after the instruction to load in the lisp code.
; The code as it stands does not allow the format to be different in
; different buffers, but you can achieve this if you want it by adding
;  (make-variable-buffer-local 'ln-format)
; in your `.emacs' file.
;   Hard cases might want to use %o or %x instead of %d.
;   Changes to ln-format will not carry into other buffers until they
; become active (even 'though they may be visible in another window).
; This could be remedied, by making ln-filter cycle through all existing
; buffers every time it gets a signal from "Wakeup!", but I don't
; really think it's worth it.

; ----------------
; Public functions
; ----------------

(defun linenumbers (&optional onoff)
  "Toggle linenumbers mode in the current buffer.
With arg, turn linenumbers mode on if arg is positive, off otherwise."
  (interactive "P")
  (setq ln-mode (if onoff
		    (> (prefix-numeric-value onoff) 0)
		  (not ln-mode)))
  (or ln-mode
      (setq ln-string ""))
  (and ln-mode
       (null ln-process)
       (ln-start-process)))

(defun linenumbers-shutdown ()
  "Disable linenumbers mode in all buffers, and terminate the linenumbers subprocess.
This command is an \"emergency switch\" for use if the subprocess starts
hogging up too many system resources."
  (interactive)
  (if (processp ln-process)
      (progn
	(set-process-filter ln-process nil)
	(set-process-sentinel ln-process nil)
	(if (eq 'run (process-status ln-process)) 
	    (kill-process ln-process))))
  (setq ln-process nil)
  (let* ((buffers (buffer-list))
	 (i (length buffers)))
    (while (>= (setq i (1- i)) 0)
      (set-buffer (nth i buffers))
      (linenumbers -1))))

; ---------
; Internals
; ---------

(defvar ln-string nil
  "String printed in the mode line describing the current line number.")

(defvar ln-process nil
  "Variable holding the linenumbers process object.")

(defvar ln-initialised nil
  "A variable which is t once local variables have been set up.")

(defun ln-initialise ()
  "Sets up local variables and their initial values."
  (make-variable-buffer-local 'ln-mode)
  (make-variable-buffer-local 'ln-string)
  (setq ln-initialised t))

(defun ln-modify-mode-line-format ()
  "Modify the mode-line-format to insert the line number after
mode-line-buffer-identification."
  (or (memq 'ln-string mode-line-format)
      (setq mode-line-format
	    (append (reverse (memq 'mode-line-buffer-identification
				   (reverse mode-line-format)))
		    '(ln-string)
		    (cdr (memq 'mode-line-buffer-identification 
			       mode-line-format))))))

(defun ln-start-process ()
  "Starts the \"wakeup\" process for linenumbers mode."
  (setq ln-process (start-process "linenumbers" nil
				  (concat exec-directory "wakeup")
				  (or ln-poll-period "0")))
  (set-process-sentinel ln-process 'ln-sentinel)
  (set-process-filter ln-process 'ln-filter)
  (process-kill-without-query ln-process))

(defun which-line ()
  "RETURN the current line number (in the buffer) of point."
  (save-restriction
    (widen)
    (save-excursion
      (beginning-of-line)
      (1+ (count-lines 1 (point))))))

(defun ln-filter (ignore ignore)
  ;; Don't even bother if we're not in the mode.
  (if ln-mode
      (progn
	(or ln-initialised (ln-initialise))
	(setq ln-string (format ln-format (which-line)))
	(ln-modify-mode-line-format))))

(defun ln-sentinel (ignore reason)
  (linenumbers-shutdown)
  (error "Whoa: the linenumbers process died unexpectedly: %s." reason))

; --------------------------
; Start the external process
; --------------------------

(or ln-process
    (ln-start-process))

; ---
; End
; ---
;----------------------------------------------------------------------
Newsgroups: gnu.emacs.sources