ivy-read function (this is ivy’s single API entrypoint) has two required parameters, one of which is the collection. This is a function returning the list of items that the user wants to narrow down, or the list itself.
Because we need to tell ivy to sort the results by associating a sorting function with a specific collection function, we wrap the supplied
counsel-ag-function collection function.
We also supply a new sorting function that will take two of the ag-generated search results, each of the form
relative_filename:line_number:line_contents, derive the filenames from that, determine the modified timestamps of both the files and then return
nil depending on which file is newer.
We finally (for this first snippet) associate the sorting function with our wrapped collection function.
(defun cpb/ag-collection (string)
"Search for pattern STRING using ag.
We only have this as a separate function so we can assoc with sort function."
;; this will use counsel--async-command to run asynchronously
(counsel-ag-function string counsel-ag-base-command ""))
;; modified from https://github.com/abo-abo/swiper/wiki/Sort-files-by-mtime
;; * directory to counsel--git-grep-dir: that's where AG is working
;; * removed directory logic: ag returns files
;; * parsed out filename from ag results
(defun eh-ivy-sort-file-by-mtime (x y)
"Determine if AG sort result X is newer than Y."
(let* ((x (concat counsel--git-grep-dir (car (split-string x ":"))))
(y (concat counsel--git-grep-dir (car (split-string y ":"))))
(x-mtime (nth 5 (file-attributes x)))
(y-mtime (nth 5 (file-attributes y))))
(time-less-p y-mtime x-mtime)))
;; ivy uses the ivy-sort-functions-alist to look up suitable sort
;; functions for any given collection function
;; we add a cons cell specifying eh-ivy-sort-file-by-mtime as the sort
;; function to go with our collection function
'(cpb/ag-collection . eh-ivy-sort-file-by-mtime))
In the second and final snippet, we create a new version of the
counsel-ag function where we specify our own collection function, and we supply a truthful
(defun cpb/counsel-ag (&optional initial-input initial-directory extra-ag-args ag-prompt)
"Grep for a string in the current directory using ag.
INITIAL-INPUT can be given as the initial minibuffer input.
INITIAL-DIRECTORY, if non-nil, is used as the root directory for search.
EXTRA-AG-ARGS string, if non-nil, is appended to `counsel-ag-base-command'.
AG-PROMPT, if non-nil, is passed as `ivy-read' prompt argument.
Modified by cpbotha: Sort results last modified file first."
(car (split-string counsel-ag-base-command))
" in directory: "))))
(let* ((pos (cl-position ? counsel-ag-base-command))
(command (substring-no-properties counsel-ag-base-command 0 pos))
"%s" "" (substring-no-properties counsel-ag-base-command pos))))
(read-string (format "(%s) args:" command) ag-args)))))
(ivy-set-prompt 'cpb/counsel-ag counsel-prompt-function)
(setq counsel--git-grep-dir (or initial-directory default-directory))
(ivy-read (or ag-prompt (car (split-string counsel-ag-base-command)))
;; yes, we want to sort the results
:unwind (lambda ()