unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Extra info in modeline (tip and questions)
@ 2009-04-14 14:03 Decebal
  2009-04-14 15:54 ` Nikolaj Schumacher
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Decebal @ 2009-04-14 14:03 UTC (permalink / raw)
  To: help-gnu-emacs

I would like to have some more info in my modeline. Default the number
of lines and the number of characters of the current buffer and in
text-mode also the number of words. I made something that is easy to
extend. I defined a vector whith the possible things to display and
pro buffer there is a vector with what to display.
The default is only lines and characters. This is done with:
    ;;; default lines and chars are displayed
    ;;; for nothing use nil
    (defvar mode-line-types
      (vector "lines" "chars")
      "*Types to dsiplay in the modeline."
      )
    (make-variable-buffer-local 'mode-line-types)

To display also words in text-mode, I use:
    (dolist (hook '(text-mode-hook))
      (add-hook hook (lambda ()
                       (setq mode-line-types (vector "lines" "words"
"chars"))
                       )
                )
      )

At the end of the post is the code.
I have a few questions:
- Can the code be written better? (I am relative new to elisp.)
- I tried to generalize. For example there is a function buffer-count-
words, which I would like to use also on a region of the buffer. But
when I call it interactively, it does not return anything. What do I
need to change?
- I defined two ways for counting words ("\\w+" and "[[:word:]\-]+").
Anyone a good idea for extending? (Almost every system counts words
diferently. It would be nice to have a mode which would give the same
count as the program that the other side is using. ;-] )

Ideas to make it better are offcourse welcome.

The code:
    ;;; includes
    (require 'cl)

    ;;; definitions
    (defstruct
      (mode-line-struct
       (:constructor nil)
       (:constructor new-mode-line-struct (type description display
function))
       )
      (type        nil :read-only t)
      (description nil :read-only t)
      (display     nil :read-only t)
      (function    nil :read-only t)
      )

    ;;; variables
    (setq mode-line-array
          (vector
           (new-mode-line-struct
            "chars"
            "Display number of chars"
            "C"
            'buffer-count-chars
            )
           (new-mode-line-struct
            "functions"
            "Display number of functions"
            "F"
            'buffer-count-functions
            )
           (new-mode-line-struct
            "lines"
            "Display number of lines"
            "L"
            'buffer-count-lines
            )
           (new-mode-line-struct
            "words"
            "Display number of words"
            "W"
            'buffer-count-words
            )
           )
          )

    (defvar buffer-mode-line
      nil
      "*Extension of modeline in the buffer."
      )

    (defvar word-type
      nil
      "*Type of word."
      )
    (make-variable-buffer-local 'word-type)

    ;;; default lines and chars are displayed
    ;;; for nothing use nil
    (defvar mode-line-types
      (vector "lines" "chars")
      "*Types to dsiplay in the modeline."
      )
    (make-variable-buffer-local 'mode-line-types)

    ;;; functions
    (defun buffer-count(expression &optional start end)
      (interactive "sExpression: \nr")
      (setq start (or start (point-min)))
      (setq end   (or end   (point-max)))
      (how-many expression start end)
      )

    (defun buffer-count-chars(&optional start end)
      (interactive "r")
      (number-to-string (buffer-count ".\\|\n" start end))
      )

    (defun buffer-count-functions(&optional start end)
      (interactive "r")
      (number-to-string (buffer-count "^(defun " start end))
      )

    (defun buffer-count-lines(&optional start end)
      (interactive "r")
      (number-to-string
       (+ (buffer-count "\n" start end) 1)
       )
      )

    (defun buffer-count-words(&optional start end)
      (interactive "r")
      (let ((regexp "\\w+"))
        (cond
         ((equal word-type "type1")
          (setq regexp "[[:word:]\-]+")
          )
         )
        (number-to-string (buffer-count regexp start end))
        )
      )

    (defun buffer-mode-line-extra()
      (let ((i         0)
            (mode-line " ")
            (total     (length mode-line-types))
            )
        (while (< i total)
          (setq mode-line
                (concat mode-line (get-mode-line-field (aref mode-line-
types i)))
                )
          (incf i)
          )
        mode-line
        )
      )

    (defun get-mode-line-field(type)
      (let ((i     0)
            (field (format "*%s*" type))
            (total (length mode-line-array))
            )
        (catch 'break
          (while (< i total)
            (if (equal type (mode-line-struct-type (aref mode-line-
array i)))
                (progn (setq field
                             (format "%s: %s "
                                     (mode-line-struct-display (aref
mode-line-array i))
                                     (funcall (mode-line-struct-
function (aref mode-line-array i)))
                                     )
                             )
                       (throw 'break nil)
                       )
              )
            (incf i)
            )
          )
        field
        )
      )

    (defun buffer-update-mode-line()
      (setq buffer-mode-line (buffer-mode-line-extra))
      (force-mode-line-update)
      )

    (unless buffer-mode-line
      (run-with-idle-timer 1 t 'buffer-update-mode-line)
      (buffer-update-mode-line)
      )

    (unless (memq 'buffer-mode-line global-mode-string)
      (setq global-mode-string
    	(append global-mode-string
    		'(" " buffer-mode-line)
    		)
    	)
      )


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

* Re: Extra info in modeline (tip and questions)
  2009-04-14 14:03 Extra info in modeline (tip and questions) Decebal
@ 2009-04-14 15:54 ` Nikolaj Schumacher
       [not found] ` <mailman.5329.1239724470.31690.help-gnu-emacs@gnu.org>
  2009-04-15 11:06 ` Decebal
  2 siblings, 0 replies; 11+ messages in thread
From: Nikolaj Schumacher @ 2009-04-14 15:54 UTC (permalink / raw)
  To: Decebal; +Cc: help-gnu-emacs

Decebal <CLDWesterhof@gmail.com> wrote:

> At the end of the post is the code.
> I have a few questions:
> - Can the code be written better? (I am relative new to elisp.)

It can be "written" "better" by not giving closing parentheses their own
line.  It's a fairly accepted convention, so I'd suggest to warm up to
it. ;)

Also there are alternatives to updating the mode-line from a timer.
The mode-line supports a special :eval form with functions that are
called automatically, or you might update the values in
`after-change-functions'.

> - I tried to generalize. For example there is a function buffer-count-
> words, which I would like to use also on a region of the buffer. But
> when I call it interactively, it does not return anything. What do I
> need to change?

You never call anything interactively for its return value.  You should
pass the region points (region-beginning) and (region-end) as
parameters when (region-active-p), if that's what you want to do...


regards,
Nikolaj Schumacher




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

* Re: Extra info in modeline (tip and questions)
       [not found] ` <mailman.5329.1239724470.31690.help-gnu-emacs@gnu.org>
@ 2009-04-15  5:53   ` Decebal
  2009-04-15 13:14     ` Nikolaj Schumacher
       [not found]     ` <mailman.5377.1239801271.31690.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 11+ messages in thread
From: Decebal @ 2009-04-15  5:53 UTC (permalink / raw)
  To: help-gnu-emacs

On Apr 14, 5:54 pm, Nikolaj Schumacher <m...@nschum.de> wrote:
> Decebal <CLDWester...@gmail.com> wrote:
> > At the end of the post is the code.
> > I have a few questions:
> > - Can the code be written better? (I am relative new to elisp.)
>
> It can be "written" "better" by not giving closing parentheses their own
> line.  It's a fairly accepted convention, so I'd suggest to warm up to
> it. ;)

I meant more codewise. I expect that I did not use the best code, not
knowing the language very well.
The reason I put the closing parentheses on its own line, is that I
find that more readable. I would even prefer:
    (defun a-function()
      .
      .
      .
    )
above:
    (defun a-function()
      .
      .
      .
      )
But maybe I should conform to the standard.


> Also there are alternatives to updating the mode-line from a timer.
> The mode-line supports a special :eval form with functions that are
> called automatically, or you might update the values in
> `after-change-functions'.

Do you have any good pointers?


> > - I tried to generalize. For example there is a function buffer-count-
> > words, which I would like to use also on a region of the buffer. But
> > when I call it interactively, it does not return anything. What do I
> > need to change?
>
> You never call anything interactively for its return value.  You should
> pass the region points (region-beginning) and (region-end) as
> parameters when (region-active-p), if that's what you want to do...

What I would like is that when I call the function interactively, that
instead of returning the value, the value is displayed in the
minibuffer. For this I need to know if the function is called
interactively. If that is the case, I should do:
    (message <return-value>)
Is there a way to know if the function called interactively?

I also have another function where I need to input a boolean value
interactively. At the moment I am doing this with n and use 0 for
false and every other value for true. Is there a better way?


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

* Re: Extra info in modeline (tip and questions)
  2009-04-14 14:03 Extra info in modeline (tip and questions) Decebal
  2009-04-14 15:54 ` Nikolaj Schumacher
       [not found] ` <mailman.5329.1239724470.31690.help-gnu-emacs@gnu.org>
@ 2009-04-15 11:06 ` Decebal
  2009-04-15 13:23   ` Nikolaj Schumacher
       [not found]   ` <mailman.5379.1239801830.31690.help-gnu-emacs@gnu.org>
  2 siblings, 2 replies; 11+ messages in thread
From: Decebal @ 2009-04-15 11:06 UTC (permalink / raw)
  To: help-gnu-emacs

On 14 apr, 16:03, Decebal <CLDWester...@gmail.com> wrote:
I was not happy with get-mode-line-field. Especially with the
    (catch 'break
I understand that this is the default way to handle a break out of a
loop, but I found it ugly, and I expect it is also expensive. So I
rewrote it in such a way that the catch is not neccesary anymore. I
made it also a little bit more general. I do not need it at the
moment, but I made a function to fetch the struct with the right type.
So I changed:
>     (defun get-mode-line-field(type)
>       (let ((i     0)
>             (field (format "*%s*" type))
>             (total (length mode-line-array))
>             )
>         (catch 'break
>           (while (< i total)
>             (if (equal type (mode-line-struct-type (aref mode-line-
> array i)))
>                 (progn (setq field
>                              (format "%s: %s "
>                                      (mode-line-struct-display (aref
> mode-line-array i))
>                                      (funcall (mode-line-struct-
> function (aref mode-line-array i)))
>                                      )
>                              )
>                        (throw 'break nil)
>                        )
>               )
>             (incf i)
>             )
>           )
>         field
>         )
>       )
into:
    (defun get-mode-line-struct(type)
      (let ((i           0)
            (this-struct nil)
            (not-ready   t)
            (total       (length mode-line-array))
            )
        (while (and not-ready (< i total))
          (if (equal type (mode-line-struct-type (aref mode-line-array
i)))
              (setq this-struct (aref mode-line-array i)
                    not-ready   nil
                    )
            (incf i)
            )
          )
        this-struct
        )
      )

    (defun get-mode-line-field(type)
      (let ((field       (format "*%s*" type))
            (this-struct (get-mode-line-struct type))
            )
        (if this-struct
            (setq field
                  (format "%s: %s "
                          (mode-line-struct-display this-struct)
                          (funcall (mode-line-struct-function this-
struct))
                          )
                  )
          )
        field
        )
      )


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

* Re: Extra info in modeline (tip and questions)
  2009-04-15  5:53   ` Decebal
@ 2009-04-15 13:14     ` Nikolaj Schumacher
       [not found]     ` <mailman.5377.1239801271.31690.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 11+ messages in thread
From: Nikolaj Schumacher @ 2009-04-15 13:14 UTC (permalink / raw)
  To: Decebal; +Cc: help-gnu-emacs

Decebal <CLDWesterhof@gmail.com> wrote:

> The reason I put the closing parentheses on its own line, is that I
> find that more readable. I would even prefer:

It probably is.  I do it in C myself.  But with Lisp you have so many
parentheses that you lose too much vertical space.

The trick is to read the indentation instead of trying to mentally match
parentheses.  Since I got used to that I actually prefer the concise representation.

