LaTeX의 itemize가 계층마다 내놓는 네 개의 글머리 레이블(마커)을 대개는 "•, -, , ·"로 기억합니다. 그런데 article.cls를 열어 보면 뒤의 셋은 하나같이 예상과 다릅니다. 제2계층은 하이픈 두 개가 아니라 굵은 en 대시(\labelitemfont \bfseries \textendash), 제3계층은 보통의 별표가 아니라 위아래 가운데에 놓인 별표* \textasteriskcentered, 제4계층은 \textperiodcentered입니다. 레이블을 손보는 일은 이 매크로들이 실제로 무엇을 담고 있는지 아는 데서 시작합니다. 이 페이지에서는 itemize의 네 마커, enumerate에서 \theenumi와 \labelenumi의 역할 분담, \arabic부터 \fnsymbol까지의 카운터 표현 명령과 그 한계, 그리고 중첩의 진짜 상한 — 곧 ! LaTeX Error: Too deeply nested.가 언제 나오는지 — 를 차례로 살펴봅니다.
itemize의 네 기본 마커는 실제로 무엇인가
itemize의 글머리 기호는 계층마다 하나씩, \labelitemi, \labelitemii, \labelitemiii, \labelitemiv라는 네 매크로에 들어 있습니다(끝의 i・ii・iii・iv는 제1~제4계층을 뜻하는 로마 숫자입니다). 표준 클래스에서의 정의는 아래 표와 같고, 넷 모두 앞머리에 \labelitemfont가 붙습니다. article.cls에서 \normalfont로 정의된 작은 고리로, 둘레가 이탤릭이든 굵은 글씨이든 마커만은 본문 서체로 나오도록 보장합니다. 제2계층만은 \labelitemfont 뒤에 \bfseries가 더 이어지므로 en 대시가 굵게 조판됩니다. 이웃보다 짙어 보이는 까닭이 여기 있습니다.
| 매크로 | 표준 클래스에서의 정의 | 실제로 나오는 글자 |
|---|---|---|
\labelitemi | \labelitemfont \textbullet | • 검은 동그라미 |
\labelitemii | \labelitemfont \bfseries \textendash | – 굵은 en 대시. 하이픈 두 개가 아닙니다 |
\labelitemiii | \labelitemfont \textasteriskcentered | ∗ 위아래 가운데에 놓인 별표. *와는 다른 글자 |
\labelitemiv | \labelitemfont \textperiodcentered | · 가운뎃점 |
계층 전체의 기호를 바꾸려면 해당 매크로를 \renewcommand로 다시 정의합니다. 전처리부나 효과를 미치고 싶은 범위 바로 앞에 두십시오. 한 가지 주의할 점은 이 매크로들이 수식 모드로 들어가지 않는다는 것입니다. $\diamond$처럼 달러 기호를 직접 쓰지 않으면 \diamond는 본문에서 쓸 수 없어 오류가 납니다. 자주 쓰는 대체 기호는 $\diamond$(◇), $\ast$(∗), $\cdot$(·), $\triangleright$(▷) 정도이고, pifont 패키지를 불러오면 \ding{"6C} 같은 장식 기호도 쓸 수 있습니다. 다만 기호에 지나치게 공을 들이면 계층 구별이 어려워지므로, 대개 제1계층만 바꿔 두는 편이 무난합니다.
% the whole of level 1 becomes a diamond -- note the explicit math shift
\renewcommand{\labelitemi}{$\diamond$}
% or, with enumitem, the same thing scoped to one list
\begin{itemize}[label=$\diamond$]
\item this list only
\end{itemize}한 항목만 레이블을 갈아 끼우는 \item[...]
한 항목만 표시를 바꾸고 싶다면 \item 바로 뒤에 대괄호로 레이블을 줍니다. \item[$\star$]이면 그 항목의 글머리가 별이 되고, \item[--]이면 대시가 됩니다. 여기서 널리 믿기는 오해 하나를 바로잡아야 합니다. 대괄호로 준 레이블은 굵어지지 않습니다. itemize 안에 \item[Word]라고 쓰면 만들어진 PDF에는 본문용 로만체만 심어지고 굵은 글꼴은 전혀 나타나지 않습니다. itemize와 enumerate의 \makelabel은 \hss\llap{...}로 정의되어 있어, 레이블은 그저 상자 안에서 오른쪽 맞춤(너비를 넘긴 만큼은 왼쪽으로 넘침)이 될 뿐 서체에는 손대지 않습니다. 굵어지는 것은 description뿐이고, 그것은 \descriptionlabel이 \bfseries를 지녔기 때문입니다.
\theenumi과 \labelenumi의 차이 — 수의 표현과 레이블의 체재
\theenumi은 수를 어떻게 표현할지(1인지 I인지 a인지)를, \labelenumi은 그 수를 줄머리에 어떻게 꾸며 낼지(앞뒤의 괄호나 마침표)를 정합니다. enumerate은 계층마다 카운터 enumi, enumii, enumiii, enumiv를 쓰고, 그 값을 \theenumi이 글자로 바꾸며, \labelenumi이 그것을 불러 구두점을 덧붙이는 두 단 구조입니다. 표준 클래스의 기본값은 아래 표와 같고, 제2계층만 둥근 괄호이고 나머지는 마침표라는 비대칭을 이룹니다.
| 카운터 | \the… 의 기본값 | 레이블의 기본값 | 줄머리에 나오는 형태 |
|---|---|---|---|
enumi | \arabic{enumi} | \theenumi. | 1. 2. 3. … |
enumii | \alph{enumii} | (\theenumii) | (a) (b) (c) … |
enumiii | \roman{enumiii} | \theenumiii. | i. ii. iii. … |
enumiv | \Alph{enumiv} | \theenumiv. | A. B. C. … |
이 두 단 구조가 힘을 발휘하는 곳은 상호 참조입니다. \ref이 돌려주는 것은 \labelenumi의 장식을 걷어 낸 맨 표현, 곧 \theenumi 쪽입니다. 그래서 \labelenumi을 (\theenumi)로 바꾸어 줄머리에 (1)을 내더라도 \ref은 괄호 없는 1을 돌려줍니다. "절차 (1)을 보라"라고 쓰려면 참조하는 쪽에서 괄호를 덧붙이거나 enumitem의 ref=을 써야 합니다. 정확히는 LaTeX이 \theenumi 앞에 \p@enumi을 붙여 참조 문자열을 만들며, 표준 클래스는 \p@enumii를 \theenumi으로, \p@enumiii를 \theenumi(\theenumii)으로 정의합니다. 그래서 제2계층 항목을 \ref 하면 "1a"처럼 부모의 번호까지 함께 돌아옵니다. 카운터를 만들고 늘리는 일반론은 카운터와 길이 페이지가 다룹니다.
% change only the representation: the head reads I. II. III. and \ref gives I
\renewcommand{\theenumi}{\Roman{enumi}}
% change only the dressing: the head reads (1) but \ref still gives a bare 1
\renewcommand{\labelenumi}{(\theenumi)}카운터 표현 명령과 그 한계
\theenumi이나 \labelenumi 안에서 수의 모습을 고르려면 LaTeX 표준의 여섯 가지 카운터 표현 명령을 씁니다. 모두 카운터 이름을 인수로 받아(\Roman{enumi}처럼) 그 값을 지정한 체재로 인쇄합니다. 중요한 것은 그중 셋에 상한이 있다는 점입니다. \alph과 \Alph은 26을 넘으면, \fnsymbol은 1~9 밖으로 나가면 모두 ! LaTeX Error: Counter too large.를 내고 멈춥니다. 27개 항목에 label=\alph*을 준 목록은 스물일곱 번째에서 반드시 이 오류가 납니다.
| 명령 | 나오는 형태 | 범위와 한계 |
|---|---|---|
\arabic | 1, 2, 3 …(아라비아 숫자) | 상한 없음. 음수도 그대로 나옵니다(−3은 −3) |
\alph | a, b, c …(소문자) | 1~26. 27 이상은 Counter too large. 0은 말없이 빈 문자열 |
\Alph | A, B, C …(대문자) | 1~26. 한계는 \alph과 같습니다 |
\roman | i, ii, iii …(소문자 로마 숫자) | 오류는 없지만 0 이하는 말없이 빈 문자열 |
\Roman | I, II, III …(대문자 로마 숫자) | 상한 없음. 4000은 M을 늘어놓아 MMMM으로 나옵니다 |
\fnsymbol | * † ‡ § ¶ ‖ ** †† ‡‡(각주 기호) | 1~9뿐. 10 이상, 0 이하는 Counter too large |
까다로운 점은 어떤 것은 소리 내어 실패하고 어떤 것은 조용히 실패한다는 것입니다. \alph{0}과 \roman{0}은 군말 없이 빈 문자열을 돌려주므로, 0에 머문 카운터를 참조하면 "레이블이 사라진 목록"이 만들어지고 원인은 짐작조차 되지 않습니다. 반면 \alph{27}은 그래도 Counter too large로 멈춰 줍니다. \fnsymbol의 아홉 기호 — \@fnsymbol의 정의에 있는 그 차례 그대로 — 는 각주를 위한 배열이라, 목록 레이블로 돌려 쓰면 열 번째 항목에서 무너집니다. 짧은 주석 목록에만 남겨 두십시오.
enumitem의 label=으로 쓰기 — 카운터로 조립하는 레이블
매크로를 다시 정의하는 방법은 강력하지만, 목록마다 체재를 달리해야 하는 자리에서는 번거롭습니다. 대개는 enumitem의 label= 쪽이 한눈에 들어오므로 먼저 이쪽을 시도해 보십시오. label= 안에서는 \arabic*, \alph*, \Alph*, \roman*, \Roman*라는 별표가 붙은 형태가 그 계층의 현재 카운터를 뜻합니다. 별표 없는 \arabic{...}도 함께 쓸 수 있어서, 둘을 섞으면 다른 카운터로 조립한 레이블을 만들 수 있습니다. 이를테면 label=\thesection.\arabic*이라고 쓰면 "3.1", "3.2"처럼 절 번호를 앞에 붙인 항목 번호가 되고, 절을 옮겨도 저절로 따라갑니다.
\usepackage{enumitem}
\setlist[enumerate,1]{label=\Roman*.} % level 1 becomes I. II. III.
\setlist[enumerate,2]{label=(\alph*)} % level 2 becomes (a) (b)
\setlist[itemize,1]{label=$\diamond$} % itemize level 1 becomes a diamond
% a label built from another counter
\begin{enumerate}[label=\thesection.\arabic*, leftmargin=*]
\item numbered 3.1 inside section 3
\end{enumerate}
% label*= accumulates onto the parent label: 1. then 1.1. 1.2.
\begin{enumerate}[label*=\arabic*.]
\item one
\begin{enumerate}[label*=\arabic*.]
\item one-point-one
\end{enumerate}
\end{enumerate}label*=은 부모의 레이블에 이어 붙는 형태라, 중첩하면 1., 1.1., 1.2.로 쌓입니다(실제로 조판해 확인했습니다). 다만 이어 붙기가 듣는 것은 줄머리의 표시뿐이고, 상호 참조에는 부모의 번호가 저절로 붙지 않습니다. "1.a" 같은 참조를 내고 싶다면 ref=\theenumi.\alph*처럼 ref=으로 명시하십시오. 그리고 넓은 레이블을 건넬 때는 leftmargin=*을 곁들이는 것을 잊지 마십시오. 기본 레이블 상자는 20pt뿐이라 \thesection.\arabic* 같은 긴 레이블은 왼쪽으로 넘칩니다. 전체에 적용하려면 \setlist[enumerate,1]{...}처럼 종류와 계층을 지정합니다.
한편 패키지를 \usepackage[shortlabels]{enumitem}으로 불러오면 옛 enumerate 패키지식으로 \begin{enumerate}[(1)]처럼 짧게 쓸 수 있습니다. 대괄호의 첫 요소로 A, a, I, i, 1을 두기만 하면 각각 \Alph*, \alph*, \Roman*, \roman*, \arabic*을 뜻합니다.
Too deeply nested — 중첩의 진짜 상한
"LaTeX의 목록은 네 단까지만 중첩할 수 있다"는 말을 자주 듣지만, 이는 절반만 옳습니다. 상한은 둘이고, latex.ltx를 읽으면 그 구조가 드러납니다. itemize는 깊이를 \@itemdepth에, enumerate은 \@enumdepth에 담는 서로 독립된 두 카운터를 가지며, 각자 자기 카운터가 3을 넘으면 \@toodeep을 부릅니다. 즉 네 단까지라는 제한은 같은 환경을 겹쳤을 때의 이야기입니다. 그 위에 \list 자체가 \ifnum \@listdepth >5라는 대역의 관문을 지니는데, 이쪽은 종류를 가리지 않습니다.
실제로 시험하면 그대로입니다. itemize를 다섯 단 겹치면 다섯째 단에서 ! LaTeX Error: Too deeply nested.가 납니다. enumerate을 다섯 단 겹쳐도 마찬가지입니다. 그런데 itemize와 enumerate을 번갈아 겹치면 여섯 단까지 오류가 전혀 나지 않고, 일곱째 단에서야 같은 오류가 납니다. 이때 막아서는 것은 \@listdepth 쪽입니다. 즉 실용상의 상한은 "같은 종류면 네 단, 번갈으면 여섯 단"입니다. 다만 이는 지식으로 알아 둘 이야기이지 허가가 아닙니다. 여섯 단 중첩이 읽히는 문서가 되는 일은 사실상 없습니다. 정말로 그만한 깊이가 필요하다면 목록이 아니라 \subsubsection 같은 표제나 easylist 패키지를 검토하십시오.
이 오류의 성가신 점은 오류가 나도 조판이 멈추지 않는다는 것입니다. \itemize의 정의에서 깊이 검사는 \ifnum ... \@toodeep \else ... \fi 꼴이라, 상한을 넘으면 LaTeX은 그저 목록을 시작하지 않고 본문을 그대로 흘려보냅니다. 그 결과 알아채기 어려운 방식으로 망가집니다. 오류는 한 번만 기록되고, PDF는 만들어지며, 그 계층의 항목만 평범한 본문으로 흘러나옵니다. 로그에서 Too deeply nested를 발견하면 PDF가 나왔더라도 반드시 해당 대목을 고치십시오. 또 한 가지, 깊은 중첩을 위해 \labelitemv를 정의해 봐야 소용없습니다. 제5계층에 닿기 전에 검사에서 걸러지기 때문입니다.