使用 expl3(无 enumitem)创建自定义列表环境

使用 expl3(无 enumitem)创建自定义列表环境

我读过很多次,你不应该重新发明轮子,但有时你必须这样做。我正在尝试创建一个基于LaTeX 提供的基本环境的enumerate样式环境,而不使用mylistlistenumitem环境,而不使用该包。我可以处理基本参数,但是,我无法理解层次的嵌套

通过比较,我想要得到类似的东西:

预期的

我的代码如下:

\documentclass{article}
\usepackage{xparse}
\usepackage{enumitem}
\setlist[enumerate,1]{label= \arabic*., left=0pt, labelsep=5pt, itemsep=4pt, partopsep=2pt}
\setlist[enumerate,2]{leftmargin=16pt, itemsep=0pt, nosep, label=\Alph*)}
\setlength{\parindent}{0pt}

\ExplSyntaxOn
\newcounter{mycount}
\cs_new_eq:NN \__mylist_start_list:nn \list
\cs_new_eq:NN \__mylist_stop_list: \endlist
\tl_new:N \l_mylist_label_tl

\keys_define:nn { mylist }
  {
    label         .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                               \tl_put_right:Nx \l_mylist_label_tl
                                 { \exp_not:V \l_tmpa_tl },
    label         .initial:n = \arabic{mycount}.,
    itemsep       .dim_set:N = \l_mylist_itemsep_dim,
    itemsep       .initial:n = 0pt,
    itemindent    .dim_set:N = \l_mylist_itemindent_dim,
    itemindent    .initial:n = 0in,
    labelsep      .dim_set:N = \l_mylist_labelsep_dim,
    labelsep      .initial:n = 0.5em,
    leftmargin    .dim_set:N = \l_mylist_leftmargin_dim,
    leftmargin    .initial:n = 0in,
    rightmargin   .dim_set:N = \l_mylist_rightmargin_dim,
    rightmargin   .initial:n = 0pt,
    labelwidth    .dim_set:N = \l_mylist_labelwidth_dim,
    labelwidth    .initial:n =  \l_mylist_leftmargin_dim - \l_mylist_labelsep_dim,
    topsep        .dim_set:N = \l_mylist_topsep_dim,
    topsep        .initial:n = -0.3ex,
    parsep        .dim_set:N = \l_mylist_parsep_dim,
    parsep        .initial:n = 0pt,
    partopsep     .dim_set:N = \l_mylist_partopsep_dim,
    partopsep     .initial:n = 2pt,
    listparindent .dim_set:N = \l_mylist_listparindent_dim,
    listparindent .initial:n = 0.5in,
  }

\NewDocumentEnvironment{mylist}{ O{} }
  {
    \IfNoValueF{#1}{ \keys_set:nn { mylist } {#1} }
    \__mylist_start_list:nn
      { \tl_use:N \l_mylist_label_tl }
      {
        \usecounter{mycount}
        \dim_set:Nn \itemsep       { \l_mylist_itemsep_dim       }
        \dim_set:Nn \itemindent    { \l_mylist_itemindent_dim    }
        \dim_set:Nn \labelsep      { \l_mylist_labelsep_dim      }
        \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_dim    }
        \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_dim    }
        \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_dim   }
        \dim_set:Nn \topsep        { \l_mylist_topsep_dim        }
        \dim_set:Nn \parsep        { \l_mylist_parsep_dim        }
        \dim_set:Nn \partopsep     { \l_mylist_partopsep_dim     }
        \dim_set:Nn \listparindent { \l_mylist_listparindent_dim }
      }
  }
  {
    \__mylist_stop_list:
  }
\ExplSyntaxOff

\begin{document}
XXXX
\hrule
\begin{enumerate}
\item Using enumerate redefined by enumitem pkg
  \begin{enumerate}
    \item value second level
    \item value second level
    \item value second level
  \end{enumerate}
\end{enumerate}
\hrule
YYY
\begin{mylist}[leftmargin=0cm]
\item Using mylist environment nested here:
  \begin{mylist}
    \item value second level
    \item value second level
    \item value second level
  \end{mylist}
