password-gen.el/password-gen.el

174 lines
5.3 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; password-gen.el --- Password generator for Emacs -*- lexical-binding: t; -*-
;; Copyright (C) 2024 Lucien Cartier-Tilet
;; Author: Lucien Cartier-Tilet <lucien@phundrak.com>
;; Maintainer: Lucien Cartier-Tilet <lucien@phundrak.com>
;; URL: https://labs.phundrak.com/phundrak/password-gen.el
;; Version: 0.1.0
;; Package-Requires: ((emacs "26.1") (transient "0.3.7"))
;; Keywords: convenience
;; 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 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 <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Password generator for Emacs, based on transient.
;;
;;; Code:
;;; Requires
(require 'transient)
(defconst password-gen-version "0.1.0")
(defgroup password-gen ()
"Password generator for Emacs"
:group 'applications
:prefix "password-gen-"
:link '(url-link :tag "Gitea" "https://labs.phundrak.com/phundrak/password-gen.el"))
;;; Internal Functions
(eval-when-compile
(defmacro password-gen--define-infix (key name description type version
default &rest reader)
"Define infix and its corresponding variable at once.
The variable is named password-gen--NAME and is of type TYPE, has
a DESCRIPTION and a specified VERSION. They KEY and READER are
for the infix declaration.
This macro is largely copied from Tecosaurs screenshot.el"
(let ((var-name (concat "password-gen--" name)))
`(progn
(defcustom ,(intern var-name) ,default
,description
:type ,type
:group 'password-gen
:version ,version)
(transient-define-infix ,(intern (concat "password-gen--set-" name)) ()
"Set password-gen options."
:class 'transient-lisp-variable
:variable ',(intern var-name)
:key ,key
:description ,description
:argument ,(concat "--" name)
:reader (lambda (&rest _) ,@reader)))))
(password-gen--define-infix
"-n" "numbers" "Include 0-9 numbers"
'boolean "0.1.0" t
(not password-gen--numbers))
(password-gen--define-infix
"-C" "uppercase" "Include A-Z characters"
'boolean "0.1.0" t
(not password-gen--uppercase))
(password-gen--define-infix
"-c" "lowercase" "Include a-z characters"
'boolean "0.1.0" t
(not password-gen--lowercase))
(password-gen--define-infix
"-s" "symbols" "Include !@#$%^&* symbols"
'boolean "0.1.0" t
(not password-gen--symbols))
(password-gen--define-infix
"-l" "length" "Length of the password"
'boolean "0.1.0" 16
(read-number "Length of the password: ")))
(defun password-gen--generate-password ()
"Generate a password based on user preferences."
(shell-command-to-string
(format "tr -dc '%s%s%s%s' < /dev/urandom | head -c %d"
(if password-gen--uppercase "A-Z" "")
(if password-gen--lowercase "a-z" "")
(if password-gen--numbers "0-9" "")
(if password-gen--symbols "!@#$%^&*")
password-gen--length)))
(defun password-gen--copy-generated-password ()
"Generate new password and add it to kill ring."
(kill-new (password-gen--generate-password)))
(defun password-gen--insert-generated-password ()
"Insert at cursor a newly generated password."
(insert (password-gen--generate-password)))
;;; Transient Actions
(eval-when-compile
(defmacro password-gen--def-action (name description transient &rest body)
"Create a function called from TRANSIENT.
DESCRIPTION is the docstring of the function named
password-gen--NAME, and it gets BODY as its body."
`(defun ,(intern (concat "password-gen--action-" name)) (&optional _args)
,(concat description "
This function is meant to be called by a transient.")
(interactive
(list (transient-args ,transient)))
,@body))
(password-gen--def-action
"quit"
"Exit password generator"
'password-gen-main
#'nil)
(password-gen--def-action
"copy"
"Generate and copy password in kill-ring."
'password-gen-main
(password-gen--copy-generated-password))
(password-gen--def-action
"insert"
"Generate and insert password at cursor."
'password-gen-main
(password-gen--insert-generated-password)))
;;; Transient Prefixes
(transient-define-prefix password-gen-main ()
["Options"
(password-gen--set-length)
(password-gen--set-uppercase)
(password-gen--set-lowercase)
(password-gen--set-numbers)
(password-gen--set-symbols)]
["Actions"
("c" "Copy" password-gen--action-copy)
("i" "Insert" password-gen--action-insert)
("q" "Quit" password-gen--action-quit)]
(interactive)
(transient-setup 'password-gen))
;;;###autoload
(defun password-gen ()
"Call the main transient for password-gen."
(interactive)
(call-interactively #'password-gen-main))
(provide 'password-gen)
;;; password-gen.el ends here