Reputation: 1885
I'm fairly new to elisp, but one thing that I really want to figure out is either how to wait for ace-jump to end before executing instructions or how get a position from ace-jump instead of moving my cursor. My goal is to be able to select a line with ace-jump, copy it, then paste it right above my current line. I started by first trying to go to a line with ace-jump then duplicate it in place, but that hasn't worked. Here is what I have for that:
(defun ace-jump-yank-line-above ()
(interactive)
(ace-jump-line-mode)
(kill-ring-save (line-beginning-position) (line-beginning-position 2) )
(yank)
)
But this gives me strange behavior
Upvotes: 4
Views: 359
Reputation: 61
ace-jump-mode is really silly... calling it just goes into some useless minor-mode where you pick the hints, but it is non-blocking: any code afterwards is executed immediately.
There is so much potential for this kind of interaction and ace-jump-mode completely wastes it away with crazy implementation. It also doesn't work at all with save-excursion and you wound need to hack around that with various hooks and state-saving variables.
I've written a new package addressing all these issues, you can find it at https://github.com/Fuco1/better-jump Hopefully people will pick it up, but it serves me well at least. Took me about 2 hours to write the basic working prototype and it already covers all the functionality of packages like ace-link, ace-window and ace-whatever-else-you-can-find (also ace-jump, obviously :))
Upvotes: 0
Reputation: 1885
Okay, none of these worked for me, but I used these answers to create a script that works. Here is the code that I used:
;; The base function for the line-based ones
(defun ace-jump-end-do (dfunc afunc)
;; Save where to return to as a marker
(setq ace-jump-do-retpos (make-marker))
(set-marker ace-jump-do-retpos (point))
;; Add our during function to the hook
(setq ace-jump-mode-end-hook
(list `(lambda()
(progn
(setq ace-jump-mode-end-hook)
(,dfunc)
(goto-char ace-jump-do-retpos)
(set-marker ace-jump-do-retpos nil)
(,afunc)
))))
(ace-jump-line-mode)
)
;; Copy the line above the current line
(defun ace-jump-yank-line-above ()
(interactive)
(ace-jump-end-do
;; At the line
(lambda ()
;; Store the line in a variable
(setq line (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
)
;; Upon returning
(lambda ()
(save-excursion
(goto-char (point-at-bol))
(insert (concat line "\n"))
)
(when (bolp) (goto-char (point-at-bol 2)))
)))
Unfortunately, this resets the end hook of ace-jump every time it's called. It works for me though since I don't have anything else hooked to it. If I run into issues, I'll need to figure something else out.
Upvotes: 0
Reputation: 20362
You can have a look at the source of my project lispy.el.
It's got several functions that use ace-jump-mode
and do something after.
For instance lispy-ace-symbol
will ace-jump to symbol and mark it.
Here's the implementation detail - the key is setting ace-jump-mode-hook
:
(defun lispy--ace-do (x bnd &optional filter func no-narrow)
"Use `ace-jump-do' to X within BND when FILTER return t.
When FUNC is not nil, call it after a successful move.
When NO-NARROW is not nil, don't narrow to BND."
(require 'ace-jump-mode)
(lispy--recenter-bounds bnd)
(unless no-narrow
(narrow-to-region (car bnd) (cdr bnd)))
(when func
(setq ace-jump-mode-end-hook
(list `(lambda()
(setq ace-jump-mode-end-hook)
(,func)))))
(let ((ace-jump-mode-scope 'window)
(ace-jump-search-filter filter))
(ace-jump-do x))
(widen))
Upvotes: 4
Reputation: 5369
I use something similar to ace-jump rather than ace-jump itself, but something like this should work (can't be sure about the call to ace-jump-line-mode):
(defun ace-jump-yank-line-above ()
(interactive)
(let ((loc (point-at-bol))
(line nil))
(save-excursion
(ace-jump-line-mode)
(setq line (buffer-substring-no-properties
(point-at-bol) (point-at-eol)))
(goto-char (1- loc))
(if (bobp)
(insert (concat line "\n"))
(insert (concat "\n" line))))))
Upvotes: 2