Skip to content

Commit

Permalink
paxedit-symbol-kill functionality added
Browse files Browse the repository at this point in the history
  • Loading branch information
promethial committed Jan 3, 2016
1 parent cab06ab commit 0d06c72
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 54 deletions.
144 changes: 119 additions & 25 deletions paxedit.el
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@
:group 'paxedit
:type 'string)

(defcustom paxedit-message-symbol-not-found "No symbol found to kill."
"Message emitted when no symbol found to kill."
:group 'paxedit
:type 'string)

;;; Internal Options

(defvar paxedit-sexp-implicit-functions nil
Expand Down Expand Up @@ -455,6 +460,16 @@ we hold These Truths
(save-excursion (goto-char rstart)
(insert (funcall func it)))))

(defun paxedit-region-buffer ()
"Return a REGION reflecting the min and max points of the current
buffer."
(cons (point-min)
(point-max)))

(defun-paxedit-region paxedit-region-narrow ()
"Narrow buffer to REGION."
(narrow-to-region rstart rend))

(defun paxedit-preserve-place ()
"Insert a unique string to preserve the current cursor position."
(insert paxedit-cursor-preserve-random))
Expand Down Expand Up @@ -723,33 +738,104 @@ or right boundary of the symbol."
(when (paxedit-region-contains-point-exclude-boundary it (point))
it)))

