尽管我对环境的了解不够充分,我还是能够根据自己的喜好(没什么特别的)为现代 JavaScript 设计列表样式。
最让人头疼的是,我需要语法高亮 React.js,但无法通过 正确呈现listing
。我非常喜欢能够对线条的背景颜色、行号、字体等进行斑马线/交替显示,但无法识别 jsx 语言。我广泛搜索了让它工作的方法,显然建议是完全切换到 Minted 包,并安装单独的第三方 jsx 词法分析器。
它可以起作用,但我还没有找到以斑马线方式交替每条线的背景颜色的方法。
任何关于如何将 Minted 输出转换为更接近列表示例的建议(包括行突出显示以及(如果可能的话)行号等)都将不胜感激。
MWE(需要--shell-escape
和jsx-词法分析器):
\documentclass[]{scrbook}
\usepackage{xcolor}
\usepackage[]{cleveref}
\usepackage{listings}
\definecolor{listing-background}{HTML}{FFFFFF}
\definecolor{listing-background-alternate}{HTML}{F8F8F8}
\definecolor{listing-rule}{HTML}{B3B2B3}
\definecolor{listing-numbers}{HTML}{B3B2B3}
\definecolor{listing-text-color}{HTML}{000000}
\definecolor{listing-keyword}{HTML}{007F00}
\definecolor{listing-keyword-2}{HTML}{1284CA}
\definecolor{listing-keyword-3}{HTML}{9137CB}
\definecolor{listing-keyword-4}{HTML}{407F7F}
\definecolor{listing-identifier}{HTML}{000000}
\definecolor{listing-identifier}{HTML}{435489}
\definecolor{listing-string}{HTML}{BA2121}
\definecolor{listing-comment}{HTML}{8E8E8E}
\lstdefinelanguage{es6}{
morekeywords=[1]{break, continue, delete, else, for, function, if, in,
new, return, this, typeof, var, void, while, with, await, async, case, catch, class, const, default, do, enum, export, extends, finally, from, implements, import, instanceof, let, static, super, switch, throw, try },
morekeywords=[2]{false, null, true, boolean, number, undefined,
Array, Boolean, Date, Math, Number, String, Object },
morekeywords=[3]{eval, parseInt, parseFloat, escape, unescape },
otherkeywords = {+,-},
sensitive,
morecomment=[s]{/*}{*/},
morecomment=[l]//,
morecomment=[s]{/**}{*/},
morestring=[b]',
morestring=[b]"
}[keywords, comments, strings]
\makeatletter
\let\old@lstKV@SwitchCases\lstKV@SwitchCases
\def\lstKV@SwitchCases#1#2#3{}
\makeatother
\usepackage{lstlinebgrd}
\makeatletter
\let\lstKV@SwitchCases\old@lstKV@SwitchCases
\lst@Key{numbers}{none}{%
\def\lst@PlaceNumber{\lst@linebgrd}%
\lstKV@SwitchCases{#1}%
{none:\\%
left:\def\lst@PlaceNumber{\llap{\normalfont
\lst@numberstyle{\thelstnumber}\kern\lst@numbersep}\lst@linebgrd}\\%
right:\def\lst@PlaceNumber{\rlap{\normalfont
\kern\linewidth \kern\lst@numbersep
\lst@numberstyle{\thelstnumber}}\lst@linebgrd}%
}{\PackageError{Listings}{Numbers #1 unknown}\@ehc}}
\makeatother
\lstdefinestyle{fancylisting}{
basicstyle=\ttfamily\linespread{1.0}\color{listing-text-color}\small,
numbers = left,
xleftmargin = 2.7em,
framexleftmargin = 2.5em,
backgroundcolor = \color{listing-background},
breaklines = true,
frame = single,
framesep = 0.19em,
rulecolor = \color{listing-rule},
frameround = ffff,
tabsize = 4,
numberstyle = \color{listing-numbers}\footnotesize\ttfamily{},
linebackgroundcolor={\ifodd\value{lstnumber}\color{listing-background-alternate}\fi},
aboveskip = 1.2em,
belowskip = 1em,
abovecaptionskip = 0em,
belowcaptionskip = 1.0em,
keywordstyle = {\color{listing-keyword}\bfseries},
keywordstyle = {[2]\color{listing-keyword-2}},
keywordstyle = {[3]\color{listing-keyword-3}\bfseries\itshape},
keywordstyle = {[4]\color{listing-keyword-4}},
sensitive = true,
identifierstyle = \color{listing-identifier},
commentstyle = \color{listing-comment},
stringstyle = \color{listing-string},
showstringspaces = false,
escapeinside = {/*@}{@*/} }
\lstset{style=fancylisting}
\lstnewenvironment{es6}[1][]
{\lstset{
language=es6,
morekeywords=[4]{+,<,>,-,=},
#1
}}
{}
\lstnewenvironment{bash}[1][]
{\lstset{
language=bash,
linebackgroundcolor=\color{white},
backgroundcolor=\color{white},
numbers=none,
frame=l,
framerule=0.5pt,
rulecolor = \color{listing-rule},
#1
}}
{}
\crefname{lstlisting}{listing}{listings}
\Crefname{lstlisting}{Listing}{Listings}
\crefname{lstinputlisting}{listing}{listings}
\Crefname{lstinputlisting}{Listing}{Listings}
\usepackage{fancyvrb}
\usepackage[cache=false,outputdir=.texpadtmp]{minted}
\begin{document}
Minted (syntax recognized, ugly formatting)
\begin{minted}{jsx}
const BlogTitle = ({ children }) => (
<h3>{children}</h3>
);
// class component
class BlogPost extends React.Component {
renderTitle(title) {
return <BlogTitle>{title}</BlogTitle>
};
render() {
return (
<div className="blog-body">
{this.renderTitle(this.props.title)}
<p>{this.props.body}</p>
</div>
);
}
}
\end{minted}
Listing (syntax not recognized, desired formatting):
\begin{es6}
const BlogTitle = ({ children }) => (
<h3>{children}</h3>
);
// class component
class BlogPost extends React.Component {
renderTitle(title) {
return <BlogTitle>{title}</BlogTitle>
};
render() {
return (
<div className="blog-body">
{this.renderTitle(this.props.title)}
<p>{this.props.body}</p>
</div>
);
}
}
\end{es6}
\end{document}
谢谢你!
答案1
这是一个经过大量调整的实验性解决方案!为了使其正常工作,您需要手动指定行高并保证所有行的行高相等。另一个问题是我的pygments
没有词法分析器。因此,您可能需要在您的终端上将jsx
代码更改为。minted language=jsx
代码
- 根据您的文档设置更改的值很重要
\g_lst_line_height_dim
。否则,背景和前景可能不会对齐。如果您要更改的边距tcolorbox
,则需要更改所有其他四个边距变量。 - 循环中可以使用两种以上的颜色。
- 如果取消注释
\bool_gset_true:N \g_lst_debug_bool
,则代码列表将在调试模式下呈现。在调试模式下,更容易确定列表框的参数。以下是调试模式的示例输出:
\documentclass{scrbook}
\usepackage{tcolorbox}
\usepackage{fancyvrb}
\usepackage{expl3}
\usepackage{tikz}
\usepackage{xcolor}
\usetikzlibrary{math, calc}
\tcbuselibrary{listings, minted, hooks, skins}
% change line number style
\renewcommand{\theFancyVerbLine}{%
\ttfamily\textcolor[rgb]{0.3,0.3,0.3}{\tiny{\arabic{FancyVerbLine}}}%
}
\definecolor{listing-background}{HTML}{FFFFFF}
\definecolor{listing-background-alternate}{HTML}{F8F8F8}
\makeatletter
\tcbset{
lststyle/.style={
enhanced,
left=8mm,
top=0mm,
bottom=0mm,
boxsep=0.5mm,
listing only,
listing engine=minted,
minted language=html, % I don't have jsx lexer on my computer
arc=0mm,
colframe=black!5,
colback=white,
minted options={
obeytabs,
breaklines,
linenos,
autogobble,
fontsize=\scriptsize,
numbersep=2.5mm,
},
underlay=\my@lst@underlay
}
}
\ExplSyntaxOn
% several variables that need tuning when the configuration changes
% first of all, define the margins of the box
\dim_new:N \g_lst_left_dim
\dim_new:N \g_lst_right_dim
\dim_new:N \g_lst_top_dim
\dim_new:N \g_lst_bottom_dim
\dim_gset:Nn \g_lst_left_dim {7.5mm}
\dim_gset:Nn \g_lst_right_dim {0.5mm}
\dim_gset:Nn \g_lst_top_dim {0.5mm}
\dim_gset:Nn \g_lst_bottom_dim {0.5mm}
% next step, define the line height
\dim_new:N \g_lst_line_height_dim
\dim_gset:Nn \g_lst_line_height_dim {9.38pt}
% this is a switch to turn on debug mode for determining the parameters above
\bool_new:N \g_lst_debug_bool
\bool_gset_false:N \g_lst_debug_bool
%\bool_gset_true:N \g_lst_debug_bool % turn on debug mode
% a list of colors to be used
\clist_new:N \g_lst_colors_clist
\clist_set:Nn \g_lst_colors_clist {listing-background, listing-background-alternate}
\int_new:N \l_lst_tmpa_int
\tl_new:N \l_lst_tmpa_tl
\tl_new:N \l_lst_tmpb_tl
\tl_new:N \l_lst_tmpc_tl
\dim_new:N \l_lst_tmpa_dim
\fp_new:N \l_lst_tmpa_fp
\fp_new:N \l_lst_tmpb_fp
\fp_new:N \l_lst_tmpc_fp
\cs_set:Npn \__lst_anchor_dist:nnnnN #1#2#3#4#5 {
\pgfpointdiff{\pgfpointanchor{#1}{#2}}%
{\pgfpointanchor{#3}{#4}}%
\edef#5{\fp_eval:n {sqrt(\pgf@x*\pgf@x + \pgf@y*\pgf@y)}}
}
% setup the drawing function
\cs_set:Npn \my@lst@underlay {
\int_set:Nn \l_lst_tmpa_int {0}
% compute height of tcolorbox
% warning: does not work if the box is breakable!
\__lst_anchor_dist:nnnnN {interior}{north~west}{interior}{south~west}\l_lst_tmpa_tl;
% compute line width of tcolorbox
\__lst_anchor_dist:nnnnN {interior}{north~west}{interior}{north~east}\l_lst_tmpb_tl;
\fp_set:Nn \l_lst_tmpa_fp {\g_lst_top_dim}
\fp_set:Nn \l_lst_tmpb_fp {\l_lst_tmpa_tl - \g_lst_bottom_dim}
\dim_set:Nn \l_lst_tmpa_dim {\l_lst_tmpb_tl pt - \g_lst_right_dim - \g_lst_left_dim}
\fp_do_while:nNnn \l_lst_tmpa_fp < \l_lst_tmpb_fp {
% compute position of end of line
\fp_set:Nn \l_lst_tmpc_fp {\l_lst_tmpa_fp + \g_lst_line_height_dim}
\fp_compare:nNnT \l_lst_tmpc_fp < \l_lst_tmpb_fp {
% if we haven't reached end of box
% acquire current color
\edef\l_lst_tmpc_tl{\clist_item:Nn \g_lst_colors_clist {
\int_mod:nn {\l_lst_tmpa_int}{\clist_count:N \g_lst_colors_clist} + 1
}
}
\bool_if:NTF \g_lst_debug_bool {
\draw[draw=black]
($(interior.north~west)+(\dim_use:N \g_lst_left_dim, -\fp_use:N \l_lst_tmpa_fp pt)$)
rectangle ++(\dim_use:N \l_lst_tmpa_dim, -\dim_use:N \g_lst_line_height_dim);
} {
\draw[draw=none,fill=\l_lst_tmpc_tl]
($(interior.north~west)+(\dim_use:N \g_lst_left_dim, -\fp_use:N \l_lst_tmpa_fp pt)$)
rectangle ++(\dim_use:N \l_lst_tmpa_dim, -\dim_use:N \g_lst_line_height_dim);
}
}
\fp_set_eq:NN \l_lst_tmpa_fp \l_lst_tmpc_fp
\int_incr:N \l_lst_tmpa_int
}
}
\ExplSyntaxOff
\makeatother
\begin{document}
\begin{tcblisting}{lststyle}
const BlogTitle = ({ children }) => (
<h3>{children}</h3>
);
// class component
class BlogPost extends React.Component {
renderTitle(title) {
return <BlogTitle>{title}</BlogTitle>
};
render() {
return (
<div className="blog-body">
{this.renderTitle(this.props.title)}
<p>{this.props.body}</p>
</div>
);
}
}
\end{tcblisting}
\end{document}