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

Add customization keywords #508

Merged
merged 2 commits into from Nov 20, 2017

Conversation

canatella
Copy link
Contributor

Hello,

This PR adds two new keyword: :customize and :custom-faces. These are shortcuts to cleanup calls to customize-set-variable and custom-set-faces'in the :config part. I do not use the Emacs internal save to custom.el setup because it's not easy to track in version control. I prefer to keep my package configuration in one place and these two keywords make this easier.

(use-package comint
  :customize
  (comint-buffer-maximum-size 20000 "Increase comint buffer size.")
  (comint-prompt-read-only t "Make the prompt read only."))

(use-package eruby-mode
  :custom-faces
  (eruby-standard-face ((t (:slant italic)))))

The comments are not mandatory for the :customize keyword.

I don't know if you would be willing to add these kind of keywords, so this PR is more about asking if theses features would be of interest for you to merge as I don't think this PR can be merged as is. I'm not sure about the normalizing function. They do not look like the other one because I did not really understood them, so I simply wrote ones that did the trick.

@jwiegley
Copy link
Owner

OK, this is a pretty brilliant idea, thank you! Have you signed copyright papers to the FSF? That's now a requirement, since we're soon to merge into Emacs core.

@canatella
Copy link
Contributor Author

Nope, where should I start for the assignment ? Should I ask on emacs-devel as suggested in the Emacs manual ?

@jwiegley
Copy link
Owner

Send an e-mail to assign@gnu.org and they'll get you sorted out. Thanks!

use-package.el Outdated

