mirror of
https://github.com/SqrtMinusOne/password-store-completion.git
synced 2025-12-10 18:03:03 +03:00
feat: main features done
This commit is contained in:
parent
49ae109e7d
commit
d9c8a2a013
1 changed files with 101 additions and 69 deletions
170
ivy-pass.el
170
ivy-pass.el
|
|
@ -44,36 +44,16 @@
|
||||||
:type 'integer
|
:type 'integer
|
||||||
:group 'ivy-pass)
|
:group 'ivy-pass)
|
||||||
|
|
||||||
(defcustom ivy-pass-autotype
|
(defcustom ivy-pass-sequences
|
||||||
'(wait
|
'((autotype . (wait
|
||||||
(field . "username")
|
(field . "username")
|
||||||
(key . "Tab")
|
(key . "Tab")
|
||||||
(field . secret)
|
(field . secret)
|
||||||
(key . "Return"))
|
(key . "Return")))
|
||||||
"A sequence to execute on autotype.
|
(password . ((field . secret)))
|
||||||
|
(username . ((field . "username")))
|
||||||
Take a look at `ivy-pass--get-commands' for possible fields."
|
(url . ((field . "url"))))
|
||||||
:group 'ivy-pass)
|
"Sequences to execute by ivy-pass."
|
||||||
|
|
||||||
(defcustom ivy-pass-password
|
|
||||||
'(wait (field . secret))
|
|
||||||
"A sequence to execute to enter password.
|
|
||||||
|
|
||||||
Take a look at `ivy-pass--get-commands' for possible fields."
|
|
||||||
:group 'ivy-pass)
|
|
||||||
|
|
||||||
(defcustom ivy-pass-username
|
|
||||||
'(wait (field . "username"))
|
|
||||||
"A sequence to execute to enter username.
|
|
||||||
|
|
||||||
Take a look at `ivy-pass--get-commands' for possible fields."
|
|
||||||
:group 'ivy-pass)
|
|
||||||
|
|
||||||
(defcustom ivy-pass-url
|
|
||||||
'(wait (field . "url"))
|
|
||||||
"A sequence to execute to enter url.
|
|
||||||
|
|
||||||
Take a look at `ivy-pass--get-commands' for possible fields."
|
|
||||||
:group 'ivy-pass)
|
:group 'ivy-pass)
|
||||||
|
|
||||||
(defun ivy-pass--async-command (command callback)
|
(defun ivy-pass--async-command (command callback)
|
||||||
|
|
@ -110,7 +90,6 @@ Call CALLBACK when the last command is executed."
|
||||||
"| xdotool type --clearmodifiers --file - --delay "
|
"| xdotool type --clearmodifiers --file - --delay "
|
||||||
(number-to-string ivy-pass-delay)))
|
(number-to-string ivy-pass-delay)))
|
||||||
|
|
||||||
|
|
||||||
(defun ivy-pass--get-wait-command (&optional miliseconds)
|
(defun ivy-pass--get-wait-command (&optional miliseconds)
|
||||||
"Return a command to sleep for `ivy-pass-initial-wait'."
|
"Return a command to sleep for `ivy-pass-initial-wait'."
|
||||||
(format "sleep %f" (/ (float (or miliseconds ivy-pass-initial-wait)) 1000)))
|
(format "sleep %f" (/ (float (or miliseconds ivy-pass-initial-wait)) 1000)))
|
||||||
|
|
@ -126,60 +105,112 @@ ENTRY is an alist, FIELD is a symbol or string that can be a key of alist"
|
||||||
(when-let ((contents (alist-get field entry nil nil #'equal)))
|
(when-let ((contents (alist-get field entry nil nil #'equal)))
|
||||||
(ivy-pass--get-type-command contents)))
|
(ivy-pass--get-type-command contents)))
|
||||||
|
|
||||||
(defun ivy-pass--get-commands (entry-name sequence)
|
(defun ivy-pass--get-commands (entry sequence)
|
||||||
"Get a list of commands to execute for ENTRY-NAME.
|
"Get a list of commands to execute for ENTRY.
|
||||||
|
|
||||||
SEQUENCE is a list of the following elements:
|
SEQUENCE is a list of the following elements:
|
||||||
- `wait'. Wait for `ivy-pass-initial-wait' miliseconds.
|
- `wait'. Wait for `ivy-pass-initial-wait' miliseconds.
|
||||||
- `(wait <miliseconds>)'. Wait for <miliseconds>.
|
- `(wait <miliseconds>)'. Wait for <miliseconds>.
|
||||||
- `(key <key>)'. Type <key>
|
- `(key <key>)'. Type <key>
|
||||||
- `(field <field>)'. Type <field> of entry."
|
- `(field <field>)'. Type <field> of entry."
|
||||||
|
(seq-filter
|
||||||
|
(lambda (command) (not (seq-empty-p command)))
|
||||||
|
(mapcar
|
||||||
|
(lambda (elem)
|
||||||
|
(unless (sequencep elem)
|
||||||
|
(setq elem (list elem)))
|
||||||
|
(pcase (car elem)
|
||||||
|
('wait (ivy-pass--get-wait-command (cdr elem)))
|
||||||
|
('key (ivy-pass--get-key-command (cdr elem)))
|
||||||
|
('field (ivy-pass--get-entry-command entry (cdr elem)))
|
||||||
|
(_ (error "Wrong field: %s" (prin1-to-string elem)))))
|
||||||
|
sequence)))
|
||||||
|
|
||||||
|
(defun ivy-pass--get-entry (entry-name)
|
||||||
|
"Get a pass entry by ENTRY-NAME."
|
||||||
(let ((entry (auth-source-pass-parse-entry entry-name)))
|
(let ((entry (auth-source-pass-parse-entry entry-name)))
|
||||||
(unless entry
|
(unless entry
|
||||||
(user-error "Entry is empty. Perhaps password was incorrect?"))
|
(user-error "The entry is empty. Perhaps password was incorrect?"))
|
||||||
(seq-filter
|
entry))
|
||||||
(lambda (command) (not (seq-empty-p command)))
|
|
||||||
(mapcar
|
|
||||||
(lambda (elem)
|
|
||||||
(unless (sequencep elem)
|
|
||||||
(setq elem (list elem)))
|
|
||||||
(pcase (car elem)
|
|
||||||
('wait (ivy-pass--get-wait-command (cdr elem)))
|
|
||||||
('key (ivy-pass--get-key-command (cdr elem)))
|
|
||||||
('field (ivy-pass--get-entry-command entry (cdr elem)))
|
|
||||||
(_ (error "Wrong field: %s" (prin1-to-string elem)))))
|
|
||||||
sequence))))
|
|
||||||
|
|
||||||
(defvar ivy-pass-history nil
|
(defun ivy-pass--get-sequence (entry sequence-name)
|
||||||
"History for `ivy-pass'")
|
(or (when-let ((str (alist-get
|
||||||
|
(format "sequence-%s" (symbol-name sequence-name))
|
||||||
|
entry nil nil #'equal)))
|
||||||
|
(condition-case err
|
||||||
|
(car (read-from-string str))
|
||||||
|
(error (error "Error in %s: %s" str (prin1-to-string err)))))
|
||||||
|
(alist-get sequence-name ivy-pass-sequences)))
|
||||||
|
|
||||||
(defmacro ivy-pass--define-sequence-funcs (sequence sequence-name)
|
(defmacro ivy-pass--def-command (name &rest body)
|
||||||
|
(declare (doc-string 2) (indent 1))
|
||||||
`(progn
|
`(progn
|
||||||
(defun ,(intern (format "ivy-pass--type-%s-command" sequence-name)) ()
|
(defun ,(intern (format "%s-command" name)) ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(ivy-exit-with-action
|
(ivy-exit-with-action
|
||||||
(lambda (entry-name)
|
(lambda (entry-name)
|
||||||
(ivy-pass--async-commands
|
(let ((entry (ivy-pass--get-entry entry-name)))
|
||||||
(ivy-pass--get-commands entry-name ,sequence)))))
|
,@body))))
|
||||||
(defun ,(intern (format "ivy-pass--type-%s-action" sequence-name)) (entry-name)
|
(defun ,(intern (format "%s-action" name)) (entry-name)
|
||||||
(ivy-pass--async-commands
|
(let ((entry (ivy-pass--get-entry entry-name)))
|
||||||
(ivy-pass--get-commands
|
,@body))))
|
||||||
entry-name
|
|
||||||
,sequence)))))
|
|
||||||
|
|
||||||
(ivy-pass--define-sequence-funcs ivy-pass-autotype "autotype")
|
(ivy-pass--def-command ivy-pass--autotype
|
||||||
(ivy-pass--define-sequence-funcs ivy-pass-password "password")
|
(ivy-pass--async-commands
|
||||||
(ivy-pass--define-sequence-funcs ivy-pass-username "username")
|
(ivy-pass--get-commands
|
||||||
(ivy-pass--define-sequence-funcs ivy-pass-url "url")
|
entry (ivy-pass--get-sequence entry 'autotype))))
|
||||||
|
|
||||||
|
(ivy-pass--def-command ivy-pass--password
|
||||||
|
(ivy-pass--async-commands
|
||||||
|
(ivy-pass--get-commands
|
||||||
|
entry (ivy-pass--get-sequence entry 'password))))
|
||||||
|
|
||||||
|
(ivy-pass--def-command ivy-pass--username
|
||||||
|
(ivy-pass--async-commands
|
||||||
|
(ivy-pass--get-commands
|
||||||
|
entry (ivy-pass--get-sequence entry 'username))))
|
||||||
|
|
||||||
|
(ivy-pass--def-command ivy-pass--url
|
||||||
|
(ivy-pass--async-commands
|
||||||
|
(ivy-pass--get-commands
|
||||||
|
entry (ivy-pass--get-sequence entry 'url))))
|
||||||
|
|
||||||
|
(ivy-pass--def-command ivy-pass--fields
|
||||||
|
(let ((sequences
|
||||||
|
(mapcar
|
||||||
|
(lambda (item)
|
||||||
|
(let ((field-name (car item)))
|
||||||
|
(when (symbolp field-name)
|
||||||
|
(setq field-name (symbol-name field-name)))
|
||||||
|
(if (string-match (rx bos "sequence-") field-name)
|
||||||
|
`(,field-name
|
||||||
|
. ,(condition-case err
|
||||||
|
(eval (car (read-from-string (cdr item))))
|
||||||
|
(error (format "Error in %s: %s" field-name
|
||||||
|
(prin1-to-string err)))))
|
||||||
|
`(,field-name . (wait (field . ,(car item)))))))
|
||||||
|
entry)))
|
||||||
|
(ivy-read "Field: " sequences
|
||||||
|
:require-match t
|
||||||
|
:sort nil
|
||||||
|
:action (lambda (data)
|
||||||
|
(ivy-pass--async-commands
|
||||||
|
(ivy-pass--get-commands
|
||||||
|
entry
|
||||||
|
(cdr data)))))))
|
||||||
|
|
||||||
(defvar ivy-pass-map
|
(defvar ivy-pass-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map (kbd "M-a") #'ivy-pass--type-autotype-command)
|
(define-key map (kbd "M-a") #'ivy-pass--autotype-command)
|
||||||
(define-key map (kbd "M-p") #'ivy-pass--type-password-command)
|
(define-key map (kbd "M-p") #'ivy-pass--password-command)
|
||||||
(define-key map (kbd "M-u") #'ivy-pass--type-username-command)
|
(define-key map (kbd "M-u") #'ivy-pass--username-command)
|
||||||
(define-key map (kbd "M-U") #'ivy-pass--type-url-command)
|
(define-key map (kbd "M-U") #'ivy-pass--url-command)
|
||||||
|
(define-key map (kbd "M-f") #'ivy-pass--fields-command)
|
||||||
map))
|
map))
|
||||||
|
|
||||||
|
(defvar ivy-pass-history nil
|
||||||
|
"History for `ivy-pass'")
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun ivy-pass ()
|
(defun ivy-pass ()
|
||||||
(interactive)
|
(interactive)
|
||||||
|
|
@ -189,10 +220,11 @@ SEQUENCE is a list of the following elements:
|
||||||
:history 'ivy-pass-history
|
:history 'ivy-pass-history
|
||||||
:keymap ivy-pass-map
|
:keymap ivy-pass-map
|
||||||
:action '(1
|
:action '(1
|
||||||
("p" ivy-pass--type-password-action "password")
|
("p" ivy-pass--password-action "password")
|
||||||
("a" ivy-pass--type-autotype-action "autotype")
|
("a" ivy-pass--autotype-action "autotype")
|
||||||
("u" ivy-pass--type-username-action "username")
|
("f" ivy-pass--fields-action "fields")
|
||||||
("U" ivy-pass--type-url-action "url"))
|
("u" ivy-pass--username-action "username")
|
||||||
|
("U" ivy-pass--url-action "url"))
|
||||||
:caller #'ivy-pass))
|
:caller #'ivy-pass))
|
||||||
|
|
||||||
(provide 'ivy-pass)
|
(provide 'ivy-pass)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue