2020-10-24 18:59:50 +01:00
|
|
|
;;; Cube --- Cube library of FG42 -*- lexical-binding: t; -*-
|
|
|
|
;;
|
2022-07-01 18:27:21 +01:00
|
|
|
;; Copyright (c) 2010-2022 Sameer Rahmani & Contributors
|
2020-10-24 18:59:50 +01:00
|
|
|
;;
|
|
|
|
;; Author: Sameer Rahmani <lxsameer@gnu.org>
|
|
|
|
;; URL: https://gitlab.com/FG42/FG42
|
|
|
|
;; Version: 3.0.0
|
|
|
|
;;
|
|
|
|
;; 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 <http://www.gnu.org/licenses/>.
|
|
|
|
;;
|
|
|
|
;;; Commentary:
|
|
|
|
;; Cubes are the building blocks of any `FG42' editor. Each `cube' is a
|
|
|
|
;; unit which defines different abilities in a deterministic and idempotent
|
|
|
|
;; way. Cubes are composable and a composition of cubes creates an editor.
|
|
|
|
;;
|
|
|
|
;;; Code:
|
2020-10-24 21:44:12 +01:00
|
|
|
(require 'seq)
|
2020-10-24 18:59:50 +01:00
|
|
|
(require 'fg42/utils)
|
2021-01-29 00:16:46 +00:00
|
|
|
|
2021-12-19 15:18:21 +00:00
|
|
|
(defvar fg42/after-cubes-setup-hook nil
|
|
|
|
"A hook that will be run after all the active cubes got setup. This hook
|
|
|
|
is dedicated for the codes that needs to do stuff based on other cubes
|
|
|
|
presence. With this hook we eliminate the need for cube ordering.
|
|
|
|
|
|
|
|
It will be called in the `fg42-config' and the proper way to use
|
|
|
|
it is to use `fg42/after-cubes' macro. ")
|
|
|
|
|
2021-01-29 00:16:46 +00:00
|
|
|
|
2021-10-12 00:35:05 +01:00
|
|
|
(defvar fg42/available-cubes '()
|
|
|
|
"A list of all the registered cubes.")
|
|
|
|
|
|
|
|
|
|
|
|
(defmacro defcube (cube-name docs props &rest body)
|
|
|
|
"Define a cube with the given CUBE-NAME, a list of PROPS, DOCS and a BODY."
|
|
|
|
(declare (indent defun) (doc-string 2))
|
2021-04-18 16:10:02 +01:00
|
|
|
|
|
|
|
;; Make sure that props is a plist and contains the `:docs' key
|
|
|
|
;; TODO: Maybe use `cl-check-type' here
|
2021-10-12 00:35:05 +01:00
|
|
|
(when (not (stringp docs))
|
|
|
|
(error "Missing docstring for '%s' cube" cube-name))
|
|
|
|
|
|
|
|
(when (not (plist-get props :title))
|
|
|
|
(error "Missing :titel key for '%s' cube" cube-name))
|
2021-04-18 16:10:02 +01:00
|
|
|
|
2021-10-12 00:35:05 +01:00
|
|
|
(let ((complete-props (plist-put props :docs docs))
|
|
|
|
(cube-name-internal (intern (format "%s-internal" cube-name)))
|
2021-05-03 01:42:57 +01:00
|
|
|
(params-var (intern (format "%s-params" cube-name)))
|
2021-04-18 13:33:39 +01:00
|
|
|
(active-var (intern (format "%s-active-p" cube-name)))
|
|
|
|
(pre-lang-server-up-hook (intern (format "%s-pre-lang-server-up-hook" cube-name)))
|
|
|
|
(post-lang-server-up-hook (intern (format "%s-post-lang-server-up-hook" cube-name)))
|
|
|
|
(pre-lang-server-down-hook (intern (format "%s-pre-lang-server-down-hook" cube-name)))
|
2021-04-18 13:36:52 +01:00
|
|
|
(post-lang-server-down-hook (intern (format "%s-post-lang-server-down-hook" cube-name)))
|
|
|
|
(pre-init-hook (intern (format "%s-pre-init-hook" cube-name)))
|
2021-05-03 01:42:57 +01:00
|
|
|
(post-init-hook (intern (format "%s-post-init-hook" cube-name)))
|
|
|
|
(post-init-hook (intern (format "%s-post-init-hook" cube-name)))
|
|
|
|
|
|
|
|
(flag-var (or (plist-get props :flag) cube-name))
|
|
|
|
(flag-docstring-var (or (plist-get props :flag-doc)
|
|
|
|
(format "The flag to enable/disable the '%s' cube." cube-name)))
|
2021-05-07 15:04:14 +01:00
|
|
|
(flag-default (plist-get props :flag-default))
|
|
|
|
(flag-conflict (plist-get props :conflicts-with))
|
2021-05-03 01:42:57 +01:00
|
|
|
(no-flag? (or (plist-get props :no-flag) ())))
|
2021-04-18 13:33:39 +01:00
|
|
|
|
2021-10-12 00:35:05 +01:00
|
|
|
(add-to-list 'fg42/available-cubes cube-name)
|
|
|
|
|
2021-03-06 10:07:27 +00:00
|
|
|
`(progn
|
2021-05-03 01:42:57 +01:00
|
|
|
|
|
|
|
;; Create a new flag for each cube to control the cubes systemwide.
|
|
|
|
(when (not ,no-flag?)
|
2021-12-19 15:18:21 +00:00
|
|
|
(defflag ,flag-var ,flag-docstring-var ,flag-default))
|
2021-05-03 01:42:57 +01:00
|
|
|
|
2021-04-18 13:33:39 +01:00
|
|
|
;; Params variable contains the list of params the is passed to
|
|
|
|
;; the current cube call
|
2021-03-06 10:07:27 +00:00
|
|
|
(defvar ,params-var nil
|
|
|
|
,(format "Parameters for the '%s' cube." cube-name))
|
2021-04-18 13:33:39 +01:00
|
|
|
|
|
|
|
;; * Hooks
|
|
|
|
|
|
|
|
;; This hook can be used by others to run code just before running that
|
|
|
|
;; code body
|
|
|
|
(defvar ,pre-init-hook nil
|
|
|
|
,(format "The hook that runs befor the '%s' cube initialization." cube-name))
|
|
|
|
|
|
|
|
|
|
|
|
;; This hook can be used by others to run code just after the body of
|
|
|
|
;; the cube
|
|
|
|
(defvar ,post-init-hook nil
|
|
|
|
,(format "The hook that runs after the '%s' cube initialization." cube-name))
|
|
|
|
|
|
|
|
|
|
|
|
;; TODO: Move language server related hooks to lang-server
|
|
|
|
;; TODO: Provide a way to let different parts of the
|
|
|
|
;; codebase to create cube hooks
|
|
|
|
|
|
|
|
;; ** Language Server
|
|
|
|
;;; The hook that enables users to change the language server configuration
|
|
|
|
;;; of the current cube before activating the server
|
|
|
|
(defvar ,pre-lang-server-up-hook nil
|
|
|
|
,(format "The hook that runs befor the '%s' cube's language server activates ." cube-name))
|
|
|
|
|
|
|
|
;;; The hook to do any post configuration for the lang server of the cube
|
|
|
|
(defvar ,post-lang-server-up-hook nil
|
|
|
|
,(format "The hook that runs after the '%s' cube's language server activates." cube-name))
|
|
|
|
|
|
|
|
;;; The hook to run code just before the language server is about to shutdown
|
|
|
|
(defvar ,pre-lang-server-down-hook nil
|
|
|
|
,(format "The hook that runs befor the '%s' cube's language server shuts down." cube-name))
|
|
|
|
|
|
|
|
;;; The hook to run code after the language server successfully shuts down
|
|
|
|
(defvar ,post-lang-server-down-hook nil
|
|
|
|
,(format "The hook that runs after the '%s' cube's language server shuts down." cube-name))
|
|
|
|
|
2021-05-03 01:42:57 +01:00
|
|
|
;; This way we can bypass the flag system if we really really want to.
|
|
|
|
(defun ,cube-name-internal (params)
|
2021-05-16 11:15:29 +01:00
|
|
|
(if (or (not (boundp (quote ,active-var)))
|
|
|
|
(not ,active-var))
|
2021-05-03 01:42:57 +01:00
|
|
|
(progn
|
|
|
|
;; Mark this cube as active
|
|
|
|
(setq ,active-var t)
|
|
|
|
|
|
|
|
;; Set the parameters in CUBE-NAME-params to be accessable
|
|
|
|
;; in the body
|
|
|
|
(setq ,params-var params)
|
|
|
|
|
|
|
|
;; Run the pre init hook
|
|
|
|
(run-hooks (quote ,pre-init-hook))
|
|
|
|
|
2021-12-12 19:51:09 +00:00
|
|
|
(fg42/info "Initializing '%s' cube." (quote ,cube-name))
|
2021-05-03 01:42:57 +01:00
|
|
|
;; Run the body
|
|
|
|
(let ((result (progn ,@body)))
|
|
|
|
;; Run the post init hook
|
|
|
|
(run-hooks (quote ,post-init-hook))
|
2021-05-07 16:03:33 +01:00
|
|
|
result))
|
2021-12-12 19:51:09 +00:00
|
|
|
(fg42/info "The '%s' cube is already active." ',cube-name)))
|
2021-04-18 13:33:39 +01:00
|
|
|
|
2021-03-06 10:07:27 +00:00
|
|
|
(defun ,cube-name (&rest params)
|
2021-05-03 01:42:57 +01:00
|
|
|
(interactive)
|
|
|
|
(if ,no-flag?
|
|
|
|
;; If no flag is need to control this cube
|
|
|
|
(,cube-name-internal params)
|
|
|
|
;; Otherwise check for the flag to be active
|
|
|
|
(if-flag ,flag-var
|
|
|
|
(,cube-name-internal params)
|
2021-12-12 19:51:09 +00:00
|
|
|
(fg42/info "The flag for '%s' cube is disabled. Skiping." ,(symbol-name cube-name)))))
|
2021-10-12 00:35:05 +01:00
|
|
|
|
|
|
|
;; Set the symbol-plist of the cube-name to its props
|
|
|
|
(setplist ',cube-name ',complete-props))))
|
2020-10-24 18:59:50 +01:00
|
|
|
|
|
|
|
|
2021-12-19 15:18:21 +00:00
|
|
|
(defmacro fg42/after-cubes (&rest body)
|
|
|
|
"Add the BODY to `fg42/after-cubes-setup-hook' hook."
|
|
|
|
(declare (indent defun))
|
|
|
|
`(add-hook 'fg42/after-cubes-setup-hook
|
|
|
|
(lambda ()
|
|
|
|
,@body)))
|
|
|
|
|
|
|
|
|
2020-10-24 18:59:50 +01:00
|
|
|
(provide 'fg42/cube)
|
|
|
|
;;; cube.el ends here
|