(defun use-package-normalize/:customize (name-symbol keyword arg)
"Normalize use-package customize keyword."
(let ((error-msg (format "%s wants a (<symbol> <form> <optional string comment>) or list of these" name-symbol)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: extraneous space after format.

use-package.el Outdated
(dolist (def arg arg)
(unless (listp def)
(use-package-error error-msg))
(seq-let [variable value comment] def
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emacs 24 and older do not include seq.el.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there some other form of destructuring binding I could use ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could try cl-destructuring-bind?

use-package.el Outdated
"Generate use-package customize keyword code."
(let ((body (use-package-process-keywords name rest state)))
(use-package-concat
(seq-map (lambda (def)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming seq.el is available, is there a reason to prefer seq-map over mapcar here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I finally have a nice sequence elisp library, I cannot use it anymore ;) I'm just using the seq-* function in my elisp because they seem more modern then the old disparate functions, but I understand the point here and will switch to mapcar.

use-package.el Outdated

(defun use-package-normalize/:custom-faces (name-symbol keyword arg)
"Normalize use-package custom-faces keyword."
(let ((error-msg (format "%s wants a (<symbol> <face-spec>) or list of these" name-symbol)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto re: extraneous space.

@canatella canatella force-pushed the add-customization-keywords branch 2 times, most recently from 1a485c8 to b1ca822 Compare October 18, 2017 12:42
@canatella
Copy link
Contributor Author

Ok, so I

  • replaced seq-map by mapcar,
  • replaced seq-let by cl-destructuring bind,
  • and removed the extra spaces.

I also contacted assign@gnu.org for the paper work.

use-package.el Outdated
(dolist (def arg arg)
(unless (listp def)
(use-package-error error-msg))
(cl-destructuring-bind (&optional variable value comment) def
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cl-destructuring-bind is a macro defined in cl-macs.el, so you will need to (eval-when-compile (require 'cl-macs)). I do not, however, think this is the best destructuring option here, as it will throw a non-use-package-specific wrong-number-of-arguments error if def has more elements than it is being destructured into (this also makes the (> (length def) 3) check further down redundant).

I suggest using pcase-let instead:

(pcase-let ((`(,variable ,value ,comment) def))
  ;; ...
  )

This has the added benefit of introducing no further dependencies (apart from the existing Emacs24+ requirement).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(eval-when-compile (require 'cl-macs))

FYI, it should rather be (eval-when-compile (require 'cl-lib)) (e.g., see https://lists.gnu.org/archive/html/emacs-devel/2014-01/msg01003.html).

I suggest using pcase-let instead:

Hmm, I'm not sure that one deals well with a different number of arguments either:

(pcase-let BINDINGS &rest BODY)

Like ‘let’ [...]
The macro is expanded and optimized under the assumption that those
patterns *will* match, so a mismatch may go undetected or may cause
any kind of error.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I always feared that might be the case re: cl-macs so thanks for confirming it. :)

My reading of the pcase and pcase-let documentation is that a backquote-style QPAT list pattern will always match, regardless of the length of the list being matched against. In other words, I think the pcase-let docstring is warning against more obvious infractions like (pcase-let (((and (pred listp) l) "wut"))), which don't match but which pcase would happily skip.

Maybe I'm wrong about this, and maybe destructuring isn't worth the trouble for such simple validation checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a backquote-style QPAT list pattern will always match, regardless of the length of the list being matched against.

Well if that were true, how would you distinguish between different list lengths? Perhaps noting that `(,one ,two ,three) is a shorthand for `(,one ,two ,three . nil) might make it clearer:

(mapcar (lambda (x)
          (pcase x
            (`(,one ,two ,three . nil) (list :exactly-three-args one two three))
            (`(,one ,two ,three . ,rest) (list :more-than-three-args one two three rest))
            (_ (list :less-than-three-args x))))
        '((1) (1 2) (1 2 3) (1 2 3 4)))
;=>
((:less-than-three-args
  (1))
 (:less-than-three-args
  (1 2))
 (:exactly-three-args 1 2 3)
 (:more-than-three-args 1 2 3
                        (4)))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going with

(let ((var (car def))
      (val (cadr def))
      (com (caadr def)) ...)

then ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean (caddr def), but otherwise seems fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, that proves what's nice about destructuring bind ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@npostavs I see, thanks for clarifying.

@canatella I don't think Emacs 24 has caddr yet. Why not just use nth for all of them? That way you afford a tiny bit more destructuring clarity.

@canatella
Copy link
Contributor Author

I replaced the destructuring bind with a good old let.

@canatella
Copy link
Contributor Author

Indeed, nth keeps a bit of the destructuring clarity. Replaced ca*dr with nth.

@canatella
Copy link
Contributor Author

Hello,

No answer from assign@gnu.org for 2 days, does it always take a bit of time, or should I try contacting them again ?

@canatella
Copy link
Contributor Author

Another thing, wouldn't it be better to customize at :init rather then :config ? I have a problem here with exec-path-from-shell which needs the exec-path-from-shell-variables to be setup before calling exec-path-from-shell-initialize.

This is not working with the current code:

(use-package exec-path-from-shell
  :ensure t
  :customize
  (exec-path-from-shell-variables
   '("PATH" "MANPATH" "ANDROID_HOME" "ANDROID_NDK_HOME"))
  :config
  (when (memq window-system '(mac ns x))
    (exec-path-from-shell-initialize)))

While this is

(use-package exec-path-from-shell
  :ensure t
  :customize
  :config
  (when (memq window-system '(mac ns x))
    (let ((exec-path-from-shell-variables
           '("PATH" "MANPATH" "ANDROID_HOME" "ANDROID_NDK_HOME")))
      (exec-path-from-shell-initialize))))

works as expected.

@npostavs
Copy link
Contributor

No answer from assign@gnu.org for 2 days, does it always take a bit of time, or should I try contacting them again ?

I think it was something like 30 days when I did it.

@canatella
Copy link
Contributor Author

Well, let's wait then...

@basil-conto
Copy link
Contributor

I did mine pretty recently - I was sent the form within a day or two and then it was confirmed a couple of weeks later.

@alphapapa
Copy link

I did the CA recently and got responses within 24 hours IIRC. But AFAIK there's only one person who does that job, so I guess he's busier at some times than others.

@canatella
Copy link
Contributor Author

Hello, the copyright assignment procedure is done, so we can go on but I have discovered a problem in my config though.

As is, this patch sets the custom variables at :config time. It's a problem for the exec-path-from-shell package which expects the variable exec-path-from-shell-variables to be set before it is required. Is it a problem with the package, or should the variables be set at :init time instead?

@jwiegley
Copy link
Owner

jwiegley commented Nov 8, 2017

I believe they should be set at :init time, as regular customizations are.

@canatella
Copy link
Contributor Author

I've modified the keyword order so that the customizations are done just before :init. The exec-path-from-shell package is now working correctly.

@dieggsy
Copy link

dieggsy commented Nov 9, 2017

@canatella should :customize be :custom-variables for consistency? (I would even consider :custom-set-variables and :custom-set-faces for clarity, though those are pretty wordy)

@canatella
Copy link
Contributor Author

I asked myself that question too. While I agree with you on the need for keyword consistency, I think that the `:custom-face' one would be much less used and keeping keyword length reasonable is nice.

What do other reviewers here think ?

@jwiegley
Copy link
Owner

jwiegley commented Nov 9, 2017

I prefer :custom and :custom-face.

Allows customization of variable using customize-set-variables. This makes it
easier to manage customization in version control. Instead of having all the
variables written in a custom.el, the variable can be customized where the rest
of the package is configured.
Allows customization of faces using customize-set-faces. This makes it
easier to manage customization in version control. Instead of having all the
faces written in a custom.el, the faces can be customized where the rest
of the package is configured.
@canatella
Copy link
Contributor Author

Good compromise, I made the change.

@dieggsy
Copy link

dieggsy commented Nov 19, 2017

@jwiegley @canatella any news on this?

@jwiegley jwiegley merged commit 41f61a1 into jwiegley:master Nov 20, 2017
@jwiegley
Copy link
Owner

Thank you for a great addition!

jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 24, 2022
jollaitbot pushed a commit to sailfishos-mirror/emacs that referenced this pull request Nov 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants