all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Arni Magnusson <arnima@hafro.is>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: 2887@emacsbugs.donarmstrong.com
Subject: bug#2887: Suggestions for simple.el
Date: Sat, 18 Apr 2009 00:08:46 +0000 (GMT)	[thread overview]
Message-ID: <alpine.LFD.0.9999.0904071723170.12755@localhost.localdomain> (raw)
In-Reply-To: <jwvprfozivy.fsf-monnier+emacsbugreports@gnu.org>

[-- 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))))))

  parent reply	other threads:[~2009-04-18  0:08 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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
2009-04-07 17:18                 ` Stefan Monnier
2009-04-07 17:18                 ` Stefan Monnier
2009-04-07 17:22                 ` Chong Yidong
2009-04-07 17:22                 ` Chong Yidong
2009-04-07 17:26                   ` Drew Adams
2009-04-07 17:26                   ` Drew Adams
2009-04-07 21:43                   ` Stefan Monnier
2009-04-07 16:09               ` Drew Adams
2009-04-18  0:08               ` Arni Magnusson [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.LFD.0.9999.0904071723170.12755@localhost.localdomain \
    --to=arnima@hafro.is \
    --cc=2887@emacsbugs.donarmstrong.com \
    --cc=monnier@iro.umontreal.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.