helm-grep-do-git-grep searches in the current directory - emacs

helm-grep-do-git-grep with a prefix arg grep whole repo and without
grep only current dir.
I want it reversed
helm-grep-do-git-grep without a prefix arg grep whole repo and with
grep only current dir.
How can i define a function to reverse it or define keyboard shortcut ?

This is a general solution for any command where you want to reverse the meaning of the prefix argument (at least for commands that interpret their prefix args as booleans).
(defun foo (&optional arg)
"Do something. Do something else with prefix ARG."
(interactive "P")
(if arg
(message "something else")
(message "something")))
(defun anti-foo (&optional arg)
"Like `foo', but with opposite behavior w.r.t. ARG."
(interactive "P")
(if arg
(foo nil)
(foo '(4))))
If you just want to replace the function (may or may not be OK, see below), you can use advice:
(advice-add 'foo
:around
(lambda (orig &rest args)
"Reverse sense of prefix arg."
(let ((arg (car args)))
(if arg
(setq args (cons nil (cdr args)))
(setq args (cons '(4) (cdr args))))
(apply orig args))))
If the function is only an end user function, it's probably OK to use advice on it (skimming the helm source, helm-grep-do-git-grep is probably OK to advise). If the function is used by other functions, advice may cause the dependent functions to misbehave (because you're effectively changing the advised function's definition).
Aside: If you're not familiar with Emacs's prefix arguments, nil is used for no prefix, '(4) is used for a single prefix, '(16) is used for a double prefix, and so on.

Related

How to make eshell-autojump case insensitive under Linux

Under Linux, eshell-autojump will do case sensitive matching which I just find a nuisance. I've tried to circumvent this by advising eshell/j with a eshell-under-windows-p that always returns t but to my chagrin eshell-under-windows-p invoked in eshell/j is unaffected by cl-letf. I've modified my eshell/j a bit to give me some debug info:
;; Modified eshell/j inside eshell-autojump.el to this
(defun eshell/j (&rest args) ; all but first ignored
"Jump to a directory you often cd to.
This compares the argument with the list of directories you usually jump to.
Without an argument, list the ten most common directories.
With a positive integer argument, list the n most common directories.
Otherwise, call `eshell/cd' with the result."
(setq args (eshell-flatten-list args))
(let ((path (car args))
(candidates (eshell-autojump-candidates))
(case-fold-search (eshell-under-windows-p))
result)
(when (not path)
(setq path 10))
(message "case-fold-search = %S" case-fold-search)
(message "eshell-under-windows-p returns %s from inside eshell/j" (eshell-under-windows-p))
(if (and (integerp path) (> path 0))
(progn
(let ((n (nthcdr (1- path) candidates)))
(when n
(setcdr n nil)))
(eshell-lisp-command (mapconcat 'identity candidates "\n")))
(while (and candidates (not result))
(if (string-match path (car candidates))
(setq result (car candidates))
(setq candidates (cdr candidates))))
(eshell/cd result))))
My init.el adds the advice to attempt to make eshell/j caseless by trying to trick it to think we are on Windows:
;; Added to init.el
(require 'eshell-autojump)
(advice-add 'eshell/j :around
(lambda (orig-fun &rest xs)
(cl-letf (((symbol-function 'eshell-under-windows-p) (lambda () t)))
(progn (message "eshell-under-windows-p returns %s from lambda" (eshell-under-windows-p)) (apply orig-fun xs)))))
But all I get in Messages buffer when I try to jump in eshell is:
;; I get in *Messages*
eshell-under-windows-p returns t from lambda
case-fold-search = nil
eshell-under-windows-p returns nil from inside eshell/j
My rookie knowledge of elisp is not enough to wrestle with probable scoping issues here. Can anyone decode why eshell-under-window-p is unaffected when called from eshell/j here?
I've found the answer. cl-letf does not work for byte compiled functions. As eshell-autojump is a package it gets byte compiled upon installation and cl-letf cannot be used to modify it's internal behavior. I had to resort to redefining the eshell/j which is a suboptimal solution.

Find and replace without regexp in dired

I'm trying to convert a website into an ebook, and there is a huge chunk of html at the beginning of every page which I want to delete. As you can imagine, using Q results in no matches due to something in the big chunk not being escaped properly. When I try and regex the problem away, I get stack overflow.
What I really need is a way to find and replace in dired without regex, in the usual M-% way. Is this possible?
The regexp behaviour is optional in theory, but the function calls in question hard-code that assumption in a few places. I think the simplest solution is to make copies which don't set the regexp flags when they run.
(eval-after-load 'dired
'(define-key dired-mode-map (kbd "C-c Q") 'my-dired-do-query-replace))
(defun my-dired-do-query-replace (from to &optional delimited)
"Do `query-replace' of FROM with TO, on all marked files.
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
with the command \\[tags-loop-continue]."
(interactive
(let ((common
(query-replace-read-args
"Query replace in marked files" nil t)))
(list (nth 0 common) (nth 1 common) (nth 2 common))))
(require 'dired-aux)
(dolist (file (dired-get-marked-files nil nil 'dired-nondirectory-p))
(let ((buffer (get-file-buffer file)))
(if (and buffer (with-current-buffer buffer
buffer-read-only))
(error "File `%s' is visited read-only" file))))
(my-tags-query-replace
from to delimited '(dired-get-marked-files nil nil 'dired-nondirectory-p)))
(defun my-tags-query-replace (from to &optional delimited file-list-form)
"Do `query-replace' of FROM with TO on all files listed in tags table.
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
with the command \\[tags-loop-continue].
Fourth arg FILE-LIST-FORM non-nil means initialize the replacement loop.
Fifth and sixth arguments START and END are accepted, for compatibility
with `query-replace', and ignored.
If FILE-LIST-FORM is non-nil, it is a form to evaluate to
produce the list of files to search.
See also the documentation of the variable `tags-file-name'."
(interactive (query-replace-read-args "Tags query replace" nil t))
(require 'etags)
(setq tags-loop-scan `(let ,(unless (equal from (downcase from))
'((case-fold-search nil)))
(if (search-forward ',from nil t)
;; When we find a match, move back
;; to the beginning of it so perform-replace
;; will see it.
(goto-char (match-beginning 0))))
tags-loop-operate `(perform-replace ',from ',to t nil ',delimited
nil multi-query-replace-map))
(tags-loop-continue (or file-list-form t)))

How to restrict a function to a subtree in emacs org-mode?

I am using org-mode and org-attach extensively which means that
there can be many attachment directories associated with one org file.
On worg I found a function from Matt Lundi which allows to see all
attachments that belong to the whole file and browse them with ido.
I would like to restrict this function to a subtree which would make it
much more useful for my use case.
Since I am not new to emacs but almost completely elisp illiterate I am
asking here.
This is the function:
(defun my-ido-find-org-attach ()
"Find files in org-attachment directory"
(interactive)
(let* ((enable-recursive-minibuffers t)
(files (find-lisp-find-files org-attach-directory "."))
(file-assoc-list
(mapcar (lambda (x)
(cons (file-name-nondirectory x)
x))
files))
(filename-list
(remove-duplicates (mapcar #'car file-assoc-list)
:test #'string=))
(filename (ido-completing-read "Org attachments: " filename-list nil t))
(longname (cdr (assoc filename file-assoc-list))))
(ido-set-current-directory
(if (file-directory-p longname)
longname
(file-name-directory longname)))
(setq ido-exit 'refresh
ido-text-init ido-text
ido-rotate-temp t)
(exit-minibuffer)))
Maybe I'm missing something, but calling org-narrow-to-subtree first should do what you want (call widen afterwards to revert that).
I thought this would be pretty darned useful myself so, inspired by your question, I wrote a version that does what you want plus a couple other bells and whistles. To invoke it you have to type C-c o. NOTE: This is NOT on the usual org-attach key prefix because that function is oddly written without a keymap so it is difficult to add the functionality onto the key prefix.
(autoload 'org-attach-dir "org-attach")
(autoload 'find-lisp-find-files "find-lisp")
(defcustom ido-locate-org-attach-all-files nil
"Non-nil means `ido-locate-org-attach' returns all files.
Otherwise the default behavior only returns files attached to the
current entry."
:group 'ido
:type 'boolean)
(defun ido-locate-org-attach (&optional find-all)
"Find files in org-attachment directory for current entry.
When called with a prefix argument, include all files in
`org-attach-directory'. With a double `C-u' prefix arg the value
of `ido-locate-org-attach-all-files' will be toggled for the
session. If you want to save it permanently for future session
then customize the variable `ido-locate-org-attach-all-files'."
(interactive "P")
(when (org-attach-dir nil)
(when (equal find-all '(16))
(setq ido-locate-org-attach-all-files
(not ido-locate-org-attach-all-files)))
(let* ((enable-recursive-minibuffers t)
(dir (if (org-xor ido-locate-org-attach-all-files
(equal find-all '(4)))
org-attach-directory
(org-attach-dir nil)))
(files (find-lisp-find-files dir "."))
(file-assoc-list
(mapcar (lambda (x)
(cons (file-name-nondirectory x)
x))
files))
(filename-list
(remove-duplicates (mapcar #'car file-assoc-list)
:test #'string=))
(filename (ido-completing-read "Org attachments: " filename-list nil t))
(longname (cdr (assoc filename file-assoc-list))))
(ido-set-current-directory
(if (file-directory-p longname)
longname
(file-name-directory longname)))
(setq ido-exit 'refresh
ido-text-init ido-text
ido-rotate-temp t)
(exit-minibuffer))))
;; Run ido-locate-org-attach when using org-open-at-point (C-c C-o) in
;; the current entry (except if you're on the header line itself it
;; will use the default behavior to open/close the entry.
(add-hook 'org-open-at-point-functions 'ido-locate-org-attach)
;; C-c o will locate files for the current entry
;; C-u C-c o will locate files for the whole file
;; C-u C-u C-c o will toggle the default current entry / whole file
(define-key org-mode-map "\C-co" 'ido-locate-org-attach)
I'll look into submitting this to be an official part of org-attach.el.
As an aside, the '(4) and '(16) are magic numbers that mean prefix arg once C-u and prefix arg twice C-u C-u before the key sequence that invoked the command interactively.

Help writing emacs lisp for emacs etags search

I'm looking for some help developing what I think should be an easy program.
I want something similar to Emacs tags-search command, but I want to collect all search results into a buffer. (I want to see all results of M-,)
I'm thinking this python style pseudo code should work, but I have no idea how to do this in emacs lisp? Any help would be greatly appreciated.
def myTagsGrep(searchValue):
for aFile in the tag list:
result = grep aFile seachValue
if len(result) > 0:
print aFile # to the buffer
print result # to the buffer
I would like to be able to browse through the buffer with the same features tags-apropos does.
Note that a similar question has been asked before:
Is there a way to get emacs tag-search command to output all results to a buffer?
Since I'm such a fan of igrep, I'd use it as the building block. From there it's two simple routines and you're done. With that library and these two functions, all you have to do is:
M-x igrep-tags ^SomeRegexp.*Here RET
Here's the code:
(require 'igrep)
(defun igrep-tags (regex)
(interactive "sTAGS Regexp: ")
(igrep igrep-program regex (tags-file-names)))
(defun tags-file-names ()
(save-excursion
(visit-tags-table-buffer)
(mapcar (lambda (f) (file-truename f))
(tags-table-files))))
And, because the list of files can get really long, and you likely don't care what that list is, you can add these two pieces of code which will make the filenames invisible after the grep has finished:
(add-hook 'compilation-finish-functions 'igrep-tags-hide-filenames)
(defun igrep-tags-hide-filenames (buffer stat)
"hide the filenames b/c they can get long"
(save-excursion
(set-buffer buffer)
(save-match-data
(goto-char (point-min))
(if (search-forward (combine-and-quote-strings (tags-file-names))
nil
(save-excursion (forward-line 10) (point)))
(let ((display-string "..<files from TAGS>.."))
(put-text-property (match-beginning 0) (match-end 0) 'invisible t)
(put-text-property (match-beginning 0) (match-end 0) 'display display-string))))))
To avoid the really long command line, you can use the following code (which creates a temporary file containing all the names of files from TAGS file and uses that instead):
(defun igrep-tags (regex)
(interactive "sTAGS Regexp: ")
(let ((igrep-find t)
(igrep-use-file-as-containing-files t))
(igrep igrep-program regex nil)))
(defvar igrep-use-file-as-containing-files nil)
(defadvice igrep-format-find-command (around igrep-format-find-command-use-filename-instead activate)
"use the second argument as a file containing filenames"
(if igrep-use-file-as-containing-files
(progn (with-temp-file
(setq igrep-use-file-as-containing-files (make-temp-file "tags-files"))
(insert (combine-and-quote-strings (tags-file-names))))
(setq ad-return-value (format "cat %s | xargs -e %s"
igrep-use-file-as-containing-files
(ad-get-arg 0))))
ad-do-it))
And, for those using Emacs 22 or earlier, you'll need the routine that's shipped with Emacs 23 (from subr.el)
(defun combine-and-quote-strings (strings &optional separator)
"Concatenate the STRINGS, adding the SEPARATOR (default \" \").
This tries to quote the strings to avoid ambiguity such that
(split-string-and-unquote (combine-and-quote-strings strs)) == strs
Only some SEPARATORs will work properly."
(let* ((sep (or separator " "))
(re (concat "[\\\"]" "\\|" (regexp-quote sep))))
(mapconcat
(lambda (str)
(if (string-match re str)
(concat "\"" (replace-regexp-in-string "[\\\"]" "\\\\\\&" str) "\"")
str))
strings sep)))
Here is the code I use to create a tag system for my personal notes. It uses bookmarks and treats each word in a bookmark as a single tag. Its not quite what you're looking for but it might get you started.
The first couple of functions are probably already implemented in emacs, but I wrote my own for reasons that I no longer recall.
;; FILTER keeps only elements of li for which pred returns true
(defun filter (pred li)
(let (acc)
(dolist (elem li)
(if (funcall pred elem)
(setq acc (cons elem acc))))
(reverse acc)))
(defun string-match-all-p (str li)
(if li
(if (string-match-p (car li) str)
(string-match-all-p str (cdr li))
nil)
t))
;;bookmarks as tags
(defun lookup-bookmark-tags (tagstring)
(interactive "s")
(let ((taglist (split-string tagstring " ")))
(let ((bookmark-alist (filter
(lambda (elem)
(string-match-all-p (car elem) taglist))
bookmark-alist)))
(call-interactively 'list-bookmarks))))
I then bind the 'tagging' behavior to a key (F11) and the 'lookup' behavior to another (F12).
(global-set-key [f11] 'bookmark-set)
(global-set-key [f12] 'lookup-bookmark-tags))
Hope that is useful to you.
This is what you want:
http://www.emacswiki.org/emacs/Icicles_-_Emacs_Tags_Enhancements#icicle-tags-search
This is the doc string for icicle-tags-search:
Search all source files listed in tags tables for matches for REGEXP.
You are prompted for the REGEXP to match. Enter REGEXP with `RET'.
You do not need `M-,' - you see all matches as search hits to visit.
All tags in a tags file are used, including duplicate tags from the
same or different source files.
By default, all tags files are used, but if you provide a prefix
argument then only the current tag table is used.
If your TAGS file references source files that no longer exist, those
files are listed. In that case, you might want to update your TAGS
file.
You can alternatively choose to search, not the search contexts as
defined by the context regexp you provide, but the non-contexts, that
is, the text in the files that does not match the regexp. To do this,
use `C-M-~' during completion. (This is a toggle, and it affects only
future search commands, not the current one.)
See also this page for more explanation about Icicles search:
http://www.emacswiki.org/emacs/Icicles_-_Search_Commands%2c_Overview

matching keys in association lists in emacs lisp

I'm using folding-mode in emacs and was trying to make a function to insert the appropriate folding marker (start or end) depending on mode. So far I have
(defun insert-folding-mode-mark ()
(interactive)
(let ((st "##{{{")
(en "##}}}")
string-to-insert)
(save-excursion
(setq string-to-insert
(let ((here (point))
sp ep)
(setq sp (search-backward st))
(goto-char here)
(setq ep (search-backward en))
(if (< sp ep) st en))))
(insert string-to-insert)))
This inserts "##{{{" at (point) unless "##{{{" precedes it, in which case it inserts "##}}}".
I'd like to replace the first (let) assignment with something that determines the start and end markers with something like
(let* ((match (assoc (intern mode-name) folding-mode-marks-alist))
(st (nth 1 match))
(en (nth 2 match)))
[is (intern) meant to be called in this way?] A truncated version of my folding-mode-marks-alist looks something like
((ess-mode "##{{{" "##}}}")
(tex-mode "%{{{" "%}}}")
(python-mode "# {{{" "# }}}")
(emacs-lisp-mode ";;{{{" ";;}}}")
(TeX-mode "%{{{" "%}}}")
(LaTeX-mode "%{{{" "%}}}"))
while the mode-name returned from various modes are {"Emacs-Lisp", "ESS[S]", "PDFLaTeX", "Python", ...}. Seems like I might want to do some partial matching with strings using (downcase), (concat x "-mode"), and so on, but was wondering if there was an idiomatic way in emacs lisp to do this sort of matching with keys of an alist, or do I just have to have a separate block of code by which I extract the keys with (mapcar 'car folding-mode-marks-alist) and convert each symbol to string (how?) to do the matching?
Thanks much!
Emacs Lisp has a destructuring-bind facility which may be helpful here. Also taking advantage of the fact that the symbol naming the current major mode is available via the variable major-mode, you can write something like this:
(destructuring-bind (st en) (cdr (assoc major-mode folding-mode-marks-alist))
; do stuff
)
Note that this won't work if (assoc major-mode folding-mode-marks-alist) returns nil, so better replace that with a call to some custom function capable of returning a sensible default.
In addition to major-mode being more appropriate than mode-name here, the function insert-folding-mode-mark as listed above would throw an error if there were no folding marker between cursor and beginning of buffer. Here is a revision without that quirk:
(require 'cl)
(defun insert-folding-mode-mark ()
(interactive)
(flet ((fn (s) (save-excursion (or (search-backward s () t) 0))))
(destructuring-bind (mode st en)
(or (assoc major-mode folding-mode-marks-alist) '(nil "" ""))
(insert (if (<= (fn st) (fn en)) st en)))))
Edit: fix problem pointed out in comment.
You may be interested to know there are comment-start and comment-end variables which should already contain the information you need based on major-mode. Something like
(search-backward (concat comment-start "{{{"))
...
(insert comment-start "{{{" comment-end)
should be sufficient. Of course, for lisp modes comment-start is ";" so you may want to do what you are doing to get ";;" but fall back on comment-start for other modes. You can also (setq comment-start ";;") though I'm not entirely sure what difference that makes for the lisp modes.