Ticket #29604

LuaTeX-ja + listings におけるギリシャ文字出力の不具合

Open Date: 2012-09-18 12:17 Last Update: 2012-12-05 10:07

Reporter:
Owner:
(None)
Type:
Status:
Closed
Component:
(None)
MileStone:
(None)
Priority:
5 - Medium
Severity:
5 - Medium
Resolution:
Fixed
File:
1

Details

lstlisting 環境内にギリシャ文字を含む場合の出力が正しくありません.

%#!lualatex
\documentclass{article}
\usepackage{listings,luatexja}
\lstset{basicstyle=\ttfamily\gtfamily,breaklines=true}
\begin{document}
\begin{lstlisting}
\TeX はギリシャ文字のΤ-Ε-Χ(タウ・イプシロン・カイ)であるから、……
\end{lstlisting}
\end{document}

具体的には,

ΤのΕΧ--(タウ・イプシロン・カイ)

のように出力されます.

Ticket History (3/17 Histories)

2012-09-18 12:17 Updated by: h7k
  • New Ticket "LuaTeX-ja + listings におけるギリシャ文字出力の不具合" created
2012-09-19 22:38 Updated by: kmaeda
Comment

listings の中身をまだよく理解できてないままで色々試してみていたのですが,LuaTeX-ja 関係なく

\documentclass{article}
\usepackage{listings,fontspec}
\setmainfont{TeXGyreTermes}
\begin{document}
\begin{lstlisting}
Τ-Ε-Χ
\end{lstlisting}
\end{document}
で既に出力が

ΤΕΧ --

となります.つまり,listings 自体の UTF-8 対応が怪しいです.

というわけで色々調べていたのですが,結局のところ listings のデフォルトでは U+FF より先にある文字が letter 扱いされないのが原因のようです.

試しにリンク先にある通り

\documentclass{article}
\usepackage{listings,luatexja}
\lstset{basicstyle=\ttfamily\gtfamily,breaklines=true}
\makeatletter
\lst@InputCatcodes
\def\lst@DefEC{%
 \lst@CCECUse \lst@ProcessLetter
  ^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f%
  ^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f%
  ^^a0^^a1^^a2^^a3^^a4^^a5^^a6^^a7^^a8^^a9^^aa^^ab^^ac^^ad^^ae^^af%
  ^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf%
  ^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf%
  ^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df%
  ^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef%
  ^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff%
  ^^^^0395^^^^03a4^^^^03a7%
  ^^00}
\lst@RestoreCatcodes
\makeatother
\begin{document}
\begin{lstlisting}
\TeX はギリシャ文字のΤ-Ε-Χ(タウ・イプシロン・カイ)であるから、……
\end{lstlisting}
\end{document}
とすると意図通りの出力が得られました.

2012-09-20 09:30 Updated by: h7k
Comment

letter 扱い

文字幅の意味で欧文(半角)になりますね.英字の字間を空けないために basewidth=.5em とすると, 若干詰まったような組版結果になります(今の場合はハイフンのおかげで幸い問題はないですが).

ギリシャ文字については,欧文扱い・和文扱いのどちらの場合もありうるので, 無条件で「listings が和文文字とみなす」(幅=2文字分,行分割方法. 実際に文字がどちらのフォントかで出力されるかは知らない話)とか, あるいは無条件で「letter 扱いとする」とか,扱いを固定化してしまうのは気が引けます.

ギリシャ文字に限らず, 今の listings 日本語対応の方法だと,和文文字とみなす範囲は U+2000--U+FFFF + SIP と固定化しています. 当時は「簡単のため」と言ってこういう仕様にしましたが,その他の箇所における「欧文・和文の分別」を 反映できるようにできたら良いですが…….

2012-09-20 10:01 Updated by: kmaeda
Comment

いずれにせよ,U+FF より先が listings の標準で考慮されないのは問題だと思うので,あとで XeTeX,LuaTeX で OpenType フォントを使う場合の対応についてメンテナの人にメールで聞いてみます. (一応ドキュメントには Lambda でギリシャ文字を UTF-8 で書く方法が書いてあるのですが,適当な environment 中にギリシャ文字を書くことが前提になっているみたいです.)

ギリシャ文字に限らず, 今の listings 日本語対応の方法だと,和文文字とみなす範囲は U+2000--U+FFFF + SIP と固定化しています. 当時は「簡単のため」と言ってこういう仕様にしましたが,その他の箇所における「欧文・和文の分別」を 反映できるようにできたら良いですが…….

とりあえず全部(和文・欧文関係なく)letter にしておいて,\lst@Append 時に引数の jacharrange を見てなんとかする,というのが素朴な発想なんですが,どうでしょう?

2012-09-20 10:36 Updated by: h7k
Comment

とりあえず全部(和文・欧文関係なく)letter にしておいて,\lst@Append 時に引数の jacharrange を見てなんとかする,というのが素朴な発想なんですが,どうでしょう?

なるほど,和文の行分割に対応するためには \lst@Append の一段階前で見ないといけませんが,この方針で対処するのは良いかもしれませんね.

2012-09-21 20:42 Updated by: kmaeda
Comment

あとで XeTeX,LuaTeX で OpenType フォントを使う場合の対応についてメンテナの人にメールで聞いてみます.

Brooks Moses さんにメールをしてみましたが,今のところ返信がありません. 少し調べてみるとプロジェクトを見つけましたが, サポートとバグが大量に投入されたまま特に何もなされていないので, しばらくはアップデートは期待できないのかな,という気がします. ちなみに件の問題も sr #296 として登録されています.

というわけなので,とりあえず LuaTeX-ja 側で暫定的に対応してしまうのがよいかもしれません.

2012-09-22 06:38 Updated by: kmaeda
Comment

試しに,単純な次のコードを試してみていました.

