6

I'm looking for a way to reduce what Emacs kills when I use backward-kill-word.

protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
    if (PropertyChanged != null)
        PropertyChanged(this, e);
}

If I'm editing the above code in Emacs and I place my cursor on the very last character (the }) and I call backward-kill-word, the entirety of e); is killed, since Emacs only considers the e to be a word.

Another example is if you place your cursor on the 'P' of PropertyChanged(this, e) and call backward-kill-word, the entirety of null) before it is killed. The closed parenthesis is simply considered to not be a word.

My question is how I can eliminate this behavior. I want characters like ), ', }, etc. to be treated as words by backward-kill-word. This means that backward-kill-word kills these characters and the cursor replaces them, just how backward-kill-word typically behaves for one-character-long words like e. One possible solution I've thought of is to somehow edit what Emacs considers to be words and simply add the characters I want to the list. Regardless, thanks for the help!

gvelasq
  • 63
  • 4
  • 1
    It's not clear (to me) just what behavior you're looking for. What does it mean to "ignore" characters such as `)` and `}`? Do you want them to be skipped over and the next word found to be killed? Or do you want the word-kill operation to do nothing if it runs into a non-word char? Or something else? Try to specify the behavior you want. – Drew Feb 02 '17 at 21:33
  • Very similar question here: [backward-kill-word ignores whitespaces, is there another friendlier version?](http://emacs.stackexchange.com/questions/10644/backward-kill-word-ignores-whitespaces-is-there-another-friendlier-version) – Dan Feb 02 '17 at 21:38
  • Understood. But besides not deleting those chars, you do not describe the behavior. Please reread what I wrote. – Drew Feb 02 '17 at 21:38
  • Ah I see. Well, I'd like characters like `}` to be treated as if they were words--so the character itself would be killed and the cursor end up in its place. – gvelasq Feb 02 '17 at 21:42
  • 1
    What about sequences of whitespace or brackets, e.g. `foo)) ))`? It sounds like you want a command that deletes the non-word characters one by one and then deletes 'foo' in one go? So more of a "backward delete char or word?" I think you may need to write your own command here. – glucas Feb 02 '17 at 22:12
  • Yes, that is correct. Effectively I want `backward-kill-word` to treat non-word characters how it treats regular characters, and I want the rest of its functionality to remain unchanged. – gvelasq Feb 02 '17 at 22:18

2 Answers2

6

Here's a quick attempt at a custom function that may do what you want:

(defun backward-kill-char-or-word ()
  "Delete the character or word before point."
  (interactive)
  (if (looking-back "\\w" 1)
      (backward-kill-word 1)
    (backward-delete-char 1)))

This looks back one character to decide what to do. If it sees a word constituent character it kills the word, otherwise it just deletes one character. There may be other cases you needed to handle, this is "lightly tested".

You can revise this to handle whitespace in different ways. If you want to delete spaces along with the next word (which is what backward-kill-word does), try this:

(defun backward-kill-char-or-word ()
  (interactive)
  (if (looking-back (rx (char word blank)) 1)
      (backward-kill-word 1)
    (backward-delete-char 1)))

If you want to delete a sequence of whitespace as a unit but stop at a word, try this:

(defun backward-kill-char-or-word ()
  (interactive)
  (cond 
   ((looking-back (rx (char word)) 1)
    (backward-kill-word 1))
   ((looking-back (rx (char blank)) 1)
    (delete-horizontal-space t))
   (t
    (backward-delete-char 1))))
glucas
  • 20,175
  • 1
  • 51
  • 83
  • This does work the way I had in mind. :) It's only missing the ability to kill the whitespace behind the cursor until a character or word is found, as `backward-kill-word` does. – gvelasq Feb 02 '17 at 22:43
  • The third piece of code that you provided--the one that uses `delete-horizontal-space`--is just what I was looking for. Thank you so much!! – gvelasq Feb 02 '17 at 23:51
3

Emacs uses syntax tables to decide what is and is not a word. Each major mode will have its own syntax table. Commands that move over or delete words will use the values in this table to determine how far to go.

The key syntax class in this case is the 'word constituent'. Deleting a word in Emacs works by deleting whole groups of adjacent word constituents.

To add characters to the 'word constituent' class you can use modify-syntax-entry. For example, to add the character ), you'd use the following:

(modify-syntax-entry ?) "w") 

By default, this will modify the current syntax table. You'll need to do a bit more to target the syntax table for a particular mode. For example, I have the following in my .init.el:

(eval-after-load "bibtex"
     (modify-syntax-entry ?% "_" bibtex-mode-syntax-table))

This will modify the syntax table for bibtex-mode after it's loaded, changing the % character to a 'symbol constituent'. See the linked manual page for more details on the different syntax classes and how to set them.

Caution

As @politza points out, changing the syntax table may have unintended consequences. Syntax classes are a pretty fundamental structure in Emacs, and many different functions depend on them, not just movement and deletion commands. So you might find surprising bugs arise as a consequence of such changes.

Tyler
  • 21,719
  • 1
  • 52
  • 92
  • I added `(modify-syntax-entry ?) "w")` to my .emacs file and `backward-kill-word` still kills `)` in addition to the word before it. :( I'm running Emacs version 25.1-2, by the way. – gvelasq Feb 02 '17 at 21:53
  • So with point at the end of ` null)` you would expect the command to delete just `)`, then if called again to delete `null`? – glucas Feb 02 '17 at 21:56
  • Yup, that is what I'd like to do. – gvelasq Feb 02 '17 at 21:58
  • I think this is a very bad idea, because other core functions depend on it; maybe even font-lock in some cases. – politza Feb 02 '17 at 22:14
  • @politza agreed. I tried to answer the immediate question, but you're quite right that it may have unexpected consequences. Updated. – Tyler Feb 02 '17 at 22:23
  • gvelasq: ok. I've answered the question "how to I add characters to the list that Emacs considers words". What you actually need is something more sophisticated, as @glucas has noted. – Tyler Feb 02 '17 at 22:26
  • 2
    I use `with-syntax-table` for the duration of my custom functions for movement and searching so that I don't touch the major-mode syntax table, and I define a custom syntax table for said movement. – lawlist Feb 02 '17 at 22:30