diff --git a/core/fg42/cube.el b/core/fg42/cube.el new file mode 100644 index 0000000..d902892 --- /dev/null +++ b/core/fg42/cube.el @@ -0,0 +1,77 @@ +;;; Cube --- Cube library of FG42 -*- lexical-binding: t; -*- +;; +;; Copyright (c) 2010-2020 Sameer Rahmani & Contributors +;; +;; Author: Sameer Rahmani +;; 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 . +;; +;;; 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: + +(require 'seq) +(require 'fg42/utils) +(require 'fg42/state) + + +(defun fg42/cube-apply (state cube) + "Apply the given CUBE to the given STATE. +It returns a new state." + state) + + +(defun fg42/cube-bind (m1 m2) + "Bind the M1 to M2. +M1 and M2 are state monads. See `fg42/utils'" + (lambda (state) + (let* ((v (funcall cube1 state))) + (funcall cube2 + (fg42/cube-apply + ;; State + (car v) + ;; Value of in the monad from M + (cdr v)))))) + + +(defun fg42/cube-compose (cube1 cube2) + "Compose CUBE1 and CUBE2 to create a new cube. +For example `(fg42/cube-compose #\'some-cube #\'some-other-cube)'" + (lambda () + (fg42/cube-bind + (funcall cube1) + (funcall cube2)))) + + +(defun fg42/cube-identity () + "Cube identity function." + (lambda (state) + (cons state '()))) + + +(defun fg42/cubes (&rest cubes) + "Create a new cube out of the given list of CUBES." + (seq-reduce (lambda (cube1 cube2) + (fg42/cube-bind cube1 cube2)) + cubes + (fg42/cube-identity))) + + +(provide 'fg42/cube) +;;; cube.el ends here diff --git a/core/fg42/state.el b/core/fg42/state.el new file mode 100644 index 0000000..eb06b0b --- /dev/null +++ b/core/fg42/state.el @@ -0,0 +1,84 @@ +;; State --- State library of FG42 -*- lexical-binding: t; -*- +;; +;; Copyright (c) 2010-2020 Sameer Rahmani & Contributors +;; +;; Author: Sameer Rahmani +;; 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 . +;; +;;; 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: +(require 'fg42/utils) + + +(defun fg42/state-return (x) + "Return a state monad containing X." + (lambda (state) + (cons state x))) + + +(defun fg42/state-bind-maker (binder-fn) + "Return a bind function for state monad. +It creates a bind function that binds monadic functions by applying BINDER-FN +to the return state and the value inside the monad before binding them. + +The BINDER-FN has to return a cons in form of (state . prev-v)." + (lambda (m f) + "Applys F on the M monad." + (lambda (state) + (let* ((v (funcall m state)) + (new-v (funcall (f (cdr v)) (car v)))) + (funcall binder-fn + ;; State + (car new-v) + ;; Value of in the monad from M + (cdr new-v)))))) + + +(defun fg42/state-unit () + "Create a new state monad. +This monad describes the entire editor configuration" + ;; Why not a cl-struct ? + ;; Because first, we want it to be human readable + (lambda (state) + (cons + (list '(:mode->keybindings . ()) + '(:mode->prefix . ()) + '(:mode->fn . ()) + '(:cubes . ())) + ()))) + + +(defun fg42/state-get (k &optional default) + "Return the value of the given K from the STATE. +It will return DEFAULT in case of a missing key." + (lambda (state) + (or (cdr (assoc k state)) default))) + + + +(defun fg42/state-cons (k v) + "Add the given value V to the list addressed by key K on STATE." + (lambda (state) + (cons (cons k (cons v (or (fg42/state-get state k) '()))) state))) + + +(provide 'fg42/state) +;;; state.el ends here diff --git a/core/fg42/utils.el b/core/fg42/utils.el index 402fb59..ff180ea 100644 --- a/core/fg42/utils.el +++ b/core/fg42/utils.el @@ -129,5 +129,34 @@ or (last paths)))) +(defmacro -> (x &optional form &rest more) + "Thread the expr through the forms FORM and rest of form in MORE. +Insert X as the second item in the first form, making a list of +it if it is not a list already. If there are more forms, insert +the first form as the second item in second form, etc." + (declare (debug (form &rest [&or symbolp (sexp &rest form)]))) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,(car form) ,x ,@(cdr form)) + (list form x))) + (:else `(-> (-> ,x ,form) ,@more)))) + + +(defmacro ->> (x &optional form &rest more) + "Thread the expr through the forms FORM and the rest at MORE. +Insert X as the last item in the first form, making a list of +it if it is not a list already. If there are more forms, insert +the first form as the +last item in second form, etc." + (declare (debug ->)) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,@form ,x) + (list form x))) + (:else `(->> (->> ,x ,form) ,@more)))) + + (provide 'fg42/utils) ;;; utils.el ends here diff --git a/lib/fg42/wm.el b/lib/fg42/wm.el index 3f3c732..4868d06 100644 --- a/lib/fg42/wm.el +++ b/lib/fg42/wm.el @@ -84,6 +84,7 @@ ;; Bind "s-r" to exit char-mode and fullscreen mode. ([?\s-r] . exwm-reset) ([?\s-g] . keyboard-quit) + ([8388640] . other-window) ;; Bind "s-w" to switch workspace interactively. ([?\s-w] . exwm-workspace-switch) ;; Bind "s-0" to "s-9" to switch to a workspace by its index. diff --git a/lib/fpkg.el b/lib/fpkg.el index eddd285..8386f70 100644 --- a/lib/fpkg.el +++ b/lib/fpkg.el @@ -125,7 +125,6 @@ `(fg42-install-extension ,(eval pkgname)) `(use-package ,(eval pkgname) ,@details))) - (defun depends-on (pkgname &rest args) "Install the package PKGNAME with respect to the ARGS." (let ((pkg (apply 'make-fpkg-dependency :name pkgname args)))