+(defvar counsel-gg-state nil
+ "The current state of candidates / count sync.")
+
+(defun counsel--gg-candidates (regex)
+ "Return git grep candidates for REGEX."
+ (setq counsel-gg-state -2)
+ (counsel--gg-count regex)
+ (let* ((default-directory counsel--git-grep-dir)
+ (counsel-gg-process " *counsel-gg*")
+ (proc (get-process counsel-gg-process))
+ (buff (get-buffer counsel-gg-process)))
+ (when proc
+ (delete-process proc))
+ (when buff
+ (kill-buffer buff))
+ (setq proc (start-process-shell-command
+ counsel-gg-process
+ counsel-gg-process
+ (format "git --no-pager grep --full-name -n --no-color -i -e %S | head -n 200"
+ regex)))
+ (set-process-sentinel
+ proc
+ #'counsel--gg-sentinel)))
+
+(defun counsel--gg-sentinel (process event)
+ (if (string= event "finished\n")
+ (progn
+ (with-current-buffer (process-buffer process)
+ (setq ivy--all-candidates (split-string (buffer-string) "\n" t))
+ (setq ivy--old-cands ivy--all-candidates))
+ (when (= 0 (cl-incf counsel-gg-state))
+ (ivy--exhibit)))
+ (if (string= event "exited abnormally with code 1\n")
+ (progn
+ (setq ivy--all-candidates '("Error"))
+ (setq ivy--old-cands ivy--all-candidates)
+ (ivy--exhibit)))))
+
+(defun counsel--gg-count (regex &optional no-async)
+ "Quickly and asynchronously count the amount of git grep REGEX matches.
+When NO-ASYNC is non-nil, do it synchronously."
+ (let ((default-directory counsel--git-grep-dir)
+ (cmd (format "git grep -i -c '%s' | sed 's/.*:\\(.*\\)/\\1/g' | awk '{s+=$1} END {print s}'"
+ regex))
+ (counsel-ggc-process " *counsel-gg-count*"))
+ (if no-async
+ (string-to-number (shell-command-to-string cmd))
+ (let ((proc (get-process counsel-ggc-process))
+ (buff (get-buffer counsel-ggc-process)))
+ (when proc
+ (delete-process proc))
+ (when buff
+ (kill-buffer buff))
+ (setq proc (start-process-shell-command
+ counsel-ggc-process
+ counsel-ggc-process
+ cmd))
+ (set-process-sentinel
+ proc
+ #'(lambda (process event)
+ (when (string= event "finished\n")
+ (with-current-buffer (process-buffer process)
+ (setq ivy--full-length (string-to-number (buffer-string))))
+ (when (= 0 (cl-incf counsel-gg-state))
+ (ivy--exhibit)))))))))
+
+(defun counsel--M-x-transformer (cmd)
+ "Add a binding to CMD if it's bound in the current window.
+CMD is a command name."
+ (let ((binding (substitute-command-keys (format "\\[%s]" cmd))))
+ (setq binding (replace-regexp-in-string "C-x 6" "<f2>" binding))
+ (if (string-match "^M-x" binding)
+ cmd
+ (format "%s (%s)" cmd
+ (propertize binding 'face 'font-lock-keyword-face)))))
+
+(defvar smex-initialized-p)
+(defvar smex-ido-cache)
+(declare-function smex-initialize "ext:smex")
+(declare-function smex-detect-new-commands "ext:smex")
+(declare-function smex-update "ext:smex")
+(declare-function smex-rank "ext:smex")
+
+;;;###autoload
+(defun counsel-M-x (&optional initial-input)
+ "Ivy version of `execute-extended-command'.
+Optional INITIAL-INPUT is the initial input in the minibuffer."
+ (interactive)
+ (unless initial-input
+ (setq initial-input (cdr (assoc this-command
+ ivy-initial-inputs-alist))))
+ (let* ((store ivy-format-function)
+ (ivy-format-function
+ (lambda (cands)
+ (funcall
+ store
+ (with-ivy-window
+ (mapcar #'counsel--M-x-transformer cands)))))
+ (cands obarray)
+ (pred 'commandp)
+ (sort t))
+ (when (require 'smex nil 'noerror)
+ (unless smex-initialized-p
+ (smex-initialize))
+ (smex-detect-new-commands)
+ (smex-update)
+ (setq cands smex-ido-cache)
+ (setq pred nil)
+ (setq sort nil))
+ (ivy-read "M-x " cands
+ :predicate pred
+ :require-match t
+ :history 'extended-command-history
+ :action
+ (lambda (cmd)
+ (when (featurep 'smex)
+ (smex-rank (intern cmd)))
+ (let ((prefix-arg current-prefix-arg))
+ (command-execute (intern cmd) 'record)))
+ :sort sort
+ :keymap counsel-describe-map
+ :initial-input initial-input)))
+
+(declare-function powerline-reset "ext:powerline")
+
+(defun counsel--load-theme-action (x)
+ "Disable current themes and load theme X."
+ (condition-case nil
+ (progn
+ (mapc #'disable-theme custom-enabled-themes)
+ (load-theme (intern x))
+ (when (fboundp 'powerline-reset)
+ (powerline-reset)))
+ (error "Problem loading theme %s" x)))
+
+;;;###autoload
+(defun counsel-load-theme ()
+ "Forward to `load-theme'.
+Usable with `ivy-resume', `ivy-next-line-and-call' and
+`ivy-previous-line-and-call'."
+ (interactive)
+ (ivy-read "Load custom theme: "
+ (mapcar 'symbol-name
+ (custom-available-themes))
+ :action #'counsel--load-theme-action))
+
+(defvar rhythmbox-library)
+(declare-function rhythmbox-load-library "ext:helm-rhythmbox")
+(declare-function dbus-call-method "dbus")
+(declare-function rhythmbox-song-uri "ext:helm-rhythmbox")
+(declare-function helm-rhythmbox-candidates "ext:helm-rhythmbox")
+
+(defun counsel-rhythmbox-enqueue-song (song)
+ "Let Rhythmbox enqueue SONG."
+ (let ((service "org.gnome.Rhythmbox3")
+ (path "/org/gnome/Rhythmbox3/PlayQueue")
+ (interface "org.gnome.Rhythmbox3.PlayQueue"))
+ (dbus-call-method :session service path interface
+ "AddToQueue" (rhythmbox-song-uri song))))
+
+(defvar counsel-rhythmbox-history nil
+ "History for `counsel-rhythmbox'.")
+
+;;;###autoload
+(defun counsel-rhythmbox ()
+ "Choose a song from the Rhythmbox library to play or enqueue."
+ (interactive)
+ (unless (require 'helm-rhythmbox nil t)
+ (error "Please install `helm-rhythmbox'"))
+ (unless rhythmbox-library
+ (rhythmbox-load-library)
+ (while (null rhythmbox-library)
+ (sit-for 0.1)))
+ (ivy-read "Rhythmbox: "
+ (helm-rhythmbox-candidates)
+ :history 'counsel-rhythmbox-history
+ :action
+ '(1
+ ("p" helm-rhythmbox-play-song "Play song")
+ ("e" counsel-rhythmbox-enqueue-song "Enqueue song"))))
+
+(defvar counsel-org-tags nil
+ "Store the current list of tags.")
+
+(defvar org-outline-regexp)
+(defvar org-indent-mode)
+(defvar org-indent-indentation-per-level)
+(defvar org-tags-column)
+(declare-function org-get-tags-string "org")
+(declare-function org-move-to-column "org")
+
+(defun counsel-org-change-tags (tags)
+ (let ((current (org-get-tags-string))
+ (col (current-column))
+ level)
+ ;; Insert new tags at the correct column
+ (beginning-of-line 1)
+ (setq level (or (and (looking-at org-outline-regexp)
+ (- (match-end 0) (point) 1))
+ 1))
+ (cond
+ ((and (equal current "") (equal tags "")))
+ ((re-search-forward
+ (concat "\\([ \t]*" (regexp-quote current) "\\)[ \t]*$")
+ (point-at-eol) t)
+ (if (equal tags "")
+ (delete-region
+ (match-beginning 0)
+ (match-end 0))
+ (goto-char (match-beginning 0))
+ (let* ((c0 (current-column))
+ ;; compute offset for the case of org-indent-mode active
+ (di (if (bound-and-true-p org-indent-mode)
+ (* (1- org-indent-indentation-per-level) (1- level))
+ 0))
+ (p0 (if (equal (char-before) ?*) (1+ (point)) (point)))
+ (tc (+ org-tags-column (if (> org-tags-column 0) (- di) di)))
+ (c1 (max (1+ c0) (if (> tc 0) tc (- (- tc) (string-width tags)))))
+ (rpl (concat (make-string (max 0 (- c1 c0)) ?\ ) tags)))
+ (replace-match rpl t t)
+ (and c0 indent-tabs-mode (tabify p0 (point)))
+ tags)))
+ (t (error "Tags alignment failed")))
+ (org-move-to-column col)))
+
+(defun counsel-org--set-tags ()
+ (counsel-org-change-tags
+ (if counsel-org-tags
+ (format ":%s:"
+ (mapconcat #'identity counsel-org-tags ":"))
+ "")))
+
+(defvar org-agenda-bulk-marked-entries)
+
+(declare-function org-get-at-bol "org")
+(declare-function org-agenda-error "org-agenda")
+
+(defun counsel-org-tag-action (x)
+ (if (member x counsel-org-tags)
+ (progn
+ (setq counsel-org-tags (delete x counsel-org-tags)))
+ (unless (equal x "")
+ (setq counsel-org-tags (append counsel-org-tags (list x)))
+ (unless (member x ivy--all-candidates)
+ (setq ivy--all-candidates (append ivy--all-candidates (list x))))))
+ (let ((prompt (counsel-org-tag-prompt)))
+ (setf (ivy-state-prompt ivy-last) prompt)
+ (setq ivy--prompt (concat "%-4d " prompt)))
+ (cond ((memq this-command '(ivy-done
+ ivy-alt-done
+ ivy-immediate-done))
+ (if (eq major-mode 'org-agenda-mode)
+ (if (null org-agenda-bulk-marked-entries)
+ (let ((hdmarker (or (org-get-at-bol 'org-hd-marker)
+ (org-agenda-error))))
+ (with-current-buffer (marker-buffer hdmarker)
+ (goto-char hdmarker)
+ (counsel-org--set-tags)))
+ (let ((add-tags (copy-sequence counsel-org-tags)))
+ (dolist (m org-agenda-bulk-marked-entries)
+ (with-current-buffer (marker-buffer m)
+ (save-excursion
+ (goto-char m)
+ (setq counsel-org-tags
+ (delete-dups
+ (append (split-string (org-get-tags-string) ":" t)
+ add-tags)))
+ (counsel-org--set-tags))))))
+ (counsel-org--set-tags)))
+ ((eq this-command 'ivy-call)
+ (delete-minibuffer-contents))))
+
+(defun counsel-org-tag-prompt ()
+ (format "Tags (%s): "
+ (mapconcat #'identity counsel-org-tags ", ")))
+
+(defvar org-setting-tags)
+(defvar org-last-tags-completion-table)
+(defvar org-tag-persistent-alist)
+(defvar org-tag-alist)
+(defvar org-complete-tags-always-offer-all-agenda-tags)
+
+(declare-function org-at-heading-p "org")
+(declare-function org-back-to-heading "org")
+(declare-function org-get-buffer-tags "org")
+(declare-function org-global-tags-completion-table "org")
+(declare-function org-agenda-files "org")
+(declare-function org-agenda-set-tags "org-agenda")
+
+;;;###autoload
+(defun counsel-org-tag ()
+ "Add or remove tags in org-mode."
+ (interactive)
+ (save-excursion
+ (if (eq major-mode 'org-agenda-mode)
+ (if org-agenda-bulk-marked-entries
+ (setq counsel-org-tags nil)
+ (let ((hdmarker (or (org-get-at-bol 'org-hd-marker)
+ (org-agenda-error))))
+ (with-current-buffer (marker-buffer hdmarker)
+ (goto-char hdmarker)
+ (setq counsel-org-tags
+ (split-string (org-get-tags-string) ":" t)))))
+ (unless (org-at-heading-p)
+ (org-back-to-heading t))
+ (setq counsel-org-tags (split-string (org-get-tags-string) ":" t)))
+ (let ((org-setting-tags t)
+ (org-last-tags-completion-table
+ (append org-tag-persistent-alist
+ (or org-tag-alist (org-get-buffer-tags))
+ (and
+ (or org-complete-tags-always-offer-all-agenda-tags
+ (eq major-mode 'org-agenda-mode))
+ (org-global-tags-completion-table
+ (org-agenda-files))))))
+ (ivy-read (counsel-org-tag-prompt)
+ (lambda (str &rest _unused)
+ (delete-dups
+ (all-completions str 'org-tags-completion-function)))
+ :history 'org-tags-history
+ :action 'counsel-org-tag-action))))
+
+;;;###autoload
+(defun counsel-org-tag-agenda ()
+ "Set tags for the current agenda item."
+ (interactive)
+ (let ((store (symbol-function 'org-set-tags)))
+ (unwind-protect
+ (progn
+ (fset 'org-set-tags
+ (symbol-function 'counsel-org-tag))
+ (org-agenda-set-tags nil nil))
+ (fset 'org-set-tags store))))
+
+(defun counsel-ag-function (string &optional _pred &rest _unused)
+ "Grep in the current directory for STRING."
+ (if (< (length string) 3)
+ (counsel-more-chars 3)
+ (let ((regex (counsel-unquote-regex-parens
+ (setq ivy--old-re
+ (ivy--regex string)))))
+ (counsel--async-command
+ (format "ag --noheading --nocolor %S" regex))
+ nil)))
+
+(defun counsel-ag (&optional initial-input)
+ "Grep for a string in the current directory using ag.
+INITIAL-INPUT can be given as the initial minibuffer input."
+ (interactive)
+ (setq counsel--git-grep-dir default-directory)
+ (ivy-read "ag: " 'counsel-ag-function
+ :initial-input initial-input
+ :dynamic-collection t
+ :history 'counsel-git-grep-history
+ :action #'counsel-git-grep-action
+ :unwind #'swiper--cleanup))
+
+(defun counsel-recoll-function (string &optional _pred &rest _unused)
+ "Grep in the current directory for STRING."
+ (if (< (length string) 3)
+ (counsel-more-chars 3)
+ (counsel--async-command
+ (format "recoll -t -b '%s'" string))
+ nil))
+
+;; This command uses the recollq command line tool that comes together
+;; with the recoll (the document indexing database) source:
+;; http://www.lesbonscomptes.com/recoll/download.html
+;; You need to build it yourself (together with recoll):
+;; cd ./query && make && sudo cp recollq /usr/local/bin
+;; You can try the GUI version of recoll with:
+;; sudo apt-get install recoll
+;; Unfortunately, that does not install recollq.
+(defun counsel-recoll (&optional initial-input)
+ "Search for a string in the recoll database.
+You'll be given a list of files that match.
+Selecting a file will launch `swiper' for that file.
+INITIAL-INPUT can be given as the initial minibuffer input."
+ (interactive)
+ (ivy-read "recoll: " 'counsel-recoll-function
+ :initial-input initial-input
+ :dynamic-collection t
+ :history 'counsel-git-grep-history
+ :action (lambda (x)
+ (when (string-match "file://\\(.*\\)\\'" x)
+ (let ((file-name (match-string 1 x)))
+ (find-file file-name)
+ (unless (string-match "pdf$" x)
+ (swiper ivy-text)))))))
+
+(defcustom counsel-yank-pop-truncate nil
+ "When non-nil, truncate the display of long strings."
+ :group 'ivy)
+
+;;;###autoload
+(defun counsel-yank-pop ()
+ "Ivy replacement for `yank-pop'."
+ (interactive)
+ (if (eq last-command 'yank)
+ (progn
+ (setq counsel-completion-end (point))
+ (setq counsel-completion-beg
+ (save-excursion
+ (search-backward (car kill-ring))
+ (point))))
+ (setq counsel-completion-beg (point))
+ (setq counsel-completion-end (point)))
+ (let ((candidates (cl-remove-if
+ (lambda (s)
+ (or (< (length s) 3)
+ (string-match "\\`[\n[:blank:]]+\\'" s)))
+ (delete-dups kill-ring))))
+ (when counsel-yank-pop-truncate
+ (setq candidates
+ (mapcar (lambda (s)
+ (if (string-match "\\`\\(.*\n.*\n.*\n.*\\)\n" s)
+ (progn
+ (let ((s (copy-sequence s)))
+ (put-text-property
+ (match-end 1)
+ (length s)
+ 'display
+ " [...]"
+ s)
+ s))
+ s))
+ candidates)))
+ (ivy-read "kill-ring: " candidates
+ :action 'counsel-yank-pop-action)))
+
+(defun counsel-yank-pop-action (s)
+ "Insert S into the buffer, overwriting the previous yank."
+ (with-ivy-window
+ (delete-region counsel-completion-beg
+ counsel-completion-end)
+ (insert (substring-no-properties s))
+ (setq counsel-completion-end (point))))
+