Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLOS-style configuration #484

Closed
wants to merge 3 commits into from
Closed

CLOS-style configuration #484

wants to merge 3 commits into from

Conversation

Ambrevar
Copy link
Member

@Ambrevar Ambrevar commented Nov 7, 2019

This should mostly fix #419.

Example init.lisp:

(defclass my-interface (remote-interface)
  ((download-directory :initform "~/temp")))

(setf *remote-interface-class* 'my-interface)

That's it!
Note that we can combine class settings by using multiple inheritance.

This allows the user to easily subclass existing classes for use in Next.
Before we kept (make-instance 'minibuffer ...) because it gave us completion
over `minibuffer' initargs.
Since (make-instance *minibuffer-class* ...) does not complete its argument, we
are better off using a wrapper now.
@Ambrevar
Copy link
Member Author

Ambrevar commented Nov 7, 2019

As opposed to what I said in #419, we don't have proper type-checking over *window-class*, etc.
We could enable it with the following:

(defun window-class-symbol-p (class-symbol)
  (closer-mop:subclassp (find-class class-symbol)
                        (find-class 'window)))
(deftype window-type ()
  `(satisfies window-class-symbol-p))
(declaim (type (window-type) *window-class*))

But note that SBCL fails to perform compile-time type-checking on non-top-level symbols because of the satisfies.

I guess it's not a big deal. Question is: should I even bother with the deftype then?

@Ambrevar
Copy link
Member Author

As mentioned in #489, mode configuration still is a bit cumbersome. What about generating a *foo-mode-class* symbol that evalutes to 'foo-mode by default?

This way configuring the class defaults would look like this:

(defclass my-web-mode (web-mode)
  (keymap-schemes ...))

(setf *web-mode-class* 'my-web-mode)

Thoughts?

@jmercouris
Copy link
Member

I like the idea, but I feel like we could take it one step further using reader macros to possibly automate that whole process for the user... I need to think a little bit about it. As an aside, I am very much liking the CLOS style configuration, I think it is a fantastic idea!

@Ambrevar
Copy link
Member Author

Ambrevar commented Nov 11, 2019 via email

@jmercouris
Copy link
Member

I have reader macros in mind, I was thinking of a special syntax for people who are new, something to make things simple for them. On the other hand, maybe that is more suited to a *customize* buffer of sorts, and we only need provide an SEXP "API".

@Ambrevar
Copy link
Member Author

I have implemented the same configuration approach for modes.

Now mode defaults can be configured by define a subclass and then setting the
default class, e.g.

(setf *web-mode-class* 'my-web-mode)

@jmercouris
Copy link
Member

Nice!

@Ambrevar
Copy link
Member Author

Merged.
@vindarel: Let me know if there is anything you'd like to revert, no problem.

I'll update the documentation just now.

@vindarel
Copy link
Contributor

should I even bother with the deftype then?

yes if it catches errors when loading the init file.

@vindarel
Copy link
Contributor

vindarel commented Nov 20, 2019

I tried the example from the doc:

(defclass my-remote-interface ()
  ((search-engines :initform
    '(("default"
       "https://duckduckgo.com/?q=~a"
       "https://duckduckgo.com/")
      ("yt"
       "https://www.youtube.com/results?search_query=~a"
       "https://www.youtube.com/")
      ("wiki"
       "https://en.wikipedia.org/w/index.php?search=~a"
       "https://en.wikipedia.org/")))))

(setf *remote-interface-class* 'my-remote-interface)

and I get:

Error: we could not load the init file because of a type error.:
#<TYPE-ERROR expected-type: (SATISFIES REMOTE-INTERFACE-TYPE-P)
             datum: MY-REMOTE-INTERFACE>

on the setf.

The example probably lacks a class inheritance. edit: OK, fixed.

btw, if I'm not mistaken the type checks don't check slots types?

(defmacro define-class-type (class-sym)
  "Define a type named CLASS-SYM-type.
An object of this type is a subclass of CLASS-SYM."
  (let ((type-pred (intern (str:concat (string class-sym) "-TYPE-P")))
        (type-fun (intern (str:concat (string class-sym) "-TYPE"))))
    `(progn
       (defun ,type-pred (class-symbol)
         (closer-mop:subclassp (find-class class-symbol)
                               (find-class ',class-sym)))
       (deftype ,type-fun ()
         '(satisfies ,type-pred)))))

@vindarel
Copy link
Contributor

and I confirm for the missing type checks:

(defclass my-remote-interface (remote-interface)
  ((search-engines :initform
    '(("default"
       "https://duckduckgo.com/?q=~a"
       "https://duckduckgo.com/")
     ;; wrong:
      (42)))))

where search-engines is typed:

   (search-engines :accessor search-engines
                   :initform '(("default" "https://duckduckgo.com/?q=~a" "https://duckduckgo.com/")
                               ("wiki" "https://en.wikipedia.org/w/index.php?search=~a" "https://en.wikipedia.org/"))
                   :type alist-of-3tuples-strings
(setf *remote-interface-class* 'my-remote-interface)
MY-REMOTE-INTERFACE

should fail.

@jmercouris jmercouris deleted the wip-clos-config branch June 18, 2020 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Functional config & hooks
3 participants