4

I have a bunch of lines of text and I'm trying to insert text starting at a certain column on each line. For example:

'Some text'            This is ok
'Another longer text'  ask Ram
'weird stuff'          see other file
'more lines'
'even more lines'

I'd like to continue typing text on the further lines, at the same column as the previous lines. The part that's cumbersome is moving to the right place on each line.

Emacs has a way of moving to the same place on each line: set-goal-column. This would work if that column already existed on each line, but that's not the case here.

One way I can work around this (which I'm actually using) is to insert a lot of spaces on each line (replace-regexp $ with a few dozen spaces), then C-x C-n (set-goal-column), and use regular C-n to move between lines. But I'd like to know whether there's a clean way of achieving something better: of setting things up so that after set-goal-column, I can just use C-n to move to the next line, and Emacs will automatically insert the appropriate number of spaces if there weren't enough columns to start with.

  • Do you really want to insert spaces? Do you expect them to go away if you immediately move to the next line? And if so, what happens if the line already contained some whitespace? Maybe look to the artist-mode source code for inspiration for how to approach this without introducing permanent whitespace unnecessarily... – phils Oct 19 '17 at 2:17
  • 1
    This may also be of use to you: (when goal-column (move-to-column goal-column t)) – phils Oct 19 '17 at 2:19
  • FYI, I think line-move-to-column is what ultimately carries out the normal behaviour. – phils Oct 19 '17 at 2:26
  • @phils I don't mind inserting actual spaces; I anyway have a before-save-hook that strips trailing whitespace (and if I didn't, I wouldn't care about trailing whitespace, so that's not a problem either). And yes I had reached a similar conclusion from looking at the source code (following line-move-to-column etc), I think I need to change line-move-to-column which does (move-to-column col) to do (move-to-column col t) instead. Or maybe (when goal-column (move-to-column goal-column t)) as you suggested. Can you post that as an answer, along with how to “modify” line-move-to-column? – ShreevatsaR Oct 19 '17 at 2:31
1

Here is advice that should do what you want:

(defun goal-column-advice (&rest _args)
  "Advice inserting spaces when needed to obey `goal-column'.

This advice is intended as :after advice for commands
`previous-line' and `next-line'.  Normally, these commands will
attempt to obey any `goal-column' setting, but only on lines that
are long enough that the `goal-column' is not past the end of the
line.  This advice changes the advised command to instead pad the
line with spaces in this circumstance.  If `goal-column' is nil,
the command behaves as if it were not advised."
  (when goal-column (move-to-column goal-column t)))

(advice-add 'previous-line :after #'goal-column-advice)
(advice-add 'next-line     :after #'goal-column-advice)

Thanks to @phils for the comment pointing out the role of move-to-column.

As @phils also notes, this method does leave trailing whitespace in your buffer, which some people may not want. The OP doesn't seem to mind, but others may need to find a different solution.

| improve this answer | |
  • Thanks for this! It didn't work for some reason, but then I realized it works if I change :force to t. BTW what do you think of the idea of using :override instead of :after in advice-add? – ShreevatsaR Oct 25 '17 at 21:49
  • You are absolutely right on both counts; I forgot to test after making the t => :force change, and the advice was initially going on next-line and previous-line, so I didn't notice that :override works too. Answer updated. – Aaron Harris Oct 26 '17 at 2:07
  • On second thought, :override isn't quite right, because we should call the original function if goal-column is not set. (In testing, it didn't seem to affect previous-line or next-line at all, though; nevertheless, we should do the right thing.) I've changed it to :around advice to correct this. – Aaron Harris Oct 26 '17 at 2:22
  • Okay, I did some more testing and found that none of the advice previously was working correctly on previous-line; the spaces were being added, but then point was being moved again after our advice. Putting the advice on line-move-1 fixes the problem, but needs to be :after advice again. Sorry for not doing more testing up front; I'm pretty sure this is right now. – Aaron Harris Oct 26 '17 at 2:55
  • Nope. The last version broke move-end-of-line (a.k.a. C-e) because that actually sets goal-column temporarily internally. I'm coming to the conclusion that the source is too tangled to try doing anything clever here; using :after advice on previous-line and next-line directly is probably the best way to go. – Aaron Harris Oct 26 '17 at 3:05
1
;; Here we create the concept of a 'tab-column.'
;; Set the tab column where you want by positioning the cursor and typeing M-+
;; Then move to another line and type M-=, and EMACS will insert enough spaces
;; to get you to the column. This is useful for alinging columns of text without tabs.
;; tab-column is a silly name; I need a better one.

(defun set-tab-column (&rest _args)
  "Sets tab column to current column"
  (interactive "P")
  (setq tab-column (current-column))
  (message "tab column set to %s" tab-column))
(global-set-key (kbd "M-+") 'set-tab-column)
(setq tab-column 0))

(defun space-to-tab-column (&rest _args)
  "Insert spaces to tab-column"
  (interactive "P")
  (let ((count 0))
    (while (> tab-column (current-column))
      (setq count (+ 1 count))
      (insert " ")
      )
    (message "%s spaces inserted" count)
    )
)
(global-set-key (kbd "M-=") 'space-to-tab-column)
| improve this answer | |
  • The first function has a close paren in the wrong place. Move the one at the end of (setq tab-column (current-column))) to the end of the next line. – nealmcb Apr 10 at 13:00
  • 1
    Thanks, but next time, feel free to edit yourself! – vy32 Apr 10 at 13:15
  • For me, since on this particular site I don't have 2K reputation, it won't let me fix tiny but important errors: "Edits must be at least 6 characters". And note that an error remains: the paren needed to be moved, not deleted. – nealmcb Apr 10 at 13:33
  • Well I appreciate the bug fix! (It was correct in my .emacs file) – vy32 Apr 10 at 14:51
  • 1
    fixed. Sorry! The 10 character limit for comments can also be counter-productive. – vy32 Apr 11 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.