Expl3 和 environ 仅从用户文本填充框标题、上部和下部

Expl3 和 environ 仅从用户文本填充框标题、上部和下部

下面的代码将获取一段文本,并使用 tcolorbox 将每段以空白行结尾的文本放入一个框中。每个输入前面都有时间戳。我希望代码用它找到的第一段以空白行结尾的文本填充框的上半部分,字体较小,然后用第二行填充下半部分,依此类推。如果在最后一个框中只找到一段文本,那么它应该填充一个框而不使用 \tcblower。

我开始编写一个新命令,即“bubbledual”,但环境“rightbubbles”必须进一步开发。

\documentclass{article}
\usepackage[many]{tcolorbox}
\usepackage{varwidth}
\usepackage{environ}
\usepackage{xparse}

\newlength{\bubblesep}
\newlength{\bubblewidth}
\setlength{\bubblesep}{2pt}
\AtBeginDocument{\setlength{\bubblewidth}{.75\textwidth}}

\newcommand{\bubble}[2][]{%
  \tcbox[
    on line,
    arc=2.5mm,
    rounded corners,
    title=#1,halign title=right
  ]{\begin{varwidth}{\bubblewidth}#2\end{varwidth}}%
}

\newcommand{\bubbledual}[3][]{%
  \tcbox[
    on line,
    arc=2.5mm,
    rounded corners,
    title=#1,halign title=right
  ]{\begin{varwidth}{\bubblewidth}#2\end{varwidth}}%
  \tcblower
  {\begin{varwidth}{\bubblewidth}#3\end{varwidth}}%
}

\ExplSyntaxOn
\seq_new:N \l__itt_bubbles_seq
\tl_new:N \l__itt_bubbles_first_tl
\tl_new:N \l__itt_bubbles_last_tl

\NewEnviron{rightbubbles}[1][]
 {
  \begin{flushright}
  \sffamily
  \seq_set_split:NnV \l__itt_bubbles_seq { \par } \BODY
  \int_compare:nTF { \seq_count:N \l__itt_bubbles_seq < 2 }
   {
     \bubble[#1]{\BODY}\par
   }
   {
    \seq_map_inline:Nn \l__itt_bubbles_seq
     {
      \bubble[#1]{##1}
      \par\nointerlineskip
      \addvspace{\bubblesep}
     }
   }
  \end{flushright}
 }
\ExplSyntaxOff

\begin{document}

\begin{rightbubbles}[ member A ]
20:20:11" 26 nov. 2020

Right-aligned gray bubbles with black text

20:23:12" 26 nov. 2020

Bubbles only break after a paragraph (equivalent to an enter press 
when chatting). Long message with multiple lines will be kept in one bubble.

20:27:54" 26 nov. 2020

Left and right edges are round.

20:30:06" 26 nov. 2020

Single line ...
\end{rightbubbles}

\end{document}

答案1

虽然迟到了,但是这里有一种方法可以做到:用 拆分输入\regex_split:nnN;这也可以处理空消息和多条消息行。

\documentclass{article}
\usepackage[many]{tcolorbox}
\usepackage{varwidth}
%\usepackage{xparse} % only needed for LaTeX prior to 2020-10-01

\newlength{\bubblesep}
\newlength{\bubblewidth}
\setlength{\bubblesep}{2pt}
\AtBeginDocument{\setlength{\bubblewidth}{.75\textwidth}}

\ExplSyntaxOn

\seq_new:N \l__itt_bubbles_seq
\tl_new:N \l__itt_bubbles_tl
\tl_new:N \l__itt_bubbles_title_tl
\dim_new:N \l__itt_bubbles_width_dim
\box_new:N \l__itt_bubbles_title_box
\box_new:N \l__itt_bubbles_upper_box
\box_new:N \l__itt_bubbles_lower_box

\NewDocumentEnvironment{rightbubbles}{O{} +b}
 {
  \itt_bubbles:nnn { flushright } { #1 } { #2 }
 }
 {}
\NewDocumentEnvironment{leftbubbles}{O{} +b}
 {
  \itt_bubbles:nnn { flushleft } { #1 } { #2 }
 }
 {}

\cs_new_protected:Nn \itt_bubbles:nnn
 {
  \begin{#1}
  \sffamily
  \tl_set:Nn \l__itt_bubbles_title_tl { #2 }
  \tl_clear:N \l__itt_bubbles_tl
  \regex_split:nnN { (\d\d:\d\d:\d\d\".*?\c{\par}) } { #3 } \l__itt_bubbles_seq
  \seq_pop_left:NN \l__itt_bubbles_seq \l_tmpa_tl % discard the first empty item
  \seq_map_indexed_function:NN \l__itt_bubbles_seq \__itt_bubbles_prepare:nn
  \tl_use:N \l__itt_bubbles_tl
  \end{#1}
 }

\cs_new_protected:Nn \__itt_bubbles_prepare:nn
 {
  \int_if_odd:nTF { #1 }
   {% start a bubble % title and top
    \tl_put_right:Nn \l__itt_bubbles_tl
     {
      \__itt_bubbles_make:Vnn \l__itt_bubbles_title_tl { #2 }
     }
   }
   {
    \tl_put_right:Nn \l__itt_bubbles_tl { { #2 } }
   }
 }

\cs_new_protected:Nn \__itt_bubbles_make:nnn
 {
  \hbox_set:Nn \l__itt_bubbles_title_box { #1 }
  \hbox_set:Nn \l__itt_bubbles_upper_box { \begin{varwidth}{\bubblewidth}#2\end{varwidth}}
  \hbox_set:Nn \l__itt_bubbles_lower_box { \begin{varwidth}{\bubblewidth}#3\end{varwidth}}
  \dim_set:Nn \l__itt_bubbles_width_dim
   {
    \dim_max:nn { \box_wd:N \l__itt_bubbles_title_box } { \box_wd:N \l__itt_bubbles_upper_box }
   }
  \dim_set:Nn \l__itt_bubbles_width_dim
   {
    \dim_max:nn { \l__itt_bubbles_width_dim } { \box_wd:N \l__itt_bubbles_lower_box }
   }
  \begin{tcolorbox}[
    left=1em,right=1em,
    width=\dim_eval:n { \l__itt_bubbles_width_dim + 3em },
    on~line,
    arc=2.5mm,
    rounded~corners,
    halign~title=right,
    title=\box_use:N \l__itt_bubbles_title_box,
  ]
  \box_use:N \l__itt_bubbles_upper_box
  \tcblower
  \box_use:N \l__itt_bubbles_lower_box
  \end{tcolorbox}
  \par
}
\cs_generate_variant:Nn \__itt_bubbles_make:nnn { V }
\ExplSyntaxOff

\begin{document}

\begin{rightbubbles}[member A]
20:20:11" 26 nov. 2020

Right-aligned gray bubbles with black text

20:23:12" 26 nov. 2020

Bubbles only break after a paragraph (equivalent to an enter press 
when chatting). Long message with multiple lines will be kept in one bubble.

20:27:54" 26 nov. 2020

Left and right edges are round.

Another paragraph.

20:30:06" 26 nov. 2020

20:30:06" 26 nov. 2020

Single line ...
\end{rightbubbles}

\begin{leftbubbles}[member B]
20:20:11" 26 nov. 2020

Right-aligned gray bubbles with black text

20:23:12" 26 nov. 2020

Bubbles only break after a paragraph (equivalent to an enter press 
when chatting). Long message with multiple lines will be kept in one bubble.
\end{leftbubbles}

\end{document}

在此处输入图片描述

答案2

这做了类似的事情。(我更喜欢更简洁、传统的\defs ,但expl3如果需要,您可以将其转换为 。)此代码附带了气泡框的变体,允许使用\tcblower

\documentclass{article}
\usepackage[many]{tcolorbox}
\usepackage{varwidth}
\usepackage{environ}
\usepackage{xparse}

\newlength{\bubblesep}
\newlength{\bubblewidth}
\setlength{\bubblesep}{2pt}
\AtBeginDocument{\setlength{\bubblewidth}{.75\textwidth}}

\newcommand{\bubble}[2][]{%
  \tcbox[
    on line,
    arc=2.5mm,
    rounded corners,
    title=#1,halign title=right
  ]{\begin{varwidth}{\bubblewidth}#2\end{varwidth}}%
}

\newcommand{\bubbledual}[3][]{%
\setbox0\hbox{\begin{varwidth}{\bubblewidth}
\small #2
\end{varwidth}}%
\setbox1\hbox{\begin{varwidth}{\bubblewidth}
#3
\end{varwidth}}%
\ifdim\wd0>\wd1\relax
\edef\mybubblewidth{\the\dimexpr\wd0+1.2cm}%
\else
\edef\mybubblewidth{\the\dimexpr\wd1+1.2cm}%
\fi
  \begin{tcolorbox}[width=\mybubblewidth,
    arc=2.5mm,
    rounded corners,
    title=#1,halign title=right
  ]
  \begin{varwidth}{\bubblewidth}
  {\small #2}
  \end{varwidth}%
  \tcblower
  \begin{varwidth}{\bubblewidth}
  #3
  \end{varwidth}%
\end{tcolorbox}}

\def\bubblesplit#1\newline#2\newline{\ifx#2\relax\relax
\bubble[\mytitle]{#1}%
\else
\bubbledual[\mytitle]{#1}{#2}%
\fi
}%



\ExplSyntaxOn
\seq_new:N \l__itt_bubbles_seq
\tl_new:N \l__itt_bubbles_first_tl
\tl_new:N \l__itt_bubbles_last_tl

\NewEnviron{rightbubbles}[1][]
 {
  \begin{flushright}
  \sffamily
  \seq_set_split:NnV \l__itt_bubbles_seq { \par } \BODY
  \int_compare:nTF { \seq_count:N \l__itt_bubbles_seq < 2 }
   {
     %\bubble[#1]{\BODY}\par
      \def\mytitle{#1}%
      \let\oldnewline\newline
      \let\newline\relax
      \expandafter\bubblesplit##1\newline\newline
      \let\newline\oldnewline
   }
   {
    \seq_map_inline:Nn \l__itt_bubbles_seq
     {
      %\bubble[#1]{##1}
      \def\mytitle{#1}%
      \let\oldnewline\newline
      \let\newline\relax
      \expandafter\bubblesplit##1\newline\newline
      \let\newline\oldnewline
      \par\nointerlineskip
      \addvspace{\bubblesep}
     }
   }
  \end{flushright}
 }
\ExplSyntaxOff

\begin{document}

\begin{rightbubbles}[ member A ]
20:20:11" 26 nov. 2020\newline
Right-aligned gray bubbles with black text

20:23:12" 26 nov. 2020\newline
Bubbles only break after a paragraph (equivalent to an enter press 
when chatting). Long message with multiple lines will be kept in one bubble.

20:27:54" 26 nov. 2020\newline
Left and right edges are round.

20:30:06" 26 nov. 2020\newline
Single line \dots

a line without time stamp
\end{rightbubbles}

\end{document}

在此处输入图片描述

相关内容