Skip to content
Snippets Groups Projects
njuthesis.dtx 198 KiB
Newer Older
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% \changes{v0.14}{2021/12/21}{移除内置的 \pkg{multirow}、\pkg{subcaption}
%   和 \pkg{wrapfig}。}
% 图片与表格。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
    booktabs,
    caption,
    graphicx,
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
    enumitem,
%    \end{macrocode}
% 按以下顺序加载两个关于引用的包。
% \pkg{hyperref} 覆写了大量命令,因此需要在其他包最后载入。
% 仅有 \pkg{cleveref} 需要在 \pkg{hyperref} 后载入,否则会报错。
%    \begin{macrocode}
    hyperref,
    cleveref
  }
% 在双面模式下,使用 \pkg{emptypage} 清除空白页的页眉、页脚和页码。
%    \begin{macrocode}
\bool_if:NT \g_@@_twoside_bool { \RequirePackage{ emptypage } }
%    \end{macrocode}
%
% \changes{v0.13}{2021/12/13}{删除会与 \pkg{ntheorem} 冲突的 \pkg{microtype}。}
% \begin{macro}{\njuline}
% 针对编译引擎,使用不同的宏包构建可以对中文正常换行的下划线命令。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\sys_if_engine_xetex:T
  {
    \RequirePackage{xeCJKfntef}
    \NewDocumentCommand \njuline { m } { \CJKunderline{#1} }
  }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% \pkg{lua-ul} 中需要在结尾使用 \tn{null} 保护尾部空白。
\sys_if_engine_luatex:T
  {
    \RequirePackage{lua-ul}
    \NewDocumentCommand \njuline { m } { \underLine{#1} \null }
  }
% \end{macro}
% \begin{macro}{\@@_check_package:nnn}
% 检查过时宏包。
%    \begin{macrocode}
\msg_new:nnn { njuthesis } { package-too-old }
  {
    Package~ "#1"~ is~ too~ old.\\
Yu Xiong's avatar
Yu Xiong committed
    The~ njuthesis~ class~ only~ supports~ "#1"~ with~
    a~ version higher~ than~ v#2.\\
    Please~ update~ an~ up-to-date~ version~ of~ it~
Yu Xiong's avatar
Yu Xiong committed
    using~ your TeX~ package~ manager~ or~ from~ CTAN.
  }
\cs_new_protected:Npn \@@_check_package:nnn #1#2#3
  {
    \@ifpackagelater {#1} {#2}
      { } { \msg_error:nnnn { njuthesis } { package-too-old } {#1} {#3} }
  }
%    \end{macrocode}
% \end{macro}
%
% 检查绘制下划线所需的 \pkg{luatexja} 包版本。该宏包在 2021-09-18 的更新
% 解决了下划线中断问题,然而在 2021-10-24 的更新才提供了正确的内嵌日期。
%    \begin{macrocode}
\sys_if_engine_luatex:T
  { \@@_check_package:nnn { luatexja } { 2021/10/24 } { 20211024.0 } }
%    \end{macrocode}
%
% \subsection{配置文件}
%
% \cls{njuthesis} 包含\emph{本科生}和\emph{研究生}两套区别较大的模板配置。
% 出于定义的简洁起见,本模板将其拆分为两个单独的参数配置文件,
% 编译过程中将会根据设置的学位信息,载入相应默认配置。
% 注意,尽管在手册的实现细节部分封面、摘要、常量等位于靠后部分,
% 拆分后实际上是在此处载入运行的,务必要注意逻辑顺序。
%
% 下文中,本科生模板配置对应 \agrd{definition-ug},用于生成
% \file{njuthesis-undergraduate.def};研究生模板配置对应
% \agrd{definition-g},用于生成 \file{njuthesis-graduate.def}。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
\int_compare:nTF { \g_@@_info_degree_int == 1 }
  { \file_input:n { njuthesis-undergraduate.def } }
  { \file_input:n { njuthesis-     graduate.def } }
%    \end{macrocode}
%
% 载入用户设置,可用于对模板做额外修改。
%    \begin{macrocode}
\msg_new:nnn { njuthesis } { load-config }
  { I~ am~ loading~ config~ file~ "#1". }
\clist_map_inline:Nn \g_@@_config_clist
    \msg_info:nnn { njuthesis } { load-config } { #1 }
    \file_input:n { #1 }
% \subsection{个人信息}
% \changes{v0.11}{2021/10/01}{将个人信息变量名改为小写字母加连字符的形式。}
% \changes{v0.15}{2022/01/22}{将个人信息设置移到载入宏包后。}
%
%    \begin{macrocode}
\keys_define:nn { nju / info }
  {
%    \end{macrocode}
%
% \begin{macro}{info/title,info/title*}
% \changes{v0.13}{2021/12/12}{简化多行标题的输入方式。}
% \changes{v0.14}{2022/01/14}{将标题断行控制符修改为 |\\|。}
% 题目。中文题目可使用 |\\| 手动断行。以下标注星号(|*|)的皆为对应的英文字段。
%    \begin{macrocode}
    title               .tl_set:N = \l_@@_info_title_tl,
    title              .initial:n = { 空 },
    title*              .tl_set:N = \l_@@_info_title_en_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/keywords,info/keywords*}
% \changes{v0.11}{2021/10/01}{修改了添加关键词的方式。}
% 关键词列表。
%    \begin{macrocode}
    keywords         .clist_set:N = \l_@@_info_keywords_clist,
    keywords*        .clist_set:N = \l_@@_info_keywords_en_clist,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/grade,info/student-id,info/author,info/author*}
% 年级、学号、姓名。
%    \begin{macrocode}
    grade               .tl_set:N = \l_@@_info_grade_tl,
    student-id          .tl_set:N = \l_@@_info_id_tl,
    author              .tl_set:N = \l_@@_info_author_tl,
    author*             .tl_set:N = \l_@@_info_author_en_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/department,info/department*,info/major,info/major*,info/field,info/field*}
% 院系、专业、方向。
%    \begin{macrocode}
    department          .tl_set:N = \l_@@_info_dept_tl,
    department*         .tl_set:N = \l_@@_info_dept_en_tl,
    major               .tl_set:N = \l_@@_info_major_tl,
    major*              .tl_set:N = \l_@@_info_major_en_tl,
    field               .tl_set:N = \l_@@_info_field_tl,
    field*              .tl_set:N = \l_@@_info_field_en_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/supervisor,info/supervisor*}
% \changes{v0.13}{2021/12/11}{修改了导师选项的变量名称。}
% \changes{v0.14}{2022/01/12}{精简导师信息选项。}
% 导师信息。中文导师全称使用 |clist| 存储,便于在本科生封面中进行分割。
%    \begin{macrocode}
    supervisor       .clist_set:N = \l_@@_info_supv_clist,
    supervisor*         .tl_set:N = \l_@@_info_supv_en_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/supervisor-ii,info/supervisor-ii*}
% 第二导师信息。
%    \begin{macrocode}
    supervisor-ii    .clist_set:N = \l_@@_info_supv_ii_clist,
    supervisor-ii*      .tl_set:N = \l_@@_info_supv_ii_en_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/submit-date}
% \changes{v0.14}{2022/01/14}{精简提交日期选项。}
% 提交日期,初始值为编译当天日期。
%    \begin{macrocode}
    submit-date         .tl_set:N = \l_@@_info_sm_date_raw_tl,
    submit-date        .initial:V = \c_@@_today_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/defend-date}
% \changes{v0.14}{2022/01/14}{精简答辩日期选项。}
% 答辩日期。
%    \begin{macrocode}
    defend-date         .tl_set:N = \l_@@_info_df_date_raw_tl,
    defend-date        .initial:V = \c_@@_today_tl,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/defend-date,info/chairman,info/reviewer}
% 答辩委员会信息。
%    \begin{macrocode}
    chairman            .tl_set:N = \l_@@_info_chairman_tl,
    reviewer         .clist_set:N = \l_@@_info_reviewer_clist,
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{info/clc,info/secret-level,info/udc,info/supervisor-contact}
% 国家图书馆封面相关信息。
%    \begin{macrocode}
    clc                 .tl_set:N = \l_@@_info_clc_tl,
    secret-level        .tl_set:N = \l_@@_info_seclv_tl,
    udc                 .tl_set:N = \l_@@_info_udc_tl,
    supervisor-contact  .tl_set:N = \l_@@_info_supv_cont_tl,
  }
%    \end{macrocode}
% \end{macro}
%
Yu Xiong's avatar
Yu Xiong committed
% \changes{v0.16}{2022/03/06}{正确处理学位和类型信息。}
% 设置学位信息。该设置需要放在 \cs{ProcessKeysOptions}
% 命令以及载入配置文件中的常量信息后进行。
%    \begin{macrocode}
\tl_set:Nx \l_@@_info_degree_tl
  {
    \clist_item:Nn \c_@@_name_degree_clist
      { \g_@@_info_degree_int }
  }
\int_compare:nTF { \g_@@_info_degree_int == 1 }
  { \tl_set:Nn \l_@@_info_diploma_tl { ug } }
  { \tl_set:Nn \l_@@_info_diploma_tl { g  } }
%    \end{macrocode}
%
% 设置类型信息。
%    \begin{macrocode}
\tl_set:Nx \l_@@_info_type_tl
  { \clist_item:Nn \c_@@_name_type_clist { \g_@@_info_type_int } }
\tl_put_left:Nx \l_@@_info_type_tl
  { \tl_use:c { c_@@_name_ \l_@@_info_diploma_tl _tl } }
%    \end{macrocode}
%
% \changes{v0.15}{2022/01/22}{正确处理双导师信息。}
% 在导言区录入用户信息后进行变量设置。此处使用到了 \pkg{ctex} 提供的命令,
% 应当位于载入文档类之后。
%    \begin{macrocode}
\ctex_at_end_preamble:n
  {
%    \end{macrocode}
% 拼合双导师的姓名和职称。
%    \begin{macrocode}
    \bool_set:Nn \l_@@_second_supv_bool
      { ! \clist_if_empty_p:N \l_@@_info_supv_ii_clist }
    \tl_set:Nx \l_@@_info_supv_full_tl
      {
        \clist_use:Nn \l_@@_info_supv_clist { \@@_hskip: }
        \bool_if:NT \l_@@_second_supv_bool
          {
            \@@_quad:
            \clist_use:Nn \l_@@_info_supv_ii_clist { \@@_hskip: }
          }
      }
    \tl_set:Nx \l_@@_info_supv_full_en_tl
      {
        \l_@@_info_supv_en_tl
        \bool_if:NT \l_@@_second_supv_bool
          { \@@_quad: \l_@@_info_supv_ii_en_tl }
      }
%    \end{macrocode}
% 将 ISO 格式的原始日期字符串格式化为中文日期表示,该字符串需要进行展开。
%    \begin{macrocode}
    \tl_set:Nn \l_@@_info_sm_date_tl
      {
        \exp_last_unbraced:NV
          \@@_date:www \l_@@_info_sm_date_raw_tl \q_stop
      }
%    \end{macrocode}
% 英文提交日期以及答辩日期仅用于研究生封面。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
    \int_compare:nF { \g_@@_info_degree_int == 1 }
      {
        \tl_set:Nn \l_@@_info_sm_date_en_tl
          {
            \exp_last_unbraced:NV
              \@@_date_en:www \l_@@_info_sm_date_raw_tl \q_stop
          }
        \tl_set:Nn \l_@@_info_df_date_tl
          {
            \exp_last_unbraced:NV
              \@@_date:www \l_@@_info_df_date_raw_tl \q_stop
          }
      }
  }
%    \end{macrocode}
%
%
Yu Xiong's avatar
Yu Xiong committed
% \subsection{字体设置}
% \pkg{fontspec} 包含于 \pkg{ctex} 宏集,无需另行载入。
Yu Xiong's avatar
Yu Xiong committed
% \subsubsection{操作系统检测}
Yu Xiong's avatar
Yu Xiong committed
% 判断用户是否自定义了中英文字体。如果其中任意一种未被定义,
Yu Xiong's avatar
Yu Xiong committed
% 则使用系统预装字体覆盖字体选项。
Yu Xiong's avatar
Yu Xiong committed
\bool_lazy_or:nnT
  { \tl_if_empty_p:N \g_@@_latin_font_tl }
  { \tl_if_empty_p:N \g_@@_cjk_font_tl   }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
% 进行操作系统检测。
% 检测 Windows 的命令由 \pkg{l3kernel} 提供,
% 检测 macOS 的命令由 \pkg{ctex} 提供,
Yu Xiong's avatar
Yu Xiong committed
% 这两种情况外的系统被判断为 Linux,一律使用自由字体。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
    \sys_if_platform_windows:TF
Yu Xiong's avatar
Yu Xiong committed
      {
        \tl_set:Nn \g_@@_latin_font_tl     { win    }
        \tl_set:Nn \g_@@_cjk_font_tl       { win    }
      }
      {
        \ctex_if_platform_macos:TF
          {
            \tl_set:Nn \g_@@_latin_font_tl { mac    }
            \tl_set:Nn \g_@@_cjk_font_tl   { mac    }
          }
          {
            \tl_set:Nn \g_@@_latin_font_tl { gyre   }
            \tl_set:Nn \g_@@_cjk_font_tl   { fandol }
          }
      }
Yu Xiong's avatar
Yu Xiong committed
% \subsubsection{定义英文字库}
%
Yu Xiong's avatar
Yu Xiong committed
% 接下来逐个定义所需要使用的字库。
% \begin{macro}{\@@_load_latin_font_win:}
% Windows 西文字体
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_latin_font_win:
Yu Xiong's avatar
Yu Xiong committed
    \setmainfont { Times~New~Roman }
    \setsansfont { Arial           }
    \setmonofont { Courier~New     }
      [ Scale = MatchLowercase ]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{macro}{\@@_load_latin_font_mac:}
Yu Xiong's avatar
Yu Xiong committed
% macOS 西文字体。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_latin_font_mac:
Yu Xiong's avatar
Yu Xiong committed
    \setmainfont { Times~New~Roman }
    \setsansfont { Arial           }
    \setmonofont { Menlo           }
      [ Scale = MatchLowercase ]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{macro}{\@@_load_latin_font_gyre:}
Yu Xiong's avatar
Yu Xiong committed
% 开源的 gyre 西文字体。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_latin_font_gyre:
Yu Xiong's avatar
Yu Xiong committed
    \setmainfont { texgyretermes }
      [
        Extension      = .otf,
        UprightFont    = *-regular,
        BoldFont       = *-bold,
        ItalicFont     = *-italic,
        BoldItalicFont = *-bolditalic
      ]
    \setsansfont { texgyreheros  }
      [
        Extension      = .otf,
        UprightFont    = *-regular,
        BoldFont       = *-bold,
        ItalicFont     = *-italic,
        BoldItalicFont = *-bolditalic
      ]
    \setmonofont { texgyrecursor }
      [
        Extension      = .otf,
        UprightFont    = *-regular,
        BoldFont       = *-bold,
        ItalicFont     = *-italic,
        BoldItalicFont = *-bolditalic,
        Scale          = MatchLowercase,
        Ligatures      = CommonOff
      ]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
Yu Xiong's avatar
Yu Xiong committed
% \subsubsection{定义中文字库}
%
Yu Xiong's avatar
Yu Xiong committed
% \begin{macro}{\@@_hide_no_script_msg:}
% 隐藏 |does not contain script "CJK"| 警告。
Yu Xiong's avatar
Yu Xiong committed
\cs_new_protected:Npn \@@_hide_no_script_msg:
  { \msg_redirect_name:nnn { fontspec } { no-script } { info } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_load_cjk_font_win:}
Yu Xiong's avatar
Yu Xiong committed
% Windows 中文字体。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_win:
    \setCJKmainfont { SimSun   }
      [ AutoFakeBold = 2.17, ItalicFont = KaiTi ]
    \setCJKsansfont { SimHei   } [ AutoFakeBold = 2.17 ]
    \setCJKmonofont { FangSong } [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhsong } { SimSun   } [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhhei  } { SimHei   } [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhfs   } { FangSong } [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhkai  } { KaiTi    } [ AutoFakeBold = 2.17 ]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{macro}{\@@_load_cjk_font_mac:}
Yu Xiong's avatar
Yu Xiong committed
% macOS 字体。
Yu Xiong's avatar
Yu Xiong committed
% TODO: 修复 macOS 字体支持,实现开箱即用。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_mac:
Yu Xiong's avatar
Yu Xiong committed
    \@@_hide_no_script_msg:
Yu Xiong's avatar
Yu Xiong committed
    \setCJKmainfont{Songti~SC~Light}[
      BoldFont=Songti~SC~Bold,
      ItalicFont=Kaiti~SC,
      BoldItalicFont=Kaiti~SC~Bold]
    \setCJKsansfont{Heiti~SC~Light}[BoldFont=Heiti~SC~Medium]
    \setCJKmonofont{STFangsong}
    \setCJKfamilyfont{zhsong}{Songti~SC~Light}[BoldFont=Songti~SC~Bold]
    \setCJKfamilyfont{zhhei}{Heiti~SC~Light}[BoldFont=Heiti~SC~Medium]
    \setCJKfamilyfont{zhfs}{STFangsong}
    \setCJKfamilyfont{zhkai}{Kaiti~SC}[BoldFont=Kaiti~SC~Bold]
    \setCJKfamilyfont{zhnewhei}{PingFang~SC}
  }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{macro}{\@@_load_cjk_font_fandol:}
