Replace file at point in emacs - emacs

I found the function here for replace filen at point but it doesn't seem to work properly: http://www.emacswiki.org/emacs/InsertFileName. It correctly finds the file-at-point but the replace appears to take the file you input and not the file detected originally from what I can see. I'm not sure how to fix this.
If I Run the function on /home/testfile
First it says file to replace so for example: /home/secondfile
Then it says replace '/home/secondfile' with: /home/secondfile
and then it says: No file at point
Any ideas??
Here is the function:
(autoload 'ffap-guesser "ffap")
(autoload 'ffap-read-file-or-url "ffap")
(defun my-replace-file-at-point (currfile newfile)
"Replace CURRFILE at point with NEWFILE.
When interactive, CURRFILE will need to be confirmed by user
and will need to exist on the file system to be recognized,
unless it is a URL.
NEWFILE does not need to exist. However, Emacs's minibuffer
completion can help if it needs to be.
"
(interactive
(let ((currfile (ffap-read-file-or-url "Replace filename: "
(ffap-guesser))))
(list currfile
(ffap-read-file-or-url (format "Replace `%s' with: "
currfile) currfile))))
(save-match-data
(if (or (looking-at (regexp-quote currfile))
(let ((filelen (length currfile))
(opoint (point))
(limit (+ (point) (length currfile))))
(save-excursion
(goto-char (1- filelen))
(and (search-forward currfile limit
'noerror)
(< (match-beginning 0) opoint))
(>= (match-end 0) opoint))))
(replace-match newfile)
(error "No file at point to replace"))))

There are probably a few things wrong/going on here. The first is, your point position when you are executing this. The second is, if you are using /home/user/something, that there is a strong possibility you will have mismatch between /home/user/something and ~/something (ffap returns the latter while at the point you may have written the former).
First:
The use of looking-at with the regexp quoted filename expects the point to be at the beginning: e.g. |/home/user/something.
Its partner, looking-back expects /home/user/something|. Being somewhere in the middle will throw this error.
One quick fix for this is changing looking-at to thing-at-point-looking-at.
Second:
If you have written /home/user/something, ffap functions (in my case) shorten this using ~.
There are probably some settings that govern this, but the easiest, quick fix I know of is using expand-file-name. This will take care of the first case, and if it is written as ~/something, the save-excursion body will replace it in the alternate case.
The only negative result I see is that, you might sometimes replace:
/home/user/something with ~/somethingelse
But, anyways, these two quick fixes just result in this complete change:
(thing-at-point-looking-at (regexp-quote (expand-file-name currfile)))

can't see where "ffap-guesser" is defined. Looks like a bug.
Maybe try instead
"find-file-at-point"

Related

How to log spelling replacements in emacs?

I want to log to a file the ispell replacements that get made (whether manual r, or from a list 0...)
Every time a "correction" is made, there are two words that are relevant:
The word that ispell identifies as incorrect.
The word that ends up in its place. [maybe "" when its skipped]
I just want to log these pairs to a file for "analysis" (and possibly flashcards)
I am still browsing code to see if there is a place to wedge this in. I see ispell-update-post-hook used in ispell-command-loop but I'm not sure if that's what I want. I also am not sure how I'd both get the above pair of words and write them to a file, as the hook doesn't (elisp ignorance?) seem to provide access.
This code does what you've requested. It does not check for duplicates in the file that's generated, it simply appends to the existing file.
(defvar save-ispell-words-file "~/spell_check.txt")
(defadvice ispell-command-loop (after save-ispell-words activate)
"Save the misspelled words and their replacements"
(when (or (null ad-return-value)
(stringp ad-return-value))
(save-excursion
(set-buffer (find-file-noselect save-ispell-words-file))
(goto-char (point-max))
(insert (format "%s %s\n" (ad-get-arg 2) (if (null ad-return-value) "\"\"" ad-return-value)))
(save-buffer))))
Tested with Emacs 27.2.

difference between calling command directly and using keybinding

I'm new to elisp, so please forgive me if the following approach is totally clumsy.
In the team I'm currently working with, there is an usual convention of closing python blocks with a pass statement (if they aren't ended by closing keywords like else or except or such). While unusual, this has the advantage that one can always recover the original indentation of the program if it is unintentionally changed (using emacs indent-region).
To get existing code in line with this convention, I wrote a small elisp function:
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(move-beginning-of-line 1)
(skip-chars-forward " ")
(if
(< 0
(let (original)
(setq original (point))
(indent-for-tab-command)
(- (point) original)
)
)
(progn
(insert "pass")
(newline)
(indent-for-tab-command)
)
)
(next-line)
)
(global-set-key (kbd "C-`") 'python-check-indent)
The idea is simply to test whether hitting TAB would change the indentation, and insert a pass statement in that case. To facilitate processing longer blocks of code, it then advances to the next line.
When I run it using M-x python-check-indent, it does what I want (except that it moves around empty lines slightly), also when running it repeatedly to process several lines. However, when I run it repeatedly using the C-` keybinding, it starts messing up the code from the second invocation on.
So here are my questions: What is the difference between invoking a command with M-x ... and using its keybinding? And how could I change the function to be not affected by this difference?
emacs-version: GNU Emacs 23.3.1 (x86_64-apple-darwin, NS apple-appkit-1038.35) of 2011-03-10 on black.porkrind.org
(edit) current workaround: I'm now wrapping it inside a keyboard-macro, so it's "bound" to C-x e, and behaves properly.
The general rule is that it is best to avoid complex interactive
commands in your functions because they could be affected by all sorts
of options.
(defun python-check-indent ()
"Check if automatic indentation changes current indent, insert pass keyword if it does."
(interactive)
(goto-char (line-beginning-position))
(skip-chars-forward " ")
(when (< 0
(let (original)
(setq original (point))
(python-indent-line)
(- (point) original)))
(insert "pass\n")
(python-indent-line))
(forward-line))
However, even this is probably not good because python-indent-line's behavior depends on last-command and python-indent-trigger-commands. I think it would be best if you replaced the first invocation of python-indent-line with the code which computes the target indentation instead of actually indenting, something like (nth python-indent-current-level python-indent-levels).
PS. If you still have problems, I suggest that you use edebug and step through the function.

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 completion-at-point-functions

I'm writing a derived mode, based on comint-mode. The mode is an interface to a command line program (GRASS gis), and the comint mode completion works for the programs. I'm trying to add on support for completing the arguments to the program, via completion-at-point-functions. A toy example is:
(setq my-commands
'(("ls"
("my-completion-1")
("my-completion-2"))
("mv"
("my-completion-3")
("my-completion-4"))))
(defun my-completion-at-point ()
(interactive)
(let ((pt (point)) ;; collect point
start end)
(save-excursion ;; collect the program name
(comint-bol)
(re-search-forward "\\(\\S +\\)\\s ?"))
(if (and (>= pt (match-beginning 1))
(<= pt (match-end 1)))
() ;; if we're still entering the command, pass completion on to
;; comint-completion-at-point by returning nil
(let ((command (match-string-no-properties 1)))
(when (member* command my-commands :test 'string= :key 'car)
;; If the command is one of my-commands, use the associated completions
(goto-char pt)
(re-search-backward "\\S *")
(setq start (point))
(re-search-forward "\\S *")
(setq end (point))
(list start end (cdr (assoc command my-commands)) :exclusive 'no))))))
(push 'my-completion-at-point completion-at-point-functions)
This almost works. I get normal completion of program names. However, if I have entered ls at the command line, hitting tab inserts my-completion- and doesn't offer the two options. Hitting tab again inserts my-completion- a second time, so that I now have ls my-completion-mycompletion-.
My actual code includes a few lines to check for multi-line commands, but makes no changes to the completion code. With this version of the code, I hitting tab on a line that starts with one of the program names in my-commands I am presented with a list of the possible arguments to complete the command with, but nothing is inserted in the buffer, and the list does not get narrowed by typing the first few letters of an argument.
I've been over the manual, but I can't figure out the correct way to write a completion-at-point function. Any ideas what I'm missing?
I have looked briefly at pcomplete, but the didn't really understand the 'documentation', and didn't make any progress.
The problem seems to be with the way you're finding start and end to return the boundaries of the argument at point. I didn't spend long enough debugging it to be sure of the details, but I think if you call the function interactively you'll see that it returns the same value for start and end, and this means that the completion UI doesn't know to use the argument at point to select from the completion table you've passed it.
Changing the last part of your function to the following seems to be one fix:
(when (member* command my-commands :test 'string= :key 'car)
;; If the command is one of my-commands, use the associated completions
(goto-char pt)
(let ((start
(save-excursion
(skip-syntax-backward "^ ")
(point))))
(list start pt (cdr (assoc command my-commands)) :exclusive 'no)))))))
This gives the expected results when added as an element of completion-at-point-functions.
Here I've used skip-syntax-backward instead of regexp search, which I think is slightly more idiomatic Elisp for this kind of thing. It just says to move point backwards across anything that is not in syntax class "whitespace". The skip-syntax functions return the distance moved rather than the value of point, so we have to add a call to point at the end of the save-excursion.
If you do use regexp searches in a function like this, it's usually a good idea to pass t for the fourth argument, noerror, so that it doesn't pass on errors to the user if it fails to match. This does mean that you have to check for yourself whether the return value is nil, though.
Finally, instead of push to add the completion function you might want to use add-hook as follows:
(add-hook 'completion-at-point-functions 'my-completion-at-point nil t)
This does two useful things: it checks whether your function is already in the hook before adding it, and (by passing t for the fourth argument, local) it only adds the function to the buffer-local value of the completion-at-point hook. This is almost certainly what you want, since you don't want to use these completions in every other Emacs buffer when you press the TAB key.

How to automatically evaluate certain lisp code after starting an emacsclient?

When starting Emacs, init.el (or .emacs.el) is evaluated. However, when starting emacsclient, no similar lisp code is evaluated.
How can I get a lisp file to be evaluated every time I open a new emacsclient?
(This would be handy for frame specific customizations.)
I assume the answer is to use some hook, but I can't seem to find the correct hook to use.
I look forward to your answers.
You can add a function to the hook 'server-visit-hook, which is run every time the server is called (every time you call emacsclient).
I use the following code to automatically change the behavior of server buffers. I use it especially with the Firefox extension It's All Text. In that extension, buffers are named according to the domain name, so you can figure out which rule to apply by using string-match to match the name of the file.
(defun server-edit-presets ()
(cond
;; When editing mail, set the goal-column to 72.
((string-match "mail\\.google\\.com\\.[0-9a-z]+\\.txt" (buffer-name))
(longlines-mode-off)
(auto-fill-mode 1)
(set-fill-column 72)
(save-excursion
;; Don't know if this is necessary, but it seems to help.
(set-buffer (buffer-name))
(goto-char (point-min))
;; Replace non-breaking strange space characters
(while (search-forward (char-to-string 160) nil t)
(replace-match " "))))))
(add-hook 'server-visit-hook 'server-edit-presets)
(add-hook 'server-visit-hook '(lambda () (longlines-mode 1)))
If you really want new frame customizations, there's create-frame-hook which takes one arg (the new frame)...
If you mean gnuclient, you can use the command-line option "-eval" to evaluate something (and then just make an alias to always eval your customizations).
#LSW:
Try 'window-setup-hook. This addresses the annoyance since it is called even if emacsclient is not passed a file.
It seems that those hooks are no more, so here's the new version.
(add-hook 'server-after-make-frame-hook 'consult-recent-file)