(defun paxedit-symbol-forward-kill (&optional n)
"Kill back"
(defun paxedit-direction-kill (forward n)
"General, context-specific implementation of symbol killing in the
forward and backward direction."
(let ((region-choice (if forward 'cl-rest 'cl-first))
(clean-choice (if forward
'paxedit-whitespace-delete-right
'paxedit-whitespace-delete-left)))
(paxedit-awhen (or (paxedit-comment-internal-region (paxedit-comment-region-cursor))
(paxedit-sexp-core-region)
(paxedit-region-buffer))
(save-restriction
(paxedit-region-narrow it)
(dotimes (_ n)
(funcall clean-choice)
(paxedit-aif (paxedit-symbol-cursor-within?)
(paxedit-region-kill (cons (point)
(funcall region-choice it)))
(paxedit-aif (paxedit-symbol-current-boundary)
(if (/= (point) (funcall region-choice it))
(paxedit-region-kill it)
(message paxedit-message-symbol-not-found))
(message paxedit-message-symbol-not-found))))))))

(defun paxedit-backward-kill (&optional n)
"Kill symbol before the cursor—-if it exists—-deleting any whitespace in
between the cursor and the symbol, while keeping the containing
expression balanced. The universal argument can be used to repeat the
command N number of times.
This context specific command takes a conservative approach by
preventing unbalancing of comments or expressions.
`paxedit-backward-kill will not kill beyond the containing
expression. Additionally, when the cursor is inside a comment, the
kill command will kill no further than the start or end of the comment
to prevent accidental commenting of other expressions or
un-commenting.
e.g.
hello -!-world -> -!-world
(+ x1-!- y1 g1) -> (+ -!- y1 g1)
(concat one-vari-!-able two) -> (concat -!-able two)
;;; Backward kill will not kill symbols beyond the expression or
;;; comment that currently contains the cursor. Note how the next
;;; examples do nothing but emit a message there is no symbol found
;;; to kill.
(-!-concat one-variable two) -> (-!-concat one-variable two)
;;;-!- hello world -> ;;;-!- hello world
;;; Using the universal argument, C-U 2, to kill two symbols
(+ x1 y1 -!-g1) -> (+ -!-g1)"
(interactive "p")
(dotimes (_ n)
(paxedit-whitespace-delete-right)
(paxedit-aif (paxedit-symbol-cursor-within?)
(progn (paxedit-region-kill (cons (point)
(cl-rest it))))
(paxedit-aif (paxedit-symbol-current-boundary)
(if (not (= (point) (cl-rest it)))
(paxedit-region-kill it)
(message "No symbol found to kill."))
(message "No symbol found to kill.")))))

(defun paxedit-symbol-backward-kill (&optional n)
"Kill back"
(paxedit-direction-kill nil n))

(defun paxedit-forward-kill (&optional n)
"Kill symbol after the cursor—-if it exists—-deleting any whitespace in
between the cursor and the symbol, while keeping the containing
expression balanced. The universal argument can be used to repeat the
command N number of times.
This context specific command takes a conservative approach by
preventing unbalancing of comments or expressions.
`paxedit-forward-kill will not kill beyond the containing
expression. Additionally, when the cursor is inside a comment, the
kill command will kill no further than the start or end of the comment
to prevent accidental commenting of other expressions or
un-commenting.
e.g.
hello -!-world -> hello -!-
(+ x1-!- y1 g1) -> (+ x1 -!- g1)
(concat one-vari-!-able two) -> (concat one-vari-!- two)
;;; Forward kill will not kill symbols beyond the expression or
;;; comment that currently contains the cursor. Note how the next
;;; examples do nothing but emit a message there is no symbol found
;;; to kill.
(concat one-variable two-!-) -> (concat one-variable two-!-)
;;; hello world-!- -> ;;; hello world-!-
;;; Using the universal argument, C-U 2, to kill two symbols
(+ x1-!- y1 g1) -> (+ x1-!-)"
(interactive "p")
(dotimes (_ n)
(paxedit-whitespace-delete-left)
(paxedit-aif (paxedit-symbol-cursor-within?)
(progn (paxedit-region-kill (cons (cl-first it)
(point))))
(paxedit-aif (paxedit-symbol-current-boundary)
(if (not (= (point) (cl-first it)))
(paxedit-region-kill it)
(message "No symbol found to kill."))
(message "No symbol found to kill.")))))
(paxedit-direction-kill t n))

;;; Comment Functions

Expand Down Expand Up @@ -862,6 +948,14 @@ or right boundary of the symbol."
;;; Cleanup Functions
;;; SEXP Deletion Cleanup

(defun paxedit--whitespace-skip (&optional clean-to-right?)
"Skip whitespace characters—-if they exist--until a non-whitespace
character or end of buffer is reached."
(paxedit-funcif clean-to-right?
'skip-chars-forward
'skip-chars-backward
(concat paxedit-general-whitespace)))

(defun paxedit-whitespace-clean (&optional clean-to-right?)
"Clean whitespace to the right or left."
(let ((empty-region-end (point)))
Expand Down
75 changes: 60 additions & 15 deletions readme.org
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Paxedit takes a departure from the above manual state of code editing through au
#+END_ABSTRACT
#+LATEX: \tableofcontents
#+TOC: nil
* Table of Contents :toc:
* Table of Contents :toc:
- [[#demo][Demo]]
- [[#introduction][Introduction]]
- [[#what-is-paxedit][What is Paxedit?]]
Expand All @@ -23,8 +23,8 @@ Paxedit takes a departure from the above manual state of code editing through au
- [[#setup][Setup]]
- [[#customization][Customization]]
- [[#functionality][Functionality]]
- [[#context-navigation][Context Navigation]]
- [[#context-refactoring][Context Refactoring]]
- [[#context-sensitive-navigation][Context Sensitive Navigation]]
- [[#context-sensitive-refactoring][Context Sensitive Refactoring]]
- [[#symbolic-expression-refactoring][Symbolic Expression Refactoring]]
- [[#symbol-refactoring][Symbol Refactoring]]
- [[#open-pair][Open Pair]]
Expand Down Expand Up @@ -172,6 +172,10 @@ Available to install via Melpa.
(define-key paxedit-mode-map (kbd "C-&") 'paxedit-kill)
(define-key paxedit-mode-map (kbd "C-*") 'paxedit-delete)
(define-key paxedit-mode-map (kbd "C-^") 'paxedit-sexp-raise)
;; Symbol backward/forward kill
(define-key paxedit-mode-map (kbd "C-w") 'paxedit-backward-kill)
(define-key paxedit-mode-map (kbd "M-w") 'paxedit-forward-kill)
;; Symbol manipulation
(define-key paxedit-mode-map (kbd "M-u") 'paxedit-symbol-change-case)
(define-key paxedit-mode-map (kbd "C-@") 'paxedit-symbol-copy)
(define-key paxedit-mode-map (kbd "C-#") 'paxedit-symbol-kill)))
Expand Down Expand Up @@ -243,7 +247,7 @@ Available to install via Melpa.
;;; using the format for paxedit-implicit-functions-elisp
#+END_SRC
* Functionality
** Context Navigation
** Context Sensitive Navigation
1. ~paxedit-backward-up~ - Move to the start of the explicit expression, implicit expression or comment.
#+BEGIN_SRC emacs-lisp
;;; Explicit expression
Expand Down Expand Up @@ -298,7 +302,7 @@ Available to install via Melpa.

(message "hello world") ; While in some comment editing-!-
#+END_SRC
** Context Refactoring
** Context Sensitive Refactoring
1. ~paxedit-transpose-forward~ - Swap the current explicit expression, implicit expression, symbol, or comment forward depending on what the cursor is on and what is available to swap with. This command is very versatile and will do the "right" thing in each context. See below for the different uses.
#+BEGIN_SRC emacs-lisp
;;; Swapping symbols, place the cursor within the symbol and run the
Expand Down Expand Up @@ -432,7 +436,6 @@ Available to install via Melpa.
;;; expression causes the comment to be removed.
(comment (message -!-"hello world")) -> (message -!-"hello world")
#+END_SRC
8. ~paxedit-backward-kill~ -
** Symbolic Expression Refactoring
1. ~paxedit-compress~ - Remove all the extraneous whitespace (e.g. newlines, tabs, spaces) to condense expression and contained sub-expressions onto one line.
#+BEGIN_SRC emacs-lisp
Expand Down Expand Up @@ -483,9 +486,52 @@ HELL-!-O -> hell-!-o

(+ some-other-num some-num-!-) -> (+ some-other-num-!-)
#+END_SRC
4. ~paxedit-backward-kill~ - Kill symbol before the cursor—if it exists—deleting any whitespace in between the cursor and the symbol, while keeping the containing expression balanced. The universal argument can be used to repeat the command N number of times. This context specific command takes a conservative approach by preventing unbalancing of comments or expressions. ~paxedit-backward-kill~ will not kill beyond the containing expression. Additionally, when the cursor is inside a comment, the kill command will kill no further than the start or end of the comment to prevent accidental commenting of other expressions or un-commenting.
#+BEGIN_SRC emacs-lisp
hello -!-world -> -!-world

(+ x1-!- y1 g1) -> (+ -!- y1 g1)

(concat one-vari-!-able two) -> (concat -!-able two)

;;; Backward kill will not kill symbols beyond the expression or
;;; comment that currently contains the cursor. Note how the next
;;; examples do nothing but emit a message there is no symbol found
;;; to kill.

(-!-concat one-variable two) -> (-!-concat one-variable two)

;;;-!- hello world -> ;;;-!- hello world

;;; Using the universal argument, C-U 2, to kill two symbols

(+ x1 y1 -!-g1) -> (+ -!-g1)
#+END_SRC
5. ~paxedit-forward-kill~ - Kill symbol after the cursor—if it exists—deleting any whitespace in between the cursor and the symbol, while keeping the containingexpression balanced. The universal argument can be used to repeat the command N number of times. This context specific command takes a conservative approach by preventing unbalancing of comments or expressions. ~paxedit-forward-kill~ will not kill beyond the containing expression. Additionally, when the cursor is inside a comment, the kill command will kill no further than the start or end of the comment to prevent accidental commenting of other expressions or un-commenting.

#+BEGIN_SRC emacs-lisp
hello -!-world -> hello -!-

(+ x1-!- y1 g1) -> (+ x1 -!- g1)

(concat one-vari-!-able two) -> (concat one-vari-!- two)

;;; Forward kill will not kill symbols beyond the expression or
;;; comment that currently contains the cursor. Note how the next
;;; examples do nothing but emit a message there is no symbol found
;;; to kill.

(concat one-variable two-!-) -> (concat one-variable two-!-)

;;; hello world-!- -> ;;; hello world-!-

;;; Using the universal argument, C-U 2, to kill two symbols

(+ x1-!- y1 g1) -> (+ x1-!-)"
#+END_SRC
** Open Pair
1. ~paxedit-open-round~ - Context specific open round. When the cursor is located within a symbol, the symbol is wrapped in parentheses (see scenario 1). If the cursor is outside of any symbol a pair of parentheses are inserted, and a space is inserted to seperate the newly created parentheses from any neighboring symbols (see scenario 2). If the cursor is located within a string a single, open parenthesis will be inserted without a matching close parenthesis (see scenario 3).
#+BEGIN_SRC emacs-lisp
#+BEGIN_SRC emacs-lisp
;;; Scenario 1. Located in symbol
(a b-!-a)

Expand Down Expand Up @@ -513,9 +559,9 @@ HELL-!-O -> hell-!-o
->

(a b (c d)-!-)
#+END_SRC
#+END_SRC
2. ~paxedit-open-quoted-round~ - Context specific single-quoted, open round. When the cursor is located within a symbol, the symbol is wrapped in single-quoted parentheses (see scenario 1). If the cursor is outside of any symbol a pair of single-quoted parentheses are inserted, and a space is inserted to seperate the newly created single-quoted parentheses from any neighboring symbols (see scenario 2). If the cursor is located within a string a single, single-quoted, open parenthesis will be inserted without a matching close parenthesis (see scenario 3).
#+BEGIN_SRC emacs-lisp
#+BEGIN_SRC emacs-lisp
;;; Scenario 1. Located in symbol
(a b-!-a)

Expand Down Expand Up @@ -543,9 +589,9 @@ HELL-!-O -> hell-!-o
->

(a b '(c d)-!-)
#+END_SRC
#+END_SRC
3. ~paxedit-open-bracket~ - Context specific open bracket. When the cursor is located within a symbol, the symbol is wrapped in brackets (see scenario 1). If the cursor is outside of any symbol a pair of brackets are inserted, and a space is inserted to seperate the newly created brackets from any neighboring symbols (see scenario 2). If the cursor is located within a string a single, open bracket will be inserted without a matching close bracket (see scenario 3).
#+BEGIN_SRC emacs-lisp
#+BEGIN_SRC emacs-lisp
;;; Scenario 1. Located in symbol
[a b-!-a]

Expand Down Expand Up @@ -573,10 +619,9 @@ HELL-!-O -> hell-!-o
->

[a b [c d]-!-]
#+END_SRC

#+END_SRC
4. ~paxedit-open-curly-bracket~ - Context specific open curly bracket. When the cursor is located within a symbol, the symbol is wrapped in curly brackets (see scenario 1). If the cursor is outside of any symbol a pair of curly brackets are inserted, and a space is inserted to seperate the newly created curly brackets from any neighboring symbols (see scenario 2). If the cursor is located within a string a single, open curly bracket will be inserted without a matching close curly bracket (see scenario 3).
#+BEGIN_SRC emacs-lisp
#+BEGIN_SRC emacs-lisp
;;; Scenario 1. Located in symbol
{a b-!-a}

Expand Down Expand Up @@ -604,7 +649,7 @@ HELL-!-O -> hell-!-o
->

{a b {c d}-!-}
#+END_SRC
#+END_SRC
** Debugging
1. ~paxedit-macro-expand-replace~ - Expand the current expression in its place if it is macro.
#+BEGIN_SRC emacs-lisp
Expand Down
40 changes: 26 additions & 14 deletions tests/paxedit-test.el
Original file line number Diff line number Diff line change
Expand Up @@ -495,42 +495,54 @@ when t '-!-(+ 1 2))" "(
("(-!-)" "()-!-")
("(1 2 -!-3)" "(1 -!-2\n 3)")))

(xt-deftest paxedit-symbol-backward-kill
(xtd-setup= (lambda (_) (paxedit-symbol-backward-kill 1))
(xt-deftest paxedit-backward-kill
(xtd-setup= (lambda (_) (paxedit-backward-kill 1))
("(hark-!-)" "(-!-)")
("(in their hill-side -!-blue)" "(in their -!-blue)")
("(in their hill-side-!- blue)" "(in their -!- blue)")
("(in their hill-side bl-!-ue)" "(in their hill-side -!-ue)")
("(in their hill-side blue) -!-" "(in their hill-side blue)-!-"))
("(in their hill-side blue) -!-" "(in their hill-side blue)-!-")
;; Context sensitive comment kill
(";;; Circumambulate-!- the city of a dreamy Sabbath afternoon." ";;; -!- the city of a dreamy Sabbath afternoon."))
;; Testing universal argument
(xtd-setup= (lambda (_) (paxedit-symbol-backward-kill 2))
("(hark ark-!-)" "(-!-)"))
(xtd-setup= (lambda (_) (paxedit-backward-kill 2))
("(hark ark-!-)" "(-!-)")
(";;; Circumambulate-!- the city of a dreamy Sabbath afternoon." ";;;-!- the city of a dreamy Sabbath afternoon."))
;; Testing conditions where symbol cannot be killed
(xtd-return= (lambda (_) (cl-letf (((symbol-function 'message) (lambda (output) (error (concat "message:: " output)))))
(condition-case ex
(call-interactively 'paxedit-symbol-backward-kill)
(call-interactively 'paxedit-backward-kill)
(error (cadr ex)))))
("-!-" "message:: No symbol found to kill.")
("-!-art" "message:: No symbol found to kill.")
("(+ 1 2)-!-" "message:: No symbol found to kill.")
("(-!-+ 1 2)" "message:: No symbol found to kill.")))
("(-!-+ 1 2)" "message:: No symbol found to kill.")
;; Context sensitive comment kill
(";;;-!-" "message:: No symbol found to kill.")
(";;-!-" "message:: No symbol found to kill.")))

(xt-deftest paxedit-symbol-forward-kill
(xtd-setup= (lambda (_) (paxedit-symbol-forward-kill 1))
(xt-deftest paxedit-forward-kill
(xtd-setup= (lambda (_) (paxedit-forward-kill 1))
("(-!-hark)" "(-!-)")
("(in their hill-side -!-blue)" "(in their hill-side -!-)")
("(in their hill-side-!- blue)" "(in their hill-side-!-)")
("(in their hill-side bl-!-ue)" "(in their hill-side bl-!-)")
("(in their hill-side blue)-!- " "(in their hill-side blue)-!-"))
("(in their hill-side blue)-!- " "(in their hill-side blue)-!-")
;; Context sensitive comment kill
(";;; in their hill-side -!-blue" ";;; in their hill-side -!-"))
;; Testing universal argument
(xtd-setup= (lambda (_) (paxedit-symbol-forward-kill 2))
("(hark -!-ark tark)" "(hark -!-)"))
(xtd-setup= (lambda (_) (paxedit-forward-kill 2))
("(hark -!-ark tark)" "(hark -!-)")
(";;; -!-quick test" ";;; -!-")
(";;; -!-test\n(+ 1 2 3)" ";;; -!-\n(+ 1 2 3)"))
;; Testing conditions where symbol cannot be killed
(xtd-return= (lambda (_) (cl-letf (((symbol-function 'message) (lambda (output) (error (concat "message:: " output)))))
(condition-case ex
(call-interactively 'paxedit-symbol-forward-kill)
(call-interactively 'paxedit-forward-kill)
(error (cadr ex)))))
("-!-" "message:: No symbol found to kill.")
("art-!-" "message:: No symbol found to kill.")
("(+ 1 2)-!-" "message:: No symbol found to kill.")
("(+ 1 2-!-)" "message:: No symbol found to kill.")))
("(+ 1 2-!-)" "message:: No symbol found to kill.")
;; Context sensitive comment kill
(";;; Circumambulate the city of a dreamy Sabbath afternoon.-!-" "message:: No symbol found to kill.")))

0 comments on commit 0d06c72

Please sign in to comment.