% Fandol 字体
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_fandol:
Yu Xiong's avatar
Yu Xiong committed
    \@@_hide_no_script_msg:
    \setCJKmainfont { FandolSong-Regular }
      [
        Extension    = .otf,
        BoldFont     = FandolSong-Bold,
        ItalicFont   = FandolKai-Regular
      ]
    \setCJKsansfont { FandolHei-Regular  }
      [
        Extension    = .otf,
        BoldFont     = FandolHei-Bold
      ]
    \setCJKmonofont { FandolFang-Regular }
      [ Extension    = .otf ]
    \setCJKfamilyfont { zhsong } { FandolSong-Regular }
      [
        Extension    = .otf,
        BoldFont     = FandolSong-Bold
      ]
    \setCJKfamilyfont { zhhei  } { FandolHei-Regular  }
      [
        Extension    = .otf,
        BoldFont     = FandolHei-Bold
      ]
    \setCJKfamilyfont { zhfs   } { FandolFang-Regular }
      [ Extension    = .otf ]
    \setCJKfamilyfont { zhkai  } { FandolKai-Regular  }
      [
        Extension    = .otf,
        AutoFakeBold = 2.17
      ]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
%
% \begin{macro}{\@@_load_cjk_font_founder:}
% 方正字库(简繁扩展)
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_founder:
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% 调整方正字体括号位置。\footnote{\hologo{XeTeX} 的调整方法来自 \url{https://www.zhihu.com/question/46241367/answer/101660183}。}
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
    \sys_if_engine_xetex:T
      { \xeCJKEditPunctStyle {quanjiao} { optimize-kerning = true } }
    \sys_if_engine_luatex:T
      { \defaultCJKfontfeatures { JFM = { zh_CN/{quanjiao,fzpr} } } }
    \setCJKmainfont { FZShuSong-Z01  }
      [ BoldFont = FZXiaoBiaoSong-B05, ItalicFont = FZKai-Z03 ]
    \setCJKsansfont { FZXiHeiI-Z08   } [ BoldFont = FZHei-B01 ]
    \setCJKmonofont { FZFangSong-Z02 }
    \setCJKfamilyfont { zhsong } { FZShuSong-Z01  }
      [ BoldFont = FZXiaoBiaoSong-B05 ]
    \setCJKfamilyfont { zhhei  } { FZHei-B01      }
Yu Xiong's avatar
Yu Xiong committed
      [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhkai  } { FZKai-Z03      }
Yu Xiong's avatar
Yu Xiong committed
      [ AutoFakeBold = 2.17 ]
    \setCJKfamilyfont { zhfs   } { FZFangSong-Z02 }
Yu Xiong's avatar
Yu Xiong committed
    \defaultCJKfontfeatures{}
  }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{macro}{\@@_load_cjk_font_noto:}
% Noto 思源字体。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_noto:
    \setCJKmainfont
      [
        UprightFont        = NotoSerifCJKsc-Regular,
        BoldFont           = NotoSerifCJKsc-Bold,
        ItalicFont         = NotoSerifCJKsc-Regular,
        BoldItalicFont     = NotoSerifCJKsc-Bold,
        ItalicFeatures     = FakeSlant,
        BoldItalicFeatures = FakeSlant
      ] { Noto~Serif~CJK~SC     }
    \setCJKsansfont
      [
        UprightFont        = NotoSansCJKsc-Regular,
        BoldFont           = NotoSansCJKsc-Bold,
        ItalicFont         = NotoSansCJKsc-Regular,
        BoldItalicFont     = NotoSansCJKsc-Bold,
        ItalicFeatures     = FakeSlant,
        BoldItalicFeatures = FakeSlant
      ] { Noto~Sans~CJK~SC      }
    \setCJKmonofont { Noto~Sans~Mono~CJK~SC }
    \setCJKfamilyfont { zhsong } { Noto~Serif~CJK~SC }
    \setCJKfamilyfont { zhhei  } { Noto~Sans~CJK~SC  }
    \setCJKfamilyfont { zhfs   } { FZFangSong-Z02    }
    \setCJKfamilyfont { zhkai  } { FZKai-Z03         }
      [AutoFakeBold=2.17]
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_load_cjk_font_source:}
% \changes{v0.14}{2021/12/20}{增加 Adobe Source Han 作为思源字体。}
% Source Han 思源字体。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_cjk_font_source:
  {
    \setCJKmainfont
      [
        UprightFont        = SourceHanSerifSC-Regular,
        BoldFont           = SourceHanSerifSC-Bold,
        ItalicFont         = SourceHanSerifSC-Regular,
        BoldItalicFont     = SourceHanSerifSC-Bold,
        ItalicFeatures     = FakeSlant,
        BoldItalicFeatures = FakeSlant
      ] { Source~Han~Serif~SC     }
    \setCJKsansfont
      [
        UprightFont        = SourceHanSansSC-Regular,
        BoldFont           = SourceHanSansSC-Bold,
        ItalicFont         = SourceHanSansSC-Regular,
        BoldItalicFont     = SourceHanSansSC-Bold,
        ItalicFeatures     = FakeSlant,
        BoldItalicFeatures = FakeSlant
      ] { Source~Han~Sans~SC      }
    \setCJKmonofont { FZFangSong-Z02      }
    \setCJKfamilyfont { zhsong } { Source~Han~Serif~SC }
    \setCJKfamilyfont { zhhei  } { Source~Han~Sans~SC  }
    \setCJKfamilyfont { zhfs   } { FZFangSong-Z02      }
    \setCJKfamilyfont { zhkai  } { FZKai-Z03           }
      [AutoFakeBold=2.17]
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
%
% \subsubsection{定义数学字库}
%
% \begin{macro}{\@@_load_math_font:}
% 设置数学字体 (XITS, 或者 \href{https://www.stixfonts.org}{STIX}, 与 Times New Roman 最为相近)
% 通用数学字体。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_math_font:
  {
    % \setmathfont{STIXTwoMath-Regular}[Extension = .otf]
    \setmathfont{XITSMath-Regular}[
      BoldFont = XITSMath-Bold,
      Extension = .otf]
    \setmathfont{NewCMMath-Regular.otf}[range={cal,bb,frak}]
    \setmathfont{NewCMMath-Regular.otf}[version=bold,range={bfcal}]
  }
%    \end{macrocode}
% \end{macro}
%
%
Yu Xiong's avatar
Yu Xiong committed
% \subsubsection{载入指定字库}
%
Yu Xiong's avatar
Yu Xiong committed
% 载入字体命令。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_load_font:
    \use:c { @@_load_latin_font_ \g_@@_latin_font_tl : }
    \use:c { @@_load_cjk_font_   \g_@@_cjk_font_tl   : }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% \changes{v0.10}{2021/09/28}{修正了数学字体。}
%    \begin{macrocode}
%    \end{macrocode}
% 自行定义 \pkg{ctex} 中的四类字体命令。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
    \NewDocumentCommand \songti   { } { \CJKfamily { zhsong } }
    \NewDocumentCommand \heiti    { } { \CJKfamily { zhhei  } }
    \NewDocumentCommand \fangsong { } { \CJKfamily { zhfs   } }
    \NewDocumentCommand \kaishu   { } { \CJKfamily { zhkai  } }
%    \end{macrocode}
% 重定义字号命令。
%    \begin{macrocode}
    \RenewDocumentCommand \large  { } { \zihao     { 4      } }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
% 载入设置的字体。此处设置与文档类一同载入,否则在导言区后载入字体可能导致一部分覆盖字体的命令失效。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
% \BeforeBeginEnvironment { document } { \@@_load_font: }
\@@_load_font:
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
Yu Xiong's avatar
Yu Xiong committed
% \subsection{页面布局}
%
Yu Xiong's avatar
Yu Xiong committed
% \subsubsection{页边距}
Yu Xiong's avatar
Yu Xiong committed
% 使用\pkg{geometry}设置页边距。
%    \begin{macrocode}
\geometry
  {
    vmargin    = 2.5 cm,
    headheight = 15 pt
  }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
Yu Xiong's avatar
Yu Xiong committed
% 草稿模式下显示页面文字范围边界以及页眉、页脚线。
%    \begin{macrocode}
\bool_if:NT \g_@@_draft_bool { \geometry { showframe } }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
% \subsubsection{页眉页脚}
Yu Xiong's avatar
Yu Xiong committed
%
% \begin{variable}{\c_@@_pagestyle_tl}
% 针对不同学位类型的默认页面样式设置。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
%<definition-ug>\tl_const:Nn \c_@@_pagestyle_tl { plain    }
%<definition-g>\tl_const:Nn \c_@@_pagestyle_tl { headings }
%    \end{macrocode}
% \end{variable}
%
% 提供设置页眉页脚的用户接口。在 \cs{fancyhead} 的可选参数中,
% \opt{E} 和 \opt{O} 分别表示在偶数页(even)和奇数页(odd),
% 而 \opt{L}、\opt{R} 和 \opt{C} 则分别表示左(left)、右
% (right)和中间(center)。按照通常的排版规则,在双面模式下,
% 偶数页的中间页眉文字在左,奇数页则在右。单面模式下,左右页眉都要显示。
%    \begin{macrocode}
%<*class>
\keys_define:nn { nju / style }
  {
%    \end{macrocode}
% \begin{macro}{style/header/format}
% \changes{v0.16}{2022/03/18}{可手动指定页眉样式。}
% 页眉格式。
%    \begin{macrocode}
    header/format .tl_gset:N = \g_@@_header_format_tl,
    header/format .initial:n = \small \kaishu,
%    \end{macrocode}
% \begin{macro}{style/header,style/header*}
% \changes{v0.16}{2022/03/18}{可手动指定页眉内容。}
% 页眉内容,分别对应双面模式和单面模式。
% 为了便于指定复杂的页眉样式,这里用 |clist| 存储位置和内容信息。
%    \begin{macrocode}
    header     .clist_gset:N = \g_@@_header_twoside_clist,
    header*    .clist_gset:N = \g_@@_header_oneside_clist,
    header        .initial:n =
      {
        { EL } { \leftmark  }, { OR } { \rightmark }
      },
    header*       .initial:n =
      {
        {  L } { \leftmark  }, {  R } { \rightmark }
      },
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{style/footer/format}
% \changes{v0.16}{2022/03/19}{可手动指定页脚样式。}
% 页脚格式。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
    footer/format .tl_gset:N = \g_@@_footer_format_tl,
    footer/format .initial:n = \small \rmfamily,
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{style/footer,style/footer*}
% \changes{v0.16}{2022/03/18}{可手动指定页脚内容。}
% 页脚内容,同页眉。
%    \begin{macrocode}
    footer     .clist_gset:N = \g_@@_footer_twoside_clist,
    footer*    .clist_gset:N = \g_@@_footer_oneside_clist,
    footer        .initial:n = { { C } { \thepage } },
    footer*       .initial:n = { { C } { \thepage } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\g_@@_header_clist,\g_@@_footer_clist}
% 设置页眉页脚。
%    \begin{macrocode}
\clist_new:N \g_@@_header_clist
\clist_new:N \g_@@_footer_clist
%    \end{macrocode}
% \end{macro}
%
% 在导言区末尾确定页眉页脚内容。
%    \begin{macrocode}
\ctex_at_end_preamble:n
  {
    \bool_if:NTF \g_@@_twoside_bool
      {
        \clist_set_eq:NN \g_@@_header_clist \g_@@_header_twoside_clist
        \clist_set_eq:NN \g_@@_footer_clist \g_@@_footer_twoside_clist
      }
      {
        \clist_set_eq:NN \g_@@_header_clist \g_@@_header_oneside_clist
        \clist_set_eq:NN \g_@@_footer_clist \g_@@_footer_oneside_clist
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
% \begin{macro}{\@@_header:nn,\@@_footer:nn}
% 对 \pkg{fancyhdr} 的命令进行包装,便于设置页眉页脚。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_header:nn #1#2
  { \fancyhead [#1] { \g_@@_header_format_tl #2 } }
\cs_new_protected:Npn \@@_footer:nn #1#2
  { \fancyfoot [#1] { \g_@@_footer_format_tl #2 } }
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
% \end{macro}
%
% 重定义 \pkg{fancyhdr} 的 \opt{plain} 样式,即本科生正文和部分特殊页面使用的的
% 页眉页脚样式。页眉无内容;页脚为居中的页码,使用五号新罗马体数字。注意标记页眉
% 页脚横线宽度的变量并不是 |dim| 类型的,但是采取了该类型的格式。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\fancypagestyle { plain }
  {
    \clist_map_inline:Nn \g_@@_footer_clist { \@@_footer:nn ##1 }
Yu Xiong's avatar
Yu Xiong committed
    \tl_set:Nn \headrulewidth { \c_zero_dim }
    \tl_set:Nn \footrulewidth { \c_zero_dim }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
Yu Xiong's avatar
Yu Xiong committed
% \changes{v0.15}{2022/01/17}{修复单页模式的页眉问题。}
% 以 \opt{plain} 样式为基础的 \opt{headings} 样式,用于研究生模板。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\fancypagestyle { headings }
    \clist_if_empty:NTF \g_@@_header_clist
        \tl_set:Nn \headrulewidth { \c_zero_dim }
        \tl_set:Nn \headrulewidth { 0.4 pt }
        \dim_set:Nn \headheight { 20 pt }
        \clist_map_inline:Nn \g_@@_header_clist
          { \@@_header:nn ##1 }
    \clist_map_inline:Nn \g_@@_footer_clist { \@@_footer:nn ##1 }
    \tl_set:Nn \footrulewidth { \c_zero_dim }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
% \begin{macro}{\frontmatter}
% 重定义 \cs{frontmatter},设置前言区默认的页眉页脚以及页码样式。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\RenewDocumentCommand \frontmatter { }
    \cleardoublepage
    \exp_args:NV \pagestyle \c_@@_pagestyle_tl
Yu Xiong's avatar
Yu Xiong committed
    \pagenumbering { Roman }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\mainmatter}
Yu Xiong's avatar
Yu Xiong committed
% \changes{v0.12}{2021/12/03}{修复了摘要页字体格式泄漏到正文的问题。}
% \changes{v0.12}{2021/12/03}{修复了页眉上长标题重叠的问题。}
% 重定义 \cs{mainmatter},在论文主体部分载入页面样式设置,
% 使用阿拉伯数字重新进行页码编号。
%    \begin{macrocode}
\RenewDocumentCommand \mainmatter { }
  {
    \cleardoublepage
    \exp_args:NV \pagestyle \c_@@_pagestyle_tl
Yu Xiong's avatar
Yu Xiong committed
    \pagenumbering { arabic }
    \normalfont \normalsize
  }
%    \end{macrocode}
% \end{macro}
Yu Xiong's avatar
Yu Xiong committed
%
% \changes{v0.16}{2022/03/18}{研究生模板的目录、摘要等页面也显示页眉。}
% 在文档起始位置设置默认页面样式。
%    \begin{macrocode}
\AtBeginEnvironment { document }
  {
    \exp_args:NV \pagestyle \c_@@_pagestyle_tl
    \pagenumbering { Roman }
  }
%    \end{macrocode}
%
Yu Xiong's avatar
Yu Xiong committed
% \subsection{章节标题格式}
% \begin{macro}{\c_@@_sec_format_tl}
% 各部分章节以及目录中章标题的格式。设置为四号、不加粗、黑体。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\tl_const:Nn \c_@@_sec_format_tl { \large \normalfont \sffamily }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_add_tocline:n,\@@_add_tocline:V}
% 添加目录条目。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_add_tocline:n #1
  { \addcontentsline { toc } { chapter } { \c_@@_sec_format_tl #1 } }
\cs_generate_variant:Nn \@@_add_tocline:n { V }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_chapter:n,\@@_chapter:V}
% 含有目录和 PDF 标签的无编号章。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_chapter:n #1
  {
    \chapter *           { #1 }
    \@@_add_tocline:n    { #1 }
    \@@_chapter_header:n { #1 }
  }
\cs_generate_variant:Nn \@@_chapter:n { V }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_chapter_header:n}
Yu Xiong's avatar
Yu Xiong committed
% 单页模式下,目录、摘要、符号表等特殊页面的页眉中间为相应标题,左右为空。这里通
% 过居中的 \tn{leftmark} 实现。
%    \begin{macrocode}
\cs_new_protected:Npn \@@_chapter_header:n #1
  {
    \bool_if:NTF \g_@@_twoside_bool
      { \markboth { #1 } { #1 } }
Yu Xiong's avatar
Yu Xiong committed
      { \markboth { \hfill #1 \hfill } { } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\njuchapter}
Yu Xiong's avatar
Yu Xiong committed
% 封装无编号章环境,供用户在正文中使用。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
\NewDocumentCommand \njuchapter { m } { \@@_chapter:n { #1 } }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
% \end{macro}
%
Yu Xiong's avatar
Yu Xiong committed
% |\keys_set:nn{ctex}| 实际相当于 \cs{ctexset}。
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
\keys_set:nn { ctex }
Yu Xiong's avatar
Yu Xiong committed
    chapter        / beforeskip = 10 pt,
    chapter        / afterskip  = 60 pt,
    chapter        / format     = \c_@@_sec_format_tl \centering,
    section        / format     = \c_@@_sec_format_tl,
    subsection     / format     = \c_@@_sec_format_tl,
    subsubsection  / format     = \c_@@_sec_format_tl,
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
%
Yu Xiong's avatar
Yu Xiong committed
% \subsection{目录格式}
Yu Xiong's avatar
Yu Xiong committed
% \changes{v0.13}{2021/12/09}{移除 \pkg{tocloft},用 \pkg{ctex} 修改目录样式。}
% 设置目录标题默认名称。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
    contentsname   = { 目\hspace{2em}录 },
    listfigurename = { 插图目录         },
    listtablename  = { 表格目录         },
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
% 设置目录中章标题的样式。
Yu Xiong's avatar
Yu Xiong committed
    chapter / tocline = \c_@@_sec_format_tl \CTEXnumberline { #1 } #2
%    \begin{macrocode}
\keys_define:nn { nju / style }
  {
%    \end{macrocode}
% \begin{macro}{style/toc-in-toc}
% \changes{v0.15}{2022/02/04}{可选择目录自身是否出现在目录中。}
% 是否在目录中显示目录自身。
%    \begin{macrocode}
    toc-in-toc .bool_gset:N = \g_@@_toc_in_toc_bool,
    toc-in-toc   .initial:n = true
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_make_toc:nn,\@@_make_toc:Vn}
Yu Xiong's avatar
Yu Xiong committed
% 通过 group 内修改标题设置,将目录页标题格式单独设置为三号粗宋体。
% 目录自身不出现在目录中时需特别处理。参考
% \url{https://tex.stackexchange.com/a/1821}。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
\cs_new_protected:Npn \@@_make_toc:nn #1#2
Yu Xiong's avatar
Yu Xiong committed
  {
    \group_begin:
      \keys_set:nn { ctex }
        { chapter/format = \centering \zihao { 3 } \bfseries }
      \bool_if:NTF \g_@@_toc_in_toc_bool
        { \@@_chapter:n { #1 } }
        {
          \chapter * { #1 }
          \pdfbookmark [0] { #1 } { #2 }
          \@@_chapter_header:n { #1 }
        }
Yu Xiong's avatar
Yu Xiong committed
    \group_end:
    \@starttoc { #2 }
  }
\cs_generate_variant:Nn \@@_make_toc:nn { Vn }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
% \end{macro}
Yu Xiong's avatar
Yu Xiong committed
% \begin{macro}{\tableofcontents,\listoffigures,\listoftables}
% 重定义目录命令,修改标题格式并插入书签。
Yu Xiong's avatar
Yu Xiong committed
%    \begin{macrocode}
Yu Xiong's avatar
Yu Xiong committed
\RenewDocumentCommand \tableofcontents { }
  { \@@_make_toc:Vn \contentsname   { toc } }
Yu Xiong's avatar
Yu Xiong committed
\RenewDocumentCommand \listoffigures   { }
  { \@@_make_toc:Vn \listfigurename { lof } }
Yu Xiong's avatar
Yu Xiong committed
\RenewDocumentCommand \listoftables    { }
  { \@@_make_toc:Vn \listtablename  { lot } }
Yu Xiong's avatar
Yu Xiong committed
%    \end{macrocode}
Yu Xiong's avatar
Yu Xiong committed
% \end{macro}
Yu Xiong's avatar
Yu Xiong committed
% \subsection{参考文献}
% \begin{variable}{\g_@@_biblatex_option_clist}
% 存储传入 \pkg{biblatex} 的选项列表。
%    \begin{macrocode}
\clist_new:N \g_@@_biblatex_option_clist
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_bib_resource_clist}
% 存储参考文献数据源列表。
%    \begin{macrocode}
\clist_new:N \g_@@_bib_resource_clist
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
\msg_new:nnn { njuthesis } { extra-bib-style }
  {
    Wrongly-placed~ bib~ style.\\
    Please~ use~ the~ `bib/style`~ field.
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\keys_define:nn { nju / bib }
  {
%    \end{macrocode}
% \begin{macro}{bib/style}
% \changes{v0.14}{2021/12/19}{提供选择参考文献样式的接口。}
% \changes{v0.15}{2022/02/11}{可使用国标以外的文献样式。}
% 参考文献样式。国家标准为顺序编码制 \opt{numeric} 和著者-出版年制
% \opt{author-year},分别对应 \pkg{biblatex} 的 \opt{gb7714-2015}
% 和 \opt{gb7714-2015ay} 样式。其余样式一律视作 \opt{unknown}。用户
% 选取的样式会被加入选项列表中,以待传进 \pkg{biblatex} 宏包。
%    \begin{macrocode}
    style             .choice:,
    style / numeric     .code:n =
        \clist_gput_right:Nn \g_@@_biblatex_option_clist
          { style = gb7714-2015      }
      },
    style / author-year .code:n =