调整段落形状以进行化妆

调整段落形状以进行化妆

最近我碰巧处理了 6 卷书中的 ~4500 个段落,~1500 张 A4 纸,并且我进行了许多页面校对操作(孤行控制、章节最后一段的行数、页面上最后一段的形状等)。
大多数操作 LaTeX 都会自动完成,但并非全部,也并非总是如此。

我为化妆过程写了一些丑陋的段落调整宏。

主要思想-将这些组件合并为一个宏:

  • \parfillskip
  • \松散度=+-1
  • 微型:
    • 追踪(\textls)
    • 字体扩展
  • 单词间距(\spacekip)

并快速将它们结合起来。

每个段落被放入这样的构造中(通过 perl 脚本):

\parx[][][]{}{}{}{}{}{%  
TEXT   
OF   
PARAGRAPH  
} 

现在我们可以设置值 [N 或无] 和标志 {1 或无} 如下:

\parx[2][1.15][]{1}{}{}{}{1}{%

(我们可以通过脚本重置所有这些值(针对项目中的所有文件)

也可以通过 TEX 编辑器的 GUI 元素更改这些参数(例如,使用 TexStudio 预览功能 - 几乎即时提供反馈)。

示例:(我们选择段落并预览)

步骤1

图 1:原始位置。 \parx 无选项

第2步

图 2:运行 TexStudio GUI 对话框

步骤 3

图 3:减少最后一行

步骤4

图 4:尝试添加行。(最后一行太短了)

步骤 5

图 5:尝试增加最后一行。(还不够)

第 6 步

图6:得到它。

7

图 7:填写最后一行。

关闭此 GUI 对话框后,我们可以返回整个文档并使用段落的新设置进行编译。


这个宏可以优化改进(或者简化)吗?

现在它变得很庞大 - 我为包含一些希腊语单词的俄语文本编写了这个宏(通过 \begingreek),并尝试保存突起、空格跳过、斜体和希腊语文本。第一个版本非常短,但在 300 页之后就慢得令人难以忍受。


这里是 MWE:

\documentclass[10pt,a5paper, notitlepage,final]{book}

\usepackage[OT1,T1,T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[polutonikogreek,russian,english]{babel}

\usepackage[text={3in,5in},centering]{geometry}

\usepackage{xifthen}
\usepackage{ltxcmds}
\usepackage{letltxmacro}
\usepackage{lipsum}
\usepackage{blindtext}
\newcommand{\ffamily}{cmr}% default typeface
\newcommand{\ParaInwAm}{1}% default inter-word space coeff. в \parx - 
\newcommand{\ParaInwAmByTypeface}{1}%  inter-word space coeff. 
% (you can change it when select typeface)

% set aliaces for font-expansion contexts (defined below)
\usepackage{expl3}
\ExplSyntaxOn
\newcommand{\setFontExpansion}[1]{%
    \str_case_x:nn {#1} {%
    {1}{\microtypecontext{expansion=small}}
    {2}{\microtypecontext{expansion=soft}}
    {3}{\microtypecontext{expansion=mid}}
    {4}{\microtypecontext{expansion=hard}}
    {5}{\microtypecontext{expansion=half}}
    }
}
\ExplSyntaxOff

\usepackage{xargs}
\usepackage{xparse}

%\lefthyphenmin=2 % 
%\righthyphenmin=2 %
%\finalhyphendemerits=50000%def=5000
%\doublehyphendemerits=12000%def=10000

\usepackage[babel=true,
protrusion=true, 
kerning=true,
expansion=alltext,
tracking=smallcaps
%spacing=true
]{microtype}

% settings FOR EXAMPLE 

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/{n}/*}% NORMAL
}{
    « = {300,     },
    » = {    , 300}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 120},
    ! = {    , 120}, %120
    ? = {    , 0}, %0
    : = {    , 1000},
    ; = {    , 1000},
    . = {    , 1000},
    - = {    ,  1000},
    {,} = {    , 1000}
}

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/it/*}% NORMAL
}{
    « = {300,     },
    » = {    , 200}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 70},
    ! = {    , 0}, %120
    ? = {    , 0}, %0
    : = {    , 100},
    ; = {    , 100},
    . = {    , 1000},
    - = {    ,  950},
    {,} = {    , 1000}
}

% settings FOR EXAMPLE
\SetExpansion% 
[ context = default,
    stretch = 20,
    shrink = 20,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = small,
    stretch = 25,
    shrink = 25,
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = mid, % sloppy from doc
    stretch = 30,
    shrink = 60,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = soft,
    stretch = 25,
    shrink = 40,
    step = 3% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = hard,
    stretch = 40,
    shrink = 70,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion % for ALL symbols
[ factor = 500, context = half ] { encoding = {OT1,T1,T2A}, shape = * }{ }

\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, size = {large}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape={n,it} }{ 0 }
\SetTracking{encoding={*}, shape={n,it} }{ 0 }

\DeclareMicrotypeSet{t2atext}{%
    encoding={OT1,T1,T2A,LGR},
    family={cmr},
    font={{OT1,T1,T2A,LGR}/*/*/{n,it}/*}}
\UseMicrotypeSet{t2atext}

\microtypecontext{protrusion=en-default}
\microtypecontext{kerning=en-default}
\microtypecontext{expansion=default}
\microtypecontext{tracking=en-default}

% save \emph and \footnote 
\LetLtxMacro\SVDemph\emph%
\LetLtxMacro\SVDfootnote\footnote%

% variant for change \spaceskip: 
% thank's https://tex.stackexchange.com/users/34311/pantlmn 
\newlength{\savedspaceskip}
\newcommand{\interword}[2]{%
  \setlength{\savedspaceskip}{\spaceskip}%
    \begingroup%
    \setlength{\spaceskip}{#1\fontdimen2\font plus #1\fontdimen3\font minus #1\fontdimen4\font}%
    #2%
    \endgroup%
  \setlength{\spaceskip}{\savedspaceskip}%
}

% main macro
% \parx
%  [tracking] ~ -10..10 - whole numb.
%  [inter-word] ~ 0 .. 1.25 float numb.
%  [fontexpansion] 1,2,3,4,5 - aliases for contexts
%  {\looseness=+1} if 1 - add line if possiple
%  {\looseness=-1} if 1 - del line if possible
%  {\parfillskip=...} if 1 - for increasing short last line 
%  {\parfillskip=...} if 1 - for decreasing long last line
%  {\parfillskip=...} if 1 - for filling last line to \textwidth

% without redefining \emph work not correctly
% \footnote redefined for turning-off tracking and set font expansion to default

\NewDocumentCommand\parx{o o o m m m m m +m}{%
  \ifthenelse{\isempty{#1} \AND  \isempty{#2} \AND \isempty{#3}}
  {% No  action
    \LetLtxMacro\emph\SVDemph%
    \microtypecontext{expansion=default,protrusion=en-default}%
    #9%
  }{% 
    \ifthenelse{\NOT\isempty{#1}}{% if #1=1
      \renewcommand{\emph}[1]{% temporary change \spaceskip for \emph
        \SVDemph{\setlength{\spaceskip}{#2\fontdimen2\font plus #2\fontdimen3\font minus #2\fontdimen4\font}##1}}%
            \textls*[#1]{%
        \ifthenelse{\NOT\isempty{#3}}{\setFontExpansion{#3}}{}%
        \renewcommand{\footnote}[1]{%
            \SVDfootnote{\microtypesetup{tracking=false}\microtypecontext{expansion=default}##1}}%
                \ifthenelse{\NOT\isempty{#2}}% #2=1
                    {\interword{#2}{#9}}%
                    {\interword{\ParaInwAmByTypeface}{#9}}% #2=0
        \LetLtxMacro\emph\SVDemph% 
        \LetLtxMacro\footnote\SVDfootnote%                   
       }% end textls
       \ifthenelse{\NOT\isempty{#3}}{\setFontExpansion{#3}}{}%   
        }{% #1=0
      \ifthenelse{\NOT\isempty{#3}}{\setFontExpansion{#3}}{}%
            \renewcommand{\emph}[1]{%% temporary change \spaceskip for \emph
                \SVDemph{\setlength{\spaceskip}{#2\fontdimen2\font plus #2\fontdimen3\font minus #2\fontdimen4\font}##1}}%
        \renewcommand{\footnote}[1]{%
            \SVDfootnote{\microtypesetup{tracking=false}\microtypecontext{expansion=default}##1}}%
            \ifthenelse{\NOT\isempty{#2}}% 
                {\interword{#2}{#9}}% #2=1
                {\interword{\ParaInwAmByTypeface}{#9}}% #2=0
      \LetLtxMacro\emph\SVDemph%  
      \LetLtxMacro\footnote\SVDfootnote%                   
      \microtypecontext{expansion=default,protrusion=en-default}%
    }%
  }%
    \ifthenelse{\NOT\isempty{#4}}{\looseness=+1}{}% increase to one line if possible
    \ifthenelse{\NOT\isempty{#5}}{\looseness=-1}{}% decrease to one  line if possible
    \ifthenelse{\NOT\isempty{#6}}{{\parfillskip=0pt plus .9\textwidth \par}}{}% ParIndentStart
    \ifthenelse{\NOT\isempty{#7}}{{\parfillskip=1.5\parindent plus .9\textwidth \par}}{}% ParIndentEnd
    \ifthenelse{\NOT\isempty{#8}}{{\parfillskip=0pt \par}}{}% ParIndentFull
}


\begin{document}

\parx[][][]{}{}{}{}{}{%
Hello, here is some text without a meaning. This text should
show what a printed text will look like at this place. If you
read this text, you will get no information. Really? Is there no
information? \emph{Is there a difference between this text and some
nonsense like “Huardest gefburn”? Kjift – not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look.} This text
should contain all letters of the alphabet and it should be written
in of the original language\footnote{There is no need for special content,
but the length of words should match the language. Hello, here
is some text without a meaning. This text should show what
a printed text will look like at this place. If you read this text,
you will get no information. Really? Is there no information?
Is there a difference between this text and some nonsense like
“Huardest gefburn”?}. Kjift – not at all! A blind text like this
gives you information about the selected font, how the letters
are written and an impression of the look. This text should
contain all letters of the alphabet and it should be written in of
the original language. There is no need for special content, but
the length of words should match should match  special the language.
}

\end{document}

这里是 TexStudio 的宏:

(请原谅我的 JS 和英语)

使用:
选择段落,运行预览,运行宏。
设置值,按 OK。重复(或取消退出)
对于 Inter word,您必须在对话框中设置 120 以在文本中设置 1.2(我们可以滚动查看整数)

//SCRIPT

/*
GUI-script for changing options of \parx macros    
*/

var s;// selected text
var p;// regex match

bye: 
while (true){
  if ( s = cursor.selectedText() ) {
  // search in selected - \parx...
  var r = /\\parx\[([0-9-]+)?\]\[([0-9.-]+)?\]\[([0-9-]+)?\]\{(.)?\}\{(.)?\}\{(.)?\}\{(.)?\}\{(.)?\}/;
   p = s.match(r);

   if ( p != -1 && p != null) {
     //get \parx options
      var cur_tr        = p[1] ? p[1]*1     : 0;// N (+\-)1,2,3 ,,,
      var cur_iw        = p[2] ? p[2]*100   : 0;// float [+-] 1.112134  (x100 in dialog)
      var cur_fe        = p[3] ? p[3]*1     : 0;// N (+\-)1,2,3 ,,,
      var cur_lp        = p[4] ? true : false;// 1 or empty
      var cur_lm        = p[5] ? true : false;// 1 or empty
      var cur_pfs   = p[6] ? true : false;// 1 or empty
      var cur_pfe   = p[7] ? true : false;// 1 or empty
      var cur_pfil  = p[8] ? true : false;// 1 or empty
      var reset         = false; 

      // create and init dialog window
      dlg = new UniversalInputDialog();
      dlg.add( reset,   "Reset all", "chbx_reset" );
      dlg.add( cur_tr,  "Tracking", "nbx_track" );
      dlg.add( cur_iw,  "Inter word x100", "nbx_iw" );// divide 100 
      dlg.add( cur_fe,  "Font expansion", "nbx_fexp" );// 
      dlg.add( cur_lp,  "Add line", "chbx_lplus" );
      dlg.add( cur_lm,  "Delete line", "chbx_lminus" );
      dlg.add( cur_pfs, "Fill - at start", "chbx_pf_start" );
      dlg.add( cur_pfe, "Fill - at end", "chbx_pf_end" );
      dlg.add( cur_pfil,"Fill - full line", "chbx_pf_fill" );      

      //run dialog
      a= dlg.exec();

      if ( a === undefined ) {
      // if pressed Cancel or close
        //alert('Bye');
        break bye;
      } else if ( a != false ) {
      // if pressed OK
        var tr = dlg.get("nbx_track") ? dlg.get("nbx_track")    : 0 ;
        var iw = dlg.get("nbx_iw")      ? dlg.get("nbx_iw")         : 0 ;
        var fe = dlg.get("nbx_fexp")    ? dlg.get("nbx_fexp")   : 0 ;
        var lp;
        var lm;
        var pfs;
        var pfe;
        var pfil; 
        if (dlg.get("chbx_lplus") == false ){lp = ''}else {lp = '1'};         
        if (dlg.get("chbx_lminus") == false ){lm = ''}else {lm = '1'};         
        if (dlg.get("chbx_pf_start") == false ){pfs = ''}else {pfs = '1'}; 
        if (dlg.get("chbx_pf_end") == false ){pfe = ''}else {pfe = '1'}; 
        if (dlg.get("chbx_pf_fill") == false ){pfil = ''}else {pfil = '1'}; 

        // set to 0 into dialog -> set empty in text
        if (tr == 0){tr=''};
        if (iw == 0){iw=''};
        if (fe == 0){fe=''};

        if (iw != 0){iw = iw / 100};

        // if 'Reset all' checked 
        if ( dlg.get("chbx_reset") == true ) {
          //alert ('Reset all');
          tr    =   '';
          iw    =   '';
          fe    =   '';
          lp    = '';
          lm    = '';
          pfs = '';
          pfe = '';
          pfil = '';
        }

        //apply changes
        n = s.replace(/\\parx\[([0-9-]+)?\]\[([0-9.-]+)?\]\[([0-9-]+)?\]\{(.)?\}\{(.)?\}\{(.)?\}\{(.)?\}\{(.)?\}/, 
          '\\parx['+tr+']['+iw+']['+fe+']{'+lp+'}{'+lm+'}{'+pfs+'}{'+pfe+'}{'+pfil+'}' );

        cursor.replaceSelectedText(n);   

      } 
   } else { alert ( "No \\parx founded!" ); break bye;}
  } else { alert( "Nothing selected!" ); break bye;}
} //end while

答案1

我注意到的第一件事是参数数量很多,其中三个是可选的,并且排成一行。第二点是参数#4#5是互斥的,参数#6#7和也是互斥的#8。这些可以合并。

但对于如此复杂的参数集合,我认为最好使用键值接口。这有几个优点:

  • 这些参数是显而易见的(当然,如果您为它们选择了好的名字),即使您有一段时间没有使用宏。
  • 它更容易扩展(参见代码中的示例)。
  • 不再有 9 个参数的限制(因此您可以使其更加复杂)。

对于\emph和,\footnote我添加了钩子,这样就不必一直重新定义它们了。有宏\set@parx@emph@hook\set@parx@footnote@hook来设置它们。和\setEmph使用\setFootnote这些宏来设置与原始宏类似的钩子。

我还为 TeXStudio 编写了一个脚本,但它对宏有一些限制。该脚本仅识别\parx可选参数,因此必须至少有一个空括号 ( )。和[]的选择名称只能包含小写字母。而且我没有找到正确初始化组合框的方法,因此当前值(如果存在)将添加到列表顶部。顺便说一句,空条目表示不设置键。expansionparfillskip

代码:

\documentclass[10pt,a5paper, notitlepage,final]{book}

\usepackage[OT1,T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[polutonikogreek,english]{babel}

\usepackage[text={3in,5in},centering]{geometry}

\newcommand{\ffamily}{cmr}% default typeface
\newcommand{\ParaInwAm}{1}% default inter-word space coeff. в \parx - 
\newcommand{\ParaInwAmByTypeface}{1}%  inter-word space coeff. 

\usepackage{xkeyval}

\usepackage[babel=true,
protrusion=true, 
kerning=true,
expansion=alltext,
tracking=smallcaps
%spacing=true
]{microtype}

% settings FOR EXAMPLE 

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/{n}/*}% NORMAL
}{
    « = {300,     },
    » = {    , 300}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 120},
    ! = {    , 120}, %120
    ? = {    , 0}, %0
    : = {    , 1000},
    ; = {    , 1000},
    . = {    , 1000},
    - = {    ,  1000},
    {,} = {    , 1000}
}

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/it/*}% NORMAL
}{
    « = {300,     },
    » = {    , 200}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 70},
    ! = {    , 0}, %120
    ? = {    , 0}, %0
    : = {    , 100},
    ; = {    , 100},
    . = {    , 1000},
    - = {    ,  950},
    {,} = {    , 1000}
}

% settings FOR EXAMPLE
\SetExpansion% 
[ context = default,
    stretch = 20,
    shrink = 20,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = small,
    stretch = 25,
    shrink = 25,
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = mid, % sloppy from doc
    stretch = 30,
    shrink = 60,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = soft,
    stretch = 25,
    shrink = 40,
    step = 3% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = hard,
    stretch = 40,
    shrink = 70,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion % for ALL symbols
[ factor = 500, context = half ] { encoding = {OT1,T1,T2A}, shape = * }{ }

\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, size = {large}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape={n,it} }{ 0 }
\SetTracking{encoding={*}, shape={n,it} }{ 0 }

\DeclareMicrotypeSet{t2atext}{%
    encoding={OT1,T1,T2A,LGR},
    family={cmr},
    font={{OT1,T1,T2A,LGR}/*/*/{n,it}/*}}
\UseMicrotypeSet{t2atext}

\microtypecontext{protrusion=en-default}
\microtypecontext{kerning=en-default}
\microtypecontext{expansion=default}
\microtypecontext{tracking=en-default}

%-------------------------------------------------------------------------------
\makeatletter
% tracking
\newif\ifparx@tracking\parx@trackingfalse
\newcommand*{\parx@tracking}{}
\define@key{parx}{tracking}{\def\parx@tracking{#1}\parx@trackingtrue}

% inter-word
\newif\ifparx@interword\parx@interwordfalse
\newcommand*{\parx@interword}{}
\define@key{parx}{interword}{\def\parx@interword{#1}\parx@interwordtrue}

\newcommand*{\interword}[1]{%
    \ifparx@interword
        \@interword{\parx@interword}{#1}%
    \else
        \@interword{\ParaInwAmByTypeface}{#1}%
    \fi
}
\newcommand*{\@interword}[2]{%
    \setlength{\spaceskip}{#1\fontdimen2\font plus #1\fontdimen3\font minus #1\fontdimen4\font}%
    #2%
}

% expansion
\newif\ifparx@expansion\parx@expansionfalse
\newcommand*{\parx@expansion}{}
\define@choicekey+{parx}{expansion}[\parx@expansion]%
  {small,soft,mid,hard,half}{\parx@expansiontrue}{}

\newcommand*{\setFontExpansion}{%
    \ifparx@expansion
        \microtypecontext{expansion=\parx@expansion}%
    \fi
}

% looseness
\newcommand*{\parx@looseness}{}
\define@key{parx}{looseness}{\def\parx@looseness{#1}}

\newcommand*{\setLooseness}{%
    \ifx\parx@looseness\@empty\else
        \global\looseness=\parx@looseness
    \fi
}

% parfillskip
\newcommand*{\parx@parfillskip}{}
\define@choicekey{parx}{parfillskip}[\parx@parfillskip]%
  {increase,decrease,fill}{}

\newcommand*{\parx@parfillskip@increase}{%
    \global\parfillskip=0pt plus .9\textwidth \par
}
\newcommand*{\parx@parfillskip@decrease}{%
    \global\parfillskip=1.5\parindent plus .9\textwidth \par
}
\newcommand*{\parx@parfillskip@fill}{%
    \global\parfillskip=0pt \par
}

\newcommand*{\setParfillskip}{%
    \ifx\parx@parfillskip\@empty\else
        \csname parx@parfillskip@\parx@parfillskip\endcsname
    \fi
}

% expanding parfillskip:
% e.g. add 'half' as \parfillskip=.5\textwidth plus .1\textwidth minus .1\textwidth \par
% change {increase,decrease,fill}{}
% to     {increase,decrease,fill,half}{}
% and add                        v-- note: name of value goes here
% \newcommand*{\parx@parfillskip@half}{%
%     \parfillskip=.5\textwidth plus .1\textwidth minus .1\textwidth \par
% }

% hook for \emph
\let\parx@orig@emph\emph%
\newcommand*{\parx@emph@hook}{}
\newcommand*{\set@parx@emph@hook}[1]{%
    \def\parx@emph@hook{#1}%
}
\renewcommand*{\emph}[1]{\parx@orig@emph{\parx@emph@hook #1}}
\newcommand*{\setEmph}{%
    \set@parx@emph@hook{%
        \setlength{\spaceskip}{\parx@interword\fontdimen2\font
                               plus \parx@interword\fontdimen3\font
                               minus \parx@interword\fontdimen4\font}%
    }%
}

% hook for \footnote
\let\parx@orig@footnote\footnote%
\newcommand*{\parx@footnote@hook}{}
\newcommand*{\set@parx@footnote@hook}[1]{%
    \def\parx@footnote@hook{#1}%
}
\renewcommand*{\footnote}[2][]{%
    \def\@tempa{#1}\ifx\@tempa\@empty
        \parx@orig@footnote{\parx@footnote@hook #2}%
    \else
        \parx@orig@footnote[#1]{\parx@footnote@hook #2}%
    \fi
}
\newcommand*{\setFootnote}{%
    \set@parx@footnote@hook{\microtypesetup{tracking=false}\microtypecontext{expansion=default}}%
}

% main macro
% \parx
%  tracking    - whole number.
%  interword   - float number
%  expansion   - choice: small,soft,mid,hard,half
%  looseness   - whole number
%  parfillskip - choice: increase,decrease,fill

\newcommand*{\parx}[2][]{%
    \begingroup
    \setkeys{parx}{#1}%
    \ifparx@tracking
        \@parx{#2}%
    \else
        \ifparx@interword
            \@parx{#2}%
        \else
            \ifparx@expansion
                \@parx{#2}%
            \else
                \set@parx@emph@hook{}%
                \microtypecontext{expansion=default,protrusion=en-default}%
                #2%
            \fi
        \fi
    \fi
    \setLooseness
    \setParfillskip
    \endgroup
}

\newcommand*{\@parx}[1]{%
    \ifparx@tracking
        \setEmph
        \textls*[\parx@tracking]{%
            \setFontExpansion
            \setFootnote
            \interword{#1}%
        }% end textls
        \setFontExpansion
    \else
        \setFontExpansion
        \setEmph
        \setFootnote
        \interword{#1}%
        \microtypecontext{expansion=default,protrusion=en-default}%
    \fi
}

\makeatother
%-------------------------------------------------------------------------------

\begin{document}

\parx[]{%
Hello, here is some text without a meaning. This text should
show what a printed text will look like at this place. If you
read this text, you will get no information. Really? Is there no
information? \emph{Is there a difference between this text and some
nonsense like “Huardest gefburn”? Kjift – not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look.} This text
should contain all letters of the alphabet and it should be written
in of the original language\footnote{There is no need for special content,
but the length of words should match the language. Hello, here
is some text without a meaning. This text should show what
a printed text will look like at this place. If you read this text,
you will get no information. Really? Is there no information?
Is there a difference between this text and some nonsense like
“Huardest gefburn”?}. Kjift – not at all! A blind text like this
gives you information about the selected font, how the letters
are written and an impression of the look. This text should
contain all letters of the alphabet and it should be written in of
the original language. There is no need for special content, but
the length of words should match should match  special the language.
}

\end{document}

剧本:

//SCRIPT

/*
GUI-script for changing options of \parx macros    
*/

var s;// selected text
var p;// regex match

bye: 
while (true){
    if ( s = cursor.selectedText() ) {
        // search in selected - \parx[...]
        var r = /\\parx\[(.)*\]/;   
        p = s.match(r);

        if ( p != -1 && p != null) {
            // create dialog window
            dlg = new UniversalInputDialog();
            dlg.add( false,   "Reset all", "chbx_reset" );

            // get \parx options
            // tracking
            var key = /tracking=([0-9-]+)?[,\]]+/;
            var opt = p[0].match(key);
            var cur_tr = 0;
            if ( opt != -1 && opt != null ) {
                cur_tr = opt[1]*1;
            }
            dlg.add( cur_tr,  "Tracking", "nbx_tracking" );

            // interword
            var key = /interword=([0-9.-]+)?[,\]]+/;
            var opt = p[0].match(key);
            var cur_iw = 0;
            if ( opt != -1 && opt != null ) {
                cur_iw = opt[1]*100;
            }
            dlg.add( cur_iw,  "Inter word x100", "nbx_interword" );

            // expansion
            var key = /expansion=([a-z]+)?[,\]]+/;
            var opt = p[0].match(key);
            var cur_fe = '';
            if ( opt != -1 && opt != null ) {
                cur_fe = opt[1];
            }
            var cur_fe_items;
            if ( cur_fe == '' ) {
                cur_fe_items = ['','small','soft','mid','hard','half'];
            } else {
                cur_fe_items = [cur_fe,'','small','soft','mid','hard','half'];
            }
            dlg.add( cur_fe_items,  "Font expansion", "cobx_expansion" );

            // looseness
            var key = /looseness=([0-9-]+)?[,\]]+/;
            var opt = p[0].match(key);
            var cur_lp = 0;
            if ( opt != -1 && opt != null ) {
                cur_lp = opt[1]*1;
            }
            dlg.add( cur_lp,  "Add/delete line", "nbx_looseness" );

            // parfillskip            
            var key = /parfillskip=([a-z]+)?[,\]]+/;
            var opt = p[0].match(key);
            var cur_pf = '';
            if ( opt != -1 && opt != null ) {
                cur_pf = opt[1];
            }
            var cur_pf_items;
            if ( cur_pf == '' ) {
                cur_pf_items = ['','increase','decrease','fill'];
            } else {
                cur_pf_items = [cur_pf,'','increase','decrease','fill','test'];
            }
            dlg.add( cur_pf_items,  "Parfillskip", "cobx_parfill" );

            //run dialog
            a = dlg.exec();

            if ( a === undefined ) {
                // if pressed Cancel or close
                //alert('Bye');
                break bye;
            } else if ( a != false ) {
            // if pressed OK
                var tr = '';
                var iw = '';
                var fe = '';
                var lp = '';
                var pf = '';
                // if not 'Reset all' checked 
                if ( dlg.get("chbx_reset") == false ) {
                    tr = dlg.get("nbx_tracking")   ? dlg.get("nbx_tracking")   : 0;
                    iw = dlg.get("nbx_interword")  ? dlg.get("nbx_interword") / 100 : 0;
                    fe = dlg.get("cobx_expansion") ? dlg.get("cobx_expansion") : '';
                    lp = dlg.get("nbx_looseness")  ? dlg.get("nbx_looseness")  : 0;
                    pf = dlg.get("cobx_parfill")   ? dlg.get("cobx_parfill")   : '';

                    // set to 0 into dialog -> not include key
                    if ( tr == 0 ) { tr = '' };
                    if ( iw == 0 ) { iw = '' }; // else { iw = iw / 100 };
                    if ( lp == 0 ) { lp = '' };
                }

                var param = '';
                if ( tr != '' ) {                                            param = param + 'tracking='    + tr };
                if ( iw != '' ) { if( param != '' ) { param = param + ',' }; param = param + 'interword='   + iw };
                if ( fe != '' ) { if( param != '' ) { param = param + ',' }; param = param + 'expansion='   + fe };
                if ( lp != '' ) { if( param != '' ) { param = param + ',' }; param = param + 'looseness='   + lp };
                if ( pf != '' ) { if( param != '' ) { param = param + ',' }; param = param + 'parfillskip=' + pf };


                //apply changes
                n = s.replace(/\\parx\[.*\]/, 
                    '\\parx['+param+']' );
                cursor.replaceSelectedText(n);

            }
        } else { alert ( "No \\parx founded!" ); break bye;}
    } else { alert( "Nothing selected!" ); break bye;}
} //end while

