Page 1 of 1

Incorrect copying when duplicating line - key binding proble

Posted: Thu May 19, 2011 10:39 am
by mmi
hey guys,

I wrote code like this:

Code: Select all

(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

Posted: Thu May 19, 2011 5:40 pm
by Duke
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:

Code: Select all

(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

Re: Incorrect copying when duplicating line - key binding proble

Posted: Thu May 19, 2011 5:47 pm
by edgar-rft
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:

Code: Select all

;; 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:

Code: Select all

(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

Posted: Fri May 20, 2011 1:44 pm
by mmi
Thanks,
both solutions work for me (Emacs 23.1.1, Ubuntu 10.10).