From 5d9c854a6cf12fff2326ee5653e87e2d3d550a8d Mon Sep 17 00:00:00 2001 From: Justin Talbott Date: Mon, 4 Dec 2017 10:57:23 -0500 Subject: [PATCH] Add `use-package-chords` and `use-package-ensure-system-package` Also update docs on usage connect to https://github.com/jwiegley/use-package/issues/516 --- lisp/use-package/bind-chord.el | 61 ++++++++++++++++ lisp/use-package/use-package-chords.el | 48 +++++++++++++ .../use-package-ensure-system-package.el | 70 +++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 lisp/use-package/bind-chord.el create mode 100644 lisp/use-package/use-package-chords.el create mode 100644 lisp/use-package/use-package-ensure-system-package.el diff --git a/lisp/use-package/bind-chord.el b/lisp/use-package/bind-chord.el new file mode 100644 index 00000000000..e0827a4230f --- /dev/null +++ b/lisp/use-package/bind-chord.el @@ -0,0 +1,61 @@ +;;; bind-chord.el --- key-chord binding helper for use-package-chords + +;; Copyright (C) 2015-2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-chords +;; Version: 0.2 +;; Package-Requires: ((bind-key "1.0") (key-chord "0.6")) +;; Filename: bind-chord.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; + +;;; Code: + +(require 'bind-key) +(require 'key-chord) + +;;;###autoload +(defmacro bind-chord (chord command &optional keymap) + "Bind CHORD to COMMAND in KEYMAP (`global-map' if not passed)." + (let ((key1 (logand 255 (aref chord 0))) + (key2 (logand 255 (aref chord 1)))) + (if (eq key1 key2) + `(bind-key (vector 'key-chord ,key1 ,key2) ,command ,keymap) + `(progn + (bind-key (vector 'key-chord ,key1 ,key2) ,command ,keymap) + (bind-key (vector 'key-chord ,key2 ,key1) ,command ,keymap))))) + +;;;###autoload +(defmacro bind-chords (&rest args) + "Bind multiple chords at once. + +Accepts keyword argument: +:map - a keymap into which the keybindings should be added + +The rest of the arguments are conses of keybinding string and a +function symbol (unquoted)." + (let* ((map (plist-get args :map)) + (maps (if (listp map) map (list map))) + (key-bindings (progn + (while (keywordp (car args)) + (pop args) + (pop args)) + args))) + (macroexp-progn + (apply + #'nconc + (mapcar (lambda (form) + (if maps + (mapcar + #'(lambda (m) + `(bind-chord ,(car form) ',(cdr form) ,m)) maps) + `((bind-chord ,(car form) ',(cdr form))))) + key-bindings))))) + +(provide 'bind-chord) +;;; bind-chord.el ends here diff --git a/lisp/use-package/use-package-chords.el b/lisp/use-package/use-package-chords.el new file mode 100644 index 00000000000..f3e85b4149a --- /dev/null +++ b/lisp/use-package/use-package-chords.el @@ -0,0 +1,48 @@ +;;; use-package-chords.el --- key-chord keyword for use-package + +;; Copyright (C) 2015-2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-chords +;; Version: 0.2 +;; Package-Requires: ((use-package "2.1") (bind-key "1.0") (bind-chord "0.2") (key-chord "0.6")) +;; Filename: use-package-chords.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; +;; The `:chords' keyword allows you to define `key-chord' bindings for +;; `use-package' declarations in the same manner as the `:bind' +;; keyword. +;; + +;;; Code: + +(require 'use-package) +(require 'bind-chord) + +(add-to-list 'use-package-keywords :chords t) + +(defalias 'use-package-normalize/:chords 'use-package-normalize-binder) + +(defun use-package-handler/:chords (name keyword arg rest state) + "Handler for `:chords' keyword in `use-package'." + (let* ((commands (remq nil (mapcar #'(lambda (arg) + (if (listp arg) + (cdr arg) + nil)) arg))) + (chord-binder + (use-package-concat + (use-package-process-keywords name + (use-package-sort-keywords + (use-package-plist-maybe-put rest :defer t)) + (use-package-plist-append state :commands commands)) + `((ignore + ,(macroexpand + `(bind-chords :package ,name ,@arg))))))) + (use-package-handler/:preface name keyword chord-binder rest state))) + +(provide 'use-package-chords) +;;; use-package-chords.el ends here diff --git a/lisp/use-package/use-package-ensure-system-package.el b/lisp/use-package/use-package-ensure-system-package.el new file mode 100644 index 00000000000..e34bb16d738 --- /dev/null +++ b/lisp/use-package/use-package-ensure-system-package.el @@ -0,0 +1,70 @@ +;;; use-package-ensure-system-package.el --- auto install system packages + +;; Copyright (C) 2017 Justin Talbott + +;; Author: Justin Talbott +;; Keywords: convenience, tools, extensions +;; URL: https://github.com/waymondo/use-package-ensure-system-package +;; Version: 0.1 +;; Package-Requires: ((use-package "2.1") (system-packages "0.1")) +;; Filename: use-package-ensure-system-package.el +;; License: GNU General Public License version 3, or (at your option) any later version +;; + +;;; Commentary: +;; +;; The `:ensure-system-package` keyword allows you to ensure system +;; binaries exist alongside your `use-package` declarations. +;; + +;;; Code: + +(require 'use-package) +(require 'system-packages) + +(add-to-list 'use-package-keywords :ensure-system-package t) + +(defun use-package-ensure-system-package-install-command (pack) + "Return the default install command for `pack'." + (let ((command + (cdr (assoc 'install (cdr (assoc system-packages-packagemanager + system-packages-supported-package-managers)))))) + (unless command + (error (format "%S not supported in %S" 'install system-packages-packagemanager))) + (unless (listp command) + (setq command (list command))) + (when system-packages-usesudo + (setq command (mapcar (lambda (part) (concat "sudo " part)) command))) + (setq command (mapconcat 'identity command " && ")) + (mapconcat 'identity (list command pack) " "))) + +(defun use-package-ensure-system-package-consify (arg) + "Turn `arg' into a cons of (`package-name' . `install-command')." + (cond + ((stringp arg) + (cons arg (use-package-ensure-system-package-install-command arg))) + ((symbolp arg) + (cons arg (use-package-ensure-system-package-install-command (symbol-name arg)))) + ((consp arg) arg))) + +(defun use-package-normalize/:ensure-system-package (name-symbol keyword args) + "Turn `arg' into a list of cons-es of (`package-name' . `install-command')." + (use-package-only-one (symbol-name keyword) args + (lambda (label arg) + (cond + ((and (listp arg) (listp (cdr arg))) + (mapcar #'use-package-ensure-system-package-consify arg)) + (t + (list (use-package-ensure-system-package-consify arg))))))) + +(defun use-package-handler/:ensure-system-package (name keyword arg rest state) + "Execute the handler for `:ensure-system-package' keyword in `use-package'." + (let ((body (use-package-process-keywords name rest state))) + (use-package-concat + (mapcar #'(lambda (cons) + `(unless (executable-find (symbol-name ',(car cons))) + (async-shell-command ,(cdr cons)))) arg) + body))) + +(provide 'use-package-ensure-system-package) +;;; use-package-ensure-system-package.el ends here -- 2.39.2