Search code examples
emacselisp

Removing enclosed text in Emacs


I would like to delete enclosed text between special characters like: ["{'<( etc .. this way I can remove text like "this is a very ... long text" with a simple keyboard shortcut. I was looking for some already existing mode that performs something similar but I didn't found any so I created some lisp code which performs good in most of situations, however it's not working correctly in all cases. For example if I have the following text entry and I put the cursor in the position"^" then I would liek to remove all the text enclosed by " but it doesn't work:

"aaaaa ] > [more text] aaaaa"
------------ ^

My lisp code is the following:

;; returns the enclosing character for the character "c"
(defun get-enc-char (c) (cond
                         ((string= c "(") ")")
                         ((string= c "[") "]")
                         ((string= c "{") "}")
                         ((string= c ">") "<")
                         ((string= c "<") ">")
                         ((string= c "'") "'")
                         ((string= c "\"") "\"")
                         (t nil)
                         )
  )

(defun delete-enclosed-text ()
  "Delete texts between any pair of delimiters."
  (interactive)
  (save-excursion
    (let (p1 p2 mychar)
      ; look for one of those characters and store the cursor position
      (skip-chars-backward "^([\'\"><{") (setq p1 (point))
      ; store the char at this point, look for its enclosed char and advance
      ; the cursor newly (this done to avoid the cases when the char and
      ; its enclosed-char are the same like " or ' chars.
      (backward-char 1) (setq mychar (thing-at-point 'char)) (forward-char 1)
      ; look forward for the enclosed char
      (skip-chars-forward (concatenate 'string "^" (get-enc-char mychar))) (setq p2 (point))
      ; only delete the region if we found the enclosed character
      (if (looking-at "[\]\}\"\'\)<>]") (kill-region p1 p2)))))

Following is an example: enter image description here


Solution

  • Here a solution based on your code

    ;; returns the enclosing character for the character "c"
      (defun get-enc-char (c) (cond
                               ((string= c "(") ")")
                               ((string= c "[") "]")
                               ((string= c "{") "}")
                               ((string= c ">") "<")
                               ((string= c "<") ">")
                               ((string= c "'") "'")
                               ((string= c "\"") "\"")
                               (t nil)
                               ))
     (defvar empty-enclose 0)
      (defun delete-enclosed-text ()
        "Delete texts between any pair of delimiters."
        (interactive)
        (setq empty-enclose 0)
        (save-excursion
          (let (p1 p2 orig)
            (setq orig (point))
            (setq p1 (point))
            (setq p2 (point))
            (setq find 0)
            (setq mychar (thing-at-point 'char))
            (if (-contains? '("(" "[" "{" "<" "'" "\"") mychar)
                (progn
                  (setq left_encloser (thing-at-point 'char))
                  (backward-char -1)
                  (if (string-equal (thing-at-point 'char) (get-enc-char left_encloser))
                      (progn
                        (backward-char -1)
                        (setq p2 (point))
                        (setq find 1)
                        (setq empty-enclose 1)))))
            (while (eq find 0)
              (skip-chars-backward "^({[<>\"'")
              (setq p1 (point))
              (backward-char 1)
              (setq left_encloser (thing-at-point 'char))
              (goto-char orig)
              (while (and (not (eobp)) (eq find 0))
                (backward-char -1)
                (skip-chars-forward "^)}]<>\"'")
                (setq right_encloser (thing-at-point 'char))
                (if (string-equal right_encloser (get-enc-char left_encloser))
                    (progn
                      (setq p2 (point))
                      (setq find 1))))
              (goto-char p1)
              (backward-char 1))
            (delete-region p1 p2)))
        (if (eq empty-enclose 0)
            (backward-char 1)))