>> Also there are alternatives to updating the mode-line from a timer.
>> The mode-line supports a special :eval form with functions that are
>> called automatically, or you might update the values in
>> `after-change-functions'.
>
> Do you have any good pointers?

Just C-h v mode-line-format and C-h v after-change-functions.

For an :eval example see:
http://nschum.de/src/emacs/window-numbering-mode/
for hooks:
http://www.emacswiki.org/emacs-en/ChangeHook

> What I would like is that when I call the function interactively, that
> instead of returning the value, the value is displayed in the
> minibuffer. For this I need to know if the function is called
> interactively. If that is the case, I should do:
>     (message <return-value>)
> Is there a way to know if the function called interactively?

Well, there is `called-interactively-p', but I would just add another
parameter like this:

(defun test (beg end &optional verbose)
  (interactive "r\nd")
  (when verbose
    (message (buffer-substring beg end))))

> I also have another function where I need to input a boolean value
> interactively. At the moment I am doing this with n and use 0 for
> false and every other value for true. Is there a better way?

You can use `y-or-n-p' or `yes-or-no-p'.  But they don't have
characters in the interactive form.  So you need to do this:

(interactive (list (y-or-n-p "bool: ")))

Often the prefix-arg is perfect for boolean options, too.


regards,
Nikolaj Schumacher




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

* Re: Extra info in modeline (tip and questions)
  2009-04-15 11:06 ` Decebal
@ 2009-04-15 13:23   ` Nikolaj Schumacher
       [not found]   ` <mailman.5379.1239801830.31690.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 11+ messages in thread
From: Nikolaj Schumacher @ 2009-04-15 13:23 UTC (permalink / raw)
  To: Decebal; +Cc: help-gnu-emacs

Decebal <CLDWesterhof@gmail.com> wrote:

> I understand that this is the default way to handle a break out of a
> loop, but I found it ugly, and I expect it is also expensive.

Ugly yes, but not that expensive.  Depending on the list length testing
the additional not-ready variable can even be slower.

If you use CL macros, something can be done about the ugliness, though.
It could be written like this

(defun get-mode-line-struct (type)
  (dotimes (i (length mode-line-array))
    (when (equal type (mode-line-struct-type (aref mode-line-array i)))
      (return (aref mode-line-array i)))))


You're using a vector, probably because you're used to it.  Since you're
not doing random-access, a list would be more "natural" in lisp.

(defun get-mode-line-struct (type)
  (dolist (s mode-line-array)
    (when (equal type (mode-line-struct-type s))
      (return s))))


regards,
Nikolaj Schumacher




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

* Re: Extra info in modeline (tip and questions)
       [not found]   ` <mailman.5379.1239801830.31690.help-gnu-emacs@gnu.org>
@ 2009-04-15 16:13     ` Decebal
  0 siblings, 0 replies; 11+ messages in thread
From: Decebal @ 2009-04-15 16:13 UTC (permalink / raw)
  To: help-gnu-emacs

On 15 apr, 15:23, Nikolaj Schumacher <m...@nschum.de> wrote:
> Decebal <CLDWester...@gmail.com> wrote:
> > I understand that this is the default way to handle a break out of a
> > loop, but I found it ugly, and I expect it is also expensive.
>
> Ugly yes, but not that expensive.  Depending on the list length testing
> the additional not-ready variable can even be slower.

Well, in principal I find neatness off code more important as
performance, so only when the not-ready variable has a to big
performance hit, I would use the catch again.


> If you use CL macros, something can be done about the ugliness, though.
> It could be written like this
>
> (defun get-mode-line-struct (type)
>   (dotimes (i (length mode-line-array))
>     (when (equal type (mode-line-struct-type (aref mode-line-array i)))
>       (return (aref mode-line-array i)))))

I use cl because of the defstruct, so I could use your code, and that
is even more neat and concise.


> You're using a vector, probably because you're used to it.  Since you're
> not doing random-access, a list would be more "natural" in lisp.
>
> (defun get-mode-line-struct (type)
>   (dolist (s mode-line-array)
>     (when (equal type (mode-line-struct-type s))
>       (return s))))

I understood that vectors are much more efficient as lists. That is
why I used them. But your solution with a list is more beautifull, so
I should rewrite for using a list. (Only change mode-line-array to
mode-line-list.)

Thanks for the input. Very usefull.
By the way: anybody found my functionality usefull?


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

* Re: Extra info in modeline (tip and questions)
       [not found]     ` <mailman.5377.1239801271.31690.help-gnu-emacs@gnu.org>
