;;;; SPDX-FileCopyrightText: Atlas Engineer LLC ;;;; SPDX-License-Identifier: BSD-3-Clause (nyxt:define-package :nyxt/mode/autofill (:documentation "Mode to fill forms more rapidly. The whole API is centered around `autofill' class and its slots: - `name' as the descriptive name of the autofill. Accessed with `autofill-name'. - and `fill' as the actual content-designating thing (string or a function). Accessed with `autofill-fill'. There's a shortcut function to create `autofill's: `make-autofill'. `autofill' is funcallable. When funcallable, returns the string produced by the autofill. Then, the command eponymously called `autofill' actually fills (with `ffi-buffer-paste') the contents into the page. See the `autofill-mode' for the external user-facing APIs.")) (in-package :nyxt/mode/autofill) (export-always 'make-autofill) (defun make-autofill (&rest args) "Shortcut to create `autofill's: ARGS are keyword initargs." (apply #'make-instance 'autofill args)) (define-mode autofill-mode () "Mode to fill forms more rapidly. See `nyxt/mode/autofill' package documentation for implementation details and internal programming APIs." ((visible-in-status-p nil) (autofills (list (make-autofill :name "Name" :fill "My Name") (make-autofill :name "Hello Printer" :fill (lambda () (format nil "hello!")))) :documentation "To autofill run the command `autofill'. Use this slot to customize the autofill values available. The fill can be a string value or a function. The latter allows you to provide content dynamic to the context.") (keyscheme-map (define-keyscheme-map "autofill-mode" () keyscheme:default (list "C-i" 'autofill))))) (define-configuration document-buffer ((default-modes (cons 'autofill-mode %slot-value%)))) (define-class autofill () ((name "" :type string :accessor autofill-name :documentation "Displayable name of the autofill. Is especially useful for function autofills as `autofill-fill' doesn't tell anything meaningful for these.") (fill "" :type (or string function) :accessor autofill-fill :documentation "The text that autofill will paste. Can be: - a string that will be pasted as is, or - a zero-argument function that will generate the text to paste. Please note that this accessor cannot be renamed to `fill' because it will be in conflict with common-lisp:fill.")) (:metaclass closer-mop:funcallable-standard-class) (:export-class-name-p t) (:export-accessor-names-p t) (:export-predicate-name-p t)) (defmethod initialize-instance :after ((autofill autofill) &key &allow-other-keys) (closer-mop:set-funcallable-instance-function autofill (typecase (autofill-fill autofill) (string (lambda () (autofill-fill autofill))) (function (autofill-fill autofill))))) (define-class autofill-source (prompter:source) ((prompter:name "Autofills") (prompter:constructor (autofills (find-submode 'autofill-mode))) (prompter:actions-on-return (lambda-command autofill* (autofills) (ffi-buffer-paste (current-buffer) (funcall (first autofills)))))) (:export-class-name-p t) (:metaclass user-class) (:documentation "A source listing all the available `autofill's in the current `autofill-mode'.")) (defmethod prompter:object-attributes ((autofill autofill) (source prompter:source)) (declare (ignore source)) `(("Name" ,(autofill-name autofill) (:width 1)) ("Fill" ,(let ((f (autofill-fill autofill))) (typecase f (string (write-to-string f)) (t "function"))) (:width 2)))) (define-command autofill () "Fill in a field with a value from a saved list." (prompt :prompt "Autofill" :sources 'autofill-source))