Monthly Archives: 10月 2017

2017-10-22

Emacsでイタリック(斜体)が表示されないのを何とかした(Windows Emacs25.3)

org-modeを使っていて、ふと斜体が表示されないのに気がつきました。

私の最近のフォント設定は前回の通り次のような単純な物でした。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)
;; デフォルトはASCII用のフォントでなければダメっぽい。
(set-face-attribute 'default nil :family "Inconsolata" :height 120)
;; ASCII以外を指定する。
(set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "MS Gothic"))

ASCII部分はプログラミング用フォントとして有名なInconsolataを使っています。 それ以外は基本的にMS ゴシック。私はMS ゴシックの低解像度ディスプレイ下でのシャープさをとても評価しているのです。

それでまず試したのはマニュアル(Bold and italic - GNU Emacs FAQ For MS Windows)にもあるこの設定。

(setq w32-enable-synthesized-fonts t)
(set-face-font 'italic "-*-Courier New-normal-i-*-*-11-*-*-*-c-*-iso8859-1")
(set-face-font 'bold-italic "-*-Courier New-bold-i-*-*-11-*-*-*-c-*-iso8859-1")

んー、確かに斜体になります。でもCourier Newは嫌なのでこれをInconsolataなどにしてみてもうまく行きません。MS Gothicなどでもダメです。Consolas等あらかじめ斜体が用意されているフォントならうまくいきます。

ひょっとしたら計算で傾かせている場合はダメなのでしょうか。でも昔は傾いたと思うのですが……。 w32-enable-synthesized-fonts を調べてみましたが、これ現在はobsoleteで何の効果も無いみたいです。ソースを過去に遡って追ってみましたが、Emacs23になってからはどこからも使われていないみたいです。 色々試してみてもどうあがいても斜体がないフォントを斜体にすることができませんでした。

仕方が無いので斜体がある等幅フォント(日本語あり)ということで、Ricty Diminishedを使ってみました。

(set-face-font 'italic "Ricty Diminished:italic")

うん、斜体になります。……でも、日本語は斜体になっていません。あれー????

日本語部分はMS Gothic(非斜体)のままです。ASCII部分は設定の通りRicty Diminishedの斜体。上のフォントセットの設定が優先されているのでしょうか?

斜体専用のfontsetを作ってASCIIもそれ以外もRicty Diminishedにし、italicフェイスのfont属性に設定してみましたが、やはり日本語(非ASCII)はMS Gothic(非斜体)です。

諦めかけたところでふと (describe-face 'default) のfontset:の項目が目に付きました。あれ、faceの属性にもfontsetってあるんですね。試しに (set-face-attribute 'italic nil :fontset "fontset-standard") とやってみるとエラーが出ません。もしかして……と思い、Ricty Diminishedだけのfontsetを:fontset属性に設定してみると、無事日本語も含めて斜体はRicty Diminishedになりました。

なるほどー、italicフェイスのfontset属性がunspecifiedだとデフォルトのfontset(defaultフェイスのfontset属性?)が使われて上で設定したMS Gothicが使われてしまうんですね。だからitalicフェイスのfontset属性で再度非ASCII用のフォントを指定してあげれば良いわけですか。

というわけで、最終的な設定は次のようになりました。

;; 記号をデフォルトのフォントにしない。(for Emacs25.2)
(setq use-default-font-for-symbols nil)

(defun my-font-available-p (name) (find-font (font-spec :name name)))
(cond
 ;; ASCII用のフォントを設定する。
 ;; Inconsolataを優先する。理由:
 ;; - 等幅プログラミング用フォント
 ;; - Windows上でのhintingが良いのでRictyより文字がぼやけない
 ((my-font-available-p "Inconsolata") (set-fontset-font nil 'ascii "Inconsolata-12") (setq-default line-spacing 0.0))
 ((my-font-available-p "Ricty Diminished") (set-fontset-font nil 'ascii "Ricty Diminished-12") (setq-default line-spacing 0.2))
 ((my-font-available-p "Consolas") (set-fontset-font nil 'ascii "Consolas-12")))
;; ASCII以外のフォントを設定する。
(set-fontset-font nil '(#x80 . #x3fffff) "MS Gothic")
;; 斜体フォントを設定する。
;; faceのfontset属性を設定するところがミソ。そうでないと上で設定した非ASCII用フォントが優先されてしまう。
(cond
 ;; Ricty Diminishedを使う。理由:
 ;; - ASCIIにも日本語文字にも斜体バージョンがある(実際には独自にFontForgeで少し角度を増やした物を使っています。その際フォント情報も調整しました)
 ;; - 日本語も等幅である
;;  - Inconsolataと同じプログラミング用フォント
 ;; - Inconsolataには斜体バージョンがない
 ;; - hintingや文字の高さの違いは斜体に限り諦められる
 ((my-font-available-p "Ricty Diminished")
  (create-fontset-from-fontset-spec "-*-*-*-italic-*-mono-*-*-*-*-*-*-fontset-myitalic")
  (set-fontset-font "fontset-myitalic" '(#x80 . #x3fffff) "Ricty Diminished")
  (set-face-attribute 'italic      nil :fontset "fontset-myitalic")
  (set-face-attribute 'bold-italic nil :fontset "fontset-myitalic"))
)

本当は日本語部分はMS Gothicの斜体にしたかったのですが、どうあがいても出来なかったので仕方がありません。日本語の斜体を使う機会は多くはありませんし諦めます。

script slant フォント
ascii normal Inconsolata
非ascii normal MS Gothic
ascii italic Ricty Diminished
非ascii italic Ricty Diminished

という組み合わせで使いたいという人はあまりいないかもしれませんが、ひとまずこんな感じで。

それにしても set-face-attribute の説明に :fontset のことが書いていないのですが大丈夫なのでしょうか。実際常に変更できるわけではないようで、少なくともdefaultフェイスに対する:fontset属性の変更は何故かうまくいきませんでした。defaultフェイスはフレームパラメータと結びついているので制約があるのでしょうか?

一番最初にASCII用のフォントを設定するところですが、同じ事を次のようにも書けます。

(set-face-attribute 'default nil :font "Inconsolata-12")
defaultフェイスのフォント関連属性を変更することで、フレームのfontパラメータも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。 :family "Inconsolata" :height 120 のような指定をするとfontset-auto1とfontset-auto2の二つが作られたりします。
(set-frame-font "Inconsolata-12") または (set-frame-parameter nil 'font "Inconsolata-12")
フレームのfontパラメータを書き換えるとdefaultフェイスも書き換わります。自動的に fontset-auto1 のようなfontsetが作られます。
(set-fontset-font "fontset-startup" 'ascii "Inconsolata-12")
今回採用した方法とほぼ同じです。起動直後はfontset-startupがフレームに設定されているため、"fontset-startup"と書いてもnilと書いても同じです。余分なfontsetは自動的に作られません。

フレーム、フレームのdefaultフェイス、フレームに現在設定されているfontsetのいずれを修正しても同じような挙動になります。

いやはや、Emacsのフォントまわりは本当に難解ですね。

(2021-07-29追記:現在はFontForgeで自分で斜体に加工したフォントを使っています)

2017-10-17

PowerShellについて少しは真面目に調べてみた

ちょっとした変換作業を効率化するためにbatを書いていたらファイル名の扱いで困った(空白を含むパスやネットワークパスの扱いが絶望的に面倒くさい)ので代わりにPowerShellでやったら(前回)すんなりうまくいったので 、気をよくしてPowerShellについて少しは真面目に勉強してみました。PowerShellってとっつきにくくて何となく見よう見まねで細部は気にせず適当にやり過ごしていたのですが、知らずに使うのも気持ちが悪いですし。

資料

PowerShellの何が分かりづらいって公式のドキュメントが不足していることですよね。特に言語仕様。結構独特な文法やセマンティックスを持っているのでその辺りの説明が必要です。

探してみると次の場所に3.0の言語仕様書があります(docx形式です)。

最新版は見当たりませんが、この手の仕様書は昔のバージョンの方がシンプルで見やすかったりもしますし我慢します。

日本語で簡単にまとめてくださっているサイトとしては次のサイトがありました。

公式っぽいところだと次のサイトが結構重要なことを書いている気がします。

パイプラインとコマンド実行と関数呼び出し

言語仕様のイントロダクションにも書いてあることですが、PowerShellでとても重要なのはパイプラインだと思います。従来のシェルスクリプトはコマンドの実行によって生じたテキストが次のコマンドへパイプでつながれていきます。しかしPowerShellではコマンドの実行結果はオブジェクトであり、それが次のコマンドへ流れていきます。この一連のオブジェクトが流れる道をパイプラインと呼びます。

PowerShellでのコマンドは、外部のスクリプトや実行ファイルだけでなくユーザーが定義した関数なども含まれます。

コマンドを実行する方法はいくつかありますが、基本的には「コマンド名 引数1 引数2 …」という単純な構文を使います。言語仕様のexpressionを見ても式の中に関数呼び出し構文というのがありません。関数もコマンドですから、式の中ですらカッコで囲んでこの構文を使って呼び出します(メソッド呼び出し構文は式の中にあります。「オブジェクト . メソッド (引数…)」みたいなやつ)。

例えば次のようなtupleという関数。この関数は引数で指定した二つの数を要素とする配列オブジェクトをパイプラインへ出力します。

function tuple($a, $b){$a,$b}

この関数を呼び出すには次のようにコマンドと同じように実行します。

tuple 2 3 #結果は (2, 3) というArray

コマンドを実行した結果、(2, 3)という2要素の配列(Array)オブジェクトが生じるのですが、特に行き先が指定されていないのでコンソールに表示されます。

tuple 2 3 > result.txt

このようにリダイレクトすれば結果をファイルへ出力することも出来ます。

次のように式の中からコマンドを実行して結果を演算することも出来ます。

(tuple 2 3) * 2 + (tuple 4 5) #結果は(2, 3, 2, 3, 4, 5)というArray

「配列 * 整数」は配列の指定回数の繰り返しを作ります。「配列 + 配列」は連結した配列を作ります。

この辺りの事情は外部のスクリプトを呼び出すときでも同じです。例えば次のようなtuple.ps1というファイルを作成します。

# tuple.ps1
$args[0],$args[1]

これを呼び出すには次のようにします。

.\tuple.ps1 2 3 #結果は (2, 3) というArray
.\tuple.ps1 2 3 > result.txt
(.\tuple.ps1 2 3) * 2 + (.\tuple.ps1 4 5) #結果は(2, 3, 2, 3, 4, 5)というArray

重要なのは、こうしてコマンドを実行するとその都度生じた値がパイプラインへ流れるということです。

流す先が実際にどこになるかは呼び出し側によって変わります。コンソール、ファイル、演算子の項、コマンドの引数、変数、などなど。

流したくなければ明示的に破棄する必要があります。

.\tuple.ps1 2 3 > $null
[void](.\tuple.ps1 2 3)
$null = .\tuple.ps1 2 3

このようにすればコマンドを実行して生じた値はどこへも流れず破棄されます。

ちなみに式のトップレベルにある代入演算子は、その結果がパイプラインへ流れません。

$a = "hello" #helloは変数に格納されるのでパイプラインへは流れない

「トップレベル」と断っていると言うことは、トップレベルでなければ流れます。

($a = "hello") # 式のトップレベルはカッコなので代入演算子の結果であるhelloがパイプラインへ流れる。

変数へ代入するたびにいちいち破棄が必要になるのは面倒だからでしょう。意味的にもリダイレクトと同じようにパイプラインの流し先を変数にしただけと考えられます。

この辺りの事情は関数の中でも同じです。

関数というと何か値を返すものと考えますが、PowerShellでももちろんそう考えても良いのですが、返す先は結局はパイプラインなのです。

function compute($filename){
  echo "begin"
  $result = 42 #$result = very_complex_processing $filename の代わり
  echo "end"
  $result
}
compute("example.txt") > result.txt

例えばこのようなcomputeという関数があったとき、result.txtはどのようになるでしょうか。 Rubyあたりをやっていると最後の$result、つまり42だけ出力されそうな気がしてしまいますが、PowerShellでは「begin end 42」が出力されます。

解説をすると次のようになります。

function compute($filename){
  echo "begin" # beginがパイプラインへ流れます。
  $result = 42 # トップレベルにある代入演算子の結果はパイプラインへ流れません。
  echo "end" # endがパイプラインへ流れます。
  $result # $resultの評価結果がパイプラインへ流れます。
}
$r = compute("example.txt") # パイプラインの接続先は変数r。$rは3要素の配列("begin", "end", 42)になります。

この辺りのことが分かっていれば、次の関数もよく理解できるでしょう。

function range($first, $last){
  for($i = $first; $i -le $last; ++$i){
    $i # パイプラインへ$iの値が流れる
  }
}
range 10 15 #結果はArray(10, 11, 12, 13, 14, 15) 10..15と同じ
2017-10-16 ,

PowerShellスクリプトへファイルをドラッグ&ドロップする(bat不要)

ショートカットのリンク先を工夫すればOK。

単純に.ps1へのショートカットを作ってもダメ。.ps1を開く既定のハンドラが登録されていないので。

次のような記事もあるくらいだし、漠然とbatファイル経由でないとダメだと思っていた。

でも次のような記事を見つけて試してみたらうまくいった。

つまり、適当なショートカットを作成して、リンク先を powershell -NoProfile -File ファイル名(.ps1) とすればOK。

色々オプションもあるみたいなので注意。

$Args にちゃんとドロップしたファイルのパスが格納される。空白文字が入っているパスでも大丈夫。UNCでも大丈夫。

考えてみれば当たり前の話なのかもしれないけど、この方法でちゃんとドロップしたファイル名だけが $Args に入るというのはちょっと不思議なような気もする。 -File ファイル名.ps1 の後に適当な文字列を入れて試すとその文字列は $Args[0] に入るのでそういう仕様みたい。