\documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_return_true: } { \tl_if_in:nnTF {#2#1} { ! } \prg_return_true: \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} \documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_return_true: } { \tl_if_in:nnTF {#2} { ! } \prg_return_true: \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} \documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_return_true: } { \tl_if_in:nnTF {#1} { ! } \prg_return_true: \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} \documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_break:n { \prg_return_true: } } { \tl_if_in:nnTnnTF {#1#2} { ! } { \prg_break:n { \prg_return_true: } } } \prg_return_false: \prg_break_point:} } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} \documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_break:n { \prg_return_true: } } { \tl_if_in:nnT {#1} { ! } { \prg_break:n { \prg_return_true: } } } \prg_return_false: \prg_break_point: } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} \documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_return_true: } { \tl_if_in:nnTF {#2} { ! } \prg_return_true: \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} This however doesn't throw any error on unknown keys. TikZ has a mechanism that determines whether something might be a colour which we can implement ourselves as well. We assume that everything that's a named colour is a colour (duh!) and that everything that contains an ! is a colour expression.
\documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_break:n { \prg_return_true: } } { \tl_if_in:nnT {#1} { ! } { \prg_break:n { \prg_return_true: } } } \prg_return_false: \prg_break_point: } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} This however doesn't throw any error on unknown keys. TikZ has a mechanism that determines whether something might be a colour which we can implement ourselves as well. We assume that everything that's a named colour is a colour (duh!) and that everything that contains an ! is a colour expression.
\documentclass{article} \usepackage{xcolor} \ExplSyntaxOn \msg_new:nnn { skyrmion / mwe } { unknown-key } { The~ key~ \l_keys_key_str\c_space_tl is~ unknown~ and~ is~ being~ ignored. } \keys_define:nn { skyrmion / mwe } { color .tl_set:N = \l__skyrmion_color_tl, color .initial:n = black, text .tl_set:N = \l__skyrmion_text_tl, unknown .code:n = \tl_if_novalue:nTF {#1} { \__skyrmion_if_colour:VTF \l_keys_key_str { \tl_set_eq:NN \l__skyrmion_color_tl \l_keys_key_tl } { \msg_error:nn { skyrmion / mwe } { unknown-key } } } { \msg_error:nn { skyrmion / mwe } { unknown-key } } ,unknown .default:V = \c_novalue_tl } \prg_new_protected_conditional:Npnn \__skyrmion_if_colour:n #1 { TF } { \cs_if_exist:cTF { \c_backslash_str color @ #1 } { \prg_break:n { \prg_return_true: } } { \tl_if_in:nnT {#1} { ! } { \prg_break:n { \prg_return_true: } } } \prg_return_false: \prg_break_point: } \prg_generate_conditional_variant:Nnn \__skyrmion_if_colour:n { V } { TF } \NewDocumentCommand \skyrmion { O{} } { \keys_set:nn { skyrmion / mwe } {#1} \textcolor {\l__skyrmion_color_tl} {\l__skyrmion_text_tl} } \ExplSyntaxOff \begin{document} \skyrmion[color = red, text = {Hello, \LaTeX}] \skyrmion[red, text = {Hello, \LaTeX}] \end{document} lang-tex