Rewrite using EIEIO
I've just pushed a new branch named eieio. It is a rewrite from scratch using EIEIO (see #2). Its functionality is minimal for now, but the code seem to be much cleaner than before, so I will continue to work on this branch. I won't continue development on the current mater branch.
The terminology in the README is no longer effective. It has been changed as follows:
- Instances of
frame-workflow-subjectclass (and its subclasses) correspond to "prototypes" in the previous version. frame-workflow-observerclass has been added. An object of this class is created for each frame managed by frame-workflow. It can hold frame-local states and handle notifications.
I will document these changes soon on the wiki.
The current version lacks some of the features that existed in the previous version. I have to (re-)implement the following features:
- [x] Add
frame-workflow-mode(which is a global minor mode) to add/remove hooks related to frame-workflow - [x] Support integration with frame-purpose
- [x] Allow customizing the layout
- [x] Editing a whole subject
- [ ] Persistence of subject
- [ ] Add support for frame-local commands (formerly actions)
- [ ] EXWM integration
frame-workflow-mode has been added. Now you have to turn on it before using any commands in frame-workflow. It also has a mode line (hopefully) got (almost) right. The previous mode line was done wrong, so I looked into the source code of projectile.
The following is a usage:
- Load
frame-workflow.el - Turn on
frame-workflow-mode - Use
frame-workflow-make-frame,frame-workflow-select-frame, orframe-workflow-switch-frameto switch the context
Readme in eieio branch has been updated.
Code looks really nice and clean, well-organized! :)
Your idea was great. I wouldn't be able to come up with it by myself. Thank you.
Now you can specify function to make a frame in a form of S expression (https://github.com/akirak/frame-workflow/commit/c7f92d5be8b209995d3ff669a7ffbd34d8206fa2). This allows you to integrate frame-workflow with frame-purpose concisely, as in the following example:
(frame-workflow-define-subject "emacs-lisp"
:make-frame '(frame-purpose-make-mode-frame 'emacs-lisp-mode))
I personally want to strip the quote symbol (') from the slot value, but I don't know how.
Cool!
To remove the quote, you'll need to make frame-workflow-define-subject a macro.
Thanks. It was a macro, but I mistakenly quoted its entire macro body. Fixed at https://github.com/akirak/frame-workflow/commit/3f62c81f8a2b331e6539712b236375d85b05cf3f
Possibly relevant section in the manual: https://www.gnu.org/software/emacs/manual/html_node/elisp/Problems-with-Macros.html#Problems-with-Macros
That's kind of awkward, because macros are intended to produce code at compile time. This macro isn't producing a Lisp form, so it's acting like a function at runtime. Also, if users call the macro in their config, and if they then byte-compile their config, it will probably produce errors or just not result in the desired behavior, because it will eval at compile time instead of runtime.
So, it should be converted into a function to require a quote? use-package doesn't require quotes in :init and :config, but I don't understand how it works.
I've added a new commit. How do you think of this solution? https://github.com/akirak/frame-workflow/commit/adb2399f6c24038c052b09fd5a709f0f94f97ebc
Well, I think that will work correctly, but you should test to make sure. ;) It's really up to you how badly you want to avoid using a quote in the call. If you want to avoid the quote, it should be a macro. If not, it can be a function. Generally, AFAIK, the accepted wisdom is that you shouldn't use a macro when a function will do. But if you want to avoid the quote, it will have to be a macro.
On the other hand, making it a macro means that it will be evaluated at compile time, and that actually removes a bit of flexibility from the user. If the user wants to pass a form to the :make-frame arg, then it's fine. But if the user wants the :make-frame arg to be evaluated before being passed to frame-workflow-define-subject, then it being a macro will make that more difficult, as the user would have to let-bind the arg outside the macro call.
If you were to ask me which is best, I would probably suggest making frame-workflow-define-subject a function, and letting users quote the argument to :make-frame if it's a form. That way it's very clear that frame-workflow-define-subject is called at runtime and the argument is evaluated immediately, unless quoted.
You might even cl-case the argument, so users could pass either a form or a function, like:
(frame-workflow-define-subject "emacs-lisp"
:make-frame #'user-make-frame-fn)
But only you know which is best, because it's your package. :) Hope this helps, rather than being confusing...
Thank you for your advice. I will make it a normal defun to allow programmatical use of the function. general.el defines general-define-key as a function but also defines general-def which is a macro that wraps the function as well as a few other functions. If it's necessary, I may add a shorthand like that.