This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Incorrect copying when duplicating line - key binding proble

4 posts · 5559 views

hey guys,

I wrote code like this:
(defun copy-char-from-line-above ()
  "Copies one character from same column but previous row"
  (interactive)
  (let (c)
    (save-excursion
       (previous-line)
       (setq c (buffer-substring-no-properties (point) (+ (point) 1)))
    )
    (insert c)
  )
)
(defalias 'cup 'copy-char-from-line-above)
(global-set-key "\C-i" 'copy-char-from-line-above)
When I run M-x cup many times it runs ok. Same, if I press C-i C-g C-i C-g ... . Problem is, when I press C-i C-i C-i ... which was my usage intention. It copies always the same letter. Why is it like so?

Re: Incorrect copying when duplicating line - key binding proble

mmi wrote:When I run M-x cup many times it runs ok. Same, if I press C-i C-g C-i C-g ... . Problem is, when I press C-i C-i C-i ... which was my usage intention. It copies always the same letter. Why is it like so?
I've had the same problem with previous-line before, and now I think this is the reason:
previous-line Emacs help page wrote: If you are thinking of using this in a Lisp program, consider using
`forward-line' with a negative argument instead. It is usually easier
to use and more reliable (no dependence on goal column, etc.).
If the goal column only is reset to the point when you press C-i C-g, that would explain the problem. Forward line doesn't do what we want, but if we take the current-column, we can at least do a reasonable hack:
(defun copy-char-from-line-above ()
  "Copies one character from same column but previous row"
  (interactive)
  (let ((c (current-column)))
    (save-excursion
     (forward-line -1)
     (forward-char c)
     (setq c (buffer-substring-no-properties (point) (+ (point) 1))))
    (insert c)))
HTH
"If you want to improve, be content to be thought foolish and stupid." -Epictetus

Re: Incorrect copying when duplicating line - key binding proble

It turns out that the problem is caused by the Emacs LINE-MOVE-VISUAL function in "simple.el". PREVIOUS-LINE calls LINE-MOVE which calls the LINE-MOVE-VISUAL function if the LINE-MOVE-VISUAL variable is true.

From the commentary in LINE-MOVE-VISUAL:
;; Check if the previous command was a line-motion command, or if
;; we were called from some other command.
(if (and (consp temporary-goal-column)
    (memq last-command `(next-line previous-line ,this-command)))
    ;; If so, there's no need to reset `temporary-goal-column',
    ;; but we may need to hscroll.
This means that if you call the LINE-MOVE-VISUAL function from another function several times in a row then the TEMPORARY-GOAL-COLUMN variable doesn't get updated and the cursor moves always to the same position in the previous line (IMO this is a bug.)

A workaround would be either to set the TEMPORARY-GOAL-COLUMN variable explicitely to NIL inside the COPY-CHAR-FROM-LINE-ABOVE function or just simply shadow the variable with a local LET variable of the same name like shown below. Notice the additional TEMPORARY-GOAL-COLUMN variable in the LET form:
(defun copy-char-from-line-above ()
  "Copies one character from same column but previous row"
  (interactive)
  (let (c temporary-goal-column)
    (save-excursion      
       (previous-line)
       (setq c (buffer-substring-no-properties (point) (+ (point) 1))))
    (insert c)))

(defalias 'cup 'copy-char-from-line-above)
(global-set-key "\C-i" 'copy-char-from-line-above)
With me and GNU Emacs 23.2.1 - x86_64-pc-linux-gnu, GTK+ Version 2.20.1, on Debian Squeeze this works as you wanted.

- edgar

Re: Incorrect copying when duplicating line - key binding proble

Thanks,
both solutions work for me (Emacs 23.1.1, Ubuntu 10.10).