Taylor Bockman
9 years ago
37 changed files with 0 additions and 20905 deletions
@ -1 +0,0 @@
|
||||
(define-package "ag" "20150814.1655" "A front-end for ag ('the silver searcher'), the C ack replacement." '((dash "2.8.0") (s "1.9.0") (cl-lib "0.5"))) |
@ -1,617 +0,0 @@
|
||||
;;; ag.el --- A front-end for ag ('the silver searcher'), the C ack replacement. |
||||
|
||||
;; Copyright (C) 2013-2014 Wilfred Hughes <me@wilfred.me.uk> |
||||
;; |
||||
;; Author: Wilfred Hughes <me@wilfred.me.uk> |
||||
;; Created: 11 January 2013 |
||||
;; Version: 0.47 |
||||
;; Package-Version: 20150814.1655 |
||||
;; Package-Requires: ((dash "2.8.0") (s "1.9.0") (cl-lib "0.5")) |
||||
;;; Commentary: |
||||
|
||||
;; Please see README.md for documentation, or read it online at |
||||
;; https://github.com/Wilfred/ag.el/#agel |
||||
|
||||
;;; License: |
||||
|
||||
;; This file is not part of GNU Emacs. |
||||
;; However, it is distributed under the same license. |
||||
|
||||
;; GNU Emacs is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation; either version 3, or (at your option) |
||||
;; any later version. |
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with GNU Emacs; see the file COPYING. If not, write to the |
||||
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
||||
;; Boston, MA 02110-1301, USA. |
||||
|
||||
;;; Code: |
||||
(eval-when-compile (require 'cl)) ;; dolist, defun*, flet |
||||
(require 'cl-lib) ;; cl-letf |
||||
(require 'dired) ;; dired-sort-inhibit |
||||
(require 'dash) |
||||
(require 's) |
||||
(require 'find-dired) ;; find-dired-filter |
||||
|
||||
(defcustom ag-executable |
||||
"ag" |
||||
"Name of the ag executable to use." |
||||
:type 'string |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-arguments |
||||
(list "--line-number" "--smart-case" "--nogroup" "--column" "--stats" "--") |
||||
"Default arguments passed to ag. |
||||
|
||||
Ag.el requires --nogroup and --column, so we recommend you add any |
||||
additional arguments to the start of this list. |
||||
|
||||
--line-number is required on Window, as otherwise ag will not |
||||
print line numbers when the input is a stream." |
||||
:type '(repeat (string)) |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-highlight-search nil |
||||
"Non-nil means we highlight the current search term in results. |
||||
|
||||
This requires the ag command to support --color-match, which is only in v0.14+" |
||||
:type 'boolean |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-reuse-buffers nil |
||||
"Non-nil means we reuse the existing search results buffer or |
||||
dired results buffer, rather than creating one buffer per unique |
||||
search." |
||||
:type 'boolean |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-reuse-window nil |
||||
"Non-nil means we open search results in the same window, |
||||
hiding the results buffer." |
||||
:type 'boolean |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-project-root-function nil |
||||
"A function to determine the project root for `ag-project'. |
||||
|
||||
If set to a function, call this function with the name of the |
||||
file or directory for which to determine the project root |
||||
directory. |
||||
|
||||
If set to nil, fall back to finding VCS root directories." |
||||
:type '(choice (const :tag "Default (VCS root)" nil) |
||||
(function :tag "Function")) |
||||
:group 'ag) |
||||
|
||||
(defcustom ag-ignore-list nil |
||||
"A list of patterns to ignore when searching." |
||||
:type '(repeat (string)) |
||||
:group 'ag) |
||||
|
||||
(require 'compile) |
||||
|
||||
;; Although ag results aren't exactly errors, we treat them as errors |
||||
;; so `next-error' and `previous-error' work. However, we ensure our |
||||
;; face inherits from `compilation-info-face' so the results are |
||||
;; styled appropriately. |
||||
(defface ag-hit-face '((t :inherit compilation-info)) |
||||
"Face name to use for ag matches." |
||||
:group 'ag) |
||||
|
||||
(defface ag-match-face '((t :inherit match)) |
||||
"Face name to use for ag matches." |
||||
:group 'ag) |
||||
|
||||
(defvar ag-search-finished-hook nil |
||||
"Hook run when ag completes a search in a buffer.") |
||||
|
||||
(defun ag/run-finished-hook (buffer how-finished) |
||||
"Run the ag hook to signal that the search has completed." |
||||
(with-current-buffer buffer |
||||
(run-hooks 'ag-search-finished-hook))) |
||||
|
||||
(defmacro ag/with-patch-function (fun-name fun-args fun-body &rest body) |
||||
"Temporarily override the definition of FUN-NAME whilst BODY is executed. |
||||
|
||||
Assumes FUNCTION is already defined (see http://emacs.stackexchange.com/a/3452/304)." |
||||
`(cl-letf (((symbol-function ,fun-name) |
||||
(lambda ,fun-args ,fun-body))) |
||||
,@body)) |
||||
|
||||
(defun ag/next-error-function (n &optional reset) |
||||
"Open the search result at point in the current window or a |
||||
different window, according to `ag-reuse-window'." |
||||
(if ag-reuse-window |
||||
;; prevent changing the window |
||||
(ag/with-patch-function |
||||
'pop-to-buffer (buffer &rest args) (switch-to-buffer buffer) |
||||
(compilation-next-error-function n reset)) |
||||
|
||||
;; just navigate to the results as normal |
||||
(compilation-next-error-function n reset))) |
||||
|
||||
;; Note that we want to use as tight a regexp as we can to try and |
||||
;; handle weird file names (with colons in them) as well as possible. |
||||
;; E.g. we use [1-9][0-9]* rather than [0-9]+ so as to accept ":034:" |
||||
;; in file names. |
||||
(defvar ag/file-column-pattern |
||||
"^\\(.+?\\):\\([1-9][0-9]*\\):\\([1-9][0-9]*\\):" |
||||
"A regexp pattern that groups output into filename, line number and column number.") |
||||
|
||||
(define-compilation-mode ag-mode "Ag" |
||||
"Ag results compilation mode" |
||||
(set (make-local-variable 'compilation-error-regexp-alist) |
||||
(list 'compilation-ag-nogroup)) |
||||
(set (make-local-variable 'compilation-error-regexp-alist-alist) |
||||
(list (cons 'compilation-ag-nogroup (list ag/file-column-pattern 1 2 3)))) |
||||
(set (make-local-variable 'compilation-error-face) 'ag-hit-face) |
||||
(set (make-local-variable 'next-error-function) #'ag/next-error-function) |
||||
(set (make-local-variable 'compilation-finish-functions) |
||||
#'ag/run-finished-hook) |
||||
(add-hook 'compilation-filter-hook 'ag-filter nil t)) |
||||
|
||||
(define-key ag-mode-map (kbd "p") #'compilation-previous-error) |
||||
(define-key ag-mode-map (kbd "n") #'compilation-next-error) |
||||
(define-key ag-mode-map (kbd "k") '(lambda () (interactive) |
||||
(let (kill-buffer-query-functions) (kill-buffer)))) |
||||
|
||||
(defun ag/buffer-name (search-string directory regexp) |
||||
"Return a buffer name formatted according to ag.el conventions." |
||||
(cond |
||||
(ag-reuse-buffers "*ag search*") |
||||
(regexp (format "*ag search regexp:%s dir:%s*" search-string directory)) |
||||
(:else (format "*ag search text:%s dir:%s*" search-string directory)))) |
||||
|
||||
(defun ag/format-ignore (ignores) |
||||
"Prepend '--ignore' to every item in IGNORES." |
||||
(apply #'append |
||||
(mapcar (lambda (item) (list "--ignore" item)) ignores))) |
||||
|
||||
(defun* ag/search (string directory |
||||
&key (regexp nil) (file-regex nil) (file-type nil)) |
||||
"Run ag searching for the STRING given in DIRECTORY. |
||||
If REGEXP is non-nil, treat STRING as a regular expression." |
||||
(let ((default-directory (file-name-as-directory directory)) |
||||
(arguments ag-arguments) |
||||
(shell-command-switch "-c")) |
||||
(unless regexp |
||||
(setq arguments (cons "--literal" arguments))) |
||||
(if ag-highlight-search |
||||
(setq arguments (append '("--color" "--color-match" "30;43") arguments)) |
||||
(setq arguments (append '("--nocolor") arguments))) |
||||
(when (char-or-string-p file-regex) |
||||
(setq arguments (append `("--file-search-regex" ,file-regex) arguments))) |
||||
(when file-type |
||||
(setq arguments (cons (format "--%s" file-type) arguments))) |
||||
(when ag-ignore-list |
||||
(setq arguments (append (ag/format-ignore ag-ignore-list) arguments))) |
||||
(unless (file-exists-p default-directory) |
||||
(error "No such directory %s" default-directory)) |
||||
(let ((command-string |
||||
(mapconcat #'shell-quote-argument |
||||
(append (list ag-executable) arguments (list string ".")) |
||||
" "))) |
||||
;; If we're called with a prefix, let the user modify the command before |
||||
;; running it. Typically this means they want to pass additional arguments. |
||||
(when current-prefix-arg |
||||
;; Make a space in the command-string for the user to enter more arguments. |
||||
(setq command-string (ag/replace-first command-string " -- " " -- ")) |
||||
;; Prompt for the command. |
||||
(let ((adjusted-point (- (length command-string) (length string) 5))) |
||||
(setq command-string |
||||
(read-from-minibuffer "ag command: " |
||||
(cons command-string adjusted-point))))) |
||||
;; Call ag. |
||||
(compilation-start |
||||
command-string |
||||
#'ag-mode |
||||
`(lambda (mode-name) ,(ag/buffer-name string directory regexp)))))) |
||||
|
||||
(defun ag/dwim-at-point () |
||||
"If there's an active selection, return that. |
||||
Otherwise, get the symbol at point, as a string." |
||||
(cond ((use-region-p) |
||||
(buffer-substring-no-properties (region-beginning) (region-end))) |
||||
((symbol-at-point) |
||||
(substring-no-properties |
||||
(symbol-name (symbol-at-point)))))) |
||||
|
||||
(defun ag/buffer-extension-regex () |
||||
"If the current buffer has an extension, return |
||||
a PCRE pattern that matches files with that extension. |
||||
Returns an empty string otherwise." |
||||
(let ((file-name (buffer-file-name))) |
||||
(if (stringp file-name) |
||||
(format "\\.%s$" (ag/escape-pcre (file-name-extension file-name))) |
||||
""))) |
||||
|
||||
(defun ag/longest-string (&rest strings) |
||||
"Given a list of strings and nils, return the longest string." |
||||
(let ((longest-string nil)) |
||||
(dolist (string strings) |
||||
(cond ((null longest-string) |
||||
(setq longest-string string)) |
||||
((stringp string) |
||||
(when (< (length longest-string) |
||||
(length string)) |
||||
(setq longest-string string))))) |
||||
longest-string)) |
||||
|
||||
(defun ag/replace-first (string before after) |
||||
"Replace the first occurrence of BEFORE in STRING with AFTER." |
||||
(replace-regexp-in-string |
||||
(concat "\\(" (regexp-quote before) "\\)" ".*\\'") |
||||
after string |
||||
nil nil 1)) |
||||
|
||||
(autoload 'vc-git-root "vc-git") |
||||
|
||||
(require 'vc-svn) |
||||
;; Emacs 23.4 doesn't provide vc-svn-root. |
||||
(unless (functionp 'vc-svn-root) |
||||
(defun vc-svn-root (file) |
||||
(vc-find-root file vc-svn-admin-directory))) |
||||
|
||||
(autoload 'vc-hg-root "vc-hg") |
||||
|
||||
(defun ag/project-root (file-path) |
||||
"Guess the project root of the given FILE-PATH. |
||||
|
||||
Use `ag-project-root-function' if set, or fall back to VCS |
||||
roots." |
||||
(if ag-project-root-function |
||||
(funcall ag-project-root-function file-path) |
||||
(or (ag/longest-string |
||||
(vc-git-root file-path) |
||||
(vc-svn-root file-path) |
||||
(vc-hg-root file-path)) |
||||
file-path))) |
||||
|
||||
(defun ag/dired-align-size-column () |
||||
(beginning-of-line) |
||||
(when (looking-at "^ ") |
||||
(forward-char 2) |
||||
(search-forward " " nil t 4) |
||||
(let* ((size-start (point)) |
||||
(size-end (search-forward " " nil t)) |
||||
(width (and size-end (- size-end size-start)))) |
||||
(when (and size-end |
||||
(< width 12) |
||||
(> width 1)) |
||||
(goto-char size-start) |
||||
(insert (make-string (- 12 width) ? )))))) |
||||
|
||||
(defun ag/dired-filter (proc string) |
||||
"Filter the output of ag to make it suitable for `dired-mode'." |
||||
(let ((buf (process-buffer proc)) |
||||
(inhibit-read-only t)) |
||||
(if (buffer-name buf) |
||||
(with-current-buffer buf |
||||
(save-excursion |
||||
(save-restriction |
||||
(widen) |
||||
(let ((beg (point-max))) |
||||
(goto-char beg) |
||||
(insert string) |
||||
(goto-char beg) |
||||
(or (looking-at "^") |
||||
(progn |
||||
(ag/dired-align-size-column) |
||||
(forward-line 1))) |
||||
(while (looking-at "^") |
||||
(insert " ") |
||||
(ag/dired-align-size-column) |
||||
(forward-line 1)) |
||||
(goto-char beg) |
||||
(beginning-of-line) |
||||
|
||||
;; Remove occurrences of default-directory. |
||||
(while (search-forward (concat " " default-directory) nil t) |
||||
(replace-match " " nil t)) |
||||
|
||||
(goto-char (point-max)) |
||||
(if (search-backward "\n" (process-mark proc) t) |
||||
(progn |
||||
(dired-insert-set-properties (process-mark proc) |
||||
(1+ (point))) |
||||
(move-marker (process-mark proc) (1+ (point))))))))) |
||||
(delete-process proc)))) |
||||
|
||||
(defun ag/dired-sentinel (proc state) |
||||
"Update the status/modeline after the process finishes." |
||||
(let ((buf (process-buffer proc)) |
||||
(inhibit-read-only t)) |
||||
(if (buffer-name buf) |
||||
(with-current-buffer buf |
||||
(let ((buffer-read-only nil)) |
||||
(save-excursion |
||||
(goto-char (point-max)) |
||||
(insert "\n ag " state) |
||||
(forward-char -1) ;Back up before \n at end of STATE. |
||||
(insert " at " (substring (current-time-string) 0 19)) |
||||
(forward-char 1) |
||||
(setq mode-line-process |
||||
(concat ":" (symbol-name (process-status proc)))) |
||||
;; Since the buffer and mode line will show that the |
||||
;; process is dead, we can delete it now. Otherwise it |
||||
;; will stay around until M-x list-processes. |
||||
(delete-process proc) |
||||
(force-mode-line-update))) |
||||
(run-hooks 'dired-after-readin-hook) |
||||
(message "%s finished." (current-buffer)))))) |
||||
|
||||
(defun ag/kill-process () |
||||
"Kill the `ag' process running in the current buffer." |
||||
(interactive) |
||||
(let ((ag (get-buffer-process (current-buffer)))) |
||||
(and ag (eq (process-status ag) 'run) |
||||
(eq (process-filter ag) (function find-dired-filter)) |
||||
(condition-case nil |
||||
(delete-process ag) |
||||
(error nil))))) |
||||
|
||||
(defun ag/escape-pcre (regexp) |
||||
"Escape the PCRE-special characters in REGEXP so that it is |
||||
matched literally." |
||||
(let ((alphanum "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")) |
||||
(apply #'concat |
||||
(mapcar |
||||
(lambda (c) |
||||
(cond |
||||
((not (string-match-p (regexp-quote c) alphanum)) |
||||
(concat "\\" c)) |
||||
(t c))) |
||||
(mapcar #'char-to-string (string-to-list regexp)))))) |
||||
|
||||
;;;###autoload |
||||
(defun ag (string directory) |
||||
"Search using ag in a given DIRECTORY for a given search STRING, |
||||
with STRING defaulting to the symbol under point. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive (list (ag/read-from-minibuffer "Search string") |
||||
(read-directory-name "Directory: "))) |
||||
(ag/search string directory)) |
||||
|
||||
;;;###autoload |
||||
(defun ag-files (string file-type directory) |
||||
"Search using ag in a given DIRECTORY for a given search STRING, |
||||
limited to files that match FILE-TYPE. STRING defaults to |
||||
the symbol under point. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive (list (ag/read-from-minibuffer "Search string") |
||||
(ag/read-file-type) |
||||
(read-directory-name "Directory: "))) |
||||
(apply #'ag/search string directory file-type)) |
||||
|
||||
;;;###autoload |
||||
(defun ag-regexp (string directory) |
||||
"Search using ag in a given directory for a given regexp. |
||||
The regexp should be in PCRE syntax, not Emacs regexp syntax. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive "sSearch regexp: \nDDirectory: ") |
||||
(ag/search string directory :regexp t)) |
||||
|
||||
;;;###autoload |
||||
(defun ag-project (string) |
||||
"Guess the root of the current project and search it with ag |
||||
for the given string. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive (list (ag/read-from-minibuffer "Search string"))) |
||||
(ag/search string (ag/project-root default-directory))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-project-files (string file-type) |
||||
"Search using ag for a given search STRING, |
||||
limited to files that match FILE-TYPE. STRING defaults to the |
||||
symbol under point. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive (list (ag/read-from-minibuffer "Search string") |
||||
(ag/read-file-type))) |
||||
(apply 'ag/search string (ag/project-root default-directory) file-type)) |
||||
|
||||
(defun ag/read-from-minibuffer (prompt) |
||||
"Read a value from the minibuffer with PROMPT. |
||||
If there's a string at point, offer that as a default." |
||||
(let* ((suggested (ag/dwim-at-point)) |
||||
(final-prompt |
||||
(if suggested |
||||
(format "%s (default %s): " prompt suggested) |
||||
(format "%s: " prompt))) |
||||
;; Ask the user for input, but add `suggested' to the history |
||||
;; so they can use M-n if they want to modify it. |
||||
(user-input (read-from-minibuffer |
||||
final-prompt |
||||
nil nil nil nil suggested))) |
||||
;; Return the input provided by the user, or use `suggested' if |
||||
;; the input was empty. |
||||
(if (> (length user-input) 0) |
||||
user-input |
||||
suggested))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-project-regexp (regexp) |
||||
"Guess the root of the current project and search it with ag |
||||
for the given regexp. The regexp should be in PCRE syntax, not |
||||
Emacs regexp syntax. |
||||
|
||||
If called with a prefix, prompts for flags to pass to ag." |
||||
(interactive (list (ag/read-from-minibuffer "Search regexp"))) |
||||
(ag/search regexp (ag/project-root default-directory) :regexp t)) |
||||
|
||||
(autoload 'symbol-at-point "thingatpt") |
||||
|
||||
;;;###autoload |
||||
(defalias 'ag-project-at-point 'ag-project) |
||||
(make-obsolete 'ag-project-at-point 'ag-project "0.19") |
||||
|
||||
;;;###autoload |
||||
(defalias 'ag-regexp-project-at-point 'ag-project-regexp) |
||||
(make-obsolete 'ag-regexp-project-at-point 'ag-project-regexp "0.46") |
||||
|
||||
;;;###autoload |
||||
(defun ag-dired (dir pattern) |
||||
"Recursively find files in DIR matching PATTERN. |
||||
|
||||
The PATTERN is matched against the full path to the file, not |
||||
only against the file name. |
||||
|
||||
The results are presented as a `dired-mode' buffer with |
||||
`default-directory' being DIR. |
||||
|
||||
See also `ag-dired-regexp'." |
||||
(interactive "DDirectory: \nsFile pattern: ") |
||||
(ag-dired-regexp dir (ag/escape-pcre pattern))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-dired-regexp (dir regexp) |
||||
"Recursively find files in DIR matching REGEXP. |
||||
REGEXP should be in PCRE syntax, not Emacs regexp syntax. |
||||
|
||||
The REGEXP is matched against the full path to the file, not |
||||
only against the file name. |
||||
|
||||
Results are presented as a `dired-mode' buffer with |
||||
`default-directory' being DIR. |
||||
|
||||
See also `find-dired'." |
||||
(interactive "DDirectory: \nsFile regexp: ") |
||||
(let* ((dired-buffers dired-buffers) ;; do not mess with regular dired buffers |
||||
(orig-dir dir) |
||||
(dir (file-name-as-directory (expand-file-name dir))) |
||||
(buffer-name (if ag-reuse-buffers |
||||
"*ag dired*" |
||||
(format "*ag dired pattern:%s dir:%s*" regexp dir))) |
||||
(cmd (concat ag-executable " --nocolor -g '" regexp "' " |
||||
(shell-quote-argument dir) |
||||
" | grep -v '^$' | sed s/\\'/\\\\\\\\\\'/ | xargs -I '{}' ls " |
||||
dired-listing-switches " '{}' &"))) |
||||
(with-current-buffer (get-buffer-create buffer-name) |
||||
(switch-to-buffer (current-buffer)) |
||||
(widen) |
||||
(kill-all-local-variables) |
||||
(if (fboundp 'read-only-mode) |
||||
(read-only-mode -1) |
||||
(setq buffer-read-only nil)) |
||||
(let ((inhibit-read-only t)) (erase-buffer)) |
||||
(setq default-directory dir) |
||||
(run-hooks 'dired-before-readin-hook) |
||||
(shell-command cmd (current-buffer)) |
||||
(insert " " dir ":\n") |
||||
(insert " " cmd "\n") |
||||
(dired-mode dir) |
||||
(let ((map (make-sparse-keymap))) |
||||
(set-keymap-parent map (current-local-map)) |
||||
(define-key map "\C-c\C-k" 'ag/kill-process) |
||||
(use-local-map map)) |
||||
(set (make-local-variable 'dired-sort-inhibit) t) |
||||
(set (make-local-variable 'revert-buffer-function) |
||||
`(lambda (ignore-auto noconfirm) |
||||
(ag-dired-regexp ,orig-dir ,regexp))) |
||||
(if (fboundp 'dired-simple-subdir-alist) |
||||
(dired-simple-subdir-alist) |
||||
(set (make-local-variable 'dired-subdir-alist) |
||||
(list (cons default-directory (point-min-marker))))) |
||||
(let ((proc (get-buffer-process (current-buffer)))) |
||||
(set-process-filter proc #'ag/dired-filter) |
||||
(set-process-sentinel proc #'ag/dired-sentinel) |
||||
;; Initialize the process marker; it is used by the filter. |
||||
(move-marker (process-mark proc) 1 (current-buffer))) |
||||
(setq mode-line-process '(":%s"))))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-project-dired (pattern) |
||||
"Recursively find files in current project matching PATTERN. |
||||
|
||||
See also `ag-dired'." |
||||
(interactive "sFile pattern: ") |
||||
(ag-dired-regexp (ag/project-root default-directory) (ag/escape-pcre pattern))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-project-dired-regexp (regexp) |
||||
"Recursively find files in current project matching REGEXP. |
||||
|
||||
See also `ag-dired-regexp'." |
||||
(interactive "sFile regexp: ") |
||||
(ag-dired-regexp (ag/project-root default-directory) regexp)) |
||||
|
||||
;;;###autoload |
||||
(defun ag-kill-buffers () |
||||
"Kill all `ag-mode' buffers." |
||||
(interactive) |
||||
(dolist (buffer (buffer-list)) |
||||
(when (eq (buffer-local-value 'major-mode buffer) 'ag-mode) |
||||
(kill-buffer buffer)))) |
||||
|
||||
;;;###autoload |
||||
(defun ag-kill-other-buffers () |
||||
"Kill all `ag-mode' buffers other than the current buffer." |
||||
(interactive) |
||||
(let ((current-buffer (current-buffer))) |
||||
(dolist (buffer (buffer-list)) |
||||
(when (and |
||||
(eq (buffer-local-value 'major-mode buffer) 'ag-mode) |
||||
(not (eq buffer current-buffer))) |
||||
(kill-buffer buffer))))) |
||||
|
||||
;; Taken from grep-filter, just changed the color regex. |
||||
(defun ag-filter () |
||||
"Handle match highlighting escape sequences inserted by the ag process. |
||||
This function is called from `compilation-filter-hook'." |
||||
(when ag-highlight-search |
||||
(save-excursion |
||||
(forward-line 0) |
||||
(let ((end (point)) beg) |
||||
(goto-char compilation-filter-start) |
||||
(forward-line 0) |
||||
(setq beg (point)) |
||||
;; Only operate on whole lines so we don't get caught with part of an |
||||
;; escape sequence in one chunk and the rest in another. |
||||
(when (< (point) end) |
||||
(setq end (copy-marker end)) |
||||
;; Highlight ag matches and delete marking sequences. |
||||
(while (re-search-forward "\033\\[30;43m\\(.*?\\)\033\\[[0-9]*m" end 1) |
||||
(replace-match (propertize (match-string 1) |
||||
'face nil 'font-lock-face 'ag-match-face) |
||||
t t)) |
||||
;; Delete all remaining escape sequences |
||||
(goto-char beg) |
||||
(while (re-search-forward "\033\\[[0-9;]*[mK]" end 1) |
||||
(replace-match "" t t))))))) |
||||
|
||||
(defun ag/get-supported-types () |
||||
"Query the ag executable for which file types it recognises." |
||||
(let* ((ag-output (shell-command-to-string (format "%s --list-file-types" ag-executable))) |
||||
(lines (-map #'s-trim (s-lines ag-output))) |
||||
(types (--keep (when (s-starts-with? "--" it) (s-chop-prefix "--" it )) lines)) |
||||
(extensions (--map (s-split " " it) (--filter (s-starts-with? "." it) lines)))) |
||||
(-zip types extensions))) |
||||
|
||||
(defun ag/read-file-type () |
||||
"Prompt the user for a known file type, or let them specify a PCRE regex." |
||||
(let* ((all-types-with-extensions (ag/get-supported-types)) |
||||
(all-types (mapcar 'car all-types-with-extensions)) |
||||
(file-type |
||||
(completing-read "Select file type: " |
||||
(append '("custom (provide a PCRE regex)") all-types))) |
||||
(file-type-extensions |
||||
(cdr (assoc file-type all-types-with-extensions)))) |
||||
(if file-type-extensions |
||||
(list :file-type file-type) |
||||
(list :file-regex |
||||
(read-from-minibuffer "Filenames which match PCRE: " |
||||
(ag/buffer-extension-regex)))))) |
||||
|
||||
(provide 'ag) |
||||
;;; ag.el ends here |
@ -1,777 +0,0 @@
|
||||
(1 |
||||
(ace-window . |
||||
[(0 9 0) |
||||
((avy |
||||
(0 2 0))) |
||||
"Quickly switch windows." single |
||||
((:url . "https://github.com/abo-abo/ace-window") |
||||
(:keywords "window" "location"))]) |
||||
(ack . |
||||
[(1 5) |
||||
nil "interface to ack-like tools" tar |
||||
((:keywords "tools" "processes" "convenience") |
||||
(:url . "https://github.com/leoliu/ack-el"))]) |
||||
(ada-mode . |
||||
[(5 1 8) |
||||
((wisi |
||||
(1 1 1)) |
||||
(cl-lib |
||||
(0 4)) |
||||
(emacs |
||||
(24 2))) |
||||
"major-mode for editing Ada sources" tar |
||||
((:keywords "languages" "ada") |
||||
(:url . "http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html"))]) |
||||
(ada-ref-man . |
||||
[(2012 0) |
||||
nil "Ada Reference Manual 2012" tar |
||||
((:keywords "languages" "ada") |
||||
(:url . "http://stephe-leake.org/ada/arm.html"))]) |
||||
(adaptive-wrap . |
||||
[(0 5) |
||||
nil "Smart line-wrapping with wrap-prefix" single |
||||
((:url . "http://elpa.gnu.org/packages/adaptive-wrap.html") |
||||
(:keywords))]) |
||||
(adjust-parens . |
||||
[(3 0) |
||||
nil "Indent and dedent Lisp code, automatically adjust close parens" tar |
||||
((:url . "http://elpa.gnu.org/packages/adjust-parens.html"))]) |
||||
(aggressive-indent . |
||||
[(1 4) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"Minor mode to aggressively keep your code always indented" single |
||||
((:url . "http://github.com/Malabarba/aggressive-indent-mode") |
||||
(:keywords "indent" "lisp" "maint" "tools"))]) |
||||
(ahungry-theme . |
||||
[(1 0 12) |
||||
((emacs |
||||
(24))) |
||||
"Ahungry color theme for Emacs. Make sure to (load-theme 'ahungry)." tar |
||||
((:keywords "ahungry" "palette" "color" "theme" "emacs" "color-theme" "deftheme") |
||||
(:url . "https://github.com/ahungry/color-theme-ahungry"))]) |
||||
(all . |
||||
[(1 0) |
||||
nil "Edit all lines matching a given regexp" single |
||||
((:url . "http://elpa.gnu.org/packages/all.html") |
||||
(:keywords "matching"))]) |
||||
(ascii-art-to-unicode . |
||||
[(1 9) |
||||
nil "a small artist adjunct" single |
||||
((:url . "http://www.gnuvola.org/software/aa2u/") |
||||
(:keywords "ascii" "unicode" "box-drawing"))]) |
||||
(auctex . |
||||
[(11 88 9) |
||||
nil "Integrated environment for *TeX*" tar |
||||
((:url . "http://www.gnu.org/software/auctex/"))]) |
||||
(aumix-mode . |
||||
[(7) |
||||
nil "run the aumix program in a buffer" single |
||||
((:url . "http://user42.tuxfamily.org/aumix-mode/index.html") |
||||
(:keywords "multimedia" "mixer" "aumix"))]) |
||||
(auto-overlays . |
||||
[(0 10 9) |
||||
nil "Automatic regexp-delimited overlays" tar |
||||
((:keywords "extensions") |
||||
(:url . "http://www.dr-qubit.org/emacs.php"))]) |
||||
(avy . |
||||
[(0 3 0) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"set-based completion" tar |
||||
((:keywords "point" "location") |
||||
(:url . "https://github.com/abo-abo/avy"))]) |
||||
(beacon . |
||||
[(0 2 1) |
||||
((seq |
||||
(1 9))) |
||||
"Highlight the cursor whenever the window scrolls" single |
||||
((:url . "https://github.com/Malabarba/beacon") |
||||
(:keywords "convenience"))]) |
||||
(bug-hunter . |
||||
[(1 0) |
||||
((seq |
||||
(1 3)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"Hunt down errors in elisp files" single |
||||
((:url . "http://github.com/Malabarba/elisp-bug-hunter") |
||||
(:keywords "lisp"))]) |
||||
(caps-lock . |
||||
[(1 0) |
||||
nil "Caps-lock as a minor mode" single |
||||
((:url . "http://elpa.gnu.org/packages/caps-lock.html") |
||||
(:keywords))]) |
||||
(chess . |
||||
[(2 0 4) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Play chess in GNU Emacs" tar |
||||
((:keywords "games") |
||||
(:url . "http://elpa.gnu.org/packages/chess.html"))]) |
||||
(cl-generic . |
||||
[(0 2) |
||||
nil "Forward cl-generic compatibility for Emacs<25" single |
||||
((:url . "http://elpa.gnu.org/packages/cl-generic.html") |
||||
(:keywords))]) |
||||
(cl-lib . |
||||
[(0 5) |
||||
nil "Properly prefixed CL functions and macros" single |
||||
((:url . "http://elpa.gnu.org/packages/cl-lib.html") |
||||
(:keywords))]) |
||||
(coffee-mode . |
||||
[(0 4 1 1) |
||||
nil "Major mode for CoffeeScript files" single |
||||
((:url . "http://github.com/defunkt/coffee-mode") |
||||
(:keywords "coffeescript" "major" "mode"))]) |
||||
(company . |
||||
[(0 8 12) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"Modular text completion framework" tar |
||||
((:keywords "abbrev" "convenience" "matching") |
||||
(:url . "http://company-mode.github.io/"))]) |
||||
(company-math . |
||||
[(1 0 1) |
||||
((company |
||||
(0 8 0)) |
||||
(math-symbol-lists |
||||
(1 0))) |
||||
"Completion backends for unicode math symbols and latex tags" single |
||||
((:url . "https://github.com/vspinu/company-math") |
||||
(:keywords "unicode" "symbols" "completion"))]) |
||||
(company-statistics . |
||||
[(0 2 1) |
||||
((emacs |
||||
(24 3)) |
||||
(company |
||||
(0 8 5))) |
||||
"Sort candidates using completion history" tar |
||||
((:keywords "abbrev" "convenience" "matching") |
||||
(:url . "https://github.com/company-mode/company-statistics"))]) |
||||
(context-coloring . |
||||
[(7 1 0) |
||||
((emacs |
||||
(24 3)) |
||||
(js2-mode |
||||
(20150713))) |
||||
"Highlight by scope" single |
||||
((:url . "https://github.com/jacksonrayhamilton/context-coloring") |
||||
(:keywords "convenience" "faces" "tools"))]) |
||||
(crisp . |
||||
[(1 3 4) |
||||
nil "CRiSP/Brief Emacs emulator" single |
||||
((:url . "http://elpa.gnu.org/packages/crisp.html") |
||||
(:keywords "emulations" "brief" "crisp"))]) |
||||
(csv-mode . |
||||
[(1 5) |
||||
nil "Major mode for editing comma/char separated values" single |
||||
((:url . "http://centaur.maths.qmul.ac.uk/Emacs/") |
||||
(:keywords "convenience"))]) |
||||
(darkroom . |
||||
[(0 1) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Remove visual distractions and focus on writing" single |
||||
((:url . "http://elpa.gnu.org/packages/darkroom.html") |
||||
(:keywords "convenience" "emulations"))]) |
||||
(dash . |
||||
[(2 12 0) |
||||
nil "A modern list library for Emacs" tar |
||||
((:keywords "lists") |
||||
(:url . "http://elpa.gnu.org/packages/dash.html"))]) |
||||
(dbus-codegen . |
||||
[(0 1) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Lisp code generation for D-Bus." single |
||||
((:url . "http://elpa.gnu.org/packages/dbus-codegen.html") |
||||
(:keywords "comm" "dbus" "convenience"))]) |
||||
(debbugs . |
||||
[(0 7) |
||||
nil "SOAP library to access debbugs servers" tar |
||||
((:keywords "comm" "hypermedia") |
||||
(:url . "http://elpa.gnu.org/packages/debbugs.html"))]) |
||||
(dict-tree . |
||||
[(0 12 8) |
||||
((trie |
||||
(0 2 5)) |
||||
(tNFA |
||||
(0 1 1)) |
||||
(heap |
||||
(0 3))) |
||||
"Dictionary data structure" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "extensions" "matching" "data structures trie" "tree" "dictionary" "completion" "regexp"))]) |
||||
(diff-hl . |
||||
[(1 8 0) |
||||
((cl-lib |
||||
(0 2))) |
||||
"Highlight uncommitted changes" tar |
||||
((:keywords "vc" "diff") |
||||
(:url . "https://github.com/dgutov/diff-hl"))]) |
||||
(dismal . |
||||
[(1 5) |
||||
((cl-lib |
||||
(0))) |
||||
"Dis Mode Ain't Lotus: Spreadsheet program Emacs" tar |
||||
((:url . "http://elpa.gnu.org/packages/dismal.html"))]) |
||||
(djvu . |
||||
[(0 5) |
||||
nil "Edit and view Djvu files via djvused" single |
||||
((:url . "http://elpa.gnu.org/packages/djvu.html") |
||||
(:keywords "files" "wp"))]) |
||||
(docbook . |
||||
[(0 1) |
||||
nil "Info-like viewer for DocBook" single |
||||
((:url . "http://elpa.gnu.org/packages/docbook.html") |
||||
(:keywords "docs" "help"))]) |
||||
(dts-mode . |
||||
[(0 1 0) |
||||
nil "Major mode for Device Tree source files" single |
||||
((:url . "http://elpa.gnu.org/packages/dts-mode.html") |
||||
(:keywords "languages"))]) |
||||
(easy-kill . |
||||
[(0 9 3) |
||||
((emacs |
||||
(24)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"kill & mark things easily" tar |
||||
((:keywords "killing" "convenience") |
||||
(:url . "https://github.com/leoliu/easy-kill"))]) |
||||
(ediprolog . |
||||
[(1 1) |
||||
nil "Emacs Does Interactive Prolog" single |
||||
((:url . "http://elpa.gnu.org/packages/ediprolog.html") |
||||
(:keywords "languages" "processes"))]) |
||||
(el-search . |
||||
[(0 0 3) |
||||
((emacs |
||||
(25))) |
||||
"Expression based incremental search for emacs-lisp-mode" single |
||||
((:url . "http://elpa.gnu.org/packages/el-search.html") |
||||
(:keywords "lisp"))]) |
||||
(eldoc-eval . |
||||
[(0 1) |
||||
nil "Enable eldoc support when minibuffer is in use." single |
||||
((:url . "http://elpa.gnu.org/packages/eldoc-eval.html") |
||||
(:keywords))]) |
||||
(electric-spacing . |
||||
[(5 0) |
||||
nil "Insert operators with surrounding spaces smartly" single |
||||
((:url . "http://elpa.gnu.org/packages/electric-spacing.html") |
||||
(:keywords))]) |
||||
(enwc . |
||||
[(1 0) |
||||
nil "The Emacs Network Client" tar |
||||
((:keywords "enwc" "network" "wicd" "manager" "nm") |
||||
(:url . "http://elpa.gnu.org/packages/enwc.html"))]) |
||||
(epoch-view . |
||||
[(0 0 1) |
||||
nil "Minor mode to visualize epoch timestamps" single |
||||
((:url . "http://elpa.gnu.org/packages/epoch-view.html") |
||||
(:keywords "data" "timestamp" "epoch" "unix"))]) |
||||
(ergoemacs-mode . |
||||
[(5 14 7 3) |
||||
((emacs |
||||
(24 1)) |
||||
(undo-tree |
||||
(0 6 5))) |
||||
"Emacs mode based on common modern interface and ergonomics." tar |
||||
((:keywords "convenience") |
||||
(:url . "https://github.com/ergoemacs/ergoemacs-mode"))]) |
||||
(f90-interface-browser . |
||||
[(1 1) |
||||
nil "Parse and browse f90 interfaces" single |
||||
((:url . "http://github.com/wence-/f90-iface/") |
||||
(:keywords))]) |
||||
(flylisp . |
||||
[(0 2) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 4))) |
||||
"Color unbalanced parentheses and parentheses inconsistent with indentation" single |
||||
((:url . "http://elpa.gnu.org/packages/flylisp.html") |
||||
(:keywords))]) |
||||
(fsm . |
||||
[(0 2) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"state machine library" single |
||||
((:url . "http://elpa.gnu.org/packages/fsm.html") |
||||
(:keywords "extensions"))]) |
||||
(ggtags . |
||||
[(0 8 10) |
||||
((emacs |
||||
(24)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"emacs frontend to GNU Global source code tagging system" single |
||||
((:url . "https://github.com/leoliu/ggtags") |
||||
(:keywords "tools" "convenience"))]) |
||||
(gnorb . |
||||
[(1 1 1) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Glue code between Gnus, Org, and BBDB" tar |
||||
((:keywords "mail" "org" "gnus" "bbdb" "todo" "task") |
||||
(:url . "https://github.com/girzel/gnorb"))]) |
||||
(gnugo . |
||||
[(3 0 0) |
||||
((ascii-art-to-unicode |
||||
(1 5)) |
||||
(xpm |
||||
(1 0 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"play GNU Go in a buffer" tar |
||||
((:keywords "games" "processes") |
||||
(:url . "http://www.gnuvola.org/software/gnugo/"))]) |
||||
(heap . |
||||
[(0 3) |
||||
nil "Heap (a.k.a. priority queue) data structure" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "extensions" "data structures" "heap" "priority queue"))]) |
||||
(hydra . |
||||
[(0 13 3) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Make bindings that stick around." tar |
||||
((:keywords "bindings") |
||||
(:url . "https://github.com/abo-abo/hydra"))]) |
||||
(ioccur . |
||||
[(2 4) |
||||
nil "Incremental occur" single |
||||
((:url . "http://elpa.gnu.org/packages/ioccur.html") |
||||
(:keywords))]) |
||||
(iterators . |
||||
[(0 1) |
||||
((emacs |
||||
(25))) |
||||
"Functions for working with iterators" single |
||||
((:url . "http://elpa.gnu.org/packages/iterators.html") |
||||
(:keywords "extensions" "elisp"))]) |
||||
(javaimp . |
||||
[(0 5) |
||||
nil "Add and reorder Java import statements in Maven projects" single |
||||
((:url . "http://elpa.gnu.org/packages/javaimp.html") |
||||
(:keywords "java" "maven" "programming"))]) |
||||
(jgraph-mode . |
||||
[(1 1) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Major mode for Jgraph files" single |
||||
((:url . "http://elpa.gnu.org/packages/jgraph-mode.html") |
||||
(:keywords "tex" "wp"))]) |
||||
(js2-mode . |
||||
[(20150909) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"Improved JavaScript editing mode" tar |
||||
((:keywords "languages" "javascript") |
||||
(:url . "https://github.com/mooz/js2-mode/"))]) |
||||
(jumpc . |
||||
[(3 0) |
||||
nil "jump to previous insertion points" single |
||||
((:url . "http://elpa.gnu.org/packages/jumpc.html") |
||||
(:keywords))]) |
||||
(landmark . |
||||
[(1 0) |
||||
nil "Neural-network robot that learns landmarks" single |
||||
((:url . "http://elpa.gnu.org/packages/landmark.html") |
||||
(:keywords "games" "neural network" "adaptive search" "chemotaxis"))]) |
||||
(let-alist . |
||||
[(1 0 4) |
||||
nil "Easily let-bind values of an assoc-list by their names" single |
||||
((:url . "http://elpa.gnu.org/packages/let-alist.html") |
||||
(:keywords "extensions" "lisp"))]) |
||||
(lex . |
||||
[(1 1) |
||||
nil "Lexical analyser construction" tar |
||||
((:url . "http://elpa.gnu.org/packages/lex.html"))]) |
||||
(lmc . |
||||
[(1 3) |
||||
nil "Little Man Computer in Elisp" single |
||||
((:url . "http://elpa.gnu.org/packages/lmc.html") |
||||
(:keywords))]) |
||||
(load-dir . |
||||
[(0 0 3) |
||||
nil "Load all Emacs Lisp files in a given directory" single |
||||
((:url . "http://elpa.gnu.org/packages/load-dir.html") |
||||
(:keywords "lisp" "files" "convenience"))]) |
||||
(load-relative . |
||||
[(1 2) |
||||
nil "relative file load (within a multi-file Emacs package)" single |
||||
((:url . "http://github.com/rocky/emacs-load-relative") |
||||
(:keywords "internal"))]) |
||||
(loc-changes . |
||||
[(1 2) |
||||
nil "keep track of positions even after buffer changes" single |
||||
((:url . "http://github.com/rocky/emacs-loc-changes") |
||||
(:keywords))]) |
||||
(markchars . |
||||
[(0 2 0) |
||||
nil "Mark chars fitting certain characteristics" single |
||||
((:url . "http://elpa.gnu.org/packages/markchars.html") |
||||
(:keywords))]) |
||||
(math-symbol-lists . |
||||
[(1 0) |
||||
nil "Lists of Unicode math symbols and latex commands" single |
||||
((:url . "https://github.com/vspinu/math-symbol-lists") |
||||
(:keywords "unicode" "symbols" "mathematics"))]) |
||||
(memory-usage . |
||||
[(0 2) |
||||
nil "Analyze the memory usage of Emacs in various ways" single |
||||
((:url . "http://elpa.gnu.org/packages/memory-usage.html") |
||||
(:keywords "maint"))]) |
||||
(metar . |
||||
[(0 1) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Retrieve and decode METAR weather information" single |
||||
((:url . "http://elpa.gnu.org/packages/metar.html") |
||||
(:keywords "comm"))]) |
||||
(midi-kbd . |
||||
[(0 2) |
||||
((emacs |
||||
(25))) |
||||
"Create keyboard events from Midi input" single |
||||
((:url . "http://elpa.gnu.org/packages/midi-kbd.html") |
||||
(:keywords "convenience" "hardware" "multimedia"))]) |
||||
(minibuffer-line . |
||||
[(0 1) |
||||
nil "Display status info in the minibuffer window" single |
||||
((:url . "http://elpa.gnu.org/packages/minibuffer-line.html") |
||||
(:keywords))]) |
||||
(minimap . |
||||
[(1 2) |
||||
nil "Sidebar showing a \"mini-map\" of a buffer" single |
||||
((:url . "http://elpa.gnu.org/packages/minimap.html") |
||||
(:keywords))]) |
||||
(muse . |
||||
[(3 20) |
||||
nil "Authoring and publishing tool for Emacs" tar |
||||
((:keywords "hypermedia") |
||||
(:url . "http://mwolson.org/projects/EmacsMuse.html"))]) |
||||
(nameless . |
||||
[(0 5 1) |
||||
((emacs |
||||
(24 4))) |
||||
"Hide package namespace in your emacs-lisp code" single |
||||
((:url . "https://github.com/Malabarba/nameless") |
||||
(:keywords "convenience" "lisp"))]) |
||||
(names . |
||||
[(20150723 0) |
||||
((emacs |
||||
(24 1)) |
||||
(cl-lib |
||||
(0 5))) |
||||
"Namespaces for emacs-lisp. Avoid name clobbering without hiding symbols." tar |
||||
((:keywords "extensions" "lisp") |
||||
(:url . "https://github.com/Bruce-Connor/names"))]) |
||||
(nhexl-mode . |
||||
[(0 1) |
||||
nil "Minor mode to edit files via hex-dump format" single |
||||
((:url . "http://elpa.gnu.org/packages/nhexl-mode.html") |
||||
(:keywords "data"))]) |
||||
(nlinum . |
||||
[(1 6) |
||||
nil "Show line numbers in the margin" single |
||||
((:url . "http://elpa.gnu.org/packages/nlinum.html") |
||||
(:keywords "convenience"))]) |
||||
(notes-mode . |
||||
[(1 30) |
||||
nil "Indexing system for on-line note-taking" tar |
||||
((:url . "http://elpa.gnu.org/packages/notes-mode.html"))]) |
||||
(num3-mode . |
||||
[(1 2) |
||||
nil "highlight groups of digits in long numbers" single |
||||
((:url . "http://elpa.gnu.org/packages/num3-mode.html") |
||||
(:keywords "faces" "minor-mode"))]) |
||||
(oauth2 . |
||||
[(0 10) |
||||
nil "OAuth 2.0 Authorization Protocol" single |
||||
((:url . "http://elpa.gnu.org/packages/oauth2.html") |
||||
(:keywords "comm"))]) |
||||
(omn-mode . |
||||
[(1 2) |
||||
nil "Support for OWL Manchester Notation" single |
||||
((:url . "http://elpa.gnu.org/packages/omn-mode.html") |
||||
(:keywords))]) |
||||
(org . |
||||
[(20151005) |
||||
nil "Outline-based notes management and organizer" tar nil]) |
||||
(osc . |
||||
[(0 1) |
||||
nil "Open Sound Control protocol library" single |
||||
((:url . "http://elpa.gnu.org/packages/osc.html") |
||||
(:keywords "comm" "processes" "multimedia"))]) |
||||
(other-frame-window . |
||||
[(1 0 1) |
||||
((emacs |
||||
(24 4))) |
||||
"Minor mode to enable global prefix keys for other frame/window buffer placement" single |
||||
((:url . "http://elpa.gnu.org/packages/other-frame-window.html") |
||||
(:keywords "frame" "window"))]) |
||||
(pabbrev . |
||||
[(4 2 1) |
||||
nil "Predictive abbreviation expansion" single |
||||
((:url . "http://elpa.gnu.org/packages/pabbrev.html") |
||||
(:keywords))]) |
||||
(pinentry . |
||||
[(0 1) |
||||
nil "GnuPG Pinentry server implementation" single |
||||
((:url . "http://elpa.gnu.org/packages/pinentry.html") |
||||
(:keywords "gnupg"))]) |
||||
(poker . |
||||
[(0 1) |
||||
nil "Texas hold'em poker" single |
||||
((:url . "http://elpa.gnu.org/packages/poker.html") |
||||
(:keywords "games"))]) |
||||
(quarter-plane . |
||||
[(0 1) |
||||
nil "Minor mode for quarter-plane style editing" single |
||||
((:url . "http://elpa.gnu.org/packages/quarter-plane.html") |
||||
(:keywords "convenience" "wp"))]) |
||||
(queue . |
||||
[(0 1 1) |
||||
nil "Queue data structure" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "extensions" "data structures" "queue"))]) |
||||
(rainbow-mode . |
||||
[(0 12) |
||||
nil "Colorize color names in buffers" single |
||||
((:url . "http://elpa.gnu.org/packages/rainbow-mode.html") |
||||
(:keywords "faces"))]) |
||||
(register-list . |
||||
[(0 1) |
||||
nil "Interactively list/edit registers" single |
||||
((:url . "http://elpa.gnu.org/packages/register-list.html") |
||||
(:keywords "register"))]) |
||||
(rich-minority . |
||||
[(1 0) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Clean-up and Beautify the list of minor-modes." single |
||||
((:url . "https://github.com/Malabarba/rich-minority") |
||||
(:keywords "mode-line" "faces"))]) |
||||
(rudel . |
||||
[(0 3) |
||||
nil "A collaborative editing framework for Emacs" tar |
||||
((:keywords "rudel" "collaboration") |
||||
(:url . "http://rudel.sourceforge.net/"))]) |
||||
(scroll-restore . |
||||
[(1 0) |
||||
nil "restore original position after scrolling" single |
||||
((:url . "http://elpa.gnu.org/packages/scroll-restore.html") |
||||
(:keywords "scrolling"))]) |
||||
(seq . |
||||
[(1 11) |
||||
nil "Sequence manipulation functions" single |
||||
((:url . "http://elpa.gnu.org/packages/seq.html") |
||||
(:keywords "sequences"))]) |
||||
(shen-mode . |
||||
[(0 1) |
||||
nil "A major mode for editing shen source code" tar |
||||
((:keywords "languages" "shen") |
||||
(:url . "http://elpa.gnu.org/packages/shen-mode.html"))]) |
||||
(sisu-mode . |
||||
[(3 0 3) |
||||
nil "Major mode for SiSU markup text" single |
||||
((:url . "http://elpa.gnu.org/packages/sisu-mode.html") |
||||
(:keywords "text" "processes" "tools"))]) |
||||
(sml-mode . |
||||
[(6 7) |
||||
nil "Major mode for editing (Standard) ML" single |
||||
((:url . "http://elpa.gnu.org/packages/sml-mode.html") |
||||
(:keywords "sml"))]) |
||||
(sokoban . |
||||
[(1 4) |
||||
nil "Implementation of Sokoban for Emacs." tar |
||||
((:keywords "games") |
||||
(:url . "http://elpa.gnu.org/packages/sokoban.html"))]) |
||||
(sotlisp . |
||||
[(1 4 1) |
||||
((emacs |
||||
(24 1))) |
||||
"Write lisp at the speed of thought." single |
||||
((:url . "https://github.com/Malabarba/speed-of-thought-lisp") |
||||
(:keywords "convenience" "lisp"))]) |
||||
(spinner . |
||||
[(1 4) |
||||
nil "Add spinners and progress-bars to the mode-line for ongoing operations" single |
||||
((:url . "https://github.com/Malabarba/spinner.el") |
||||
(:keywords "processes" "mode-line"))]) |
||||
(stream . |
||||
[(1 0) |
||||
((emacs |
||||
(25))) |
||||
"Implementation of streams" single |
||||
((:url . "http://elpa.gnu.org/packages/stream.html") |
||||
(:keywords "stream" "laziness" "sequences"))]) |
||||
(svg . |
||||
[(0 1) |
||||
((emacs |
||||
(25))) |
||||
"svg image creation functions" single |
||||
((:url . "http://elpa.gnu.org/packages/svg.html") |
||||
(:keywords "image"))]) |
||||
(svg-clock . |
||||
[(0 5) |
||||
((svg |
||||
(0 1)) |
||||
(emacs |
||||
(25 0))) |
||||
"Analog clock using Scalable Vector Graphics" single |
||||
((:url . "http://elpa.gnu.org/packages/svg-clock.html") |
||||
(:keywords "demo" "svg" "clock"))]) |
||||
(swiper . |
||||
[(0 5 1) |
||||
((emacs |
||||
(24 1))) |
||||
"Isearch with an overview. Oh, man!" tar |
||||
((:keywords "matching") |
||||
(:url . "https://github.com/abo-abo/swiper"))]) |
||||
(tNFA . |
||||
[(0 1 1) |
||||
((queue |
||||
(0 1))) |
||||
"Tagged non-deterministic finite-state automata" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "extensions" "matching" "data structures tnfa" "nfa" "dfa" "finite state automata" "automata" "regexp"))]) |
||||
(temp-buffer-browse . |
||||
[(1 4) |
||||
nil "temp buffer browse mode" single |
||||
((:url . "http://elpa.gnu.org/packages/temp-buffer-browse.html") |
||||
(:keywords "convenience"))]) |
||||
(test-simple . |
||||
[(1 1) |
||||
((cl-lib |
||||
(0))) |
||||
"Simple Unit Test Framework for Emacs Lisp" single |
||||
((:url . "http://github.com/rocky/emacs-test-simple") |
||||
(:keywords "unit-test"))]) |
||||
(timerfunctions . |
||||
[(1 4 2) |
||||
((cl-lib |
||||
(0 5))) |
||||
"Enhanced versions of some timer.el functions" single |
||||
((:url . "http://elpa.gnu.org/packages/timerfunctions.html") |
||||
(:keywords))]) |
||||
(tiny . |
||||
[(0 1) |
||||
nil "Quickly generate linear ranges in Emacs" tar |
||||
((:keywords "convenience") |
||||
(:url . "https://github.com/abo-abo/tiny"))]) |
||||
(trie . |
||||
[(0 2 6) |
||||
((tNFA |
||||
(0 1 1)) |
||||
(heap |
||||
(0 3))) |
||||
"Trie data structure" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "extensions" "matching" "data structures trie" "ternary search tree" "tree" "completion" "regexp"))]) |
||||
(undo-tree . |
||||
[(0 6 5) |
||||
nil "Treat undo history as a tree" single |
||||
((:url . "http://www.dr-qubit.org/emacs.php") |
||||
(:keywords "convenience" "files" "undo" "redo" "history" "tree"))]) |
||||
(uni-confusables . |
||||
[(0 1) |
||||
nil "Unicode confusables table" tar |
||||
((:url . "http://elpa.gnu.org/packages/uni-confusables.html"))]) |
||||
(vlf . |
||||
[(1 7) |
||||
nil "View Large Files" tar |
||||
((:keywords "large files" "utilities") |
||||
(:url . "https://github.com/m00natic/vlfi"))]) |
||||
(w3 . |
||||
[(4 0 49) |
||||
nil "Fully customizable, largely undocumented web browser for Emacs" tar |
||||
((:keywords "faces" "help" "comm" "news" "mail" "processes" "mouse" "hypermedia") |
||||
(:url . "http://elpa.gnu.org/packages/w3.html"))]) |
||||
(wcheck-mode . |
||||
[(2014 6 21) |
||||
nil "General interface for text checkers" single |
||||
((:url . "https://github.com/tlikonen/wcheck-mode") |
||||
(:keywords "text" "spell" "check" "languages" "ispell"))]) |
||||
(wconf . |
||||
[(0 2 0) |
||||
((emacs |
||||
(24 4))) |
||||
"Minimal window layout manager" single |
||||
((:url . "https://github.com/ilohmar/wconf") |
||||
(:keywords "windows" "frames" "layout"))]) |
||||
(web-server . |
||||
[(0 1 1) |
||||
((emacs |
||||
(24 3))) |
||||
"Emacs Web Server" tar |
||||
((:keywords "http" "server" "network") |
||||
(:url . "https://github.com/eschulte/emacs-web-server"))]) |
||||
(websocket . |
||||
[(1 5) |
||||
nil "Emacs WebSocket client and server" tar |
||||
((:keywords "communication" "websocket" "server") |
||||
(:url . "http://elpa.gnu.org/packages/websocket.html"))]) |
||||
(windresize . |
||||
[(0 1) |
||||
nil "Resize windows interactively" single |
||||
((:url . "http://elpa.gnu.org/packages/windresize.html") |
||||
(:keywords "window"))]) |
||||
(wisi . |
||||
[(1 1 1) |
||||
((cl-lib |
||||
(0 4)) |
||||
(emacs |
||||
(24 2))) |
||||
"Utilities for implementing an indentation/navigation engine using a generalized LALR parser" tar |
||||
((:keywords "parser" "indentation" "navigation") |
||||
(:url . "http://stephe-leake.org/emacs/ada-mode/emacs-ada-mode.html"))]) |
||||
(wpuzzle . |
||||
[(1 1) |
||||
nil "find as many word in a given time" single |
||||
((:url . "http://elpa.gnu.org/packages/wpuzzle.html") |
||||
(:keywords))]) |
||||
(xclip . |
||||
[(1 3) |
||||
nil "use xclip to copy&paste" single |
||||
((:url . "http://elpa.gnu.org/packages/xclip.html") |
||||
(:keywords "convenience" "tools"))]) |
||||
(xelb . |
||||
[(0 2) |
||||
((emacs |
||||
(24 4)) |
||||
(cl-generic |
||||
(0 2))) |
||||
"X protocol Emacs Lisp Binding" tar |
||||
((:keywords "unix") |
||||
(:url . "https://github.com/ch11ng/xelb"))]) |
||||
(xpm . |
||||
[(1 0 3) |
||||
nil "edit XPM images" tar |
||||
((:keywords "multimedia" "xpm") |
||||
(:url . "http://www.gnuvola.org/software/xpm/"))]) |
||||
(yasnippet . |
||||
[(0 8 0) |
||||
nil "Yet another snippet extension for Emacs." tar |
||||
((:keywords "convenience" "emulation") |
||||
(:url . "http://github.com/capitaomorte/yasnippet"))]) |
||||
(ztree . |
||||
[(1 0 2) |
||||
nil "Text mode directory tree" tar |
||||
((:keywords "files" "tools") |
||||
(:url . "https://github.com/fourier/ztree"))])) |
@ -1 +0,0 @@
|
||||
Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent <elpasign@elpa.gnu.org> (trust undefined) created at 2015-10-24T02:05:02-0700 using DSA |
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
(define-package "clojure-mode" "20151022.27" "Major mode for Clojure code" '((emacs "24.3")) :url "http://github.com/clojure-emacs/clojure-mode" :keywords '("languages" "clojure" "clojurescript" "lisp")) |
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
(define-package "coffee-mode" "20151019.2009" "Major mode to edit CoffeeScript files in Emacs" '((emacs "24.1") (cl-lib "0.5")) :url "http://github.com/defunkt/coffee-mode" :keywords '("coffeescript" "major" "mode")) |
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
(define-package "dash" "20151021.113" "A modern list library for Emacs" 'nil :keywords '("lists")) |
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
(define-package "epl" "20150517.433" "Emacs Package Library" '((cl-lib "0.3")) :url "http://github.com/cask/epl" :keywords '("convenience")) |
@ -1,11 +0,0 @@
|
||||
(define-package "flycheck" "20151022.1349" "On-the-fly syntax checking" |
||||
'((dash "2.4.0") |
||||
(pkg-info "0.4") |
||||
(let-alist "1.0.1") |
||||
(cl-lib "0.3") |
||||
(emacs "24.3")) |
||||
:url "https://www.flycheck.org" :keywords |
||||
'("convenience" "languages" "tools")) |
||||
;; Local Variables: |
||||
;; no-byte-compile: t |
||||
;; End: |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent <elpasign@elpa.gnu.org> (trust undefined) created at 2015-06-12T02:05:02-0700 using DSA |
@ -1 +0,0 @@
|
||||
(define-package "let-alist" "1.0.4" "Easily let-bind values of an assoc-list by their names" 'nil :url "http://elpa.gnu.org/packages/let-alist.html" :keywords '("extensions" "lisp")) |
@ -1 +0,0 @@
|
||||
(define-package "pkg-info" "20150517.443" "Information about packages" '((epl "0.8")) :url "https://github.com/lunaryorn/pkg-info.el" :keywords '("convenience")) |
@ -1 +0,0 @@
|
||||
(define-package "s" "20150924.406" "The long lost Emacs string manipulation library." 'nil :keywords '("strings")) |
@ -1,605 +0,0 @@
|
||||
;;; s.el --- The long lost Emacs string manipulation library. |
||||
|
||||
;; Copyright (C) 2012-2015 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Version: 1.10.0 |
||||
;; Package-Version: 20150924.406 |
||||
;; Keywords: strings |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; The long lost Emacs string manipulation library. |
||||
;; |
||||
;; See documentation on https://github.com/magnars/s.el#functions |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'ucs-normalize) |
||||
|
||||
(defun s-trim-left (s) |
||||
"Remove whitespace at the beginning of S." |
||||
(if (string-match "\\`[ \t\n\r]+" s) |
||||
(replace-match "" t t s) |
||||
s)) |
||||
|
||||
(defun s-trim-right (s) |
||||
"Remove whitespace at the end of S." |
||||
(if (string-match "[ \t\n\r]+\\'" s) |
||||
(replace-match "" t t s) |
||||
s)) |
||||
|
||||
(defun s-trim (s) |
||||
"Remove whitespace at the beginning and end of S." |
||||
(s-trim-left (s-trim-right s))) |
||||
|
||||
(defun s-collapse-whitespace (s) |
||||
"Convert all adjacent whitespace characters to a single space." |
||||
(replace-regexp-in-string "[ \t\n\r]+" " " s)) |
||||
|
||||
(defun s-split (separator s &optional omit-nulls) |
||||
"Split S into substrings bounded by matches for regexp SEPARATOR. |
||||
If OMIT-NULLS is non-nil, zero-length substrings are omitted. |
||||
|
||||
This is a simple wrapper around the built-in `split-string'." |
||||
(split-string s separator omit-nulls)) |
||||
|
||||
(defun s-split-up-to (separator s n &optional omit-nulls) |
||||
"Split S up to N times into substrings bounded by matches for regexp SEPARATOR. |
||||
|
||||
If OMIT-NULLS is non-nil, zero-length substrings are omitted. |
||||
|
||||
See also `s-split'." |
||||
(save-match-data |
||||
(let ((op 0) |
||||
(r nil)) |
||||
(with-temp-buffer |
||||
(insert s) |
||||
(setq op (goto-char (point-min))) |
||||
(while (and (re-search-forward separator nil t) |
||||
(< 0 n)) |
||||
(let ((sub (buffer-substring-no-properties op (match-beginning 0)))) |
||||
(unless (and omit-nulls |
||||
(equal sub "")) |
||||
(push sub r))) |
||||
(setq op (goto-char (match-end 0))) |
||||
(setq n (1- n))) |
||||
(let ((sub (buffer-substring-no-properties op (point-max)))) |
||||
(unless (and omit-nulls |
||||
(equal sub "")) |
||||
(push sub r)))) |
||||
(nreverse r)))) |
||||
|
||||
(defun s-lines (s) |
||||
"Splits S into a list of strings on newline characters." |
||||
(s-split "\\(\r\n\\|[\n\r]\\)" s)) |
||||
|
||||
(defun s-join (separator strings) |
||||
"Join all the strings in STRINGS with SEPARATOR in between." |
||||
(mapconcat 'identity strings separator)) |
||||
|
||||
(defun s-concat (&rest strings) |
||||
"Join all the string arguments into one string." |
||||
(apply 'concat strings)) |
||||
|
||||
(defun s-prepend (prefix s) |
||||
"Concatenate PREFIX and S." |
||||
(concat prefix s)) |
||||
|
||||
(defun s-append (suffix s) |
||||
"Concatenate S and SUFFIX." |
||||
(concat s suffix)) |
||||
|
||||
(defun s-repeat (num s) |
||||
"Make a string of S repeated NUM times." |
||||
(let (ss) |
||||
(while (> num 0) |
||||
(setq ss (cons s ss)) |
||||
(setq num (1- num))) |
||||
(apply 'concat ss))) |
||||
|
||||
(defun s-chop-suffix (suffix s) |
||||
"Remove SUFFIX if it is at end of S." |
||||
(let ((pos (- (length suffix)))) |
||||
(if (and (>= (length s) (length suffix)) |
||||
(string= suffix (substring s pos))) |
||||
(substring s 0 pos) |
||||
s))) |
||||
|
||||
(defun s-chop-suffixes (suffixes s) |
||||
"Remove SUFFIXES one by one in order, if they are at the end of S." |
||||
(while suffixes |
||||
(setq s (s-chop-suffix (car suffixes) s)) |
||||
(setq suffixes (cdr suffixes))) |
||||
s) |
||||
|
||||
(defun s-chop-prefix (prefix s) |
||||
"Remove PREFIX if it is at the start of S." |
||||
(let ((pos (length prefix))) |
||||
(if (and (>= (length s) (length prefix)) |
||||
(string= prefix (substring s 0 pos))) |
||||
(substring s pos) |
||||
s))) |
||||
|
||||
(defun s-chop-prefixes (prefixes s) |
||||
"Remove PREFIXES one by one in order, if they are at the start of S." |
||||
(while prefixes |
||||
(setq s (s-chop-prefix (car prefixes) s)) |
||||
(setq prefixes (cdr prefixes))) |
||||
s) |
||||
|
||||
(defun s-shared-start (s1 s2) |
||||
"Returns the longest prefix S1 and S2 have in common." |
||||
(let ((search-length (min (length s1) (length s2))) |
||||
(i 0)) |
||||
(while (and (< i search-length) |
||||
(= (aref s1 i) (aref s2 i))) |
||||
(setq i (1+ i))) |
||||
(substring s1 0 i))) |
||||
|
||||
(defun s-shared-end (s1 s2) |
||||
"Returns the longest suffix S1 and S2 have in common." |
||||
(let* ((l1 (length s1)) |
||||
(l2 (length s2)) |
||||
(search-length (min l1 l2)) |
||||
(i 0)) |
||||
(while (and (< i search-length) |
||||
(= (aref s1 (- l1 i 1)) (aref s2 (- l2 i 1)))) |
||||
(setq i (1+ i))) |
||||
;; If I is 0, then it means that there's no common suffix between |
||||
;; S1 and S2. |
||||
;; |
||||
;; However, since (substring s (- 0)) will return the whole |
||||
;; string, `s-shared-end' should simply return the empty string |
||||
;; when I is 0. |
||||
(if (zerop i) |
||||
"" |
||||
(substring s1 (- i))))) |
||||
|
||||
(defun s-chomp (s) |
||||
"Remove one trailing `\\n`, `\\r` or `\\r\\n` from S." |
||||
(s-chop-suffixes '("\n" "\r") s)) |
||||
|
||||
(defun s-truncate (len s) |
||||
"If S is longer than LEN, cut it down to LEN - 3 and add ... at the end." |
||||
(if (> (length s) len) |
||||
(format "%s..." (substring s 0 (- len 3))) |
||||
s)) |
||||
|
||||
(defun s-word-wrap (len s) |
||||
"If S is longer than LEN, wrap the words with newlines." |
||||
(with-temp-buffer |
||||
(insert s) |
||||
(let ((fill-column len)) |
||||
(fill-region (point-min) (point-max))) |
||||
(buffer-substring-no-properties (point-min) (point-max)))) |
||||
|
||||
(defun s-center (len s) |
||||
"If S is shorter than LEN, pad it with spaces so it is centered." |
||||
(let ((extra (max 0 (- len (length s))))) |
||||
(concat |
||||
(make-string (ceiling extra 2) ? ) |
||||
s |
||||
(make-string (floor extra 2) ? )))) |
||||
|
||||
(defun s-pad-left (len padding s) |
||||
"If S is shorter than LEN, pad it with PADDING on the left." |
||||
(let ((extra (max 0 (- len (length s))))) |
||||
(concat (make-string extra (string-to-char padding)) |
||||
s))) |
||||
|
||||
(defun s-pad-right (len padding s) |
||||
"If S is shorter than LEN, pad it with PADDING on the right." |
||||
(let ((extra (max 0 (- len (length s))))) |
||||
(concat s |
||||
(make-string extra (string-to-char padding))))) |
||||
|
||||
(defun s-left (len s) |
||||
"Returns up to the LEN first chars of S." |
||||
(if (> (length s) len) |
||||
(substring s 0 len) |
||||
s)) |
||||
|
||||
(defun s-right (len s) |
||||
"Returns up to the LEN last chars of S." |
||||
(let ((l (length s))) |
||||
(if (> l len) |
||||
(substring s (- l len) l) |
||||
s))) |
||||
|
||||
(defun s-ends-with? (suffix s &optional ignore-case) |
||||
"Does S end with SUFFIX? |
||||
|
||||
If IGNORE-CASE is non-nil, the comparison is done without paying |
||||
attention to case differences. |
||||
|
||||
Alias: `s-suffix?'" |
||||
(let ((start-pos (- (length s) (length suffix)))) |
||||
(and (>= start-pos 0) |
||||
(eq t (compare-strings suffix nil nil |
||||
s start-pos nil ignore-case))))) |
||||
|
||||
(defalias 's-ends-with-p 's-ends-with?) |
||||
|
||||
(defun s-starts-with? (prefix s &optional ignore-case) |
||||
"Does S start with PREFIX? |
||||
|
||||
If IGNORE-CASE is non-nil, the comparison is done without paying |
||||
attention to case differences. |
||||
|
||||
Alias: `s-prefix?'. This is a simple wrapper around the built-in |
||||
`string-prefix-p'." |
||||
(string-prefix-p prefix s ignore-case)) |
||||
|
||||
(defalias 's-starts-with-p 's-starts-with?) |
||||
|
||||
(defalias 's-suffix? 's-ends-with?) |
||||
(defalias 's-prefix? 's-starts-with?) |
||||
(defalias 's-suffix-p 's-ends-with?) |
||||
(defalias 's-prefix-p 's-starts-with?) |
||||
|
||||
(defun s--truthy? (val) |
||||
(not (null val))) |
||||
|
||||
(defun s-contains? (needle s &optional ignore-case) |
||||
"Does S contain NEEDLE? |
||||
|
||||
If IGNORE-CASE is non-nil, the comparison is done without paying |
||||
attention to case differences." |
||||
(let ((case-fold-search ignore-case)) |
||||
(s--truthy? (string-match-p (regexp-quote needle) s)))) |
||||
|
||||
(defalias 's-contains-p 's-contains?) |
||||
|
||||
(defun s-equals? (s1 s2) |
||||
"Is S1 equal to S2? |
||||
|
||||
This is a simple wrapper around the built-in `string-equal'." |
||||
(string-equal s1 s2)) |
||||
|
||||
(defalias 's-equals-p 's-equals?) |
||||
|
||||
(defun s-less? (s1 s2) |
||||
"Is S1 less than S2? |
||||
|
||||
This is a simple wrapper around the built-in `string-lessp'." |
||||
(string-lessp s1 s2)) |
||||
|
||||
(defalias 's-less-p 's-less?) |
||||
|
||||
(defun s-matches? (regexp s &optional start) |
||||
"Does REGEXP match S? |
||||
If START is non-nil the search starts at that index. |
||||
|
||||
This is a simple wrapper around the built-in `string-match-p'." |
||||
(s--truthy? (string-match-p regexp s start))) |
||||
|
||||
(defalias 's-matches-p 's-matches?) |
||||
|
||||
(defun s-blank? (s) |
||||
"Is S nil or the empty string?" |
||||
(or (null s) (string= "" s))) |
||||
|
||||
(defun s-present? (s) |
||||
"Is S anything but nil or the empty string?" |
||||
(not (s-blank? s))) |
||||
|
||||
(defun s-presence (s) |
||||
"Return S if it's `s-present?', otherwise return nil." |
||||
(and (s-present? s) s)) |
||||
|
||||
(defun s-lowercase? (s) |
||||
"Are all the letters in S in lower case?" |
||||
(let ((case-fold-search nil)) |
||||
(not (string-match-p "[[:upper:]]" s)))) |
||||
|
||||
(defun s-uppercase? (s) |
||||
"Are all the letters in S in upper case?" |
||||
(let ((case-fold-search nil)) |
||||
(not (string-match-p "[[:lower:]]" s)))) |
||||
|
||||
(defun s-mixedcase? (s) |
||||
"Are there both lower case and upper case letters in S?" |
||||
(let ((case-fold-search nil)) |
||||
(s--truthy? |
||||
(and (string-match-p "[[:lower:]]" s) |
||||
(string-match-p "[[:upper:]]" s))))) |
||||
|
||||
(defun s-capitalized? (s) |
||||
"In S, is the first letter upper case, and all other letters lower case?" |
||||
(let ((case-fold-search nil)) |
||||
(s--truthy? |
||||
(string-match-p "^[[:upper:]][^[:upper:]]*$" s)))) |
||||
|
||||
(defun s-numeric? (s) |
||||
"Is S a number?" |
||||
(s--truthy? |
||||
(string-match-p "^[0-9]+$" s))) |
||||
|
||||
(defun s-replace (old new s) |
||||
"Replaces OLD with NEW in S." |
||||
(replace-regexp-in-string (regexp-quote old) new s t t)) |
||||
|
||||
(defun s--aget (alist key) |
||||
(cdr (assoc key alist))) |
||||
|
||||
(defun s-replace-all (replacements s) |
||||
"REPLACEMENTS is a list of cons-cells. Each `car` is replaced with `cdr` in S." |
||||
(replace-regexp-in-string (regexp-opt (mapcar 'car replacements)) |
||||
(lambda (it) (s--aget replacements it)) |
||||
s)) |
||||
|
||||
(defun s-downcase (s) |
||||
"Convert S to lower case. |
||||
|
||||
This is a simple wrapper around the built-in `downcase'." |
||||
(downcase s)) |
||||
|
||||
(defun s-upcase (s) |
||||
"Convert S to upper case. |
||||
|
||||
This is a simple wrapper around the built-in `upcase'." |
||||
(upcase s)) |
||||
|
||||
(defun s-capitalize (s) |
||||
"Convert the first word's first character to upper case and the rest to lower case in S." |
||||
(concat (upcase (substring s 0 1)) (downcase (substring s 1)))) |
||||
|
||||
(defun s-titleize (s) |
||||
"Convert each word's first character to upper case and the rest to lower case in S. |
||||
|
||||
This is a simple wrapper around the built-in `capitalize'." |
||||
(capitalize s)) |
||||
|
||||
(defmacro s-with (s form &rest more) |
||||
"Threads S through the forms. Inserts S as the last item |
||||
in the first form, making a list of it if it is not a list |
||||
already. If there are more forms, inserts the first form as the |
||||
last item in second form, etc." |
||||
(declare (debug (form &rest [&or (function &rest form) fboundp]))) |
||||
(if (null more) |
||||
(if (listp form) |
||||
`(,(car form) ,@(cdr form) ,s) |
||||
(list form s)) |
||||
`(s-with (s-with ,s ,form) ,@more))) |
||||
|
||||
(put 's-with 'lisp-indent-function 1) |
||||
|
||||
(defun s-index-of (needle s &optional ignore-case) |
||||
"Returns first index of NEEDLE in S, or nil. |
||||
|
||||
If IGNORE-CASE is non-nil, the comparison is done without paying |
||||
attention to case differences." |
||||
(let ((case-fold-search ignore-case)) |
||||
(string-match-p (regexp-quote needle) s))) |
||||
|
||||
(defun s-reverse (s) |
||||
"Return the reverse of S." |
||||
(if (multibyte-string-p s) |
||||
(let ((input (string-to-list s)) |
||||
(output ())) |
||||
(while input |
||||
;; Handle entire grapheme cluster as a single unit |
||||
(let ((grapheme (list (pop input)))) |
||||
(while (memql (car input) ucs-normalize-combining-chars) |
||||
(push (pop input) grapheme)) |
||||
(setq output (nconc (nreverse grapheme) output)))) |
||||
(concat output)) |
||||
(concat (nreverse (string-to-list s))))) |
||||
|
||||
(defun s-match-strings-all (regex string) |
||||
"Return a list of matches for REGEX in STRING. |
||||
|
||||
Each element itself is a list of matches, as per |
||||
`match-string'. Multiple matches at the same position will be |
||||
ignored after the first." |
||||
(let ((all-strings ()) |
||||
(i 0)) |
||||
(while (and (< i (length string)) |
||||
(string-match regex string i)) |
||||
(setq i (1+ (match-beginning 0))) |
||||
(let (strings |
||||
(num-matches (/ (length (match-data)) 2)) |
||||
(match 0)) |
||||
(while (/= match num-matches) |
||||
(push (match-string match string) strings) |
||||
(setq match (1+ match))) |
||||
(push (nreverse strings) all-strings))) |
||||
(nreverse all-strings))) |
||||
|
||||
(defun s-match (regexp s &optional start) |
||||
"When the given expression matches the string, this function returns a list |
||||
of the whole matching string and a string for each matched subexpressions. |
||||
If it did not match the returned value is an empty list (nil). |
||||
|
||||
When START is non-nil the search will start at that index." |
||||
(save-match-data |
||||
(if (string-match regexp s start) |
||||
(let ((match-data-list (match-data)) |
||||
result) |
||||
(while match-data-list |
||||
(let* ((beg (car match-data-list)) |
||||
(end (cadr match-data-list)) |
||||
(subs (if (and beg end) (substring s beg end) nil))) |
||||
(setq result (cons subs result)) |
||||
(setq match-data-list |
||||
(cddr match-data-list)))) |
||||
(nreverse result))))) |
||||
|
||||
(defun s-slice-at (regexp s) |
||||
"Slices S up at every index matching REGEXP." |
||||
(save-match-data |
||||
(let (i) |
||||
(setq i (string-match regexp s 1)) |
||||
(if i |
||||
(cons (substring s 0 i) |
||||
(s-slice-at regexp (substring s i))) |
||||
(list s))))) |
||||
|
||||
(defun s-split-words (s) |
||||
"Split S into list of words." |
||||
(s-split |
||||
"[^[:word:]0-9]+" |
||||
(let ((case-fold-search nil)) |
||||
(replace-regexp-in-string |
||||
"\\([[:lower:]]\\)\\([[:upper:]]\\)" "\\1 \\2" |
||||
(replace-regexp-in-string "\\([[:upper:]]\\)\\([[:upper:]][0-9[:lower:]]\\)" "\\1 \\2" s))) |
||||
t)) |
||||
|
||||
(defun s--mapcar-head (fn-head fn-rest list) |
||||
"Like MAPCAR, but applies a different function to the first element." |
||||
(if list |
||||
(cons (funcall fn-head (car list)) (mapcar fn-rest (cdr list))))) |
||||
|
||||
(defun s-lower-camel-case (s) |
||||
"Convert S to lowerCamelCase." |
||||
(s-join "" (s--mapcar-head 'downcase 'capitalize (s-split-words s)))) |
||||
|
||||
(defun s-upper-camel-case (s) |
||||
"Convert S to UpperCamelCase." |
||||
(s-join "" (mapcar 'capitalize (s-split-words s)))) |
||||
|
||||
(defun s-snake-case (s) |
||||
"Convert S to snake_case." |
||||
(s-join "_" (mapcar 'downcase (s-split-words s)))) |
||||
|
||||
(defun s-dashed-words (s) |
||||
"Convert S to dashed-words." |
||||
(s-join "-" (mapcar 'downcase (s-split-words s)))) |
||||
|
||||
(defun s-capitalized-words (s) |
||||
"Convert S to Capitalized words." |
||||
(let ((words (s-split-words s))) |
||||
(s-join " " (cons (capitalize (car words)) (mapcar 'downcase (cdr words)))))) |
||||
|
||||
(defun s-titleized-words (s) |
||||
"Convert S to Titleized Words." |
||||
(s-join " " (mapcar 's-titleize (s-split-words s)))) |
||||
|
||||
(defun s-word-initials (s) |
||||
"Convert S to its initials." |
||||
(s-join "" (mapcar (lambda (ss) (substring ss 0 1)) |
||||
(s-split-words s)))) |
||||
|
||||
;; Errors for s-format |
||||
(progn |
||||
(put 's-format-resolve |
||||
'error-conditions |
||||
'(error s-format s-format-resolve)) |
||||
(put 's-format-resolve |
||||
'error-message |
||||
"Cannot resolve a template to values")) |
||||
|
||||
(defun s-format (template replacer &optional extra) |
||||
"Format TEMPLATE with the function REPLACER. |
||||
|
||||
REPLACER takes an argument of the format variable and optionally |
||||
an extra argument which is the EXTRA value from the call to |
||||
`s-format'. |
||||
|
||||
Several standard `s-format' helper functions are recognized and |
||||
adapted for this: |
||||
|
||||
(s-format \"${name}\" 'gethash hash-table) |
||||
(s-format \"${name}\" 'aget alist) |
||||
(s-format \"$0\" 'elt sequence) |
||||
|
||||
The REPLACER function may be used to do any other kind of |
||||
transformation." |
||||
(let ((saved-match-data (match-data))) |
||||
(unwind-protect |
||||
(replace-regexp-in-string |
||||
"\\$\\({\\([^}]+\\)}\\|[0-9]+\\)" |
||||
(lambda (md) |
||||
(let ((var |
||||
(let ((m (match-string 2 md))) |
||||
(if m m |
||||
(string-to-number (match-string 1 md))))) |
||||
(replacer-match-data (match-data))) |
||||
(unwind-protect |
||||
(let ((v |
||||
(cond |
||||
((eq replacer 'gethash) |
||||
(funcall replacer var extra)) |
||||
((eq replacer 'aget) |
||||
(funcall 's--aget extra var)) |
||||
((eq replacer 'elt) |
||||
(funcall replacer extra var)) |
||||
(t |
||||
(set-match-data saved-match-data) |
||||
(if extra |
||||
(funcall replacer var extra) |
||||
(funcall replacer var)))))) |
||||
(if v v (signal 's-format-resolve md))) |
||||
(set-match-data replacer-match-data)))) template |
||||
;; Need literal to make sure it works |
||||
t t) |
||||
(set-match-data saved-match-data)))) |
||||
|
||||
(defvar s-lex-value-as-lisp nil |
||||
"If `t' interpolate lisp values as lisp. |
||||
|
||||
`s-lex-format' inserts values with (format \"%S\").") |
||||
|
||||
(defun s-lex-fmt|expand (fmt) |
||||
"Expand FMT into lisp." |
||||
(list 's-format fmt (quote 'aget) |
||||
(append '(list) |
||||
(mapcar |
||||
(lambda (matches) |
||||
(list |
||||
'cons |
||||
(cadr matches) |
||||
`(format |
||||
(if s-lex-value-as-lisp "%S" "%s") |
||||
,(intern (cadr matches))))) |
||||
(s-match-strings-all "${\\([^}]+\\)}" fmt))))) |
||||
|
||||
(defmacro s-lex-format (format-str) |
||||
"`s-format` with the current environment. |
||||
|
||||
FORMAT-STR may use the `s-format' variable reference to refer to |
||||
any variable: |
||||
|
||||
(let ((x 1)) |
||||
(s-lex-format \"x is: ${x}\")) |
||||
|
||||
The values of the variables are interpolated with \"%s\" unless |
||||
the variable `s-lex-value-as-lisp' is `t' and then they are |
||||
interpolated with \"%S\"." |
||||
(declare (debug (form))) |
||||
(s-lex-fmt|expand format-str)) |
||||
|
||||
(defun s-count-matches (regexp s &optional start end) |
||||
"Count occurrences of `regexp' in `s'. |
||||
|
||||
`start', inclusive, and `end', exclusive, delimit the part of `s' |
||||
to match. " |
||||
(with-temp-buffer |
||||
(insert s) |
||||
(goto-char (point-min)) |
||||
(count-matches regexp (or start 1) (or end (point-max))))) |
||||
|
||||
(defun s-wrap (s prefix &optional suffix) |
||||
"Wrap string S with PREFIX and optionally SUFFIX. |
||||
|
||||
Return string S with PREFIX prepended. If SUFFIX is present, it |
||||
is appended, otherwise PREFIX is used as both prefix and |
||||
suffix." |
||||
(concat prefix s (or suffix prefix))) |
||||
|
||||
(provide 's) |
||||
;;; s.el ends here |
Loading…
Reference in new issue