\end{mylist}
\hrule
\end{document}

我不知道如何创建和访问枚举的不同级别的嵌套。

第一次尝试:添加计数器并检测嵌套级别。

\documentclass{article}
\usepackage{xparse}
\usepackage{enumitem}
\setlist[enumerate,1]{label= \arabic*., left=0pt, labelsep=5pt, itemsep=4pt, partopsep=2pt}
\setlist[enumerate,2]{leftmargin=16pt, itemsep=0pt, nosep, label=\Alph*)}
\setlength{\parindent}{0pt}

\ExplSyntaxOn
\newcounter{mycounti}
\newcounter{mycountii}
\newcounter{mycountiii}
\int_new:N \l_mylist_level_int
\cs_new_eq:NN \__mylist_start_list:nn \list
\cs_new_eq:NN \__mylist_stop_list: \endlist
\tl_new:N \l_mylist_label_i_tl
\tl_new:N \l_mylist_label_ii_tl
\tl_new:N \l_mylist_label_iii_tl

% topsep partopsep parsep itemsep
\cs_new_protected:Npn \__mylist_vspace_keys:nnnnn #1#2#3#4#5
  {
    \keys_define:nn { mylist/level-#1 }
      {
        topsep        .dim_set:c = { l_mylist_topsep_#1_dim },
        topsep        .initial:n = {#2},
        partopsep     .dim_set:c = { l_mylist_partopsep_#1_dim },
        partopsep     .initial:n = {#3},
        parsep        .dim_set:c = { l_mylist_parsep_#1_dim },
        parsep        .initial:n = {#4},
        itemsep       .dim_set:c = { l_mylist_itemsep_#1_dim },
        itemsep       .initial:n = {#5},
      }
  }
\__mylist_vspace_keys:nnnnn { i  }{ 0cm }{ 0cm }{ 0cm }{ 0mm }
\__mylist_vspace_keys:nnnnn { ii }{ 0cm }{ 0cm }{ 0cm }{ 0mm }

% leftmargin rightmargin listparindent labelwidth labelsep itemindent
\cs_new_protected:Npn \__mylist_hspace_keys:nnnnnnn #1#2#3#4#5#6#7
  {
    \keys_define:nn { mylist/level-#1 }
      {
        leftmargin    .dim_set:c = { l_mylist_leftmargin_#1_dim },
        leftmargin    .initial:n = {#2},
        rightmargin   .dim_set:c = { l_mylist_rightmargin_#1_dim },
        rightmargin   .initial:n = {#3},
        listparindent .dim_set:c = { l_mylist_listparindent_#1_dim },
        listparindent .initial:n = {#4},
        labelwidth    .dim_set:c = { l_mylist_labelwidth_#1_dim },
        labelwidth    .initial:n = {#5},
        labelsep      .dim_set:c = { l_mylist_labelsep_#1_dim },
        labelsep      .initial:n = {#6},
        itemindent    .dim_set:c = { l_mylist_itemindent_#1_dim },
        itemindent    .initial:n = {#7},
      }
  }
\__mylist_hspace_keys:nnnnnnn {i }{ 0cm }{ 0cm }{ 0cm }{ 0.5in }{ 0.5em }{ 0cm }
\__mylist_hspace_keys:nnnnnnn {ii}{ 1cm }{ 0cm }{ 16pt }{ 0cm }{ 0.25cm }{ 0cm }

\cs_new_protected:Npn \__mylist_level_i_defns:
  {
    \usecounter{mycounti}
    \dim_set:Nn \itemsep       { \l_mylist_itemsep_i_dim       }
    \dim_set:Nn \itemindent    { \l_mylist_itemindent_i_dim    }
    \dim_set:Nn \labelsep      { \l_mylist_labelsep_i_dim      }
    \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_i_dim    }
    \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_i_dim  }
    \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_i_dim   }
    \dim_set:Nn \topsep        { \l_mylist_topsep_i_dim        }
    \dim_set:Nn \parsep        { \l_mylist_parsep_i_dim        }
    \dim_set:Nn \partopsep     { \l_mylist_partopsep_i_dim     }
    \dim_set:Nn \listparindent { \l_mylist_listparindent_i_dim }
  }

\cs_new_protected:Npn \__mylist_level_ii_defns:
  {
    \usecounter{mycountii}
    \dim_set:Nn \itemsep       { \l_mylist_itemsep_ii_dim       }
    \dim_set:Nn \itemindent    { \l_mylist_itemindent_ii_dim    }
    \dim_set:Nn \labelsep      { \l_mylist_labelsep_ii_dim      }
    \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_ii_dim    }
    \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_ii_dim  }
    \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_ii_dim   }
    \dim_set:Nn \topsep        { \l_mylist_topsep_ii_dim        }
    \dim_set:Nn \parsep        { \l_mylist_parsep_ii_dim        }
    \dim_set:Nn \partopsep     { \l_mylist_partopsep_ii_dim     }
    \dim_set:Nn \listparindent { \l_mylist_listparindent_ii_dim }
  }

% label
\keys_define:nn { mylist/level-i }
  {
    label .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                       \tl_put_right:Nx \l_mylist_label_i_tl { \exp_not:V \l_tmpa_tl },
    label .initial:n = \arabic{mycounti}.,
  }

\keys_define:nn { mylist/level-ii }
  {
    label .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                       \tl_put_right:Nx \l_mylist_label_ii_tl { \exp_not:V \l_tmpa_tl },
    label .initial:n = \Alph{mycountii}),
  }

\NewDocumentEnvironment{mylist}{ O{} }
  {
    \int_incr:N \l_mylist_level_int
    \IfNoValueF{#1}
      {
        \int_case:nn { \l_mylist_level_int }
          {
            {1} { \keys_set:nn { mylist / level-i  } {#1} }
            {2} { \keys_set:nn { mylist / level-ii } {#1} }
          }
      }
    \__mylist_start_list:nn
      {
        \int_case:nn { \l_mylist_level_int }
          {
            {1} { \tl_use:N \l_mylist_label_i_tl  }
            {2} { \tl_use:N \l_mylist_label_ii_tl }
          }
      }
      {
        \def\makelabel##1{\hss\llap{##1}} % ugly :(
        \use:c { __mylist_level_ \int_to_roman:n { \l_mylist_level_int } _defns: }
      }
  }
  { \__mylist_stop_list: }

\ExplSyntaxOff

\begin{document}
XXXX
\hrule
\begin{enumerate}
\item Using enumerate redefined by enumitem pkg
  \begin{enumerate}
    \item value second level
    \item value second level
    \item value second level
  \end{enumerate}
\end{enumerate}
\hrule
YYY
\begin{mylist}
\item Using mylist environment nested here:
  \begin{mylist}
    \item value second level
    \item value second level
    \item value second level
  \end{mylist}
\end{mylist}
\hrule
\end{document}

第二次尝试:现在更接近我想要的并且具有更明确的水平。

\documentclass{article}
\usepackage{xparse}
\usepackage{enumitem}
\setlist[enumerate,1]{label= \arabic*., left=0pt, labelsep=5pt, itemsep=4pt, partopsep=2pt}
\setlist[enumerate,2]{leftmargin=16pt, itemsep=0pt, nosep, label=\Alph*)}
\setlength{\parindent}{0pt}

\ExplSyntaxOn
\newcounter{mycounti}
\newcounter{mycountii}
\newcounter{mycountiii}
\int_new:N \l_mylist_level_int
\cs_new_eq:NN \__mylist_start_list:nn \list
\cs_new_eq:NN \__mylist_stop_list: \endlist
\tl_new:N \l_mylist_label_i_tl
\tl_new:N \l_mylist_label_ii_tl
\tl_new:N \l_mylist_label_iii_tl

% topsep partopsep parsep itemsep
\cs_new_protected:Npn \__mylist_vspace_keys:nnnnn #1#2#3#4#5
  {
    \keys_define:nn { mylist / level-#1 }
      {
        topsep        .dim_set:c = { l_mylist_topsep_#1_dim },
        topsep        .initial:n = {#2},
        partopsep     .dim_set:c = { l_mylist_partopsep_#1_dim },
        partopsep     .initial:n = {#3},
        parsep        .dim_set:c = { l_mylist_parsep_#1_dim },
        parsep        .initial:n = {#4},
        itemsep       .dim_set:c = { l_mylist_itemsep_#1_dim },
        itemsep       .initial:n = {#5},
      }
  }
\__mylist_vspace_keys:nnnnn { i   }{ 0cm }{ 0cm }{ 0cm }{ 0mm }
\__mylist_vspace_keys:nnnnn { ii  }{ 0cm }{ 0cm }{ 0cm }{ 0mm }
\__mylist_vspace_keys:nnnnn { iii }{ 0cm }{ 0cm }{ 0cm }{ 0mm }

% rightmargin listparindent itemindent labelwidth labelsep (no leftmargin here)
\cs_new_protected:Npn \__mylist_hspace_keys:nnnnnn #1#2#3#4#5#6%#7
  {
    \keys_define:nn { mylist / level-#1 }
      {
        rightmargin   .dim_set:c = { l_mylist_rightmargin_#1_dim },
        rightmargin   .initial:n = {#2},
        listparindent .dim_set:c = { l_mylist_listparindent_#1_dim },
        listparindent .initial:n = {#3},
        itemindent    .dim_set:c = { l_mylist_itemindent_#1_dim },
        itemindent    .initial:n = {#4},
        labelwidth    .dim_set:c = { l_mylist_labelwidth_#1_dim },
        labelwidth    .initial:n = {#5},
        labelsep      .dim_set:c = { l_mylist_labelsep_#1_dim },
        labelsep      .initial:n = {#6},
        %leftmargin    .dim_set:c = { l_mylist_leftmargin_#1_dim },
        %leftmargin    .initial:n = {#7},
      }
  }
\__mylist_hspace_keys:nnnnnn { i   }{ 0cm }{ 0cm }{ 0cm }{ 1.25em }{ 0.50em }%{ 1.75em }
\__mylist_hspace_keys:nnnnnn { ii  }{ 0cm }{ 0cm }{ 0cm }{ 1.25em }{ 0.50em }%{ 1.75em }
\__mylist_hspace_keys:nnnnnn { iii }{ 0cm }{ 0cm }{ 0cm }{ 1.25em }{ 0.50em }%{ 1.75em }

\cs_new_protected:Npn \__mylist_level_i_defns:
  {
    \usecounter{mycounti}
    \dim_set:Nn \itemsep       { \l_mylist_itemsep_i_dim       }
    \dim_set:Nn \itemindent    { \l_mylist_itemindent_i_dim    }
    \dim_set:Nn \labelsep      { \l_mylist_labelsep_i_dim      }
    \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_i_dim    }
    \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_i_dim    }
    \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_i_dim   }
    \dim_set:Nn \topsep        { \l_mylist_topsep_i_dim        }
    \dim_set:Nn \parsep        { \l_mylist_parsep_i_dim        }
    \dim_set:Nn \partopsep     { \l_mylist_partopsep_i_dim     }
    \dim_set:Nn \listparindent { \l_mylist_listparindent_i_dim }
  }

\cs_new_protected:Npn \__mylist_level_ii_defns:
  {
    \usecounter{mycountii}
    \dim_set:Nn \itemsep       { \l_mylist_itemsep_ii_dim       }
    \dim_set:Nn \itemindent    { \l_mylist_itemindent_ii_dim    }
    \dim_set:Nn \labelsep      { \l_mylist_labelsep_ii_dim      }
    \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_ii_dim    }
    \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_ii_dim    }
    \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_ii_dim   }
    \dim_set:Nn \topsep        { \l_mylist_topsep_ii_dim        }
    \dim_set:Nn \parsep        { \l_mylist_parsep_ii_dim        }
    \dim_set:Nn \partopsep     { \l_mylist_partopsep_ii_dim     }
    \dim_set:Nn \listparindent { \l_mylist_listparindent_ii_dim }
  }

\cs_new_protected:Npn \__mylist_level_iii_defns:
  {
    \usecounter{mycountiii}
    \dim_set:Nn \itemsep       { \l_mylist_itemsep_iii_dim       }
    \dim_set:Nn \itemindent    { \l_mylist_itemindent_iii_dim    }
    \dim_set:Nn \labelsep      { \l_mylist_labelsep_iii_dim      }
    \dim_set:Nn \labelwidth    { \l_mylist_labelwidth_iii_dim    }
    \dim_set:Nn \leftmargin    { \l_mylist_leftmargin_iii_dim    }
    \dim_set:Nn \rightmargin   { \l_mylist_rightmargin_iii_dim   }
    \dim_set:Nn \topsep        { \l_mylist_topsep_iii_dim        }
    \dim_set:Nn \parsep        { \l_mylist_parsep_iii_dim        }
    \dim_set:Nn \partopsep     { \l_mylist_partopsep_iii_dim     }
    \dim_set:Nn \listparindent { \l_mylist_listparindent_iii_dim }
  }

% Set label and leftmargin
\keys_define:nn { mylist / level-i }
  {
    label      .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                            \tl_put_right:Nx \l_mylist_label_i_tl { \exp_not:V \l_tmpa_tl },
    label      .initial:n = \arabic{mycounti}.,
    leftmargin .dim_set:c = { l_mylist_leftmargin_i_dim },
    leftmargin .initial:n = {1.75em},
  }

\keys_define:nn { mylist / level-ii }
  {
    label      .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                            \tl_put_right:Nx \l_mylist_label_ii_tl { \exp_not:V \l_tmpa_tl },
    label      .initial:n = \Alph{mycountii}),
    leftmargin .dim_set:c = { l_mylist_leftmargin_ii_dim },
    leftmargin .initial:n = {1.75em},
  }

\keys_define:nn { mylist / level-iii }
  {
    label      .code:n    = \tl_set:Nn \l_tmpa_tl {#1}
                            \tl_put_right:Nx \l_mylist_label_iii_tl { \exp_not:V \l_tmpa_tl },
    label      .initial:n = \roman{mycountiii}.,
    leftmargin .dim_set:c = { l_mylist_leftmargin_iii_dim },
    leftmargin .initial:n = {1.75em},
  }

\NewDocumentEnvironment{mylist}{ O{} }
  {
    \int_incr:N \l_mylist_level_int
    \IfNoValueF{#1}
      {
        \int_case:nn { \l_mylist_level_int }
          {
            {1} { \keys_set:nn { mylist / level-i   } {#1} }
            {2} { \keys_set:nn { mylist / level-ii  } {#1} }
            {3} { \keys_set:nn { mylist / level-iii } {#1} }
          }
      }
    \__mylist_start_list:nn
      {
        \int_case:nn { \l_mylist_level_int }
          {
            {1} { \tl_use:N \l_mylist_label_i_tl  }
            {2} { \tl_use:N \l_mylist_label_ii_tl }
            {3} { \tl_use:N \l_mylist_label_iii_tl }
          }
      }
      {
        \use:c { __mylist_level_ \int_to_roman:n { \l_mylist_level_int } _defns: }
      }
  }
  { \__mylist_stop_list: }
\ExplSyntaxOff
\begin{document}
XXXX
\hrule
\begin{enumerate}
\item Using enumerate redefined by enumitem pkg
  \begin{enumerate}
    \item value second level
    \item value second level
    \item value second level
  \end{enumerate}
\end{enumerate}
\hrule
YYY
\begin{mylist}[itemsep=4pt, parsep=2pt]
\item Using mylist environment nested here:
  \begin{mylist}
    \item value second level
    \item value second level
    \item value second level
  \end{mylist}
\end{mylist}
\hrule
\end{document}

新输出

我无法使用与 中相同的值,enumitem并且 的使用leftmargin是一个问题,但它非常接近我想要的。我不知道代码是否完全正确,但它是有用的。

相关内容