229 lines
8.7 KiB
EmacsLisp
Raw Normal View History

2019-10-20 16:24:07 -05:00
;;; paradox.el --- A modern Packages Menu. Colored, with package ratings, and customizable. -*- lexical-binding:t -*-
;; Copyright (C) 2014-2015 Artur Malabarba <emacs@endlessparentheses.com>
;; Author: Artur Malabarba <emacs@endlessparentheses.com>
;; URL: https://github.com/Malabarba/paradox
;; Version: 2.5.1
;; Keywords: package packages
;; Package-Requires: ((emacs "24.4") (seq "1.7") (let-alist "1.0.3") (spinner "1.7.3") (hydra "0.13.2"))
;; Prefix: paradox
;; Separator: -
;;; Commentary:
;;
;; Paradox can be installed from Melpa with M-x `package-install' RET
;; paradox.
;; It can also be installed manually in the usual way, just be mindful of
;; the dependencies.
;;
;; To use it, simply call M-x `paradox-list-packages' (instead of the
;; regular `list-packages').
;; This will give you most features out of the box. If you want to be
;; able to star packages as well, just configure the
;; `paradox-github-token' variable then call `paradox-list-packages'
;; again.
;;
;; If you'd like to stop using Paradox, you may call `paradox-disable'
;; and go back to using the regular `list-packages'.
;;
;; ## Current Features ##
;;
;; ### Several Improvements ###
;;
;; Paradox implements many small improvements to the package menu
;; itself. They all work out of the box and are completely customizable!
;; *(Also, hit `h' to see all keys.)*
;;
;; * Visit the package's homepage with `v' (or just use the provided buttons).
;; * Shortcuts for package filtering:
;; * <f r> filters by regexp (`occur');
;; * <f u> display only packages with upgrades;
;; * <f k> filters by keyword (Emacs 24.4 only).
;; * `hl-line-mode' enabled by default.
;; * Display useful information on the mode-line and cleanup a bunch of
;; useless stuff.
;; * **Customization!** Just call M-x `paradox-customize' to see what you can
;; do.
;; * Customize column widths.
;; * Customize faces (`paradox-star-face', `paradox-status-face-alist' and `paradox-archive-face').
;; * Customize local variables.
;;
;; ### Package Ratings ###
;;
;; Paradox also integrates with
;; **GitHub Stars**, which works as **rough** package rating system.
;; That is, Paradox package menu will:
;;
;; 1. Display the number of GitHub Stars each package has (assuming it's
;; in a github repo, of course);
;; 2. Possibly automatically star packages you install, and unstar
;; packages you delete (you will be asked the first time whether you
;; want this);
;; 3. Let you star and unstar packages by hitting the `s' key;
;; 4. Let you star all packages you have installed with M-x `paradox-star-all-installed-packages'.
;;
;; Item **1.** will work out of the box, the other items obviously
;; require a github account (Paradox will help you generate a token the
;; first time you call `paradox-list-packages').
;;
;; ## How Star Displaying Works ##
;;
;; We generate a map of Package Name -> Repository from
;; [Melpa](https://github.com/milkypostman/melpa.git)'s `recipe'
;; directory, some repos may correspond to more than one package.
;; This map is used count the stars a given package has.
;; _This doesn't mean you need Melpa to see the star counts, the numbers
;; will be displayed regardless of what archives you use._
;;
;; Currently, packages that are not hosted on GitHub are listed with a
;; blank star count, which is clearly different from 0-star packages
;; (which are displayed with a 0, obviously).
;; If you know of an alternative that could be used for these packages,
;; [open an issue](https://github.com/Bruce-Connor/paradox/issues/new)
;; here, I'd love to hear.
;;; License:
;;
;; This file is NOT part of GNU Emacs.
;;
;; 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 2
;; 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.
;;; Code:
(require 'package)
(require 'cl-lib)
(require 'paradox-core)
(require 'paradox-execute)
(require 'paradox-menu)
(defconst paradox-version "2.5.1" "Version of the paradox.el package.")
(defun paradox-bug-report ()
"Opens github issues page in a web browser. Please send any bugs you find.
Please include your Emacs and paradox versions."
(interactive)
(message "Your paradox-version is: %s, and your emacs version is: %s.\nPlease include this in your report!"
paradox-version emacs-version)
(browse-url "https://github.com/Bruce-Connor/paradox/issues/new"))
(defun paradox-customize ()
"Open the customization menu in the `paradox' group."
(interactive)
(customize-group 'paradox t))
(defgroup paradox nil
"Customization group for paradox."
:prefix "paradox-"
:group 'emacs
:package-version '(paradox . "0.1"))
;;; External Commands
;;;###autoload
(defun paradox-list-packages (no-fetch)
"Improved version of `package-list-packages'. The heart of Paradox.
Function is equivalent to `package-list-packages' (including the
prefix NO-FETCH), but the resulting Package Menu is improved in
several ways.
Among them:
1. Uses `paradox-menu-mode', which has more functionality and
keybinds than `package-menu-mode'.
2. Uses some font-locking to improve readability.
3. Optionally shows the number GitHub stars and Melpa downloads
for packages.
4. Adds useful information in the mode-line."
(interactive "P")
(when (paradox--check-github-token)
(paradox-enable)
(let ((is-25 (fboundp 'package--with-response-buffer)))
(unless no-fetch
(if is-25
(add-to-list 'package--downloads-in-progress 'paradox--data)
(paradox--refresh-remote-data)))
(package-list-packages no-fetch)
(unless no-fetch
(when (stringp paradox-github-token)
(paradox--refresh-user-starred-list
(bound-and-true-p package-menu-async)))
(when is-25
(paradox--refresh-remote-data))))))
;;;###autoload
(defun paradox-upgrade-packages (&optional no-fetch)
"Upgrade all packages. No questions asked.
This function is equivalent to `list-packages', followed by a
`package-menu-mark-upgrades' and a `package-menu-execute'. Except
the user isn't asked to confirm deletion of packages.
If `paradox-execute-asynchronously' is non-nil, part of this
operation may be performed in the background.
The NO-FETCH prefix argument is passed to `list-packages'. It
prevents re-download of information about new versions. It does
not prevent downloading the actual packages (obviously)."
(interactive "P")
(save-window-excursion
(let ((package-menu-async nil))
(paradox-list-packages no-fetch))
(package-menu-mark-upgrades)
(paradox-menu-execute 'noquery)))
(defun paradox-enable ()
"Enable paradox, overriding the default package-menu."
(interactive)
(when (and (fboundp 'package--update-downloads-in-progress)
(not (fboundp 'package--with-response-buffer)))
(message "[Paradox] Your Emacs snapshot is outdated, please install a more recent one.")
(setq package-menu-async nil))
(paradox--override-definition 'package-menu--print-info 'paradox--print-info)
(when (fboundp 'package-menu--print-info-simple)
(paradox--override-definition 'package-menu--print-info-simple 'paradox--print-info))
(paradox--override-definition 'package-menu--generate 'paradox--generate-menu)
;; Tough it may not look like it, this is totally necessary too.
(paradox--override-definition 'package-menu-mode 'paradox-menu-mode)
(paradox--core-enable))
;;;###autoload
(defun paradox-require (feature &optional filename noerror package refresh)
"Like `require', but also install FEATURE if it is absent.
FILENAME is passed to `require'.
If NOERROR is non-nil, don't complain if the feature couldn't be
installed, just return nil.
- If FEATURE is present, `require' it and return t.
- If FEATURE is not present, install PACKAGE with `package-install'.
If PACKAGE is nil, assume FEATURE is the package name.
After installation, `require' FEATURE.
By default, the current package database is only updated if it is
empty. Passing a non-nil REFRESH argument forces this update."
(or (require feature filename t)
(let ((package (or package
(if (stringp feature)
(intern feature)
feature))))
(require 'package)
(unless (and package-archive-contents (null refresh))
(package-refresh-contents))
(and (condition-case e
(package-install package)
(error (if noerror nil (error (cadr e)))))
(require feature filename noerror)))))
(provide 'paradox)
;;; paradox.el ends here