* 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
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.