Elisp: Old variable values seem to stick - emacs

Beginner question for emacs lisp.
In my .emacs I have written the following:
(defun line-text-up-with-parentheses-above()
(interactive)
(line-text-up-with-char-above "("))
(defun line-text-up-with-char-above(charval)
(interactive)
(setq now-point (point))
(previous-line)
(setq above-point (point))
(forward-char)
(search-forward charval (line-end-position) nil)
(setq above-paren (point))
(goto-char now-point)
(insert (make-string (- above-paren above-point) ? )))
(global-set-key (kbd "\<C-S-iso-lefttab>") 'line-text-up-with-parentheses-above)
The function intends to line the text at the point up with the character after the "(" on the line above it.
Everything seem to work fine, unless the function is called twice in a row. In this case, the text before the point advances exactly the same amount as last time.
Seems like the variables aren't being set the second time around.
Does anyone know how to fix this?
Many thanks!

You calculate the intended indentation. However, you always insert it regardless of how many spaces the current line contains.
You could either simply delete the spaces on the current line before inserting the new spaces, or you could try to calculate the number of spaces needed and insert or delete, as needed.
Some hints:
By using setq you are using global variables, try to bind them using let.
Instead of recording where the point is before you move it around and restore it afterwards, you could use the special construct save-excursion.

I think the variables are being set correctly (although Lindydancer is correct to suggest let instead of setq). And your function works fine for me if I call it with point at the first non-whitespace character on the line you want to 'line up'. The only problem I see is that the function lines up with wherever point is when you call it, which is not correct if point is not at the first non-whitespace character.
You can fix this be adding (back-to-indentation) immediately after (interactive) in line-text-up-with-char-above. Actually, once you wrap everything in save-excursion you'll want to add back-to-indentation as the first function within the save-excursion form.

Protip: align and specifically align-regexp.

Related

Emacs: contextual margin settings or filling text to narrow range of columns?

I'd like to quickly generate text in a buffer that looks like this:
(fact "This is some text which will hang out
only on this part of the screen, ideally
automatically flowing to the correct
margins as I type."
(+ 1 1) => 2
;; more Clojure tests...
)
I have an Elisp keybinding which quickly spits out a starting template and puts my cursor in the right place:
(global-set-key "\C-of" (lambda ()
(interactive)
(insert "(fact \"\"\n\n )")
(backward-char 6)))
Now, when I am typing in the string portion ("This is some text..."), it'd be awesome if I could get Emacs to automatically flow text to the "correct" margins. Is there some way Emacs can be made to adjust margins and wraparound behavior based on where you're typing? At least, the first time you are typing there?
Barring that, for a given selection of text, how can I do the equivalent of fill-region, but with the desired left and right margins? Currently fill-region deletes all space between fact and "This is...., and left-justifies the rest.
There might be a simpler way that I'm overlooking now, but I would just do this:
Configure the text block in a temporary buffer, by doing this there:
a. Set fill-column to the width of the text block that you want.
b. Put the text at the beginning of the line, i.e., not indented.
c. Fill the text.
d. Use indent-rigidly to indent the text to the column you want, except for the first line.
Insert into your target buffer (fact followed by the indentation you want for the first line of the text block. Then insert the contents of the temporary buffer. Then insert whatever other text/code you need.
IOW, I would separate filling the text block from indenting it.
The following seems to work for the moment for my alternative (weaker) case:
;; Set up Midje fact with mark inserted at beginning of comment text
;; (refill as needed in appropriate columns, using C-oF).
(global-set-key "\C-of" (lambda ()
(interactive)
(insert "(fact \"\"\n\n )")
(backward-char 6)
(set-mark (point))))
;; Perform the refill operation to properly reformat the text string
;; in a Midje fact, started with C-of:
(global-set-key "\C-oF" (lambda ()
(interactive)
(set-left-margin (mark) (point) 37)
(fill-region (mark) (point))))
I expect I'll have to tweak this as I get experience using it, but it is pretty close. Still, it'd be nice to figure out how to have this happen automatically, while I'm typing inside the string.

Don't Indent After Two Newlines

I've got RET bound to newline-and-indent. Whenever I skip a line, it leaves a line with no indent and indents the current line, which is how it should be. In certain circumstances, I'd like it to not indent the current line after skipping. Some examples:
Default behavior
This is a test.
Line two.
How I'd like it:
This is a test.
Line two.
I'm not quite sure the best way to go about implementing this. One solution which just reeks of inelegance is to try to detect two presses of in a row and then outdent the current line. Any ideas?
This solution assumes you want the changes in text-mode, adjust the code appropriately if it's a different mode.
(add-hook 'text-mode-hook
(lambda () (setq indent-line-function 'indent-relative-only-when-previous-has-non-whitespace)))
(defun indent-relative-only-when-previous-has-non-whitespace ()
"Only call indent-relative when previous line has non whitespace"
(interactive)
(when (save-excursion
(beginning-of-line 0)
(looking-at "^\\s *\\S "))
(indent-relative)))

How to make the tilde overwrite a space in Emacs?

I'd like (in TeX-related modes) the tilde key to insert itself as usual if point is on anything (in particular a line end), but if a point is on space, I'd like the tilde to overwrite it. (This would be a quite useful feature after pasting something into TeX source file.) I hacked something like this:
(defun electric-tie ()
"Inserts a tilde at point unless the point is at a space
character, in which case it deletes the space first."
(interactive)
(while (equal (char-after) 32) (delete-char 1))
(while (equal (char-before) 32) (delete-char -1))
(insert "~"))
(add-hook 'TeX-mode-hook (lambda () (local-set-key "~" 'electric-tie)))
My questions are simple: is it correct (it seems to work) and can it be done better? (I assume that if the answer to the first question is in the affirmative, the latter is a question of style.)
As mentioned, it's better to use a "character" literal than a number literal. You have the choice between ? , ?\ , and ?\s where the last one is only supported since Emacs-22 but is otherwise the recommended way, since it's (as you say) "more easily visible" and also there' no risk that the space char will be turned into something else (or removed) by things like fill-paragraph or whitespace trimming.
You can indeed use eq instead of equal, but the difference is not important.
Finally, I'd call (call-interactively 'self-insert-command) rather than insert by hand, but the difference is not that important (e.g. it'll let you insert 3 tildes with C-u ~).
Some points:
Instead of 32 use ?  (question-mark space) to express character literal.
Instead of defining keys in the major-mode hooks, do it in an eval-after-load block. The difference is that major-mode hook runs every time you use the major-mode, but there is only one keymap per major-mode. So there is no point in repeatedly redefining a key in it.
see: https://stackoverflow.com/a/8139587/903943
It looks like this command should not take a numeric argument, but it's worth understanding interactive specs to know how other commands you write can be made to be more flexible by taking numeric arguments into consideration.
One more note about your new modifications:
Your way to clear spaces around point is not wrong, but I'd do this:
(defun foo ()
(interactive)
(skip-chars-forward " ")
(delete-region (point) (+ (point) (skip-chars-backward " "))))

emacs: back two lines in function?

I have a function in my emacs dot file to insert a date in my journal. After adding it, I would like to jump back a couple of lines and place the cursor below the date. How do I do that in the function?
(defun ddd ()
"Insert date at point journal style."
(interactive)
(insert (format-time-string "[%Y-%m-%d %a]"))
(insert "\n")
(insert "\n")
(insert "\n")
(insert "** end\n")
(gobacktwolineshere))
Any ideas?
You want the function forward-line, specifically
(forward-line -2)
goes backward two lines. For more information, type C-h f forward-line RET inside emacs. Depending on where you've left point, you might not end up at the beginning of the line. If you want this, add a call to beginning-of-line.
Remember that if you can tell Emacs to do it interactively (e.g. with <up> or C-p in this instance) then you can ask Emacs what it does when you type that, by prefixing C-hk.
In this case, Emacs tells you that those keys run the command previous-line, and also:
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.).
You might want to use save-excursion to make it more robust:
(defun ddd ()
"Insert date at point journal style."
(interactive)
(insert (format-time-string "[%Y-%m-%d %a]\n"))
(save-excursion (insert "\n\n** end\n")))
If you know how many characters you want to go back, you can use (backward-char 9).

Delete until whitespace in Emacs

Is there an Emacs function to delete (forward or backwards) until the first whitespace? For example, I have the following line, and the cursor is marked by the caret:
someword ?(&)!* morewords
^
I want to delete the backwards the sequence of non-alphanumeric characters, but not the word someword. Using backward-delete-word will wipe out the word as well. The same is with the cursor before the weird characters and kill-word.
emacs has the function zap-to-char which will delete everything up to a specific character. So, this won't work for all whitespace but if your specific problem is everything up to a space you can use this function. Give the function a negative argument to zap backwards.
I don't know of any function, but it's easy enough to make one:
(defun my-delete-backward-to-ws ()
(interactive)
(delete-region (point) (save-excursion (skip-syntax-backward "^ ") (point))))