\def\lst@DefEC{\@tempcnta="80\lstu@DefEC}
\def\lstu@DefEC{
  \ifnum\@tempcnta<"10000
  \catcode\@tempcnta=13
  \lccode`~=\@tempcnta\lccode`\/=\@tempcnta\lowercase{\gdef~{\lst@ProcessLetter/}}%
  \advance\@tempcnta\@ne
  \expandafter\lstu@DefEC\fi}
ただ,\lstu@DefEC のループを "F0000 までにすると,ものすごく時間がかかるうえに途中で
! TeX capacity exceeded, sorry [hash size=265536].
\lstu@DefEC ...ase {\gdef ~{\lst@ProcessLetter /}}
                                                  \advance \@tempcnta \@ne \...
となってしまいます. あと,上のコードでは \gdef を使っているのですが,これは \def にすると "10000 まででも
! TeX capacity exceeded, sorry [save size=50000].
が発生してしまうからで,\gdef にしても問題ないのか(他パッケージと衝突しないか)というのが気になります.

解決法として考えたのは,lstlisting 環境(再定義する)の入力中から U+80 以上の文字を全て拾ってきて,それらの文字に限定して上のコードを実行してから本来の lstlisting 環境に入力を流し込むことなのですが,私の TeX 力が不足しているために実装できないです. 何かもっとよい方法はありますでしょうか?

文字を active にしない方針もあるかもしれませんが,それを始めると大改造になってしまいそうな…….

2012-09-22 10:00 Updated by: h7k
Comment

jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました. 現状の lltjp-listings.sty の仕様を取り込むには,

  • \lst@ProcessLetter のところで \futurelet を用いて文字トークンを取得,補助マクロ(仮に \ltj@lstPL とする)
  • \ltj@lstPL では,先に取得した引数情報から,jacharrange, prebreakpenalty, postbreakpenalty の値を調べて,必要なら出力処理を行う

という形になるのかな.

ただ,\lstu@DefEC のループを "F0000 までにすると,ものすごく時間がかかるうえに途中で
TeX capacity exceeded, sorry [hash size=265536].

「BMP (+ SIP, SMP も?) しか想定していないよ」と割りきってしまってもいいのではないかと思います.

2012-09-22 15:37 Updated by: kmaeda
Comment

jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました.

確認しました.最初「あれ? どちらも幅同じ?」と思ったのですが,lltjp-listings.sty を無効にしないとだめなのですね.

lstlisting 環境(再定義する)の入力中から U+80 以上の文字を全て拾ってきて

token_filter で非 active 文字の前に \lst@ProcessLetter を挿入する,というのを考えたのですが,token_filter の使い方がよくわからない……. process_input_buffer でもいいかな(U+FFFFF あたりを \lst@ProcessLetter にする).

2012-09-22 15:55 Updated by: h7k
Comment

jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました.

lltjp-listings.sty を,引数の jacharrange を見るように変更してみました (commit 855baf9, 08415b5). test13-listings.tex でテストした限りではうまくいってそうですが, 現段階では listings.sty の extendedchars オプションと衝突します^^;

process_input_buffer でもいいかな(U+FFFFF あたりを \lst@ProcessLetter にする).

全く私は考えていませんでした.どうなんだろう.

2012-09-23 02:17 Updated by: kmaeda
Comment

process_input_buffer でもいいかな(U+FFFFF あたりを \lst@ProcessLetter にする).

全く私は考えていませんでした.どうなんだろう.

とりあえずこんな感じです.速度的には明らかにこちらの方が有利ですが,どうでしょうか? これ以外テストしていないので,何か問題ありかもしれません.

\documentclass{article}
\usepackage{listings,fontspec}
\setmainfont{Linux Libertine O}
\makeatletter
\lst@AddToHook{Init}{
  \catcode"FFFFF=13
  \lccode`\~="FFFFF\lowercase{\let~\lst@ProcessLetter}
  \directlua{luatexbase.add_to_callback('process_input_buffer',
    function(buf)
      local ret = ''
      for i = 1, utf.len(buf) do
        local c = utf.sub(buf, i, i)
        if tex.getcatcode(utf.byte(c)) \string~= 13 then
          ret = ret .. utf.char(1048575) % U+FFFFF
        end
        ret = ret .. c
      end
      return ret
    end, 'lstu.process_input_buffer', 1)}}
\lst@AddToHook{EndGroup}{\directlua{luatexbase.remove_from_callback('process_input_buffer', 'lstu.process_input_buffer')}}
\makeatother
\begin{document}
\noindent
\TeX{} is an abbreviation of τέχνη (ΤΕΧΝΗ – technē).
\begin{lstlisting}
\TeX is an abbreviation of τέχνη (ΤΕΧΝΗ – technē).
\TeX is an abbreviation of τέχνη (ΤΕΧΝΗ – technē).
\end{lstlisting}
\TeX{} is an abbreviation of τέχνη (ΤΕΧΝΗ – technē).
\end{document}
\makeatletter から \makeatother までをコメントアウトすると比較できます.

2012-09-23 17:08 Updated by: h7k
Comment

とりあえずこんな感じです.速度的には明らかにこちらの方が有利ですが,どうでしょうか?

ありがとうございます.test13-listings.pdf でテストした限りでは,うまくいっています. commit 3ab54a4 で取り込みました.

2012-09-23 17:22 Updated by: kmaeda
Comment

commit 3ab54a4 で取り込みました.

おお,採用された. showexpl でうまく動くかが心配だったのですが,試した限りだと \jobname.tmp の出力には U+FFFFF の挿入は反映されていないみたいで,問題ないですね.

ただ,commit 855baf9 以降マニュアルのコンパイルができなくなっています.

! Improper alphabetic constant.
<to be read again> 
                   \lst@um$ 
l.474 $
       f_{高温}$~($f_{\text{high temperature}}$).
? 

2012-09-23 18:15 Updated by: h7k
Comment

ただ,commit 855baf9 以降マニュアルのコンパイルができなくなっています.

<lst@ProcessLetter><lst@um$> という使われ方(<>で制御綴を表したつもり)があったとは. とりあえず < U+0080 は避ける形にして,修正しました (14046c0).

2012-09-23 19:04 Updated by: kmaeda
  • Resolution Update from None to Fixed
Comment

とりあえず < U+0080 は避ける形にして,修正しました (14046c0).

確認しました.active 文字の定義にかかっていた時間がなくなって,よくなったと思います.他に不具合がなければこれで一段落ですかね.

2012-12-05 10:07 Updated by: h7k
  • Status Update from Open to Closed
  • Ticket Close date is changed to 2012-12-05 10:07
Comment

ひとまず完了とします.

Attachment File List

Edit

You are not logged in. I you are not logged in, your comment will be treated as an anonymous post. » Login