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}
とすると意図通りの出力が得られました.letter 扱い
文字幅の意味で欧文(半角)になりますね.英字の字間を空けないために basewidth=.5em とすると, 若干詰まったような組版結果になります(今の場合はハイフンのおかげで幸い問題はないですが).
ギリシャ文字については,欧文扱い・和文扱いのどちらの場合もありうるので, 無条件で「listings が和文文字とみなす」(幅=2文字分,行分割方法. 実際に文字がどちらのフォントかで出力されるかは知らない話)とか, あるいは無条件で「letter 扱いとする」とか,扱いを固定化してしまうのは気が引けます.
ギリシャ文字に限らず, 今の listings 日本語対応の方法だと,和文文字とみなす範囲は U+2000--U+FFFF + SIP と固定化しています. 当時は「簡単のため」と言ってこういう仕様にしましたが,その他の箇所における「欧文・和文の分別」を 反映できるようにできたら良いですが…….
いずれにせよ,U+FF より先が listings の標準で考慮されないのは問題だと思うので,あとで XeTeX,LuaTeX で OpenType フォントを使う場合の対応についてメンテナの人にメールで聞いてみます. (一応ドキュメントには Lambda でギリシャ文字を UTF-8 で書く方法が書いてあるのですが,適当な environment 中にギリシャ文字を書くことが前提になっているみたいです.)
ギリシャ文字に限らず, 今の listings 日本語対応の方法だと,和文文字とみなす範囲は U+2000--U+FFFF + SIP と固定化しています. 当時は「簡単のため」と言ってこういう仕様にしましたが,その他の箇所における「欧文・和文の分別」を 反映できるようにできたら良いですが…….
とりあえず全部(和文・欧文関係なく)letter にしておいて,\lst@Append 時に引数の jacharrange を見てなんとかする,というのが素朴な発想なんですが,どうでしょう?
とりあえず全部(和文・欧文関係なく)letter にしておいて,\lst@Append 時に引数の jacharrange を見てなんとかする,というのが素朴な発想なんですが,どうでしょう?
なるほど,和文の行分割に対応するためには \lst@Append の一段階前で見ないといけませんが,この方針で対処するのは良いかもしれませんね.
試しに,単純な次のコードを試してみていました.
\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 にしない方針もあるかもしれませんが,それを始めると大改造になってしまいそうな…….
jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました. 現状の lltjp-listings.sty の仕様を取り込むには,
という形になるのかな.
ただ,\lstu@DefEC のループを "F0000 までにすると,ものすごく時間がかかるうえに途中で
TeX capacity exceeded, sorry [hash size=265536].
「BMP (+ SIP, SMP も?) しか想定していないよ」と割りきってしまってもいいのではないかと思います.
jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました.
確認しました.最初「あれ? どちらも幅同じ?」と思ったのですが,lltjp-listings.sty を無効にしないとだめなのですね.
lstlisting 環境(再定義する)の入力中から U+80 以上の文字を全て拾ってきて
token_filter で非 active 文字の前に \lst@ProcessLetter を挿入する,というのを考えたのですが,token_filter の使い方がよくわからない……. process_input_buffer でもいいかな(U+FFFFF あたりを \lst@ProcessLetter にする).
jacharrange を見て,和文(2文字幅)か欧文(1文字幅)かを切り替えるたたき台を作ってみました.
lltjp-listings.sty を,引数の jacharrange を見るように変更してみました (commit 855baf9, 08415b5). test13-listings.tex でテストした限りではうまくいってそうですが, 現段階では listings.sty の extendedchars オプションと衝突します^^;
process_input_buffer でもいいかな(U+FFFFF あたりを \lst@ProcessLetter にする).
全く私は考えていませんでした.どうなんだろう.
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 までをコメントアウトすると比較できます.とりあえずこんな感じです.速度的には明らかにこちらの方が有利ですが,どうでしょうか?
ありがとうございます.test13-listings.pdf でテストした限りでは,うまくいっています. commit 3ab54a4 で取り込みました.
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}}$).
?
ただ,commit 855baf9 以降マニュアルのコンパイルができなくなっています.
<lst@ProcessLetter><lst@um$> という使われ方(<>で制御綴を表したつもり)があったとは. とりあえず < U+0080 は避ける形にして,修正しました (14046c0).
とりあえず < U+0080 は避ける形にして,修正しました (14046c0).
確認しました.active 文字の定義にかかっていた時間がなくなって,よくなったと思います.他に不具合がなければこれで一段落ですかね.
ひとまず完了とします.
lstlisting 環境内にギリシャ文字を含む場合の出力が正しくありません.
%#!lualatex \documentclass{article} \usepackage{listings,luatexja} \lstset{basicstyle=\ttfamily\gtfamily,breaklines=true} \begin{document} \begin{lstlisting} \TeX はギリシャ文字のΤ-Ε-Χ(タウ・イプシロン・カイ)であるから、…… \end{lstlisting} \end{document}具体的には,
のように出力されます.