* bug#2887: Suggestions for simple.el @ 2009-04-04 13:32 Arni Magnusson 2009-04-04 14:21 ` Stefan Monnier 2020-09-19 21:50 ` Lars Ingebrigtsen 0 siblings, 2 replies; 23+ messages in thread From: Arni Magnusson @ 2009-04-04 13:32 UTC (permalink / raw) To: bug-gnu-emacs [-- Attachment #1: Type: text/plain, Size: 986 bytes --] Dear Emacs maintainers, I would like to suggest adding a few functions to the simple.el library. I do this with hesitation - since I know the idea is to keep it simple and let users write extensions to suit their preferences - but I believe a large number of Emacs users would appreciate having access to these functions out of the box. I just finished teaching an Emacs workshop, where I ended up distributing these functions to my colleagues, but I found it hard to explain whey they're not already in simple.el. Please see the attached file suggestions-simple.el. Instead of giving detailed reasons for including each function, I have only briefly commented on which functionality I'm extending, or which gap I'm bridging. I have used these functions a lot, but I am sure the Emacs maintainers can see ways to improve them in terms of robustness, speed, function names, documentation, etc. I would be happy to discuss any further details with you. All the best, Arni Magnusson [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: suggestions-simple.el --] [-- Type: text/x-emacs-lisp; name="suggestions-simple.el", Size: 4086 bytes --] ;; simple::backward-kill-word ;; subr::backward-delete-char (defun backward-delete-word (N) "Delete previous N words." (interactive "*p")(delete-word (- N))) ;; simple::kill-word ;; C::delete-char (defun delete-word (N) "Delete following N words." (interactive "*p") (delete-region (point)(save-excursion (forward-word N)(point)))) ;; simple::kill-line ;; simple::kill-region (defun kill-line-or-region () "Kill region if selected, otherwise kill line." (interactive) (if (and mark-active transient-mark-mode)(kill-region (point)(mark))(kill-line))) ;; simple::transpose-lines ;; simple::kill-whole-line (defun pull-line-down (N) "Pull line down N times." (interactive "*p") (let ((col (current-column)))(kill-whole-line 1)(forward-line N)(yank 1)(pop kill-ring)(forward-line -1) (move-to-column col))) ;; simple::transpose-lines ;; simple::kill-whole-line (defun pull-line-up (N) "Pull line up N times." (interactive "*p") (let ((col (current-column)))(kill-whole-line 1)(forward-line (- N))(yank 1)(pop kill-ring)(forward-line -1) (move-to-column col))) ;; simple::goto-line ;; C::point (defun pos-at-beginning-of-line (N) "Return the position at beginning of line N." (save-excursion (goto-line N)(point))) (defun pos-at-end-of-line (N) "Return the position at end of line N." (save-excursion (goto-line N)(end-of-line)(point))) ;; simple::zap-to-char ;; C::delete-region (defun zap-back-to-char (char) "Delete region back to, but not including, CHAR." (interactive "cZap back to char: ") (let ((case-fold-search nil)) (delete-region (point)(progn (search-backward (char-to-string char))(forward-char)(point))))) ;; simple::zap-to-char ;; C::delete-region (defun zap-up-to-char (char) "Delete region up to, but not including, CHAR." (interactive "cZap to char: ") (let ((case-fold-search nil)) (delete-region (point)(progn (search-forward (char-to-string char))(backward-char)(point))))) ;; simple::delete-trailing-whitespace ;; whitespace::whitespace-buffer (defun clean-trails () "Delete ^M glyphs, spaces, and tabs from line ends." (interactive) ; \r means ^M (save-excursion (goto-char (point-min)) ; unlike delete-trailing-whitespace, clean-trails removes ^M (\r) in lisp-mode (let ((count 0))(while (re-search-forward "[\r\t ]+$" nil t)(replace-match "")(setq count (+ count 1))) (message "Cleaned %d lines" count)))) ;; simple::delete-blank-lines ;; whitespace::whitespace-buffer (defun delete-all-blank-lines () "Delete all blank lines in buffer." (interactive) (save-excursion (goto-char (point-min)) (let ((count 0))(while (search-forward "\n\n" nil t)(goto-char (point-min)) (while (search-forward "\n\n" nil t)(replace-match "\n")(setq count (+ count 1))) (goto-char (point-min))) (if (= (following-char) 10)(progn (delete-char 1)(setq count (+ count 1)))) (message "Deleted %d blank lines" count)))) ;; simple::delete-indentation (defun delete-indentation-nospace () "Join this line to previous with no whitespace at join." (interactive) (delete-indentation)(delete-horizontal-space)) ;; simple::end-of-buffer ;; simple::goto-line (defun goto-longest-line () "Go to longest line in buffer." (interactive) (let ((line 1)(length 0)) (save-excursion (goto-char (point-min))(end-of-line)(setq length (current-column)) (while (not (eobp)) (progn (end-of-line 2) (if (> (current-column) length)(progn (setq line (line-number-at-pos))(setq length (current-column))))))) (goto-line line)(message "Line %d is %d characters" line length))) ;; C::downcase-region ;; C::downcase-word ;; belongs in simple (defun downcase-word-or-region (N) "Downcase N words or region." (interactive "*p") (if (and mark-active transient-mark-mode)(downcase-region (point)(mark))(downcase-word N))) (defun upcase-word-or-region (N) "Upcase N words or region." (interactive "*p") (if (and mark-active transient-mark-mode)(upcase-region (point)(mark))(upcase-word N))) ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-04 13:32 bug#2887: Suggestions for simple.el Arni Magnusson @ 2009-04-04 14:21 ` Stefan Monnier 2009-04-04 23:35 ` Arni Magnusson 2020-09-19 21:50 ` Lars Ingebrigtsen 1 sibling, 1 reply; 23+ messages in thread From: Stefan Monnier @ 2009-04-04 14:21 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 > Please see the attached file suggestions-simple.el. Instead of giving > detailed reasons for including each function, I have only briefly > commented on which functionality I'm extending, or which gap I'm bridging. I'd rather see detailed reasons for each function/command you suggest. E.g. why do you need a backward-delete-word when we already provide backward-kill-word? Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-04 14:21 ` Stefan Monnier @ 2009-04-04 23:35 ` Arni Magnusson 2009-04-05 3:27 ` Stefan Monnier 0 siblings, 1 reply; 23+ messages in thread From: Arni Magnusson @ 2009-04-04 23:35 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 Thank you, Stefan, for the prompt reply and interest. Please find below my list of raisons d'être. Arni `backward-delete-word' `delete-word' Users can delete words while leaving the kill-ring unchanged. For example, the user has copied a table from somewhere and is now deleting some words before yanking the table where it belongs. It would be frustrating for the user to yank and see recently deleted words instead of the table. `kill-line-or-region' Users can bind C-k to kill lines and regions (do what I mean), as an alternative to the default C-k and C-w setup. `pull-line-down' `pull-line-up' Users can move lines up and down more effectively thank with `transpose-lines'. `pos-at-beginning-of-line' `pos-at-end-of-line' Useful when writing a variety of editing functions. Should be in simple.el for the same resons as `line-beginning-position' and `line-end-position' are there. `zap-back-to-char' `zap-up-to-char' Zapping is typically to delete garbage until some important location. The existing `zap-to-char' often deletes the beginning of that important location, an opening brace or the like. `clean-trails' Like `delete-trailing-white', but reports how many lines were cleaned, and deletes ^M as well. Many programs and programmers write files with trailing spaces and ^M glyphs. It's nice to be able to clean those and get body count in one keystroke. `delete-all-blank-lines' It's often useful to get rid of extra vertical spacing in source code, output files, etc., sometimes undoing after enjoying the squeezed view. Without this command, it would take a lot of keystrokes to delete all blank lines while retaining the cursor buffer position. `delete-indentation-nospace' The `delete-indentation' command is very useful, but it often creates an unwanted space. Users will probably bind this command to a keystroke close to the `delete-indentation' keystroke. `goto-longest-line' Users can find out the maximum width (columns) of a text file, to check the coding style or for some other reason. Sometimes it's easiest to call "wc -L" via `shell-command' or `dired-do-shell-command', but `goto-longest-line' will often be quicker and moves the cursor to the longest line, for closer examination. I remember when I wrote this command I thought about implementing a separate non-interactive function called `longest-line' that would just return the line number. Then `goto-longest-line' would call `longest-line' to do the calculations, and other functions might call `longest-line' with some other purpose than moving the cursor to it. I would be happy to contribute a two-function implementation instead, since `longest-line' might be useful for many users. `downcase-word-or-region' `upcase-word-or-region' Users can bind M-l and M-u to downcase/upcase words or regions (do what I mean), as an alternative to the default C-x C-l, C-x C-u, M-l, and M-u setup. ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-04 23:35 ` Arni Magnusson @ 2009-04-05 3:27 ` Stefan Monnier 2009-04-05 14:26 ` Leo 2009-04-05 20:17 ` Arni Magnusson 0 siblings, 2 replies; 23+ messages in thread From: Stefan Monnier @ 2009-04-05 3:27 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 > `backward-delete-word' > `delete-word' > Users can delete words while leaving the kill-ring unchanged. For example, > the user has copied a table from somewhere and is now deleting some words > before yanking the table where it belongs. It would be frustrating for the > user to yank and see recently deleted words instead of the table. Which leads to the following questions: - is it really that important given that the user could get the same result by yanking first and deleting the words afterwards? - why is this important for *kill-word, but not for all the other kill operations? - the most important one: who's going to do M-x delete-word rather than work around the problem some other way? I.e. such a command is basically useless unless it's bound to a key, so the problem is not so much the command as it is to find a key for it. > `kill-line-or-region' > Users can bind C-k to kill lines and regions (do what I mean), as an > alternative to the default C-k and C-w setup. That might be OK. Many people who'd like it, might prefer to just use some variant of delete-selection-mode, tho. > `pull-line-down' > `pull-line-up' > Users can move lines up and down more effectively thank with > `transpose-lines'. Can you summarize the difference? > `pos-at-beginning-of-line' > `pos-at-end-of-line' > Useful when writing a variety of editing functions. Should be in simple.el > for the same resons as `line-beginning-position' and `line-end-position' > are there. Actually, line-*-position are in the C code (and if they were written in Lisp, they should be in subr.el rather than in simple.el). The problem with pos-at-*-of-line is that goto-line is costly, so Elisp generally shouldn't encourage its use. > `zap-back-to-char' > `zap-up-to-char' > Zapping is typically to delete garbage until some important location. > The existing `zap-to-char' often deletes the beginning of that > important location, an opening brace or the like. I never use zap-to-char, so I'll let other people judge if that can be useful. > `clean-trails' > Like `delete-trailing-white', but reports how many lines were cleaned, and > deletes ^M as well. Many programs and programmers write files with > trailing spaces and ^M glyphs. It's nice to be able to clean those and get > body count in one keystroke. The report of number of lines cleaned sounds like a good addition to delete-trailing-whitespace. Not sure about ^M since I basically never bumped into it (or rather I always handle it via eol-conversion), but if it's useful, it would also be beter to incorporate it into delete-trailing-whitespace than create a new command for it. > `delete-all-blank-lines' > It's often useful to get rid of extra vertical spacing in source code, > output files, etc., sometimes undoing after enjoying the squeezed view. > Without this command, it would take a lot of keystrokes to delete all > blank lines while retaining the cursor buffer position. I've never needed such a command, so again, I'll let other people judge if it is sufficiently generally useful to find its way in Emacs. > `delete-indentation-nospace' > The `delete-indentation' command is very useful, but it often creates an > unwanted space. Users will probably bind this command to a keystroke close > to the `delete-indentation' keystroke. delete-indentation tries to guess when spaces are wanted. Maybe we could improve the guess instead? > `goto-longest-line' > Users can find out the maximum width (columns) of a text file, to check > the coding style or for some other reason. Sometimes it's easiest to call > "wc -L" via `shell-command' or `dired-do-shell-command', but > `goto-longest-line' will often be quicker and moves the cursor to the > longest line, for closer examination. > I remember when I wrote this command I thought about implementing a > separate non-interactive function called `longest-line' that would just > return the line number. Then `goto-longest-line' would call `longest-line' > to do the calculations, and other functions might call `longest-line' with > some other purpose than moving the cursor to it. I would be happy to > contribute a two-function implementation instead, since `longest-line' > might be useful for many users. There's no point not moving to the line, even if used from Elisp (since it's just as easy to wrap the call in a save-excursion if needed), so the command works as well from Lisp. > `downcase-word-or-region' > `upcase-word-or-region' > Users can bind M-l and M-u to downcase/upcase words or regions (do what I > mean), as an alternative to the default C-x C-l, C-x C-u, M-l, and M-u > setup. That sounds OK. This said, I think those new commands, unbound to any key, shouldn't be placed in simple.el (which is preloaded) but into some other file. I'm tempted to say "misc.el", where we could stuff any number of "commands that users might like, but for which we couldn't come up with a good key-binding". Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-05 3:27 ` Stefan Monnier @ 2009-04-05 14:26 ` Leo 2009-04-05 20:17 ` Arni Magnusson 1 sibling, 0 replies; 23+ messages in thread From: Leo @ 2009-04-05 14:26 UTC (permalink / raw) To: bug-gnu-emacs On 2009-04-05 04:27 +0100, Stefan Monnier wrote: >> `zap-back-to-char' >> `zap-up-to-char' > >> Zapping is typically to delete garbage until some important location. >> The existing `zap-to-char' often deletes the beginning of that >> important location, an opening brace or the like. > > I never use zap-to-char, so I'll let other people judge if that can > be useful. I think those functions are already in emacs. Take a look at its lisp dir, i think it is misc.el. -- .: Leo :. [ sdl.web AT gmail.com ] .: I use Emacs :. www.git-scm.com git - the one true version control system ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-05 3:27 ` Stefan Monnier 2009-04-05 14:26 ` Leo @ 2009-04-05 20:17 ` Arni Magnusson 2009-04-05 21:59 ` Lennart Borgman 2009-04-06 2:14 ` Stefan Monnier 1 sibling, 2 replies; 23+ messages in thread From: Arni Magnusson @ 2009-04-05 20:17 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 Thank you, Stefan, for the insightful comments. We're discussing quite a few things at once, but I'll try to be concise: >> `backward-delete-word' >> `delete-word' > >> Users can delete words while leaving the kill-ring unchanged. For >> example, the user has copied a table from somewhere and is now >> deleting some words before yanking the table where it belongs. It >> would be frustrating for the user to yank and see recently deleted >> words instead of the table. > > Which leads to the following questions: > > - is it really that important given that the user could get the same > result by yanking first and deleting the words afterwards? The default behavior of practically all editors is to delete words without altering the clipboard. The principle of least surprise says Emacs should at least make it easy for users to bind C-backspace to `backward-delete-word' and C-delete to `delete-word', if that's the behavior they prefer. > - why is this important for *kill-word, but not for all the other kill > operations? Because deleting words is probably the most common deletion, after deleting characters. It would frustrate many more users if `delete-char' would alter the kill ring. > - the most important one: who's going to do M-x delete-word rather > than work around the problem some other way? I.e. such a command is > basically useless unless it's bound to a key, so the problem is not > so much the command as it is to find a key for it. The Emacs manual and the documentation of `kill-word' and `backward-kill-word' could mention that some users may prefer binding C-backspace to `backward-delete-word' and C-delete to `delete-word'. >> `kill-line-or-region' > >> Users can bind C-k to kill lines and regions (do what I mean), as an >> alternative to the default C-k and C-w setup. > > That might be OK. Many people who'd like it, might prefer to just use > some variant of delete-selection-mode, tho. Again, the important distinction between killing and deleting. Even in `delete-selection-mode', the `kill-line-or-region' command is useful for yanking the text later. >> `pull-line-down' >> `pull-line-up' > >> Users can move lines up and down more effectively thank with >> `transpose-lines'. > > Can you summarize the difference? To move a line 3 down, call `pull-line-down' 3 times or with a numerical argument of 3. Likewise with `pull-line-up'. Most Emacs users would probably do this by killing and yanking, but it's considerably quicker using the pull-line-* commands. The `transpose-lines' command may be useful in some circumstances, but not in the tasks described above. >> `pos-at-beginning-of-line' >> `pos-at-end-of-line' > >> Useful when writing a variety of editing functions. Should be in >> simple.el for the same resons as `line-beginning-position' and >> `line-end-position' are there. > > Actually, line-*-position are in the C code (and if they were written > in Lisp, they should be in subr.el rather than in simple.el). The > problem with pos-at-*-of-line is that goto-line is costly, so Elisp > generally shouldn't encourage its use. My commands that call pos-at-*-of-line work faster than I can blink my eyes, but I understand your concern. To optimize the speed the functions would probably need to be implemented in C code, but that's beyond my programming capabilities. Still, if I'm not mistaken, Emacs Lisp programmers would have to use something just as expensive to perform this task, so pos-at-*-of-line would save them some typing and thinking. >> `zap-back-to-char' >> `zap-up-to-char' > >> Zapping is typically to delete garbage until some important location. >> The existing `zap-to-char' often deletes the beginning of that >> important location, an opening brace or the like. > > I never use zap-to-char, so I'll let other people judge if that can be > useful. It's a common task to delete everything between the point and another location. Zapping is best if that location contains a somewhat rare character, usually some kind of symbol or parenthesis. In my experience the character itself should usually not be deleted as well. >> `clean-trails' > >> Like `delete-trailing-white', but reports how many lines were >> cleaned, and deletes ^M as well. Many programs and programmers write >> files with trailing spaces and ^M glyphs. It's nice to be able to >> clean those and get body count in one keystroke. > > The report of number of lines cleaned sounds like a good addition to > delete-trailing-whitespace. Not sure about ^M since I basically never > bumped into it (or rather I always handle it via eol-conversion), but > if it's useful, it would also be beter to incorporate it into > delete-trailing-whitespace than create a new command for it. Yes, it would be a nice improvement to upgrade the `delete-trailing-whitespace' command so it counts cleaned lines. Files with mixed Unix/Dos line endings are sometimes created when people using different OS's work together on a project. Many programs choke on input files that contain mixed Unix/Dos line endings, often without helpful error messages. If the Emacs maintainers decide to make `delete-trailing-whitespace' also delete trailing ^M in mixed line-ending files, it would make me (and presumably many other users) happy, but it might create a backwards-compatibility issue. Adding an &optional ctrl-M flag to `delete-trailing-whitespace' (non-nil to remove trailing ^M as well) would not enable to users to bind a simple keystroke to do that. What I propose is a separate function `delete-trailing-whitespace-M' that removes both trailing whitespace and trailing ^M in files with mixed line endings. A bulky solution, but I think users will appreciate it. >> `delete-all-blank-lines' > >> It's often useful to get rid of extra vertical spacing in source >> code, output files, etc., sometimes undoing after enjoying the >> squeezed view. Without this command, it would take a lot of >> keystrokes to delete all blank lines while retaining the cursor >> buffer position. > > I've never needed such a command, so again, I'll let other people > judge if it is sufficiently generally useful to find its way in Emacs. It's often a good way to get an overview of code that is vertically stretched. I remove all comments (one keystroke) and all blank lines (another keystroke), absorb the information and undo. I also use it on certain program input files where blank lines would be problematic. >> `delete-indentation-nospace' > >> The `delete-indentation' command is very useful, but it often creates >> an unwanted space. Users will probably bind this command to a >> keystroke close to the `delete-indentation' keystroke. > > delete-indentation tries to guess when spaces are wanted. Maybe we > could improve the guess instead? These functions are used in a wide variety of situations (text, code, data), making guesswork practically hopeless. I use `delete-indentation' and `delete-indentation-nospace' a lot, and I'm not sure which one I use more frequently. >> `goto-longest-line' > >> Users can find out the maximum width (columns) of a text file, to >> check the coding style or for some other reason. Sometimes it's >> easiest to call "wc -L" via `shell-command' or >> `dired-do-shell-command', but `goto-longest-line' will often be >> quicker and moves the cursor to the longest line, for closer >> examination. > >> I remember when I wrote this command I thought about implementing a >> separate non-interactive function called `longest-line' that would >> just return the line number. Then `goto-longest-line' would call >> `longest-line' to do the calculations, and other functions might call >> `longest-line' with some other purpose than moving the cursor to it. >> I would be happy to contribute a two-function implementation instead, >> since `longest-line' might be useful for many users. > > There's no point not moving to the line, even if used from Elisp > (since it's just as easy to wrap the call in a save-excursion if > needed), so the command works as well from Lisp. Good call, one function it is. >> `downcase-word-or-region' >> `upcase-word-or-region' > >> Users can bind M-l and M-u to downcase/upcase words or regions (do >> what I mean), as an alternative to the default C-x C-l, C-x C-u, M-l, >> and M-u setup. > > That sounds OK. Great. > This said, I think those new commands, unbound to any key, shouldn't > be placed in simple.el (which is preloaded) but into some other file. > I'm tempted to say "misc.el", where we could stuff any number of > "commands that users might like, but for which we couldn't come up > with a good key-binding". I would slip them into simple.el, since they load very fast and rhyme with what's already there. Allow me to propose the following bindings that are undefined in Emacs 22.3.1: C-x C-backspace backward-delete-word C-x C-delete delete-word C-; kill-line-or-region M-n pull-line-down M-p pull-line-up C-, zap-back-to-char C-. zap-up-to-char C-' clean-trails C-" delete-all-blank-lines M-& delete-indentation-nospace C-= goto-longest-line M-down downcase-word-or-region M-up upcase-word-or-region ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-05 20:17 ` Arni Magnusson @ 2009-04-05 21:59 ` Lennart Borgman 2009-04-06 2:14 ` Stefan Monnier 1 sibling, 0 replies; 23+ messages in thread From: Lennart Borgman @ 2009-04-05 21:59 UTC (permalink / raw) To: Arni Magnusson, 2887 On Sun, Apr 5, 2009 at 10:17 PM, Arni Magnusson <arnima@hafro.is> wrote: >>> It's often useful to get rid of extra vertical spacing in source >>> code, output files, etc., sometimes undoing after enjoying the >>> squeezed view. Without this command, it would take a lot of >>> keystrokes to delete all blank lines while retaining the cursor >>> buffer position. >> >> I've never needed such a command, so again, I'll let other people >> judge if it is sufficiently generally useful to find its way in Emacs. > > It's often a good way to get an overview of code that is vertically > stretched. I remove all comments (one keystroke) and all blank lines > (another keystroke), absorb the information and undo. I also use it on > certain program input files where blank lines would be problematic. I can see the idea, but I would suggest a minor mode that hide comments and blank lines instead. That would allow editing the file with comments and blank line hidden. > M-down downcase-word-or-region > M-up upcase-word-or-region Key bindings is a scarce resource. Those two bindings are already used by windmove.el for moving between windows (and that is something that perhaps should be on by default). ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-05 20:17 ` Arni Magnusson 2009-04-05 21:59 ` Lennart Borgman @ 2009-04-06 2:14 ` Stefan Monnier 2009-04-06 3:02 ` Drew Adams 2009-04-07 2:46 ` Arni Magnusson 1 sibling, 2 replies; 23+ messages in thread From: Stefan Monnier @ 2009-04-06 2:14 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 > The Emacs manual and the documentation of `kill-word' and > `backward-kill-word' could mention that some users may prefer binding > C-backspace to `backward-delete-word' and C-delete to `delete-word'. The Emacs manual is already "too large" to contain all the info we want to put in it, so mentioning such things is unlikely. But it's probably a good idea to add those commands to misc.el. Then the EmacsWiki can mention them. > My commands that call pos-at-*-of-line work faster than I can blink my > eyes, but I understand your concern. Try them on 200MB buffers. > To optimize the speed the functions would probably need to be > implemented in C code, but that's beyond my programming > capabilities. The core loop is in goto-line and is already written in C. > Still, if I'm not mistaken, Emacs Lisp programmers would > have to use something just as expensive to perform this task, so > pos-at-*-of-line would save them some typing and thinking. The point is to force them to use goto-line explicitly, so as to hopefully make the cost more obvious. > It's a common task to delete everything between the point and another > location. Zapping is best if that location contains a somewhat rare > character, usually some kind of symbol or parenthesis. In my experience > the character itself should usually not be deleted as well. I tend to use C-s for that (as well as for movement). But I understand that other people have other habits. > Yes, it would be a nice improvement to upgrade the > `delete-trailing-whitespace' command so it counts cleaned lines. Feel free to provide a patch for it (tho, since we're in the pretest, there's no hurry: it won't be installed right now). > Files with mixed Unix/Dos line endings are sometimes created when people > using different OS's work together on a project. Many programs choke on > input files that contain mixed Unix/Dos line endings, often without > helpful error messages. I understand the problem, yes. I just don't know it enough to understand which kind of solution is more handy. The few times I've had such a thing, I just did M-% C-q C-m RET RET !. For such rare occurrences, anything more specialized would be useless because I wouldn't remember it. Obviously, if it happens commonly to you, you'll want another solution. > If the Emacs maintainers decide to make `delete-trailing-whitespace' also > delete trailing ^M in mixed line-ending files, it would make me (and > presumably many other users) happy, but it might create a > backwards-compatibility issue. It might, but I'm not sure it'd be such a big deal. The docstring explicitly mentions that a form-feed is not considered as whitespace by this function, so that might be taken to mean that "every other whitespace-like chars" (such as C-m) would be considered as whitespace. > These functions are used in a wide variety of situations (text, code, > data), making guesswork practically hopeless. I use `delete-indentation' > and `delete-indentation-nospace' a lot, and I'm not sure which one I use > more frequently. What bindings do you use? >> This said, I think those new commands, unbound to any key, shouldn't >> be placed in simple.el (which is preloaded) but into some other file. >> I'm tempted to say "misc.el", where we could stuff any number of >> "commands that users might like, but for which we couldn't come up >> with a good key-binding". > I would slip them into simple.el, since they load very fast and rhyme with > what's already there. As mentioned, simple.el is preloaded, so anything we add to it increases the size of Emacs for everyone, whether they use it or not. > Allow me to propose the following bindings that are > undefined in Emacs 22.3.1: There's a good reason why they're undefined: most of those keys can't be pressed under a tty. Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-06 2:14 ` Stefan Monnier @ 2009-04-06 3:02 ` Drew Adams 2009-04-07 2:46 ` Arni Magnusson 1 sibling, 0 replies; 23+ messages in thread From: Drew Adams @ 2009-04-06 3:02 UTC (permalink / raw) To: 'Stefan Monnier', 2887, 'Arni Magnusson' > But it's probably a good idea to add those commands to misc.el. > Then the EmacsWiki can mention them. Huh? What kind of reasoning is that? If that's the reason, just put the code on EmacsWiki - no reason to add it to Emacs. Sheesh. ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-06 2:14 ` Stefan Monnier 2009-04-06 3:02 ` Drew Adams @ 2009-04-07 2:46 ` Arni Magnusson 2009-04-07 14:02 ` Stefan Monnier 1 sibling, 1 reply; 23+ messages in thread From: Arni Magnusson @ 2009-04-07 2:46 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 >> My commands that call pos-at-*-of-line work faster than I can blink >> my eyes, but I understand your concern. > > Try them on 200MB buffers. When I'm editing a 212MB text file, many things become sluggish, but pos-at-*-of-line is not one of them: M-x benchmark (pos-at-end-of-line 1000000) ; 0.157s 10 M-x benchmark (pos-at-end-of-line 1000000) ; 0.719s This speed is similar to line-*-position: M-x benchmark (line-end-position 1000000) ; 0.172s 10 M-x benchmark (line-end-position 1000000) ; 0.734s >> Yes, it would be a nice improvement to upgrade the >> `delete-trailing-whitespace' command so it counts cleaned lines. > > Feel free to provide a patch for it (tho, since we're in the pretest, > there's no hurry: it won't be installed right now). Here is a candidate upgrade of `delete-trailing-whitespace': (defun delete-trailing-whitespace () "Delete all the trailing whitespace across the current buffer. All whitespace after the last non-whitespace character in a line is deleted. This respects narrowing, created by \\[narrow-to-region] and friends. A formfeed is not considered whitespace by this function." (interactive "*") (save-match-data (save-excursion (goto-char (point-min)) (let ((count 0)(table (syntax-table))) (modify-syntax-entry ?\f "." table) ; never delete formfeeds (modify-syntax-entry ?\n "." table) ; never delete newline (with-syntax-table table (while (re-search-forward "\\s-+$" nil t) (replace-match "")(setq count (1+ count))) (message "Cleaned %d lines" count)))))) Although the code is substantially different, it performs precisely the same deletions as the existing revision 1.985, and the computational speed is comparable. The user-visible difference is that it reports how many lines were cleaned. The code is clear and extensible. One possible change is to add one important line, while still fulfilling the current documentation: (modify-syntax-entry ?\r " " table) ; always delete trailing ^M And here's a version that deletes only trailing spaces, tabs, and ^M glyphs: (defun delete-trailing-whitespace () "Delete all the trailing whitespace across the current buffer. All whitespace after the last non-whitespace character in a line is deleted. This respects narrowing, created by \\[narrow-to-region] and friends. A formfeed is not considered whitespace by this function." (interactive "*") (save-match-data (save-excursion (goto-char (point-min)) (let ((count 0)) (while (re-search-forward "[ \r\t]+$" nil t) (replace-match "")(setq count (1+ count))) (message "Cleaned %d lines" count))))) This performs 4x faster than the first candidate upgrade, because the regexp matches only 3 characters, whereas "\\s-+$" matches 147 different characters in text-mode. The syntax table definitions of whitespace can be confusing, e.g. the ^M glyph is considered whitespace in text-mode but not in emacs-lisp-mode... After this explanatory introduction, my real proposal is to define a variable to determine the behavior of `delete-trailing-whitespace': (defvar trailing-whitespace-regexp "\\s-+$" "Regular expression describing what `delete-trailing-whitespace' should delete. Note that regardless of the value of `trailing-whitespace-regexp', `delete-trailing-whitespace' will never delete formfeed and newline characters. The default value \"\\\\s-+$\" uses the current syntax table definitions of whitespace, but an expression like \"[ \\r\\t]+$\" is faster and consistent across modes.") (defun delete-trailing-whitespace () "Delete all trailing whitespace, as defined by `trailing-whitespace-regexp', in the current buffer. All whitespace after the last non-whitespace character in a line is deleted. This respects narrowing, created by \\[narrow-to-region] and friends. Note that regardless of the value of `trailing-whitespace-regexp', `delete-trailing-whitespace' will never delete formfeed and newline characters." (interactive "*") (save-match-data (save-excursion (goto-char (point-min)) (let ((count 0)(table (syntax-table))) (modify-syntax-entry ?\f "." table) ; never delete formfeeds (modify-syntax-entry ?\n "." table) ; never delete newline (with-syntax-table table (while (re-search-forward whitespace-regexp nil t) (replace-match "")(setq count (1+ count))) (message "Cleaned %d lines" count)))))) This version of `delete-trailing-whitespace' can mimic my `clean-trails', making that function unnecessary. >> These functions are used in a wide variety of situations (text, code, >> data), making guesswork practically hopeless. I use >> `delete-indentation' and `delete-indentation-nospace' a lot, and I'm >> not sure which one I use more frequently. > > What bindings do you use? M-j and C-M-j, overriding the defaults. >> Allow me to propose the following bindings that are undefined in >> Emacs 22.3.1: > > There's a good reason why they're undefined: most of those keys can't > be pressed under a tty. Good point. Here are some undefined keystrokes in Emacs 22.3.1 that seem to get through: C-x j backward-delete-word C-x C-j delete-word C-x x kill-line-or-region M-n pull-line-down M-p pull-line-up C-M-z zap-back-to-char C-M-m zap-up-to-char C-x C-a delete-all-blank-lines M-& delete-indentation-nospace C-x w goto-longest-line C-x y downcase-word-or-region C-x C-y upcase-word-or-region Thank you for your patience and thoughtful responses, Arni ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-07 2:46 ` Arni Magnusson @ 2009-04-07 14:02 ` Stefan Monnier 2009-04-07 16:09 ` Drew Adams ` (2 more replies) 0 siblings, 3 replies; 23+ messages in thread From: Stefan Monnier @ 2009-04-07 14:02 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 > The default behavior of practically all editors is to delete words > without altering the clipboard. The principle of least surprise says > Emacs should at least make it easy for users to bind C-backspace to > `backward-delete-word' and C-delete to `delete-word', if that's the > behavior they prefer. But do those editors offer the equivalent of M-y? > When I'm editing a 212MB text file, many things become sluggish, but > pos-at-*-of-line is not one of them: > M-x benchmark (pos-at-end-of-line 1000000) ; 0.157s This timing means that if a command calls this function for lines near point, that command becomes sluggish when you get to the end of the buffer. If it calls it 100 times, the command becomes completely unusable. > This speed is similar to line-*-position: > M-x benchmark (line-end-position 1000000) ; 0.172s > 10 M-x benchmark (line-end-position 1000000) ; 0.734s Of course. But line-end-position is usually called with small args because it's a relative position. > Here is a candidate upgrade of `delete-trailing-whitespace': Please send it as a patch so we can see what's changed rather than only see the end result. > This performs 4x faster than the first candidate upgrade, because the > regexp matches only 3 characters, whereas "\\s-+$" matches 147 different > characters in text-mode. Actually, it isn't quite for that reason, it's much worse: \s- is a regexp that may potentially match *any* character (depending on the syntax-table text-property), so contrary to [ \t\r] which can use a "fastmap" to quickly skip over irrelevant chars, \s- has to spend a lot more time on each char. > The syntax table definitions of whitespace can be confusing, e.g. the > ^M glyph is considered whitespace in text-mode but not in > emacs-lisp-mode... Agreed. > After this explanatory introduction, my real proposal is to define a > variable to determine the behavior of `delete-trailing-whitespace': > (defvar trailing-whitespace-regexp "\\s-+$" > "Regular expression describing what `delete-trailing-whitespace' > should delete. Note that regardless of the value of > `trailing-whitespace-regexp', `delete-trailing-whitespace' will never > delete formfeed and newline characters. > The default value \"\\\\s-+$\" uses the current syntax table definitions > of whitespace, but an expression like \"[ \\r\\t]+$\" is faster and > consistent across modes.") I think [ \t\r] is a good default, and if we introduce a config var (which I'm not sure is worth the trouble), there's no reason to keep the special treatment of formfeed. > (let ((count 0)(table (syntax-table))) > (modify-syntax-entry ?\f "." table) ; never delete formfeeds > (modify-syntax-entry ?\n "." table) ; never delete newline > (with-syntax-table table > (while (re-search-forward whitespace-regexp nil t) > (replace-match "")(setq count (1+ count))) > (message "Cleaned %d lines" count)))))) This modifies the current syntax-table (because `syntax-table' returns the table itself, not a copy). > Good point. Here are some undefined keystrokes in Emacs 22.3.1 that seem > to get through: > C-x j backward-delete-word > C-x C-j delete-word > C-x x kill-line-or-region > M-n pull-line-down > M-p pull-line-up > C-M-z zap-back-to-char > C-M-m zap-up-to-char > C-x C-a delete-all-blank-lines > M-& delete-indentation-nospace > C-x w goto-longest-line > C-x y downcase-word-or-region > C-x C-y upcase-word-or-region > Thank you for your patience and thoughtful responses, I think I will prefer to leave those unbound for now, waiting for more generally useful commands, or more general agreement that they are generally useful. Note that for some of them (e.g. kill-line-or-region or downcase-word-or-region), you might want to try and argue that their functionality should simply be folded into the kill-line resp. downcase-word (which might let us free up C-x C-u and C-x C-l, and maybe even C-w). Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-07 14:02 ` Stefan Monnier @ 2009-04-07 16:09 ` Drew Adams [not found] ` <008701c9b79b$41f3f250$0200a8c0@us.oracle.com> 2009-04-18 0:08 ` Arni Magnusson 2 siblings, 0 replies; 23+ messages in thread From: Drew Adams @ 2009-04-07 16:09 UTC (permalink / raw) To: 'Stefan Monnier', 2887, 'Arni Magnusson'; +Cc: emacs-devel > > C-x j backward-delete-word > > C-x C-j delete-word > > C-x x kill-line-or-region > > M-n pull-line-down > > M-p pull-line-up > > C-M-z zap-back-to-char > > C-M-m zap-up-to-char > > C-x C-a delete-all-blank-lines > > M-& delete-indentation-nospace > > C-x w goto-longest-line > > C-x y downcase-word-or-region > > C-x C-y upcase-word-or-region > > I think I will prefer to leave those unbound for now, waiting for more > generally useful commands, or more general agreement that they are > generally useful. So it sounds as if you're actually going to add these things to Emacs (even if you don't bind them by default)? If so, that's quite surprising, especially since the policy has always been _not_ to add functions simply because they _might_ be generally useful. Not to mention the tradition of case-by-case discussion in emacs-devel first, including discussion of rationale (e.g. use cases). Whatever. In that case, below is my version of `goto-longest-line', published under that name over two years ago. I also sent it to emacs-devel on two occasions: 2008-1-23 (thread "find longest lines during isearch") and 2008-06-21 (thread "Another neat Eclispe'ism"). http://lists.gnu.org/archive/html/emacs-devel/2008-01/msg01611.html http://lists.gnu.org/archive/html/emacs-devel/2008-06/msg01442.html My version has these advantages: * If the region is active, it is restricted to the region. * If repeated, it goes to the longest line after the cursor. * You can use it to search from point forward only, by using `C-SPC' first. * It highlights the line (using `hl-line-highlight'). * It returns, as a list: the line #, its length, a list of other lines just as long (there can be more than one "longest line"), and the number of lines checked. * Interactively, it echoes all of that info. Example messages: Line 234: 76 chars, (459 lines measured) Line 234: 76 chars, Others: {239, 313} (459 lines measured) I bind [(control end)] to this command in `isearch-mode-map' (when `window-system'). This is the way I typically call it: `C-s C-end'. Repeatedly move to longest line after point: `C-x C-end C-end...'. And `C-g' returns you to the point where searching starts, so you can use it to see where long lines are without necessarily moving there and staying. I also bind it to `C-x L', but I typically use it from Isearch. A related command is `goto-long-line', which goes to the first line that is at least N chars long. N is the `fill-column' by default, or provided explicitly by `C-u'. If you are really interested in adding general, miscellaneous commands and functions that might be useful ("waiting for more generally useful commands"), I have plenty more, and there are hundreds more by others, on Emacs Wiki and elsewhere. The `goto-long*-line' commands and others are here: http://www.emacswiki.org/emacs/misc-cmds.el. And there is a wiki page loaded with commands for finding, visualizing, and moving to long lines: http://www.emacswiki.org/emacs/FindLongLines. I really didn't think this was how Emacs development proceeded, but apparently there has been a change (?). FWIW, I think emacs-devel is the proper place to discuss additions and other changes to Emacs. It's OK for enhancement suggestions to be submitted to the bugs list, but concrete discussion about adding or changing Emacs code should be done in emacs-devel, IMO. And such discussion should precede actually making changes. ;---------------8<----------------------- (defun goto-longest-line (beg end) "Go to the first of the longest lines in the region or buffer. If the region is active, it is checked. If not, the buffer (or its restriction) is checked. Returns a list of three elements: (LINE LINE-LENGTH OTHER-LINES LINES-CHECKED) LINE is the first of the longest lines measured. LINE-LENGTH is the length of LINE. OTHER-LINES is a list of other lines checked that are as long as LINE. LINES-CHECKED is the number of lines measured. Interactively, a message displays this information. If there is only one line in the active region, then the region is deactivated after this command, and the message mentions only LINE and LINE-LENGTH. If this command is repeated, it checks for the longest line after the cursor. That is *not* necessarily the longest line other than the current line. That longest line could be before or after the current line. To search only from the current line forward, not throughout the buffer, you can use `C-SPC' to set the mark, then use this \(repeatedly)." (interactive (if (or (not mark-active) (null (mark))) (list (point-min) (point-max)) (if (< (point) (mark)) (list (point) (mark)) (list (mark) (point))))) (when (and (not mark-active) (= beg end)) (error "The buffer is empty")) (when (and mark-active (> (point) (mark))) (exchange-point-and-mark)) (when (< end beg) (setq end (prog1 beg (setq beg end)))) (when (eq this-command last-command) (forward-line 1) (setq beg (point))) (goto-char beg) (when (eobp) (error "End of buffer")) (cond ((<= end (save-excursion (goto-char beg) (forward-line 1) (point))) (beginning-of-line) (when (require 'hl-line nil t) (let ((hl-line-mode t)) (hl-line-highlight)) (add-hook 'pre-command-hook #'hl-line-unhighlight nil t)) (let ((lineno (line-number-at-pos)) (chars (save-excursion (end-of-line) (current-column)))) (message "Only line %d: %d chars" lineno chars) (let ((visible-bell t)) (ding)) (setq mark-active nil) (list lineno chars nil 1))) (t (let* ((start-line (line-number-at-pos)) (max-width 0) (line start-line) long-lines col) (when (eobp) (error "End of buffer")) (while (and (not (eobp)) (< (point) end)) (end-of-line) (setq col (current-column)) (when (>= col max-width) (if (= col max-width) (setq long-lines (cons line long-lines)) (setq long-lines (list line))) (setq max-width col)) (forward-line 1) (setq line (1+ line))) (setq long-lines (nreverse long-lines)) (let ((lines long-lines)) (while (and lines (> start-line (car lines))) (pop lines)) (goto-char (point-min)) (when (car lines) (forward-line (1- (car lines))))) (when (require 'hl-line nil t) (let ((hl-line-mode t)) (hl-line-highlight)) (add-hook 'pre-command-hook #'hl-line-unhighlight nil t)) (when (interactive-p) (let ((others (cdr long-lines))) (message "Line %d: %d chars%s (%d lines measured)" (car long-lines) max-width (concat (and others (format ", Others: {%s}" (mapconcat (lambda (line) (format "%d" line)) (cdr long-lines) ", ")))) (- line start-line)))) (list (car long-lines) max-width (cdr long-lines) (- line start-line)))))) ^ permalink raw reply [flat|nested] 23+ messages in thread
[parent not found: <008701c9b79b$41f3f250$0200a8c0@us.oracle.com>]
* bug#2887: Suggestions for simple.el [not found] ` <008701c9b79b$41f3f250$0200a8c0@us.oracle.com> @ 2009-04-07 17:18 ` Stefan Monnier 2009-04-07 17:22 ` Chong Yidong [not found] ` <87iqlg4bwl.fsf@cyd.mit.edu> 2 siblings, 0 replies; 23+ messages in thread From: Stefan Monnier @ 2009-04-07 17:18 UTC (permalink / raw) To: Drew Adams; +Cc: 2887, emacs-devel, 'Arni Magnusson' > So it sounds as if you're actually going to add these things to Emacs > (even if you don't bind them by default)? No. Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el [not found] ` <008701c9b79b$41f3f250$0200a8c0@us.oracle.com> 2009-04-07 17:18 ` Stefan Monnier @ 2009-04-07 17:22 ` Chong Yidong [not found] ` <87iqlg4bwl.fsf@cyd.mit.edu> 2 siblings, 0 replies; 23+ messages in thread From: Chong Yidong @ 2009-04-07 17:22 UTC (permalink / raw) To: Drew Adams; +Cc: 2887, emacs-devel, 'Arni Magnusson' "Drew Adams" <drew.adams@oracle.com> writes: >> I think I will prefer to leave those unbound for now, waiting for more >> generally useful commands, or more general agreement that they are >> generally useful. > > So it sounds as if you're actually going to add these things to Emacs > (even if you don't bind them by default)? > > If so, that's quite surprising, especially since the policy has always > been _not_ to add functions simply because they _might_ be generally > useful. I don't think that's what Stefan was saying (but he can speak for himself). You're right, of course, that it's not a good idea to add functions simply because they *might* be useful, especially since simple.el is loaded by default. I have not looked through bug#2887 in detail, but my impression is that most of the suggested functions aren't quite suitable for default inclusion in Emacs. They are, however, Valuable Excercises For the Novice Emacs Lisp coder. Maybe someone should set up a page on Emacswiki for this sort of thing. ^ permalink raw reply [flat|nested] 23+ messages in thread
[parent not found: <87iqlg4bwl.fsf@cyd.mit.edu>]
* bug#2887: Suggestions for simple.el [not found] ` <87iqlg4bwl.fsf@cyd.mit.edu> @ 2009-04-07 17:26 ` Drew Adams 2009-04-07 21:43 ` Stefan Monnier 1 sibling, 0 replies; 23+ messages in thread From: Drew Adams @ 2009-04-07 17:26 UTC (permalink / raw) To: 'Chong Yidong'; +Cc: 2887, emacs-devel, 'Arni Magnusson' > most of the suggested functions aren't quite suitable for default > inclusion in Emacs. They are, however, Valuable Excercises For the > Novice Emacs Lisp coder. Maybe someone should set up a page on > Emacswiki for this sort of thing. Feel free to act on your own suggestion - anyone can edit EmacsWiki. ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el [not found] ` <87iqlg4bwl.fsf@cyd.mit.edu> 2009-04-07 17:26 ` Drew Adams @ 2009-04-07 21:43 ` Stefan Monnier 1 sibling, 0 replies; 23+ messages in thread From: Stefan Monnier @ 2009-04-07 21:43 UTC (permalink / raw) To: Chong Yidong; +Cc: 2887 Actually, I do think that a "find longest line" command would be a good addition to misc.el: it's not terribly hard to write, but it's not trivial either. Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-07 14:02 ` Stefan Monnier 2009-04-07 16:09 ` Drew Adams [not found] ` <008701c9b79b$41f3f250$0200a8c0@us.oracle.com> @ 2009-04-18 0:08 ` Arni Magnusson 2009-04-18 19:32 ` Stefan Monnier 2 siblings, 1 reply; 23+ messages in thread From: Arni Magnusson @ 2009-04-18 0:08 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 [-- Attachment #1: Type: TEXT/PLAIN, Size: 5540 bytes --] Thanks Stefan, for forwarding my suggestions to emacs-devel. The discussion raised many good points. After considering the viewpoints we have heard so far, here are my (revised) opinions: `backward-delete-word' `delete-word' I think Emacs should provide a simple way for beginning users to have C-backspace and C-delete behave like they would expect, i.e. leaving the clipboard intact. There are different ways to provide this, using a variable and/or functions. Users should not need to write their own functions for something this fundamental. `kill-line-or-region' C-k should probably be bound to this function. This would be appreciated by many `transient-mark-mode' users. I haven't used Emacs without `transient-mark-mode', but don't those people still want C-w bound to `kill-region'? `pull-line-down' `pull-line-up' These are admittedly simple tricks of lesser importance, but anyone trying out the existing `transpose-lines' will read its documentation twice and try to master pulling lines up or down, before giving up. I find myself using these almost every day, with code, data, and config files. `pos-at-beginning-of-line' `pos-at-end-of-line' You're right, it's best to avoid `goto-line'. I have reimplemented these functions (see attachment) to improve the speed. I think they bridge an obvious gap in Emacs Lisp, making it considerably easier to read and write functions that operate on buffer text. `zap-back-to-char' `zap-up-to-char' I believe these more useful than the existing `zap-to-char', which often deletes the beginning of that important location, an opening brace or the like. `delete-trailing-white' > I think [ \t\r] is a good default, and if we introduce a config var > (which I'm not sure is worth the trouble), there's no reason to keep the > special treatment of formfeed. I agree that hardwiring [ \t\r] works fastest and is easy to use and maintain. Attached is my proposed upgrade of this function, where cleaned lines are counted. `delete-all-blank-lines' Vertical analog to `delete-trailing-white', which I use about as often. Anyone trying out the existing `delete-blank-lines' will wonder whether there is a keybinding to delete all blank lines, instead of just around the point. `delete-indentation-nospace' Similar to `delete-indentation' but leaves no space between the joined lines. I find myself using these almost every day, with prose, code, data, and config files. I have bound the two functions to neighboring keybindings. `goto-longest-line' I should probably withdraw this suggestion. After seeing Drew Adam's version, I have concluded that my version is too clunky to be in simple.el, and Drew's version is too large to be in simple.el. Despite being a vertical analog to `end-of-buffer', simple.el should probably not provide this functionality. `downcase-word-or-region' `upcase-word-or-region' M-l and M-u could be bound to this function. This would be appreciated by many `transient-mark-mode' users. I haven't used Emacs without `transient-mark-mode', but don't those people still want C-x C-l and C-x C-u bound to `downcase-region' and `upcase-region'? --- By suggesting so many functions at once, I've taken more of your time than I should. I'm very grateful for your hard work maintaining Emacs, and discussions like this are worthwhile if they lead to improved editing efficiency for users. The functions are all very short, very convenient in my opinion, and importantly they rhyme with functions that are already in simple.el. > This said, I think those new commands, unbound to any key, shouldn't be > placed in simple.el (which is preloaded) but into some other file. I'm > tempted to say "misc.el", where we could stuff any number of "commands > that users might like, but for which we couldn't come up with a good > key-binding". Ooo, I'm afraid misc.el might be a regrettable move in the long run. I think descriptive package names are the way to go, as the base Emacs distribution continues to grow. Perhaps simple.el could be split into something like base-buffers.el, base-mark.el, etc. As it stands, after careful examination of the base packages, I believe my suggested functions belong in simple.el. There are many commands in simple.el that are not bound to keys, including: * Variations of existing bound functions `next-error-no-select', `previous-error-no-select' `newline-and-indent', `reindent-then-newline-and-indent' `undo-only' * Modify buffer text `forward-to-indentation', `backward-to-indentation' `fixup-whitespace' * Information `what-line', `what-cursor-position' `blink-matching-open' * Others that I have bound `copy-region-as-kill' `insert-buffer' My suggested commands are mainly in one category: * Variations of existing bound functions `backward-delete-word', `delete-word' `kill-line-or-region' `pull-line-down', `pull-line-up' `zap-back-to-char', `zap-up-to-char' `delete-indentation-nospace' `downcase-word-or-region', `upcase-word-or-region' * Modify buffer text `delete-all-blank-lines' There are mainly two ways users can find out about such unbound commands: docstring cross-references, and brief entries in the Emacs/Emacs Lisp manuals. The latter manual mentions practically all commands in simple.el. Again, my apologies for the length of this message. If any of my suggestions end up being accepted, I could add some cross-references to their docstrings. Best regards, Arni [-- Attachment #2: Type: TEXT/PLAIN, Size: 294 bytes --] (defun pos-at-beginning-of-line (N) "Return the position at beginning of line N." (save-excursion (goto-char (point-min))(line-beginning-position N))) (defun pos-at-end-of-line (N) "Return the position at end of line N." (save-excursion (goto-char (point-min))(line-end-position N))) [-- Attachment #3: Type: TEXT/PLAIN, Size: 2368 bytes --] (defun backward-delete-word (N) "Delete previous N words." (interactive "*p")(delete-word (- N))) (defun delete-word (N) "Delete following N words." (interactive "*p") (delete-region (point)(save-excursion (forward-word N)(point)))) (defun kill-line-or-region () "Kill region if selected, otherwise kill line." (interactive) (if (and mark-active transient-mark-mode)(kill-region (point)(mark))(kill-line))) (defun pull-line-down (N) "Pull line down N times." (interactive "*p") (let ((col (current-column)))(kill-whole-line 1)(forward-line N)(yank 1)(pop kill-ring)(forward-line -1) (move-to-column col))) (defun pull-line-up (N) "Pull line up N times." (interactive "*p") (let ((col (current-column)))(kill-whole-line 1)(forward-line (- N))(yank 1)(pop kill-ring)(forward-line -1) (move-to-column col))) (defun zap-back-to-char (char) "Delete region back to, but not including, CHAR." (interactive "cZap back to char: ") (let ((case-fold-search nil)) (delete-region (point)(progn (search-backward (char-to-string char))(forward-char)(point))))) (defun zap-up-to-char (char) "Delete region up to, but not including, CHAR." (interactive "cZap to char: ") (let ((case-fold-search nil)) (delete-region (point)(progn (search-forward (char-to-string char))(backward-char)(point))))) (defun delete-all-blank-lines () "Delete all blank lines in buffer." (interactive) (save-excursion (goto-char (point-min)) (let ((count 0))(while (search-forward "\n\n" nil t)(goto-char (point-min)) (while (search-forward "\n\n" nil t)(replace-match "\n")(setq count (+ count 1))) (goto-char (point-min))) (if (= (following-char) 10)(progn (delete-char 1)(setq count (+ count 1)))) (message "Deleted %d blank lines" count)))) (defun delete-indentation-nospace () "Join this line to previous with no whitespace at join." (interactive) (delete-indentation)(delete-horizontal-space)) (defun downcase-word-or-region (N) "Downcase N words or region." (interactive "*p") (if (and mark-active transient-mark-mode)(downcase-region (point)(mark))(downcase-word N))) (defun upcase-word-or-region (N) "Upcase N words or region." (interactive "*p") (if (and mark-active transient-mark-mode)(upcase-region (point)(mark))(upcase-word N))) [-- Attachment #4: Type: TEXT/PLAIN, Size: 535 bytes --] 10,16c10,13 < (while (re-search-forward "\\s-$" nil t) < (skip-syntax-backward "-" (save-excursion (forward-line 0) (point))) < ;; Don't delete formfeeds, even if they are considered whitespace. < (save-match-data < (if (looking-at ".*\f") < (goto-char (match-end 0)))) < (delete-region (point) (match-end 0)))))) --- > (let ((count 0)) > (while (re-search-forward "[ \t\r]+$" nil t) > (replace-match "")(setq count (1+ count))) > (message "Cleaned %d lines" count))))) [-- Attachment #5: Type: TEXT/PLAIN, Size: 586 bytes --] (defun delete-trailing-whitespace () "Delete all the trailing whitespace across the current buffer. All whitespace after the last non-whitespace character in a line is deleted. This respects narrowing, created by \\[narrow-to-region] and friends. A formfeed is not considered whitespace by this function." (interactive "*") (save-match-data (save-excursion (goto-char (point-min)) (let ((count 0)) (while (re-search-forward "[ \t\r]+$" nil t) (replace-match "")(setq count (1+ count))) (message "Cleaned %d lines" count))))) [-- Attachment #6: Type: TEXT/PLAIN, Size: 721 bytes --] (defun delete-trailing-whitespace () "Delete all the trailing whitespace across the current buffer. All whitespace after the last non-whitespace character in a line is deleted. This respects narrowing, created by \\[narrow-to-region] and friends. A formfeed is not considered whitespace by this function." (interactive "*") (save-match-data (save-excursion (goto-char (point-min)) (while (re-search-forward "\\s-$" nil t) (skip-syntax-backward "-" (save-excursion (forward-line 0) (point))) ;; Don't delete formfeeds, even if they are considered whitespace. (save-match-data (if (looking-at ".*\f") (goto-char (match-end 0)))) (delete-region (point) (match-end 0)))))) ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-18 0:08 ` Arni Magnusson @ 2009-04-18 19:32 ` Stefan Monnier 2009-04-19 1:13 ` Arni Magnusson 0 siblings, 1 reply; 23+ messages in thread From: Stefan Monnier @ 2009-04-18 19:32 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 > `backward-delete-word' > `delete-word' > I think Emacs should provide a simple way for beginning users to have > C-backspace and C-delete behave like they would expect, i.e. leaving > the clipboard intact. There are different ways to provide this, using > a variable and/or functions. Users should not need to write their own > functions for something this fundamental. I think the difference between these and the standard commands is too small to deserve a separate command. There are plenty of ways to get around the problem of "kill when I only want delete" (typically, doing the kill after the C-y, or using M-y, ...). I would only consider some general "kill-next-kill" feature which would allow to turn any killing command into a deleting one (e.g. a kill-next-kill command which would cause the subsequent commands's effect on the kill-ring to be cancelled). > `kill-line-or-region' > C-k should probably be bound to this function. This would be appreciated by > many `transient-mark-mode' users. I haven't used Emacs without > transient-mark-mode', but don't those people still want C-w bound to > kill-region'? Yes, we couldn't really get rid of C-w, I think, but users of transient-mark-mode could use that key for other things. > `pull-line-down' > `pull-line-up' > These are admittedly simple tricks of lesser importance, but anyone trying > out the existing `transpose-lines' will read its documentation twice and try > to master pulling lines up or down, before giving up. I find myself using > these almost every day, with code, data, and config files. I don't find transpose-lines very useful, so I might accept a proposal that makes it more useful, but not one that adds yet more refinements. > `pos-at-beginning-of-line' > `pos-at-end-of-line' > You're right, it's best to avoid `goto-line'. I have reimplemented these > functions (see attachment) to improve the speed. I think they bridge an > obvious gap in Emacs Lisp, making it considerably easier to read and write > functions that operate on buffer text. The reimplementation doesn't change anything: its performance will still suck on large files. It's just fundamentally an operation that is slow and that we should generally avoid, so I don't want to add yet more ways (additionally to goto-line) to do that. The "obvious gap" that you talk about is only "obvious" if you think in terms of lines, which is almost always the wrong way to think about the text in Emacs. > `zap-back-to-char' > `zap-up-to-char' > I believe these more useful than the existing `zap-to-char', which often > deletes the beginning of that important location, an opening brace or > the like. Maybe a better approach would be to add config var to zap-to-char whether it also zaps the char or not. In any case, I'd rather wait for other people to support this option, since I have no idea how common it is. > `delete-trailing-white' >> I think [ \t\r] is a good default, and if we introduce a config var (which >> I'm not sure is worth the trouble), there's no reason to keep the special >> treatment of formfeed. > I agree that hardwiring [ \t\r] works fastest and is easy to use and > maintain. Attached is my proposed upgrade of this function, where cleaned > lines are counted. Thanks. We'll consider using it for Emacs-23.2. > `delete-all-blank-lines' > Vertical analog to `delete-trailing-white', which I use about as > often. Anyone trying out the existing `delete-blank-lines' will wonder > whether there is a keybinding to delete all blank lines, instead of just > around the point. Can someone figure out a way to tweak flush-lines such that it can be used for that purpose without having to jump through as many hooks? Maybe we can just say that if you call flush-lines with an empty argument (which currently would flush *all* lines) it will flush all empty lines. > `delete-indentation-nospace' > Similar to `delete-indentation' but leaves no space between the joined > lines. I find myself using these almost every day, with prose, code, data, > and config files. I have bound the two functions to neighboring keybindings. Here again, I'm not sure the difference is worth the trouble. I'd rather make fixup-whitespace customizable so you can specify when to keep a space and when not to. You can then customize it to never keep a space, and then use M-^ for delete-indentation-nospace and M-^ SPC when you do want a space. > `downcase-word-or-region' > `upcase-word-or-region' > M-l and M-u could be bound to this function. This would be appreciated by > many `transient-mark-mode' users. Yes, I think it would be a good change. > I haven't used Emacs without transient-mark-mode', but don't those > people still want C-x C-l and C-x C-u bound to `downcase-region' and > `upcase-region'? It's possible, but it's less sure than with C-w because those commands are used much less frequently, so it might be OK to just tell people to use C-u C-x C-x M-u instead of C-x C-u. Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-18 19:32 ` Stefan Monnier @ 2009-04-19 1:13 ` Arni Magnusson 2009-04-19 1:40 ` Arni Magnusson 2009-04-19 3:14 ` Stefan Monnier 0 siblings, 2 replies; 23+ messages in thread From: Arni Magnusson @ 2009-04-19 1:13 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 >> `backward-delete-word' >> `delete-word' > > I would only consider some general "kill-next-kill" feature which would > allow to turn any killing command into a deleting one (e.g. a > kill-next-kill command which would cause the subsequent commands's > effect on the kill-ring to be cancelled). This would mean two keystrokes to delete a word, right? First `kill-next-kill' and then `kill-word'. It's an idea, but I still believe that many users would appreciate binding single keystrokes to the functions I suggested. They would most likely bind them to C-backspace and C-delete. >> `pos-at-beginning-of-line' >> `pos-at-end-of-line' > > The reimplementation doesn't change anything: its performance will still > suck on large files. It's just fundamentally an operation that is slow > and that we should generally avoid, so I don't want to add yet more ways > (additionally to goto-line) to do that. I don't understand, I think these functions are blazing fast. In practice, I would probably not use Emacs to perform 100,000 iterations on a 200 MB file - but that's why I'm surprised to see that it takes less than a second: 100000 M-x benchmark (pos-at-end-of-line 10) ; 0.421s I'm using a small arg of 10, because that's the case where you predicted that `line-end-position' would be much faster. 100000 M-x benchmark (line-end-position 10) ; 0.220s This is necessarily faster, since `pos-at-end-of-line' calls `line-end-position', but the (save-excursion (goto-char (point-min)) overhead is not as great as one might expect. With few iterations and large arg, the speed is also comparable: 10 M-x benchmark (pos-at-end-of-line 100000) ; 0.156s 10 M-x benchmark (line-end-position 100000) ; 0.156s Most things become more sluggish with a 200 MB file. Overall, I think these functions make it considerably easier to read and write functions that operate on buffer text - with minimal performance cost. In practice, I use it without iteration, and with a 1 MB source code file it doesn't register in a benchmark (0.000000s). I hesitate to introduce another function to the discussion, but here's an example where I use `pos-at-beginning-of-line' and `pos-at-end-of-line'. Since you're the maintainer of newcomment.el, it might pique your interest: (defun comment-line-or-region () "Comment line or region." (interactive) (require 'newcomment) (if (and mark-active transient-mark-mode) (comment-region (pos-at-beginning-of-line (line-number-at-pos (region-beginning))) (pos-at-end-of-line (line-number-at-pos (region-end)))) (comment-region (line-beginning-position)(line-end-position)))) Same idea as `kill-line-or-region'. Without the `pos-at-beginning-of-line' and `pos-at-end-of-line', (comment-region (region-beginning) (region-end)) it would misbehave when the region consists of a partially selected first and/or last line. Someone like you might be able to improve this function, but it's served me well and has no discernible speed lag. >> `delete-all-blank-lines' > > Can someone figure out a way to tweak flush-lines such that it can be > used for that purpose without having to jump through as many hooks? > Maybe we can just say that if you call flush-lines with an empty > argument (which currently would flush *all* lines) it will flush all > empty lines. This is definitely an idea, making better use of the default value of the regexp. But do you really mean flush all empty lines, or just the empty lines below the point? The idea behind `delete-all-blank-lines' is to really delete all empty lines, without moving the point, in one keystroke. I could probably edit `flush-lines' to do exactly that, although it operates only on text after the point for non-default regexps. Phew, it looks like the rest of our discussion threads have closed successfully, meaning that we have fully understood each others' ideas, and the decisions will depend on your good judgement and the Emacs elders. Cheers, Arni ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-19 1:13 ` Arni Magnusson @ 2009-04-19 1:40 ` Arni Magnusson 2009-04-19 3:14 ` Stefan Monnier 1 sibling, 0 replies; 23+ messages in thread From: Arni Magnusson @ 2009-04-19 1:40 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887 > [...] understood each others' ideas [...] Whoa, that should have been each other's ideas. Lisp programmers need to be extra careful with their apostrophes :) Arni ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-19 1:13 ` Arni Magnusson 2009-04-19 1:40 ` Arni Magnusson @ 2009-04-19 3:14 ` Stefan Monnier 2009-04-19 13:41 ` Arni Magnusson 1 sibling, 1 reply; 23+ messages in thread From: Stefan Monnier @ 2009-04-19 3:14 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 >> I would only consider some general "kill-next-kill" feature which would >> allow to turn any killing command into a deleting one >> (e.g. a kill-next-kill command which would cause the subsequent commands's >> effect on the kill-ring to be cancelled). > This would mean two keystrokes to delete a word, right? Yes, at least. Maybe you can amortize it so it's only N+1 for N words. > It's an idea, but I still believe that many users would appreciate > binding single keystrokes to the functions I suggested. Yes, that's where we disagree. > (defun comment-line-or-region () > "Comment line or region." > (interactive) > (require 'newcomment) > (if (and mark-active transient-mark-mode) > (comment-region > (pos-at-beginning-of-line (line-number-at-pos (region-beginning))) > (pos-at-end-of-line (line-number-at-pos (region-end)))) > (comment-region (line-beginning-position)(line-end-position)))) A perfect example of the kind of performance bug that comes up when you think in terms of lines, as encouraged by pos-at-beginning/end-of-line. The above should be: (defun comment-line-or-region () "Comment line or region." (interactive) (require 'newcomment) (if (and mark-active transient-mark-mode) (comment-region (save-excursion (goto-char (region-beginning)) (line-beginning-position)) (save-excursion (goto-char (region-end)) (line-end-position))) (comment-region (line-beginning-position) (line-end-position)))) line-number-at-pos is also a "function to avoid", just as bad as goto-line. Your code will walk over the whole buffer 4 times (twice to compute the line-number at region beg and end, then twice to find the beg/end of those 2 lines). >>> `delete-all-blank-lines' >> >> Can someone figure out a way to tweak flush-lines such that it can be used >> for that purpose without having to jump through as many hooks? Maybe we >> can just say that if you call flush-lines with an empty argument (which >> currently would flush *all* lines) it will flush all empty lines. > This is definitely an idea, making better use of the default value of the > regexp. But do you really mean flush all empty lines, or just the empty > lines below the point? The idea behind `delete-all-blank-lines' is to really > delete all empty lines, without moving the point, in one keystroke. I could > probably edit `flush-lines' to do exactly that, although it operates only on > text after the point for non-default regexps. I don't think the position-preservation is important enough to warrant a different command. So do C-SPC M-< before and C-u C-SPC afterwards if you want to preserve point. Or try to provide some way for flush-lines to operate on the whole buffer, without having to move point. Stefan ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-19 3:14 ` Stefan Monnier @ 2009-04-19 13:41 ` Arni Magnusson 0 siblings, 0 replies; 23+ messages in thread From: Arni Magnusson @ 2009-04-19 13:41 UTC (permalink / raw) To: Stefan Monnier; +Cc: 2887, bug-lisp-manual [Arni Magnusson wrote:] >> (defun pos-at-beginning-of-line (N) >> "Return the position at beginning of line N." >> (save-excursion >> (goto-char (point-min))(line-beginning-position N))) >> >> (defun pos-at-end-of-line (N) >> "Return the position at end of line N." >> (save-excursion >> (goto-char (point-min))(line-end-position N))) >> >> (defun comment-line-or-region () >> "Comment line or region." >> (interactive) >> (require 'newcomment) >> (if (and mark-active transient-mark-mode) >> (comment-region >> (pos-at-beginning-of-line >> (line-number-at-pos (region-beginning))) >> (pos-at-end-of-line >> (line-number-at-pos (region-end)))) >> (comment-region >> (line-beginning-position)(line-end-position)))) [Stefan Monnier wrote:] > A perfect example of the kind of performance bug that comes up when you > think in terms of lines, as encouraged by pos-at-beginning/end-of-line. > The above should be: > > (defun comment-line-or-region () > "Comment line or region." > (interactive) > (require 'newcomment) > (if (and mark-active transient-mark-mode) > (comment-region > (save-excursion > (goto-char (region-beginning))(line-beginning-position)) > (save-excursion > (goto-char (region-end))(line-end-position))) > (comment-region > (line-beginning-position)(line-end-position)))) > > line-number-at-pos is also a "function to avoid", just as bad as > goto-line. Your code will walk over the whole buffer 4 times (twice to > compute the line-number at region beg and end, then twice to find the > beg/end of those 2 lines). --- Aha, now I see what you mean. One should use relative motion in Emacs Lisp programs and avoid referring to absolute line numbers (`goto-line', `line-beginning-position', `line-end-position', `line-number-at-pos'). Thank you Stefan, for explaining this to me - now I would like to help others to avoid using these functions in Emacs Lisp programs, when possible. Couldn't this be mentioned in the docstrings and in the Emacs Lisp Manual? They had already helped me by tagging a warning sign on functions like: `next-line', `previous-line' `beginning-of-buffer', `end-of-buffer' `replace-string', `replace-regexp' `insert-file', `insert-buffer' In my notes, I have also written that (goto-char (point-min)) is better than (goto-line 1), but now I can't see where this is documented. Besides the docstrings and the function entries in the manual, there is a section in the manual called "Emacs Programming Tips" where the pitfalls of *-line-* functions could be mentioned. Thanks, Arni ^ permalink raw reply [flat|nested] 23+ messages in thread
* bug#2887: Suggestions for simple.el 2009-04-04 13:32 bug#2887: Suggestions for simple.el Arni Magnusson 2009-04-04 14:21 ` Stefan Monnier @ 2020-09-19 21:50 ` Lars Ingebrigtsen 1 sibling, 0 replies; 23+ messages in thread From: Lars Ingebrigtsen @ 2020-09-19 21:50 UTC (permalink / raw) To: Arni Magnusson; +Cc: 2887 "Arni Magnusson" <arnima@hafro.is> writes: > I would like to suggest adding a few functions to the simple.el library. I > do this with hesitation - since I know the idea is to keep it simple and > let users write extensions to suit their preferences - but I believe a > large number of Emacs users would appreciate having access to these > functions out of the box. There was a lot of discussion that followed after posting the patch, but it didn't seem like there was a lot of enthusiasm for adding these basic functions to Emacs eleven years ago, so it seems unlikely that there'll be more progress here now, and I'm closing this bug report. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2020-09-19 21:50 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-04-04 13:32 bug#2887: Suggestions for simple.el Arni Magnusson 2009-04-04 14:21 ` Stefan Monnier 2009-04-04 23:35 ` Arni Magnusson 2009-04-05 3:27 ` Stefan Monnier 2009-04-05 14:26 ` Leo 2009-04-05 20:17 ` Arni Magnusson 2009-04-05 21:59 ` Lennart Borgman 2009-04-06 2:14 ` Stefan Monnier 2009-04-06 3:02 ` Drew Adams 2009-04-07 2:46 ` Arni Magnusson 2009-04-07 14:02 ` Stefan Monnier 2009-04-07 16:09 ` Drew Adams [not found] ` <008701c9b79b$41f3f250$0200a8c0@us.oracle.com> 2009-04-07 17:18 ` Stefan Monnier 2009-04-07 17:22 ` Chong Yidong [not found] ` <87iqlg4bwl.fsf@cyd.mit.edu> 2009-04-07 17:26 ` Drew Adams 2009-04-07 21:43 ` Stefan Monnier 2009-04-18 0:08 ` Arni Magnusson 2009-04-18 19:32 ` Stefan Monnier 2009-04-19 1:13 ` Arni Magnusson 2009-04-19 1:40 ` Arni Magnusson 2009-04-19 3:14 ` Stefan Monnier 2009-04-19 13:41 ` Arni Magnusson 2020-09-19 21:50 ` Lars Ingebrigtsen
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git 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).