答案2

虽然我认为键值接口更灵活、更易于阅读,但你是对的,它不适合快速编辑。

所以在这里我修改了我之前的答案。\parx现在有 6 个参数,前 5 个用于调整。它们都是数字。它们的含义在代码中宏之前的注释中给出。这里的参数都是必需的,但如果您愿意,您可以轻松地将其中一些转换为可选参数。

对于\emph\footnote使用与前一个答案相同的钩子。

而且我还写了一个新剧本。

我保留旧答案,以便您(也可能是其他人)可以选择您更喜欢的答案。

代码:

\documentclass[10pt,a5paper, notitlepage,final]{book}

\usepackage[OT1,T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[polutonikogreek,english]{babel}

\usepackage[text={3in,5in},centering]{geometry}

\newcommand{\ffamily}{cmr}% default typeface
\newcommand{\ParaInwAm}{1}% default inter-word space coeff. в \parx - 
\newcommand{\ParaInwAmByTypeface}{1}%  inter-word space coeff. 

\usepackage[babel=true,
protrusion=true, 
kerning=true,
expansion=alltext,
tracking=smallcaps
%spacing=true
]{microtype}

% settings FOR EXAMPLE 

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/{n}/*}% NORMAL
}{
    « = {300,     },
    » = {    , 300}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 120},
    ! = {    , 120}, %120
    ? = {    , 0}, %0
    : = {    , 1000},
    ; = {    , 1000},
    . = {    , 1000},
    - = {    ,  1000},
    {,} = {    , 1000}
}

\SetProtrusion
[context=en-default]
{% NORMAL - 
    encoding = {T2A},
    family = cmr,
    font={T2A/cmr/*/it/*}% NORMAL
}{
    « = {300,     },
    » = {    , 200}, %1000
    „ = {0,     },
    “ = {    , 0},
    ( = {120,     },% 1000
    ) = {    , 70},
    ! = {    , 0}, %120
    ? = {    , 0}, %0
    : = {    , 100},
    ; = {    , 100},
    . = {    , 1000},
    - = {    ,  950},
    {,} = {    , 1000}
}

% settings FOR EXAMPLE
\SetExpansion% 
[ context = default,
    stretch = 20,
    shrink = 20,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = small,
    stretch = 25,
    shrink = 25,
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = mid, % sloppy from doc
    stretch = 30,
    shrink = 60,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = soft,
    stretch = 25,
    shrink = 40,
    step = 3% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion% 
[ context = hard,
    stretch = 40,
    shrink = 70,
    step = 5% 
]{ encoding = {OT1,T1,T2A} }{ }

\SetExpansion % for ALL symbols
[ factor = 500, context = half ] { encoding = {OT1,T1,T2A}, shape = * }{ }

\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, size = {large}, shape=sc}{0}
\SetTracking[context = en-default]{encoding={OT1,T1,T2A}, shape={n,it} }{ 0 }
\SetTracking{encoding={*}, shape={n,it} }{ 0 }

\DeclareMicrotypeSet{t2atext}{%
    encoding={OT1,T1,T2A,LGR},
    family={cmr},
    font={{OT1,T1,T2A,LGR}/*/*/{n,it}/*}}
\UseMicrotypeSet{t2atext}

\microtypecontext{protrusion=en-default}
\microtypecontext{kerning=en-default}
\microtypecontext{expansion=default}
\microtypecontext{tracking=en-default}

%-------------------------------------------------------------------------------
\makeatletter
% tracking
\newif\ifparx@tracking\parx@trackingfalse
\newcommand*{\parx@tracking}{}
\newcommand*{\parx@handle@tracking}[1]{%
    \def\parx@tracking{#1}\parx@trackingtrue
}

% inter-word
\newif\ifparx@interword\parx@interwordfalse
\newcommand*{\parx@interword}{}
\newcommand*{\parx@handle@interword}[1]{%
    \def\parx@interword{#1}\parx@interwordtrue
}

\newcommand*{\interword}[1]{%
    \ifparx@interword
        \@interword{\parx@interword}{#1}%
    \else
        \@interword{\ParaInwAmByTypeface}{#1}%
    \fi
}
\newcommand*{\@interword}[2]{%
    \setlength{\spaceskip}{#1\fontdimen2\font plus #1\fontdimen3\font minus #1\fontdimen4\font}%
    #2%
}

% expansion
\newif\ifparx@expansion\parx@expansionfalse
\newcommand*{\parx@expansion}{}
\newcommand*{\parx@handle@expansion}[1]{%
    \def\@tempa{#1}\ifx\@tempa\@empty\else
        \ifcase#1
        \or\def\parx@expansion{small}% #1 = 1
        \or\def\parx@expansion{soft}%  #1 = 2
        \or\def\parx@expansion{mid}%   #1 = 3
        \or\def\parx@expansion{hard}%  #1 = 4
        \or\def\parx@expansion{half}%  #1 = 5
        \fi
        \parx@expansiontrue
    \fi
}

\newcommand*{\setFontExpansion}{%
    \ifparx@expansion
        \microtypecontext{expansion=\parx@expansion}%
    \fi
}

% looseness
\newcommand*{\parx@looseness}{}
\newcommand*{\parx@handle@looseness}[1]{%
    \def\parx@looseness{#1}%
}

\newcommand*{\setLooseness}{%
    \ifx\parx@looseness\@empty\else
        \global\looseness=\parx@looseness
    \fi
}

% parfillskip
\newcommand*{\parx@parfillskip}{}
\newcommand*{\parx@handle@parfillskip}[1]{%
    \def\@tempa{#1}\ifx\@tempa\@empty\else
        \ifcase#1
        \or\def\parx@parfillskip{increase}% #1 = 1
        \or\def\parx@parfillskip{decrease}% #1 = 2
        \or\def\parx@parfillskip{fill}%     #1 = 3
        \fi
    \fi
}

\newcommand*{\parx@parfillskip@increase}{%
    \global\parfillskip=0pt plus .9\textwidth \par
}
\newcommand*{\parx@parfillskip@decrease}{%
    \global\parfillskip=1.5\parindent plus .9\textwidth \par
}
\newcommand*{\parx@parfillskip@fill}{%
    \global\parfillskip=0pt \par
}

\newcommand*{\setParfillskip}{%
    \ifx\parx@parfillskip\@empty\else
        \csname parx@parfillskip@\parx@parfillskip\endcsname
    \fi
}

% expanding parfillskip:
% e.g. add 'half' as \parfillskip=.5\textwidth plus .1\textwidth minus .1\textwidth \par
% add   \or\def\parx@parfillskip{half}%     #1 = 4
% after \or\def\parx@parfillskip{fill}%     #1 = 3
% and add                        v-- note: name of value goes here
% \newcommand*{\parx@parfillskip@half}{%
%     \parfillskip=.5\textwidth plus .1\textwidth minus .1\textwidth \par
% }

% hook for \emph
\let\parx@orig@emph\emph%
\newcommand*{\parx@emph@hook}{}
\newcommand*{\set@parx@emph@hook}[1]{%
    \def\parx@emph@hook{#1}%
}
\renewcommand*{\emph}[1]{\parx@orig@emph{\parx@emph@hook #1}}
\newcommand*{\setEmph}{%
    \set@parx@emph@hook{%
        \setlength{\spaceskip}{\parx@interword\fontdimen2\font
                               plus \parx@interword\fontdimen3\font
                               minus \parx@interword\fontdimen4\font}%
    }%
}

% hook for \footnote
\let\parx@orig@footnote\footnote%
\newcommand*{\parx@footnote@hook}{}
\newcommand*{\set@parx@footnote@hook}[1]{%
    \def\parx@footnote@hook{#1}%
}
\renewcommand*{\footnote}[2][]{%
    \def\@tempa{#1}\ifx\@tempa\@empty
        \parx@orig@footnote{\parx@footnote@hook #2}%
    \else
        \parx@orig@footnote[#1]{\parx@footnote@hook #2}%
    \fi
}
\newcommand*{\setFootnote}{%
    \set@parx@footnote@hook{\microtypesetup{tracking=false}\microtypecontext{expansion=default}}%
}

% main macro
% \parx
% #1: tracking    - whole number, -10 - 10
% #2: interword   - float number, 0 - 1.25
% #3: expansion   - whole number, 1: small, 2: soft, 3: mid, 4: hard, 5: half
% #4: looseness   - whole number, -1, 1
% #5: parfillskip - whole number, 1: increase, 2: decrease, 3: fill
% #6: text

\newcommand*{\parx}[6]{%
    \begingroup
    \parx@handle@tracking{#1}%
    \parx@handle@interword{#2}%
    \parx@handle@expansion{#3}%
    \parx@handle@looseness{#4}%
    \parx@handle@parfillskip{#5}%
    \ifparx@tracking
        \@parx{#6}%
    \else
        \ifparx@interword
            \@parx{#6}%
        \else
            \ifparx@expansion
                \@parx{#6}%
            \else
                \set@parx@emph@hook{}%
                \microtypecontext{expansion=default,protrusion=en-default}%
                #6%
            \fi
        \fi
    \fi
    \setLooseness
    \setParfillskip
    \endgroup
}

\newcommand*{\@parx}[1]{%
    \ifparx@tracking
        \setEmph
        \textls*[\parx@tracking]{%
            \setFontExpansion
            \setFootnote
            \interword{#1}%
        }% end textls
        \setFontExpansion
    \else
        \setFontExpansion
        \setEmph
        \setFootnote
        \interword{#1}%
        \microtypecontext{expansion=default,protrusion=en-default}%
    \fi
}

\makeatother
%-------------------------------------------------------------------------------

\begin{document}

\parx{}{}{}{}{}{%
Hello, here is some text without a meaning. This text should
show what a printed text will look like at this place. If you
read this text, you will get no information. Really? Is there no
information? \emph{Is there a difference between this text and some
nonsense like “Huardest gefburn”? Kjift – not at all! A blind
text like this gives you information about the selected font, how
the letters are written and an impression of the look.} This text
should contain all letters of the alphabet and it should be written
in of the original language\footnote{There is no need for special content,
but the length of words should match the language. Hello, here
is some text without a meaning. This text should show what
a printed text will look like at this place. If you read this text,
you will get no information. Really? Is there no information?
Is there a difference between this text and some nonsense like
“Huardest gefburn”?}. Kjift – not at all! A blind text like this
gives you information about the selected font, how the letters
are written and an impression of the look. This text should
contain all letters of the alphabet and it should be written in of
the original language. There is no need for special content, but
the length of words should match should match  special the language.
}

\end{document}

脚本:

//SCRIPT

/*
GUI-script for changing options of \parx macros    
*/

var s;// selected text
var p;// regex match

bye: 
while (true){
    if ( s = cursor.selectedText() ) {
        // search in selected - \parx[...]
        var r = /\\parx\{([0-9-]+)?\}\{([0-9.-]+)?\}\{([0-9-]+)?\}\{([0-9-]+)?\}\{([0-9-]+)?\}/;   
        p = s.match(r);

        if ( p != -1 && p != null) {
            // get \parx options
            var cur_tr = p[1] ? p[1]*1   : 0;
            var cur_iw = p[2] ? p[2]*100 : 0;
            var cur_fe = p[3] ? p[3]*1   : 0;
            var cur_lp = p[4] ? p[4]*1   : 0;
            var cur_pf = p[5] ? p[5]*1   : 0;

            // create dialog window
            dlg = new UniversalInputDialog();
            dlg.add( false,   "Reset all", "chbx_reset" );
            dlg.add( cur_tr,  "Tracking", "nbx_tracking" );
            dlg.add( cur_iw,  "Inter word x100", "nbx_interword" );
            dlg.add( cur_fe,  "Font expansion", "cobx_expansion" );
            dlg.add( cur_lp,  "Add/delete line", "nbx_looseness" );
            dlg.add( cur_pf,  "Parfillskip", "cobx_parfill" );

            //run dialog
            a = dlg.exec();

            if ( a === undefined ) {
                // if pressed Cancel or close
                //alert('Bye');
                break bye;
            } else if ( a != false ) {
            // if pressed OK
                var tr = '';
                var iw = '';
                var fe = '';
                var lp = '';
                var pf = '';
                // if not 'Reset all' checked 
                if ( dlg.get("chbx_reset") == false ) {
                    tr = dlg.get("nbx_tracking")   ? dlg.get("nbx_tracking")   : 0;
                    iw = dlg.get("nbx_interword")  ? dlg.get("nbx_interword") / 100 : 0;
                    fe = dlg.get("cobx_expansion") ? dlg.get("cobx_expansion") : 0;
                    lp = dlg.get("nbx_looseness")  ? dlg.get("nbx_looseness")  : 0;
                    pf = dlg.get("cobx_parfill")   ? dlg.get("cobx_parfill")   : 0;

                    // set to 0 into dialog -> empty parameternot include key
                    if ( tr == 0 ) { tr = '' };
                    if ( iw == 0 ) { iw = '' };
                    if ( fe == 0 ) { fe = '' };
                    if ( lp == 0 ) { lp = '' };
                    if ( pf == 0 ) { pf = '' };
                }

                //apply changes
                n = s.replace(/\\parx\{([0-9-]+)?\}\{([0-9.-]+)?\}\{([0-9-]+)?\}\{([0-9-]+)?\}\{([0-9-]+)?\}/, 
                    '\\parx{'+tr+'}{'+iw+'}{'+fe+'}{'+lp+'}{'+pf+'}' );
                cursor.replaceSelectedText(n);

            }
        } else { alert ( "No \\parx founded!" ); break bye;}
    } else { alert( "Nothing selected!" ); break bye;}
} //end while

相关内容