Download
(defvar auto-install-version "$Id: auto-install.el,v 1.54 2012/01/15 12:10:20 rubikitch Exp rubikitch $")
(require 'url)
(require 'dired)
(require 'find-func)
(require 'bytecomp)
(require 'thingatpt)
(require 'ffap)
(eval-when-compile (require 'cl))
(when (<= emacs-major-version 22)
(autoload 'ignore-errors "cl-macs")
(unless (fboundp 'url-file-nondirectory)
(defun url-file-nondirectory (file)
"Return the nondirectory part of FILE, for a URL."
(cond
((null file) "")
((string-match (eval-when-compile (regexp-quote "?")) file)
(file-name-nondirectory (substring file 0 (match-beginning 0))))
(t (file-name-nondirectory file))))))
(defgroup auto-install nil
"Auto install elisp files."
:group 'external)
(defcustom auto-install-directory "~/.emacs.d/auto-install/"
"The directory for saving elisp files.
This directory is used when a downloaded
elisp file does not already exist in other directory.
Otherwise, the existing file of the same name is replaced."
:type 'string
:group 'auto-install)
(defcustom auto-install-buffer-name "auto-install"
"The temporary buffer for storing download content."
:type 'string
:group 'auto-install)
(defcustom auto-install-emacswiki-base-url "http://www.emacswiki.org/cgi-bin/wiki/download/"
"The base emacswiki.org url from which to download elisp files."
:type 'string
:group 'auto-install)
(defcustom auto-install-gist-base-url "http://gist.github.com/"
"The base gist.github.com url from which to download elisp files."
:type 'string
:group 'auto-install)
(defcustom auto-install-filter-url
'(("color-grep" "http://www.bookshelf.jp/elc/"))
"Alist mapping filter url for library.
Default command `auto-install-from-library' will install from EmacsWiki,
if it can't find match in this alist."
:type '(repeat (list (string :tag "Library")
(string :tag "Download URL")))
:group 'auto-install)
(defcustom auto-install-save-confirm t
"Whether confirmation is needed to save downloaded content.
Nil means no confirmation is needed.
If non-nil, the downloaded content is shown in a buffer and you are
prompted to confirm saving it to a file."
:type 'boolean
:group 'auto-install)
(defcustom auto-install-replace-confirm nil
"Whether confirmation is needed to replace an existing elisp file.
Nil means no confirmation is needed."
:type 'boolean
:group 'auto-install)
(defcustom auto-install-install-confirm nil
"Whether confirmation is needed to install a downloaded elisp file.
Nil means no confirmation is needed."
:type 'boolean
:group 'auto-install)
(defcustom auto-install-from-dired-confirm t
"Whether confirmation is needed to download marked files from Dired.
Nil means no confirmation is needed."
:type 'boolean
:group 'auto-install)
(defcustom auto-install-wget-command "wget"
"*Wget command. Use only if `auto-install-use-wget' is non-nil."
:type 'string
:group 'auto-install)
(defcustom auto-install-use-wget (executable-find "wget")
"*Use wget instead of `url-retrieve'.
It is enabled by default when wget is found."
:type 'boolean
:group 'auto-install)
(defcustom auto-install-batch-list
nil
"This list contain packages information for batch install.
Have four arguments per list:
First argument is extension name.
Second argument is delay time for batch install.
Third argument is libraries number limit in delay time.
Fourth argument is list of libraries url or extension name.
If you want to add files, please edit auto-install-batch-list.el in EmacsWiki.
Use M-x `auto-install-batch-edit'. "
:group 'auto-install)
(defvar auto-install-batch-list-internal nil
"The real value of `auto-install-batch-list'. ")
(defvar auto-install-batch-list-el-url
"http://www.rubyist.net/~rubikitch/archive/auto-install-batch-list.el"
"The url of auto-install-batch-list.el.
It is downloaded and evaluated just after M-x `auto-install-batch'. ")
(defvar auto-install-download-buffer nil
"The download buffer used by `url-retrieve'.
This variable is always buffer-local.")
(make-variable-buffer-local 'auto-install-download-buffer)
(defvar auto-install-download-url nil
"The url from which to download files.
This variable is always buffer-local.")
(make-variable-buffer-local 'auto-install-download-url)
(defvar auto-install-last-url nil
"The last url used in `auto-install-from-url'.")
(defvar auto-install-last-gist-id nil
"The last gist id you visit in `auto-install-from-gist'.")
(defvar auto-install-package-name-list nil
"The package name list for completion input.")
(defvar auto-install-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-d") 'auto-install-buffer-diff)
(define-key map (kbd "C-c C-c") 'auto-install-buffer-save)
(define-key map (kbd "C-c C-q") 'auto-install-buffer-quit)
map)
"Keymap used by variable `auto-install-minor-mode'.")
(defvar auto-install-add-load-path-flag t
"If non-nil, add `auto-install-directory' to `load-path'.
This variable is intended to be used in test.")
(defvar auto-install-add-exec-path-flag t
"If non-nil, add `auto-install-directory' to `exec-path'.
This variable is intended to be used in test.
It is needed because `auto-install-batch' can install non-elisp files.")
(defvar auto-install-waiting-url-list nil
"URLs in downloading.")
(defvar auto-install-url-queue nil
"Installation order.")
(defvar auto-install-download-buffer-alist nil
"Pairs of URL and downloaded buffer.")
(defvar auto-install-batch-using nil)
(define-minor-mode auto-install-minor-mode
"Auto Install minor mode."
:init-value nil
:lighter " Auto-Install"
:keymap auto-install-minor-mode-map
:group 'auto-install)
(defun auto-install-from-buffer ()
"Install the elisp file in the current buffer."
(interactive)
(let (filename)
(setq filename (read-string (format "Filename (%s): " (buffer-name)) nil nil (buffer-name)))
(auto-install-mode)
(auto-install-buffer-save filename)))
(defun auto-install-from-url (&optional url)
"Install an elisp file from a given url."
(interactive)
(or url (setq url (read-string (format "URL (%s): " (or auto-install-last-url "")) nil nil auto-install-last-url)))
(setq auto-install-last-url url)
(auto-install-download url))
(defun auto-install-from-emacswiki (&optional file)
"Install an elisp file from EmacsWiki.org."
(interactive)
(cond (auto-install-package-name-list
(or file (setq file (auto-install-get-candidate "Package" auto-install-package-name-list)))
(auto-install-download (concat auto-install-emacswiki-base-url file)))
(t
(auto-install-download "http://www.emacswiki.org/cgi-bin/emacs?action=index;raw=1"
'auto-install-handle-emacswiki-package-install))))
(defun auto-install-from-gist (&optional gistid-or-url)
"Install an elisp file from gist.github.com.
Optional argument GISTID-OR-URL is gist ID or URL for download
elisp file from gist.github.com."
(interactive)
(or gistid-or-url
(setq gistid-or-url (read-string (format "Gist ID or URL (%s): " (or auto-install-last-gist-id ""))
nil nil
auto-install-last-gist-id)))
(let ((gistid (file-name-sans-extension (file-name-nondirectory gistid-or-url))))
(setq auto-install-last-gist-id gistid)
(auto-install-download (format "%s%s.txt" auto-install-gist-base-url gistid))))
(defun auto-install-from-library (&optional library)
"Update an elisp LIBRARY.
Default this function will found 'download url' from `auto-install-filter-url',
if not found, try to download from EmacsWiki."
(interactive
(let* ((dirs load-path)
(suffixes (find-library-suffixes)))
(list (auto-install-get-candidate "Library name" (auto-install-get-library-list)))))
(let ((filename (file-name-nondirectory (find-library-name library)))
(base-url auto-install-emacswiki-base-url)
(library-name (replace-regexp-in-string "\\(\\.el.*$\\)" "" library)))
(if (assoc library-name auto-install-filter-url)
(setq base-url (cadr (assoc library-name auto-install-filter-url))))
(auto-install-download (concat base-url filename))))
(defun auto-install-from-directory (directory)
"Update elisp files under DIRECTORY from EmacsWiki.
You can use this command to update elisp file under DIRECTORY."
(interactive "DDirectory: ")
(let (filename)
(dolist (file (directory-files directory t))
(if (file-directory-p file)
(unless (string-match "^\\.\\.?$" (file-name-nondirectory file))
(auto-install-from-directory file))
(setq filename (file-name-nondirectory file))
(unless (string-match "^\\.?#" filename)
(if (string-match "^.*\\.el" filename)
(auto-install-download (concat auto-install-emacswiki-base-url filename))))))))
(defun auto-install-from-dired ()
"Update dired marked elisp files from EmacsWiki.org.
You can use this to download marked files in Dired asynchronously."
(interactive)
(if (eq major-mode 'dired-mode)
(if (or (not auto-install-from-dired-confirm)
(yes-or-no-p "Do you want install marked files from EmacsWiki.org?"))
(dolist (file (dired-get-marked-files))
(auto-install-download (concat auto-install-emacswiki-base-url (file-name-nondirectory file)))))
(error "This command is only for `dired-mode'.")))
(defun auto-install-network-available-p (host)
(if auto-install-use-wget
(eq (call-process auto-install-wget-command nil nil nil "-q" "--spider" host) 0)
(with-current-buffer (url-retrieve-synchronously (concat "http://" host))
(prog1 (not (zerop (buffer-size)))
(kill-buffer (current-buffer))))))
(require 'timer)
(defun auto-install-update-emacswiki-package-name (&optional unforced)
"Update the list of elisp package names from `EmacsWiki'.
By default, this function will update package name forcibly.
If UNFORCED is non-nil, just update package name when `auto-install-package-name-list' is nil."
(interactive)
(unless (and unforced
auto-install-package-name-list)
(if (and (auto-install-network-available-p "www.emacswiki.org")
(with-timeout (5 nil)
(progn (auto-install-download "http://www.emacswiki.org/cgi-bin/emacs?action=index;raw=1"
'auto-install-handle-emacswiki-package-name))
t))
(message
(concat "Network unreachable!\n"
"Try M-x auto-install-handle-emacswiki-package-name afterward."))
(sit-for 2))))
(defun auto-install-dired-mark-files ()
"Mark dired files that contain at `EmacsWiki.org'."
(interactive)
(if (eq major-mode 'dired-mode)
(if auto-install-package-name-list
(auto-install-dired-mark-files-internal)
(auto-install-download "http://www.emacswiki.org/cgi-bin/emacs?action=index;raw=1"
'auto-install-handle-dired-mark-files))
(error "This command just use in `dired-mode'.")))
(defun auto-install-mode ()
"Major mode for auto-installing elisp code."
(interactive)
(set-syntax-table emacs-lisp-mode-syntax-table)
(lisp-mode-variables)
(setq font-lock-mode t)
(font-lock-fontify-buffer)
(setq buffer-read-only t)
(and view-read-only (view-mode 1))
(auto-install-minor-mode t)
(setq major-mode 'auto-install-minor-mode))
(defun auto-install-buffer-quit ()
"Quit from `auto-install' temporary buffer."
(interactive)
(if (eq major-mode 'auto-install-minor-mode)
(auto-install-quit)
(error "This command just use in `auto-install-minor-mode'.")))
(defun auto-install-compatibility-setup ()
"Install Compatibility commands for install-elisp.el users."
(interactive)
(defalias 'install-elisp 'auto-install-from-url)
(if (require 'anything-auto-install nil t)
(defalias 'install-elisp-from-emacswiki 'anything-auto-install-from-emacswiki)
(defalias 'install-elisp-from-emacswiki 'auto-install-from-emacswiki))
(defalias 'install-elisp-from-gist 'auto-install-from-gist)
(message "Install-elisp compatibility installed.
install-elisp = %s
install-elisp-from-emacswiki = %s
install-elisp-from-gist = %s"
(symbol-function 'install-elisp)
(symbol-function 'install-elisp-from-emacswiki)
(symbol-function 'install-elisp-from-gist)))
(defun auto-install-batch (&optional extension-name)
"Batch install many files (libraries and non-elisp files) in some extension.
EXTENSION-NAME is extension name for batch install.
Note that non-elisp can be installed only via `auto-install-batch'"
(interactive)
(if (and auto-install-batch-list-internal extension-name)
(auto-install-batch-real extension-name)
(auto-install-download
auto-install-batch-list-el-url
(lexical-let ((extension-name extension-name))
(lambda (buf)
(with-current-buffer buf
(eval-buffer)
(run-at-time 0 nil 'auto-install-batch-real extension-name)))))))
(defun auto-install-batch-edit ()
"Edit auto-install-batch-list.el"
(interactive)
(cond ((fboundp 'yaoddmuse-edit)
(yaoddmuse-edit "EmacsWiki" "auto-install-batch-list.el"))
((fboundp 'oddmuse-edit)
(oddmuse-edit "EmacsWiki" "auto-install-batch-list.el"))
(t
(browse-url "http://www.emacswiki.org/emacs/?action=edit;id=auto-install-batch-list.el"))))
(defun auto-install-batch-real (&optional extension-name)
(setq auto-install-batch-using t)
(when auto-install-add-exec-path-flag
(add-to-list 'exec-path auto-install-directory))
(destructuring-bind (name delay-time limit-number (&rest urls))
(auto-install-batch-get-info
(or
extension-name
(completing-read "Extension name: " (mapcar 'car auto-install-batch-list-internal)))
auto-install-batch-list-internal)
(or name (error "Haven't install information for `%s'." extension-name))
(setq auto-install-waiting-url-list urls
auto-install-url-queue urls)
(if (not (and
delay-time
(> delay-time 0)
limit-number
(> limit-number 0)))
(auto-install-from-url-list urls)
(let ((delay-counter 0)
install-list)
(while urls
(if (> (length urls) limit-number)
(progn
(setq install-list (nthcar limit-number urls))
(run-with-timer
(* delay-counter delay-time)
nil
'auto-install-from-url-list install-list)
(setq urls (nthcdr+ limit-number urls))
(incf delay-counter))
(setq install-list urls)
(run-with-timer
(* delay-counter delay-time)
nil
'auto-install-from-url-list install-list)
(setq urls nil)))))))
(defun auto-install-flatten (obj &rest rest)
(cond (rest (append (auto-install-flatten obj) (auto-install-flatten rest)))
((null obj) nil)
((listp obj) (append (auto-install-flatten (car obj)) (auto-install-flatten (cdr obj))))
(t (list obj))))
(defun auto-install-batch-get-info (extension batch-list)
(let* ((it (assoc extension batch-list))
(urls (car (last it)))
(urlp (lambda (url) (string-match "^https?://" url))))
(cond ((not it)
'(nil nil nil (nil)))
((loop for url in urls always (funcall urlp url))
it)
(t
(append
(butlast it)
(list (auto-install-flatten
(loop for url in urls collect
(if (funcall urlp url)
url
(car (last (auto-install-batch-get-info url batch-list))))))))))))
(dont-compile
(when (fboundp 'expectations)
(expectations
(desc "auto-install-flatten")
(expect '(1 2 3 4 5 6 7 8 9)
(auto-install-flatten '((1 2 3) (4 5) (((6)) 7) nil nil 8 9)))
(expect '(1 2 3 4 5 6 7 8 9)
(auto-install-flatten '(1 2 3) '(4 5) '(((6)) 7) nil nil 8 9))
(desc "auto-install-batch-get-info")
(expect '(nil nil nil (nil))
(auto-install-batch-get-info
"not-found"
'(("foo" nil nil ("https://example.com/1.el")))))
(expect '("foo" nil nil ("http://example.com/1.el"))
(auto-install-batch-get-info
"foo"
'(("foo" nil nil ("http://example.com/1.el")))))
(expect '("withdep" nil nil ("http://example.com/1.el"
"http://example.com/2.el"))
(auto-install-batch-get-info
"withdep"
'(("foo" nil nil ("http://example.com/1.el"))
("withdep" nil nil ("foo" "http://example.com/2.el")))))
(expect '("withdep-recursive" nil nil ("http://example.com/1.el"
"http://example.com/2.el"
"http://example.com/3.el"))
(auto-install-batch-get-info
"withdep-recursive"
'(("foo" nil nil ("http://example.com/1.el"))
("withdep" nil nil ("foo" "http://example.com/2.el"))
("withdep-recursive" nil nil ("withdep" "http://example.com/3.el")))))
)))
(defun auto-install-use-wget-p ()
(and auto-install-use-wget
(executable-find auto-install-wget-command)))
(defun auto-install-download (url &optional handle-function)
"Download elisp file from URL.
HANDLE-FUNCTION for handle download content,
default is `auto-install-handle-download-content'."
(unless (file-exists-p auto-install-directory)
(make-directory auto-install-directory)
(when auto-install-add-load-path-flag
(add-to-list 'load-path auto-install-directory))
(message "Create directory %s for install elisp file." auto-install-directory))
(funcall
(if (auto-install-use-wget-p)
'auto-install-download-by-wget
'auto-install-download-by-url-retrieve)
url handle-function (auto-install-get-buffer url)))
(defun auto-install-download-by-wget (url handle-function download-buffer)
(with-current-buffer download-buffer
(setq auto-install-download-buffer (get-buffer-create (concat (buffer-name download-buffer)
"-wget")))
(setq auto-install-download-url url)
(set-process-sentinel
(start-process "auto-install-wget" (current-buffer)
auto-install-wget-command "-q" "-O-" "--no-check-certificate" url)
(lexical-let ((handle-function handle-function))
(lambda (proc stat)
(auto-install-download-callback-continue (buffer-name (process-buffer proc))
handle-function))))))
(defun auto-install-download-by-url-retrieve (url handle-function download-buffer)
(let* ((url-request-method "GET")
(url-request-extra-headers nil)
(url-mime-accept-string "*/*")
(parsed-url (url-generic-parse-url url))
(download-buffer-name (buffer-name download-buffer)))
(with-current-buffer download-buffer
(setq auto-install-download-url url)
(setq auto-install-download-buffer
(url-retrieve parsed-url
'auto-install-download-callback
(list download-buffer-name handle-function))))))
(defun auto-install-download-callback (&optional redirect download-buffer-name handle-function)
"The callback for `auto-install-download'.
With `auto-install-download', this downloads elisp files asynchronously.
REDIRECT is the argument for check download status.
DOWNLOAD-BUFFER-NAME is the name of download buffer.
HANDLE-FUNCTION is function for handle download content."
(if (eq (car redirect) ':error)
(with-current-buffer (get-buffer download-buffer-name)
(message "Download from '%s' failed." auto-install-download-url)
(kill-buffer download-buffer-name))
(auto-install-download-callback-continue download-buffer-name handle-function)))
(defun auto-install-download-callback-continue (download-buffer-name handle-function)
(auto-install-retrieve-decode download-buffer-name)
(with-current-buffer (get-buffer download-buffer-name)
(message "Download from '%s' successful." auto-install-download-url)
(funcall (or handle-function 'auto-install-handle-download-content)
(current-buffer))))
(defun auto-install-retrieve-decode (retrieve-buffer-name)
"Decode the RETRIEVE-BUFFER-NAME with coding detection."
(declare (special url-http-end-of-headers))
(with-current-buffer (get-buffer retrieve-buffer-name)
(insert
(with-current-buffer auto-install-download-buffer
(set-buffer-multibyte t)
(if (and (boundp 'url-http-end-of-headers)
(numberp url-http-end-of-headers))
(goto-char (1+ url-http-end-of-headers))
(if (auto-install-use-wget-p)
(goto-char (point-min))
(search-forward "\n\n" nil t)))
(decode-coding-region
(point) (point-max)
(coding-system-change-eol-conversion
(detect-coding-region (point-min) (point-max) t) 'dos))
(buffer-substring (point) (point-max))))
(goto-char (point-min))))
(defun auto-install-handle-download-content (download-buffer)
"Handle the content downloaded to buffer DOWNLOAD-BUFFER."
(with-current-buffer download-buffer
(auto-install-mode)
(setq mode-line-format (list "Type C-c C-c to continue; Type C-c C-d for view diff; Type C-c C-q to quit."))
(setq header-line-format (list auto-install-download-url))
(setq auto-install-download-buffer-alist
(cons (cons auto-install-download-url download-buffer)
auto-install-download-buffer-alist))
(setq auto-install-waiting-url-list
(remove auto-install-download-url auto-install-waiting-url-list))
(unless auto-install-waiting-url-list
(switch-to-buffer (or (assoc-default (car auto-install-url-queue)
auto-install-download-buffer-alist)
download-buffer))
(if (not (and (not auto-install-batch-using) (auto-install-check-update)))
(unless auto-install-save-confirm
(auto-install-buffer-save))
(message "%s is up-to-date" (url-file-nondirectory auto-install-download-url))
(kill-buffer))
)))
(defun auto-install-check-update ()
(let* ((new-file (url-file-nondirectory auto-install-download-url))
(old-file (auto-install-get-path new-file))
(old-content (and old-file
(with-temp-buffer
(insert-file-contents-literally old-file)
(buffer-string)))))
(equal old-content (buffer-string))))
(defun auto-install-handle-emacswiki-package-name (download-buffer &optional prompt-install)
"Handle elisp package name from `EmacsWiki'.
DOWNLOAD-BUFFER is the name of download buffer.
PROMPT-INSTALL is non-nil, will prompt package name for install."
(auto-install-update-emacswiki-package-list download-buffer)
(when prompt-install
(auto-install-download
(concat auto-install-emacswiki-base-url
(auto-install-get-candidate "Package" auto-install-package-name-list)))))
(defun auto-install-handle-dired-mark-files (download-buffer)
"Handle dired mark files that exist at `EmacsWiki'.
DOWNLOAD-BUFFER is the name of download buffer."
(auto-install-update-emacswiki-package-list download-buffer)
(auto-install-dired-mark-files-internal))
(defun auto-install-handle-emacswiki-package-install (download-buffer)
"Handle elisp package install from `EmacsWiki'.
DOWNLOAD-BUFFER is the name of download buffer."
(auto-install-handle-emacswiki-package-name download-buffer t))
(defun auto-install-update-emacswiki-package-list (download-buffer)
"Filter and update package name list from `EmacsWiki'.
DOWNLOAD-BUFFER is the name of download buffer."
(goto-char (point-min))
(setq auto-install-package-name-list
(loop while (re-search-forward "^.*\\.el$" nil t)
collect (match-string 0)))
(kill-buffer download-buffer)
(message "Update package name from `EmacsWiki' successful."))
(defun auto-install-buffer-diff ()
"View different between old version.
This command just run when have exist old version."
(interactive)
(let* ((new-file (url-file-nondirectory auto-install-download-url))
(old-file (auto-install-get-path new-file)))
(if old-file
(ediff-buffers (current-buffer) (find-file-noselect old-file))
(message "Haven't old version exist."))))
(defun auto-install-buffer-save (&optional filename)
"Save downloaded content to file FILENAME."
(interactive)
(if (eq major-mode 'auto-install-minor-mode)
(let (file-path)
(unless filename
(setq filename (url-file-nondirectory auto-install-download-url)))
(unless auto-install-batch-using
(while (not (string-match ".*\.el$" filename))
(setq filename (read-string "Please input file name suffix with `.el': "))))
(setq file-path
(or
(auto-install-get-path filename)
(expand-file-name filename auto-install-directory)))
(if (and (file-exists-p file-path)
(file-writable-p file-path)
auto-install-replace-confirm
(not (yes-or-no-p (format "Do you want replace file: '%s' ?" file-path))))
(auto-install-quit)
(if (auto-install-check-update)
(auto-install-install-next-file)
(let ((before-save-hook before-save-hook)
(auto-async-byte-compile-exclude-files-regexp
(regexp-quote file-path)))
(remove-hook 'before-save-hook 'time-stamp)
(write-file file-path)
(auto-install-install file-path)))))
(error "This command just use in `auto-install-minor-mode'.")))
(defun auto-install-install (file-path)
"Install elisp file FILE-PATH."
(if (and auto-install-install-confirm
(not (yes-or-no-p (format "Do you want install file: '%s' ?" file-path))))
(auto-install-quit)
(let (byte-compile-warnings)
(when (and (string= "el" (file-name-extension file-path))
(not (ignore-errors (byte-compile-file file-path t))))
(message "Auto-Install ERROR: Compiled file '%s' failed." file-path))
(auto-install-install-next-file))))
(defun auto-install-install-next-file ()
(setq auto-install-url-queue (cdr auto-install-url-queue))
(let (byte-compile-warnings)
(cond ((car auto-install-url-queue)
(switch-to-buffer (assoc-default (car auto-install-url-queue)
auto-install-download-buffer-alist))
(unless auto-install-save-confirm
(auto-install-buffer-save)))
(t
(auto-install-cleanup)
(message "Installation is completed.")))))
(defun auto-install-cleanup ()
(while auto-install-minor-mode
(kill-buffer))
(setq auto-install-url-queue nil)
(setq auto-install-download-buffer-alist nil)
(setq auto-install-batch-using nil))
(defun auto-install-quit ()
"Quit auto-install."
(kill-buffer (current-buffer))
(message "Quit auto-install process."))
(defun auto-install-get-path (library)
"Return the absolute file path of the Lisp source of LIBRARY."
(if (string-match "\\.el\\(c\\(\\..*\\)?\\)\\'" library)
(setq library (replace-match "" t t library)))
(or
(locate-file library
(or find-function-source-path load-path)
(find-library-suffixes))
(locate-file library
(or find-function-source-path load-path)
load-file-rep-suffixes)))
(defun auto-install-get-buffer (url)
"Get a buffer for temporary storage of downloaded content.
Uses `current-time' to make buffer name unique."
(get-buffer-create (format "*%s %s <%s>*"
auto-install-buffer-name url
(format-time-string "%m/%d %H:%M:%S"))))
(defun auto-install-dired-mark-files-internal ()
"Mark files that match `auto-install-package-name-list'."
(set-buffer (window-buffer))
(save-excursion
(let (filename)
(dired-unmark-all-marks)
(goto-char (point-min))
(while (not (eobp))
(setq filename (dired-get-filename nil t))
(if (and filename
(not (file-directory-p filename))
(member (file-name-nondirectory filename) auto-install-package-name-list))
(dired-mark 1))
(dired-next-line 1)))))
(defun auto-install-region-or-thing (&optional thing)
"Return region or thing around point.
If `mark-active' and variable `transient-mark-mode', return region.
If THING is non-nil, return THING around point;
otherwise return symbol around point."
(if (and mark-active
transient-mark-mode)
(buffer-substring-no-properties (region-beginning)
(region-end))
(setq thing (or thing 'symbol))
(ignore-errors
(save-excursion
(buffer-substring-no-properties (beginning-of-thing thing)
(end-of-thing thing))))))
(defun auto-install-get-library-list (&optional dirs string)
"Do completion for file names passed to `locate-file'.
DIRS is directory to search path.
STRING is string to match."
(or dirs (setq dirs load-path))
(or string (setq string ""))
(let ((string-dir (file-name-directory string))
name
names)
(dolist (dir dirs)
(unless dir
(setq dir default-directory))
(if string-dir
(setq dir (expand-file-name string-dir dir)))
(when (file-directory-p dir)
(dolist (file (file-name-all-completions
(file-name-nondirectory string) dir))
(setq name (if string-dir (concat string-dir file) file))
(if (string-match (format "^.*\\.el%s$" (regexp-opt load-file-rep-suffixes)) name)
(add-to-list 'names name)))))
names))
(defun auto-install-get-candidate (prompt collection)
"Get candidate from completing list.
PROMPT is string for prompt.
COLLECTION is list for completing candidates."
(completing-read (format "%s (%s): " prompt (or (auto-install-region-or-thing) ""))
collection
nil nil nil nil
(auto-install-region-or-thing)))
(defun auto-install-from-url-list (&optional url-list)
"Batch install many packages form URL-LIST."
(if (listp url-list)
(dolist (url url-list)
(auto-install-from-url url))
(error "Invalid url list for install.")))
(defun nthcdr+ (n list)
"Take cdr N times on LIST, return the result.
If LIST length below N, return entire list.
If LIST is nil, return nil."
(if (or (null list)
(> n (length list)))
list
(nthcdr n list)))
(defun nthcar (n list)
"Return first N elements of LIST.
If LIST length below N, return entire list.
If LIST is nil, return nil."
(reverse (nthcdr (- (length list) n) (reverse list))))
(defvar auto-install-maintainer-mail-address
(concat "rubiki" "tch@ru" "by-lang.org"))
(defvar auto-install-bug-report-salutation
"Describe bug below, using a precise recipe.
When I executed M-x ...
How to send a bug report:
1) Be sure to use the LATEST version of auto-install.el.
2) Enable debugger. M-x toggle-debug-on-error or (setq debug-on-error t)
3) Use Lisp version instead of compiled one: (load \"auto-install.el\")
4) If you got an error, please paste *Backtrace* buffer.
5) Type C-c C-c to send.
# If you are a Japanese, please write in Japanese:-)")
(defun auto-install-send-bug-report ()
(interactive)
(reporter-submit-bug-report
auto-install-maintainer-mail-address
"auto-install.el"
(apropos-internal "^auto-install-" 'boundp)
nil nil
auto-install-bug-report-salutation))
(provide 'auto-install)