user1539179
user1539179

Reputation: 1885

Duplicating a line in emacs with Ace-Jump

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

Answers (4)

Matus Goljer
Matus Goljer

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

user1539179
user1539179

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

abo-abo
abo-abo

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

Dan
Dan

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

Related Questions