diff options
author | Miguel Ángel Moreno <mail@migalmoreno.com> | 2022-02-23 20:42:07 +0100 |
---|---|---|
committer | Miguel Ángel Moreno <mail@migalmoreno.com> | 2022-02-23 20:42:07 +0100 |
commit | 44cb065a2d0915227bec2a4f48c71ca220b206b0 (patch) | |
tree | 92fcee828c444fb6b64e4c5580e9fd8fa483c066 |
feat: Adds initial commit
-rw-r--r-- | README.org | 24 | ||||
-rw-r--r-- | fdroid.el | 165 |
2 files changed, 189 insertions, 0 deletions
diff --git a/README.org b/README.org new file mode 100644 index 0000000..0402042 --- /dev/null +++ b/README.org @@ -0,0 +1,24 @@ +=fdroid.el= is an Emacs interface to [[https://github.com/mvdan/fdroidcl][fdroidcl]]. Its purpose is to aid the management of F-Droid repository packages to be installed in an Android device from the comfort of Emacs. + +To install it, simply put the =fdroid.el= file in your =load-path=, or optionally manually download the source and point to it. + +#+begin_src elisp +(add-to-list 'load-path "path/to/source/fdroid.el") +#+end_src + +This package makes use of the [[https://github.com/oantolin/embark][Embark]] and [[https://github.com/minad/consult][consult]] packages to provide a more coherent interface to the interactive commands, so ensure these are installed too. An example configuration might look like what follows. + +#+begin_src elisp +(global-set-key (kbd "C-c -") #'fdroid-list-packages) +(with-eval-after-load 'fdroid + (custom-set-variables + '(fdroid-log-events t) ; Whether messages should be logged after an operation + '(fdroid-program (executable-find "fdroidcl")))) ; Path to `fdroidcl' +#+end_src + +In the above configuration, we only set one keybinding because =fdroid-list-packages= shows all packages available for the current F-Droid repository, and from then one can use the following Embark actions on a particular package: + +- ~i~ :: install the current package. +- ~u~ :: uninstall the current package. +- ~d~ :: download the current package. +- ~s~ :: show more information about the current package. diff --git a/fdroid.el b/fdroid.el new file mode 100644 index 0000000..3c6caf4 --- /dev/null +++ b/fdroid.el @@ -0,0 +1,165 @@ +;; -*- lexical-binding: t; -*- +(require 'consult) +(require 'embark) + +(defgroup fdroid nil + "Manage F-Droid packages through `fdroidcl'." + :group 'external + :prefix "fdroid-" + :tag "F-Droid") + +(defcustom fdroid-program (executable-find "fdroidcl") + "Holds the executable path for `fdroidcl'." + :group 'froid + :type 'string) + +(defcustom fdroid-log-events nil + "Selects whether to log the exectuion of events." + :group 'fdroid + :type 'boolean) + +(cl-defmacro with--fdroidcl (commands &body body) + "Executes `fdroidcl' with COMMANDS and performs operations set by BODY." + `(with-temp-buffer + (apply #'call-process fdroid-program nil t nil ,commands) + (goto-char (point-min)) + ,@body)) + +(cl-defun fdroid--list-packages (&optional keywords) + "Lists all packages in current F-Droid repository. Optionally, filter packages by KEYWORDS + and returns a list of matching results." + (with--fdroidcl + (if keywords + `("search" ,keywords) + '("search")) + (let ((results (make-hash-table :test 'equal))) + (while (not (eobp)) + (when (re-search-forward (rx (: bol (group (+ (or alpha punct))) + (+ blank) + (or "- " (group (* anychar))) + " - " (group (+ any)) + "\n" (+ blank) (group (+ any)))) + (point-at-eol 2) t) + (puthash (match-string 1) (list + :name (match-string 2) + :version (match-string 3) + :description (match-string 4)) + results)) + (forward-line 1)) + results))) + +(defun fdroid--format-package (key value table) + "Embellishes package entry with KEY and VALUE from TABLE for user completion." + (let ((name (cl-getf value :name)) + (version (cl-getf value :version)) + (description (cl-getf value :description))) + (if (not (string-empty-p name)) + (puthash (format "%s - %s (%s): %s" name version key description) + key table) + (puthash (format "%s - %s: %s" key version description) + key table)))) + +(defun fdroid--build-candidate-list (&optional keywords) + "Builds candidate list with KEYWORDS to be leveraged on completion functions." + (let ((completion-hash (make-hash-table :test 'equal))) + (cl-loop for k being the hash-keys + in (fdroid--list-packages (or keywords)) using (hash-value v) + collect (fdroid--format-package k v completion-hash)) + completion-hash)) + +(cl-defun fdroid--prompt-completion (&key (multiple nil) (keywords nil)) + "Prompts the user for a package from the full list of packages, or +from the filtered list drawn from KEYWORDS if provided. If specified, prompt the user +for a MULTIPLE package selection." + (interactive) + (let ((candidates (if keywords + (fdroid--build-candidate-list) + (fdroid--build-candidate-list keywords)))) + (if multiple + (consult-completing-read-multiple + "Package(s): " + candidates) + (consult--read + candidates + :prompt "Package: " + :sort nil + :category 'fdroid)))) + +;;;###autoload +(defun fdroid-list-packages () + "Main point of entry to the user facing interactive commands." + (interactive) + (fdroid--prompt-completion)) + +;;;###autoload +(defun fdroid-update () + "Updates current F-Droid repository package index." + (interactive) + (with--fdroidcl + '("update") + (when fdroid-log-events + (message "Repository updated!")))) + +;;;###autoload +(defun fdroid-search (keywords) + "Searches for packages with KEYWORDS in current F-Droid repository." + (interactive "sKeywords: ") + (fdroid--prompt-completion keywords)) + +;;;###autoload +(defun fdroid-install (package) + "Installs or upgrades a single PACKAGE on the device." + (interactive + (list (gethash (fdroid--prompt-completion) (fdroid--build-candidate-list)))) + (with--fdroidcl + `("install" ,package) + (when fdroid-log-events + (message "Package \"%s\" successfully installed on device." package)))) + +;;;###autoload +(defun fdroid-install-multiple (packages) + "Installs or upgrades multiple PACKAGES on the device." + (interactive + (list (mapcar (lambda (e) + (gethash e (fdroid--build-candidate-list))) + (fdroid--prompt-completion :multiple t)))) + (with--fdroidcl + `("install" ,@packages) + (when fdroid-log-events + (message "Packages \"%s\" successfully installed on device." (mapconcat #'identity packages " "))))) + +;;;###autoload +(defun fdroid-uninstall (package) + "Uninstalls PACKAGE from device." + (interactive + (list (gethash (fdroid--prompt-completion) (fdroid--build-candidate-list)))) + (with--fdroidcl + `("uninstall" ,package) + (when fdroid-log-events + (message "Package \"%s\" successfully uninstalled from device." package)))) + +;;;###autoload +(defun fdroid-download (package) + "Downloads PACKAGE to the device." + (interactive + (list (gethash (fdroid--prompt-completion) (fdroid--build-candidate-list)))) + (with--fdroidcl + `("download" ,package) + (when fdroid-log-events + (message "Package \"%s\" successfully downloaded to device." package)))) + +;;;###autoload +(defun fdroid-show (package) + "Shows detailed information about PACKAGE." + (interactive)) + +(embark-define-keymap embark-fdroid-actions + "Keymap for `fdroidcl' actions which take F-Droid package identifiers." + ("i" fdroid-install) + ("d" fdroid-download) + ("u" fdroid-uninstall) + ("s" fdroid-show)) + +(add-to-list 'embark-keymap-alist '(fdroid . embark-fdroid-actions)) + +(provide 'fdroid) |