FG42/lib/fg42/extension.el

100 lines
3.0 KiB
EmacsLisp

;;; extension --- Extension library of FG42
;;; Commentary:
;;; Code:
;; This library provides some basic means to create a new FG42 extensions
(require 'cl-lib)
;; Variables -----------------------------
(defvar activated-extensions ()
"A list of all activated extensions.")
(defvar disabled-abilities (make-hash-table)
"A hash of all the disabled abilities.")
;; TODO: add a function to extension structure to support for
;; external dependenies list
;; Structures -----------------------------
(cl-defstruct fg42-extension
"Each FG42 extension should implement a copy of this structure."
name
docs
(version nil)
;; Describes
(major-modes nil)
;; Callbacks
(on-initialize nil)
(on-load)
;; An associated array of major modes to their
;; debugger function
(print-debugger nil))
;; Functions ------------------------------
(defun active-ability? (name)
"Return t if ability with the given NAME was not in disabled-abilities."
(if (gethash name disabled-abilities) nil t))
(defun disable (&rest abilities)
"Add the given ABILITIES to disabled-abilities hash."
(dolist (abl abilities)
(puthash abl t disabled-abilities)))
;; Macros ---------------------------------
(defmacro ability (name deps &rest body)
"Define an ability with the given NAME, DEPS, and BODY.
*deps* should be a list of abilities with the defined ability dependens
to them.
*body* is a block of code which will run as the ability initializer code."
(declare (doc-string 2) (indent 0))
`(if (active-ability? (intern ,(symbol-name name)))
(when (null (delq t (mapcar 'active-ability? (quote ,deps))))
,@body)))
(defmacro defability (name deps &optional docs &rest body)
"Define an ability with the given NAME, DEPS, DOCS and BODY.
*deps* should be a list of abilities with the defined ability dependens
to them.
*body* is a block of code which will run as the ability initializer code."
(declare (doc-string 3) (indent 2))
;; TODO: there's no point of using `if' in the quoted code. evaluate
;; the `if' in compile time and return nil or evalute the body.
`(if (active-ability? (intern ,(symbol-name name)))
(when (null (delq t (mapcar 'active-ability? (quote ,deps))))
,@body)))
(defmacro extension (name &rest args)
"A simple DSL to define new fg42 extension by given NAME and ARGS."
;(declare (doc-string 1) (indent 1))
`(setq ,name (apply 'make-fg42-extension :name ,(symbol-name name) (quote ,args))))
(defmacro with-ability (name &rest body)
"If the ability with the given NAME is not disabled, Run the BODY."
`(when (active-ability? (intern ,(symbol-name name)))
,@body))
(defun describe-extension (extension)
"Show the doc-string of the EXTENSION."
(interactive)
(let ((doc-file (fg42-extension-docs (symbol-value extension)))
(b (get-buffer-create (concat "*" (symbol-name extension) " docs*"))))
(set-buffer b)
(insert-file-contents (concat fg42-home "/" doc-file))
(read-only-mode t)
(switch-to-buffer b)
(org-mode)))
(provide 'fg42/extension)
;;; extension ends here