@ 2009-04-28  7:55       ` Decebal
  2009-04-28 10:27         ` Decebal
  2009-04-28  8:04       ` Decebal
  1 sibling, 1 reply; 11+ messages in thread
From: Decebal @ 2009-04-28  7:55 UTC (permalink / raw)
  To: help-gnu-emacs

On 15 apr, 15:14, Nikolaj Schumacher <m...@nschum.de> wrote:
> It probably is.  I do it in C myself.  But with Lisp you have so many
> parentheses that you lose too much vertical space.

I now also put all the parentheses on the same line. I still need a
little bit to get used to it, but at saves a lot off lines. (Up to
25%.)


> > What I would like is that when I call the function interactively, that
> > instead of returning the value, the value is displayed in the
> > minibuffer. For this I need to know if the function is called
> > interactively. If that is the case, I should do:
> >     (message <return-value>)
> > Is there a way to know if the function called interactively?
>
> Well, there is `called-interactively-p', but I would just add another

I changed them to:
    (defun buffer-count(expression &optional start end)
      (interactive "sExpression: \nr")
      (if (equal start end)
          (setq start (point-min)
                end   (point-max))
        (setq start (or start (point-min)))
        (setq end   (or end   (point-max))))
      (let ((ret-val (how-many expression start end)))
        (if (interactive-p)
            (message (format "%d" ret-val))
          ret-val)))

    (defun buffer-count-chars(&optional start end)
      (interactive "r")
      (let ((ret-val (number-to-string (buffer-count ".\\|\n" start
end))))
        (if (interactive-p)
            (message ret-val)
          ret-val)))

    (defun buffer-count-functions(&optional start end)
      (interactive "r")
      (let ((ret-val (number-to-string (buffer-count "^(defun " start
end))))
        (if (interactive-p)
            (message ret-val)
          ret-val)))

    (defun buffer-count-lines(&optional start end)
      (interactive "r")
      (let ((ret-val (number-to-string
                      (+ (buffer-count "\n" start end) 1))))
        (if (interactive-p)
            (message ret-val)
          ret-val)))

    ;;; ### possibillity to give word-type
    (defun buffer-count-words(&optional start end)
      (interactive "r")
      (let ((regexp "\\w+")
            (ret-val))
        (cond
         ((equal word-type "lisp")
          (setq regexp "[[:word:]\-]+")))
        (setq ret-val (number-to-string (buffer-count regexp start
end)))
        (if (interactive-p)
            (message ret-val)
          ret-val)))

The only thing lacking is that when the function is called with C-u
prepended, it should be put at point in the current buffer instead of
in the minibuffer. How would I do that?


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

* Re: Extra info in modeline (tip and questions)
       [not found]     ` <mailman.5377.1239801271.31690.help-gnu-emacs@gnu.org>
  2009-04-28  7:55       ` Decebal
@ 2009-04-28  8:04       ` Decebal
  2009-04-28  8:23         ` Decebal
  1 sibling, 1 reply; 11+ messages in thread
From: Decebal @ 2009-04-28  8:04 UTC (permalink / raw)
  To: help-gnu-emacs

On 15 apr, 15:14, Nikolaj Schumacher <m...@nschum.de> wrote:
> > I also have another function where I need to input a boolean value
> > interactively. At the moment I am doing this with n and use 0 for
> > false and every other value for true. Is there a better way?
>
> You can use `y-or-n-p' or `yes-or-no-p'.  But they don't have
> characters in the interactive form.  So you need to do this:
>
> (interactive (list (y-or-n-p "bool: ")))

I tried this (in a function test), but that gives:
    test: Wrong type argument: stringp, t



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

* Re: Extra info in modeline (tip and questions)
  2009-04-28  8:04       ` Decebal
@ 2009-04-28  8:23         ` Decebal
  0 siblings, 0 replies; 11+ messages in thread
From: Decebal @ 2009-04-28  8:23 UTC (permalink / raw)
  To: help-gnu-emacs

On 28 apr, 10:04, Decebal <CLDWester...@gmail.com> wrote:
> On 15 apr, 15:14, Nikolaj Schumacher <m...@nschum.de> wrote:
>
> > > I also have another function where I need to input a boolean value
> > > interactively. At the moment I am doing this with n and use 0 for
> > > false and every other value for true. Is there a better way?
>
> > You can use `y-or-n-p' or `yes-or-no-p'.  But they don't have
> > characters in the interactive form.  So you need to do this:
>
> > (interactive (list (y-or-n-p "bool: ")))
>
> I tried this (in a function test), but that gives:
>     test: Wrong type argument: stringp, t

The problem was somewhere else in the function. '(interactive (list (y-
or-n-p "bool: ")))' works as it should.

The only problem is that I use more parameters. At the moment I have
in the function:
    (interactive "r\nsHead: \nnKill Region? ")
And the last should be the bool. How would I do that?


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

* Re: Extra info in modeline (tip and questions)
  2009-04-28  7:55       ` Decebal
@ 2009-04-28 10:27         ` Decebal
  0 siblings, 0 replies; 11+ messages in thread
From: Decebal @ 2009-04-28 10:27 UTC (permalink / raw)
  To: help-gnu-emacs

On 28 apr, 09:55, Decebal <CLDWester...@gmail.com> wrote:
> The only thing lacking is that when the function is called with C-u
> prepended, it should be put at point in the current buffer instead of
> in the minibuffer. How would I do that?

I solved that one also. I only found it more usefull to put it in the
kill-ring instead of the current buffer. The function buffer-count-
chars becomes:
    (defun buffer-count-chars(do-yank &optional start end)
      (interactive "P\nr")
      (let ((ret-val (number-to-string (buffer-count nil ".\\|\n"
start end))))
        (buffer-count-exit do-yank (interactive-p) ret-val nil)))

I also defined the function buffer-count-exit (I like DRY):
    (defun buffer-count-exit(do-yank is-interactive ret-val is-number)
      (let ((yank-val))
        (if is-number
            (setq yank-val (format "%d" ret-val))
          (setq yank-val ret-val))
        (if do-yank
            (kill-new yank-val)
          (if is-interactive
              (message yank-val)
            ret-val))))

The function get-mode-line-field should also be changed:
    (defun get-mode-line-field(type)
      (let ((field       (format "*%s*" type))
            (this-struct (get-mode-line-struct type)))
        (if this-struct
            (setq field
                  (format "%s: %s "
                          (mode-line-struct-display this-struct)
                          (funcall (mode-line-struct-function this-
struct) nil))))
        field))


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

end of thread, other threads:[~2009-04-28 10:27 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-14 14:03 Extra info in modeline (tip and questions) Decebal
2009-04-14 15:54 ` Nikolaj Schumacher
     [not found] ` <mailman.5329.1239724470.31690.help-gnu-emacs@gnu.org>
2009-04-15  5:53   ` Decebal
2009-04-15 13:14     ` Nikolaj Schumacher
     [not found]     ` <mailman.5377.1239801271.31690.help-gnu-emacs@gnu.org>
2009-04-28  7:55       ` Decebal
2009-04-28 10:27         ` Decebal
2009-04-28  8:04       ` Decebal
2009-04-28  8:23         ` Decebal
2009-04-15 11:06 ` Decebal
2009-04-15 13:23   ` Nikolaj Schumacher
     [not found]   ` <mailman.5379.1239801830.31690.help-gnu-emacs@gnu.org>
2009-04-15 16:13     ` Decebal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).