header

2016年7月6日水曜日

Nimlang の関数を Emacs から呼び出す②

結構時間があいてしまってあれなのですが、以前 Nimlang の関数を Emacs から呼び出す(途中までしかできてない) という記事を書いてそのまま放置だったけれど、Nim のバージョンが上がってから試したらすんなり動いたというのと、el-get に登録したので紹介します。(Nim の lambda_lifting に関するバグがなおったあと良くなったとおもいますが、詳しいバージョンや Issue 番号など忘れてしまいました)

おさらい

Emacs25 から追加される dynamic module という機能で C の関数を呼び出すという機能を利用して、C にコンパイル可能な Nim で Emacs 用の拡張を作るという試みです。

その他日本語記事:

確認している Emacs と Nim

以下のバージョンで確認しています。

  • emacs-version(master branch): 25.1.50.1
  • Nim version(devel branch): 0.14.02

インストール

el-get に登録したので`el-get-list-package` とかでインストールできます。dynamic module を利用した拡張は(MELPA などで簡単にインストールして使える形で提供しているのは)まだないので、他の Dynamic Module の拡張のやり方を真似しようかな思っているので MELPA にはまだ登録していません。なので、位置づけとしては、Nim で Emacs の拡張を書くお遊びパッケージという感じです。

使い方

インストールが終わったら、

(el-get 'sync 'nim-emacs-module)

でロードパスの登録と autoload を使えるようにして、M-x `nim-emacs-module-init`で~/.emacs.d/に nim-emacs-module ディレクトリを作ります。(確認してないけど、別に手動でも OK です)

あとは作りたいパッケージ名の名前でファイルを作ります。例えば sample-xxx 関数を持つなら、sample.nim というファイル名になります。ここでつけるファイル名が Nim では(Nim でいう)モジュール名になり、なおかつ Emacs 用の関数の prefix 名となります。(便宜上そうなるように設計してるだけで Emacs 側にそれを強制するルールはありませんが)

あとは開いたファイルで, M-x nim-emacs-module-insert-template で必要な設定がファイルに挿入されます。

現在の nim-emacs-module では以下のようなコードが挿入されます。 (挿入されるものは将来的に変更されるかもしれないので、こんなニュアンスなんだという理解のほうがいいかもです。)

# `plugin_is_GPL_compatible` indicates that its code is
# released under the GPL or compatible license; Emacs will refuse to
# load modules that don't export such a symbol.
{.emit:\"int plugin_is_GPL_compatible;\".}
import emacs_module # Primitive wrapper for emacs_module.h
import emextra      # Helper library
init(emacs)
# Example(Create a file named `mod_test.nim`):
emacs.defun(return_t, 1):
  env.intern(env, \"t\".cstring)
# Provide functions registered by above from here.
emacs.provide()
# How to test the example's code:
#
#   $ emacs -Q -L .
#
# and then in *scratch* buffer, evaluate those lines:
#
#   The file name ‘ mod-test ‘ is added as prefix name of each functions and
#   its package name.
#   (require 'mod-test)
#   (mod-test-return-t)

Nim では#がコメントなので実質数行のコードですが、なんとなく Emacs で拡張作ってる方には Nim を知らなくてもわかるのではと思います。

この例では、ファイル名が mod-test.nim で関数名が return_t、引数の数が1つの Emacs の関数`mod-test-return-t`が作られます。

コンパイルの方法は nim-mode で C-c C-c でコンパイルできるようにしていますが、M-x nim-emacs-module-compile でもコンパイルできるはずです。

コンパイル後は上記コメントのように mod-test パッケージを require して、関数を試すという感じです。

今後

Emacs の dynamic module 機能がまだ始まったばかりなので今後どうなるかわかりませんが、多言語で複数パッケージを管理するスキームができたら真似してみたいなぁとおもいます。あと C、Nim とも初心者なので、まだ Nim<->Emacs Module 間でのメモリの扱いがどうなるのかわからなくてプリミティブなテストしか作ってないので時間があればもうちょっとなんとかしたいなぁという感じです。(Pull Requests 大歓迎です)

2016年1月18日月曜日

Nimlang 用の Emacs おすすめ設定

Nimlang 公式?の emacs メジャーモードは nim-mode でコード補完や eldoc サポートはこのリポジトリに入っているのですが、それ以外にあったほうがよいものとか

※注意 nim-mode はすでにインストール済みを前提に書いています。

なにはなくとも nimsuggest

nimsuggest は nim 用の IDE(or text editor)支援ツールでこれがないとコード補完と eldoc の機能が使えないので、Emacs で nim を書くにはほぼ必須ツールです。

リンク先にインストール方法は書いているとおもいますが、nim 本体と同じディレクトリに git clone して nimsuggest のディレクトリで

nim e ./compile_without_nimble.nims

をすればよかったと思います。ちなみに.nims ファイルは nimscript の略です。ghq を使っている場合は、同.nims ファイルの–path:../nim を Nim にしないとダメでした

無事ビルドしたら以下を emacs に設定することで eldoc と company-mode が使えるようになります。

(setq nim-nimsuggest-path "nimsuggest のバイナリへのパス")
(add-to-list 'company-backends 'company-nim)

flycheck (MELPA からインストール可能)

https://github.com/ALSchwalm/flycheck-nim

特にそのままでも使えますが、前述の nimscript の機能が新しいので syntax チェック機能がまだ未対応のようので nims や nimble ファイルを書くのであれば今のところ下の設定で flycheck は無視したほうがいいかもしれません。(おそらく syntax チェックは公式がそのうち対応するので)

(defun my-turn-on-flycheck-nim ()
  (when (and buffer-file-name
             (not (member
                   (file-name-extension buffer-file-name)
                   '("nims" "nimble"))))
    (flycheck-mode t)))
(add-to-list 'nim-mode-map 'my-turn-on-flycheck-nim)

indent-guide (MELPA からインストール可能)

インデント構造を見やすくする拡張です。リンク先に screenshot があるのでそれを見たほうがわかりやすいです。 https://github.com/zk-phi/indent-guide

quickrun (MELPA からインストール可能)

自分が紹介しなくてもみなさん知っているかもしれないですが、ワンコマンドで現在ファイルを実行する拡張です。多(プログラミング)言語に対応していますが nim も入っています。 https://github.com/syohex/emacs-quickrun

おわり

自分が使っているのはだいたいこんな感じです。他に便利拡張が教えてください。

2016年1月13日水曜日

Emacs から ibus をトグルする拡張作った

Evil 使ってる時に Normal モードに入った時に日本語をオフしたかったので作った。普通に shell command で`ibus engine`呼び出してるだけだけど、あまり良さそうな情報がなかったので自分で書いた。ここから ダウンロードできます。

設定

(require 'ibus-toggle)
(define-key global-map (kbd "C-o") 'tibus-toggle)

tibus-toggle でトグルできます。

Evil から使うなら、自分はこうしてます。指定するキーボードは`ibus read-config` コマンドでみれます。

(add-hook 'evil-normal-state-entry-hook
          '(lambda () (tibus-set-engine "'xkb:us::eng'")))

1/18/2016 追記 カーソル手前の文字が日本語だったら mozc にする設定を思いつきました。便利かどうか謎ですがよかったら使ってみてください。

(require 'rx)
(add-hook 'evil-emacs-state-entry-hook
          '(lambda ()
             (let ((c (char-before (max (point) (point-min)))))
               (when (and c (string-match (rx (category japanese))
                                          (char-to-string c)))
                 (tibus-set-engine "'mozc-jp'")))))

感想

ホントは mozc から変更したかった。けどそういうオプションなさそうだったので妥協して ibus で操作することにした。mozc 便利だけどかゆいところに手が届かない感じだ。

Emacs の smie.el で nimlang 用のメジャーモードのインデントを改善した

nimlang について日本語で検索しても英語で検索してもあまり情報がないのであまりつかっている人はいないかもしれませんが、Emacs の nimlang 用のメジャーモードである nim-mode のインデントを smie.el を使って改善したので紹介します。あと SMIE についての使用感とか…

ただ、Emacs25.1 で追加予定の if-let 関数(subr-x.el の)を使っており、むりやり古いバージョンの Emacs で動かそうとした場合 24.4 までがテストが通る限界でした。なので 24.3 以下ではおそらく travis のテストでしか確認してませんがダメだと思います。

nim-mode をアップデートすれば自動的に使えるようになっています。(というか古い python.el から流用しているインデントのコードははぼなくなった) あと関係ないですが、nimsuggest という nim 用の ide 支援ツールを使うと eldoc で情報が取得できれば表示されるようになっているのでインストールしたほうがいいです。

以降は smie について書きます。nim の構文は例として書きますが、nim については特に言及しません。

smie.el とは

説明なしでここまできてしまいましたが、emacs24.3(たぶん)で導入されたインデント計算エンジンです。

キータの記事 が非常にわかりやすかったです。

ざっくりいうと BNF っぽい書き方でインデント計算をよしなにやってくれるライブラリです。(実際は言語用のインデント数をあわせたり、デバッグでそんなにすんなりいかないかもしれませんが)

smie.el を使うメリット

以下のようなインデントを簡単に処理できます。

  • 例 1: condition の部分が長く折り返す場合

    if true or false and true or false
       true or false and true or false:
      echo "long condition lines should be indented"
    elif true or false and true or false
         true or false and true or false:
      echo "long condition lines should be indented"
    else:
      echo "foo"
    

    上記のような場合、カーソルのあるポイントから後ろに戻って if を探して etc.とかやってたのが、

    (defconst nim-mode-smie-grammar
    (smie-prec2->grammar
     (smie-merge-prec2s
      (smie-bnf->prec2
       '((id)
         (stmts (stmt ";" stmt) (stmts))
         (stmt (exp) (exp))
         (exp (id) (exp) (exp "=" exp))
         (conditions
          ("if" exp "elif" exp "else" ":")))
       ;; 演算子の順位付けのための設定
       ;; 以下は if/when/case がネストした場合でも
       ;; 最短の親要素を探すために必要でした。(elif や else で
       ;; インデント計算するとき)
       '((nonassoc "if" "when" "case")
         (assoc "of") (assoc "elif") (assoc "else")))))
    

    のように書くだけだったりと劇的に簡単にインデントを計算ができるようになります。(細かいインデント調整は必要になりますが、、、))

  • 例 2: 同じ予約語を使いまわしている場合でも…

    proc complex() =
      case condition:
        of "with colon":
          if true:
            echo "foo"
          else: echo "one line else"
        of "second OF":
          echo "hello"
        of "one line OF": echo "hello"
        else:
          echo "case done"
          when true:
            echo "hello"
          elif true:
            echo "make sure 'elif' is working"
          else: echo "one line else"
          if true:
            echo "after ELSE ended with single line"
    

    nim では if 文 when 文とも elif と else を使い、さらに case 文でも elif と else を使うという実際実装するのが非常にめんどくさそうな構文を持っています。(python.el からかなり パクって 再利用していたので古い nim-mode でも特に苦労はなかったですが、) このような場合、問題になる elif と else がどこに属しているかを探すのが結構めんどうでした。

    それが smie を使うとパースしたときに特定のインデント設定を書くのが非常に楽です。

    どう楽かというと smie では XXX-smie-rules というような関数を各言語ように作り、トークンに対してインデント計算を補助できます。

    上記の例でいうと:

      (defun nim-mode-smie-rules (kind token)
      "Nim-mode ’ s indent rules.
    See also ‘ smie-rules-function ’ about KIND and TOKEN."
      (pcase (cons kind token)
         (`(:after . "else")
          (if-let ((name (smie-rule-parent-p "if" "when" "case")))
             ...))))
    

    のような感じで親が何かで簡単に分岐できます。

    …実際には上記の例では smie-rule-parent-p は名前しか返してくれないので、`smie-indent–parent`関数を使いました。(親のポイントと名前を返してくれます。)

    ただ名前に–が入っているしもしかしたら使わないほうがよいかも… XXX-rules 関数の中で使う文には問題はなかったです。

    余談ですが、nim の case 文は case のあとにコロンはオプショナルで付けば1段階インデントを深くします。(なければ case と同じインデントが of, elif,else で続く)

実装するときの注意とか

  • BNF っぽい書き方をする smie の grammar 変数ですが、なれるまで結構苦労するので、一個ずつテストを作ったほうがいいかもしれません。一つの変更が広範囲に影響するので、、
  • 上記の grammar 変数ですが、いい感じに書くと親と子の要素を highlight してくれるので成功しているかのだいたいの確認になります。 (正確にコード読んでないですが、ハイライトが成功しているなら smie-rules-parent 関数とかが正常に機能していました。)
  • このハイライトですが、グラマーが複雑になってくると動かなくなる場合があるので(カーソルが動かなくなる)、以下のようにデフォルトの show-paren の関数を set するのもいいかもしれません。

    (setq-local show-paren-data-function #'show-paren--default)
    
  • smie.el は作者が Emacs のメンテナーの Stefan Monnier さんなので、edebug に対応してたりとなかなかソースみるのが面白い は edebug に対応しているので M-x smie-edebug で SPC でステップ実行できるので emacs 初心者にも結構やさしいです。

    自分は message buffer にでれば十分だったので以下のような advice を書いて edebug は使いませんでしたが、

    (defadvice nim-mode-smie-rules (around output-debug-message activate)
      "Output debug information."
      (message (format "Point: %d" (point)))
      (message (format "- IN - Kind: ’%s ’ Token: ’%s ’"
                       (ad-get-arg 0) (ad-get-arg 1)))
      ad-do-it
      (message (format "- OUT - ’%s ’" ad-return-value)))
    
  • キータの記事でも書かれてましたが、smie.el を使って書かれている ruby-mode, elixir-mode や tuareg-mode を見てみるのが参考になりました。 python っぽい文法であれば、nim-mode が参考になるかも…まだ足りない部分かなりあるとおもいますが、
  • xxx-smie-rules 関数に関する memo
    • kind が:list-intro の時は数値でなく t or nil を返す
    • :elem - empty-line-token の時は token を返す (実装が black magic 的って作者が comment に書いてる…)

おわり

smie.el メジャーモードのインデント計算では非常に便利だったので、新たに言語のメジャーモードを書く方がいましたら、ぜひ使ってみてください。

2016年1月5日火曜日

Blogger に post するコマンドラインツールを作った

このブログの更新には googlecl というコマンドラインツール経由で emacs から記事を書いていたけれど、結構前から googlecl が oauth2 に対応してなくてブログが更新できなかった。自分がなんか作った途端マーフィーの法則でもっといいツールが出たりすぐ治るのではという恐れがあってずっと googlecl の github Issues が更新されるのを待つ日々が続いたが、更新されなそうなので、シンプルに google blogger にポストするだけのコマンドラインツールを作った。実装には勉強ついでに nimlang を使ってみた。 (自分用に Emacs から post するコードも入っているので興味がある人は後半の方もみてみてください。)

前準備

nim の実行環境がない人は、先に ここから nim をインストールしてください。あと、 nimble という nim 用のパッケージマネージャもあったほうが管理が楽です。

あと Google の Blogger 用の API 利用するのに Google Developper Console で登録する必要があります。 もはや記憶の彼方でどうやったかあまり思い出せないのですが、多分ググればいろいろ情報があるのでは、、、(適当)

とりあえず、client id と client secret というのが必要です。

インストール

準備ができたら、

git clone https://github.com/yuutayamada/nim-blogger
cd CLONED DIRECTORY
nimble make

で nimblogger という実行ファイルが作れます。

ホントは nimble install でインストールできるようにしたかったけど、-d:ssl というフラグをつけないとビルドできず install のときどうやって指定するのかよくわからなかったので、このようになってしまいました。

# たぶん Google Developper Console の API manager から
# みつけられるとおもいます
export GOOGLE_API_CLIENT_ID="developper console から client_id をコピペしてください"
export GOOGLE_API_CLIENT_SECRET="developper console から client_secret をコピペしてください"

のあと

nimblogger --help

で使い方がでるとおもいます。 (注意 Refresh token なんちゃらってでたらもう一回やると成功するかもしれません。)

Emacs から

自分用なので使いたい人は使ってというスタンスで、misc ディレクトリに org-mode のドキュメントから html に変換してポストするコードが入ってます。

使いたい人は、下のような設定をしたあと`nimblogger:post-article`関数で投稿できるとおもいます。

(load "path/to/misc/nimblogger")
(setq nimblogger:blog-name "blog の名前"
      ;; binary file へのパス
      nimblogger:command "path/to/nim-blogger/nimblogger")
(define-key org-mode-map (kbd "C-S-p") 'nimblogger:post-article)

おわりに

自分が必要な最低限はできたけど、Google の更新についてく自信がないいので、いいツールがあれば教えてください。

2015年12月30日水曜日

Nimlang の関数を Emacs から呼び出す(途中までしかできてない)

Syohex さんの Emacs に mruby を組み込んでみた 記事を参考に Emacs の dynamic module 機能(Emacs 25.1 から導入予定)で Nimlang の関数を Emacs から呼べるか試してみた。ここ においてありますが、結論からいうと Emacs から nim の関数呼び出しには成功したが、引数を読み込もうとすると これ に近いエラーがでてコンパイルに失敗する。というわけでタイトルの通り途中までしかできていません。

上記の Nim の github issues を見ると作者の方が問題のコードリライトしてるらしく待ってればそのうちなおるのではという感じなのでしばらく待ってみようと思います。

これだけだと、あれなのでこんな感じになったよという報告だけ(だれに?)

# `plugin_is_GPL_compatible' indicates that its code is
# released under the GPL or compatible license; Emacs will refuse to
# load modules that don't export such a symbol.
{.emit:"int plugin_is_GPL_compatible;".}
import strutils
import emacs_module as emacs
emacs.addFunc(Fmod_test_return_t, 0):
  env.intern(env, "t".cstring)
emacs.defuns("libsample", """
DEFUN ("mod-test-return-t", Fmod_test_return_t, 1, 1, NULL, NULL);
""")

emacs_module というのは emacs-module.h の nim 用の wrapper で nim の練習ついでに作ってみました。(env.intern しか動くの確認できてないんですが、、、) 上記の nim のコードは引数がなんであれ t を返すというものです。なんかこれだけエラー起きずにコンパイルできました。`env.intern`の部分から Fmod_test_return_t 関数の中身を記述しています。addFunc というのは nim の template で次のように展開されます。

proc Fmod_test_return_t*(env: ptr emacs_env, nargs: ptrdiff_t,
                         args: ptr array[0..0, emacs_value],
                         data: pointer): emacs_value {.exportc.} =
  env.intern(env, "t".cstring)

自分の理解が正しければ、Emacs の dynamic module で C の関数を読み出す場合は引数と戻り値はすべて同じようなので(型が決まってるので) template で省略するようにしてみました。

まぁ特にまとめはありませんが、時間をおいてまた挑戦してみようと思います。ありきたりな感想ですが Emacs の拡張が Emacs Lisp 以外できたのは、ちょっと感動しました。

2015年12月20日日曜日

xterm-keybinder が urxvt に対応しました。

ターミナル上の Emacs で C-;とかの普段使えないキーバインドを使えるようにする拡張 xterm-keybinder ですが urxvt にも対応したので、紹介します。といっても README と対して内容変わらないのですが、宣伝しないと誰も使ってくれないので、、、

How it works

単純にターミナルエミュレータのなんかのキーを押したら特定のキーシーケンスを出すという設定をして、Emacs 側でそれを解析するという処理をしているだけです。(ただ hyper と super キーを含めると結構数が多いのでパッケージ化したほうが、便利と思ったので公開しています。)

Install

MELPA から xterm-keybinder でインストールできます。もともとは xterm 用に作りましたが、urxvt の設定を追加した感じです。

以下は emacs 側の設定です。

(require 'cl-lib)
(add-hook
 'tty-setup-hook
 '(lambda ()
    (cl-case (assoc-default 'terminal-initted (terminal-parameters))
      (terminal-init-rxvt
       (when (getenv "COLORTERM" (selected-frame))
         (urxvt-keybinder-setup))))))

あとは

urxvtd -q -o -f

で urxvt をデーモン起動して

# xterm-keybinder.el と同じディレクトリに emacs-urxvt-client と
# いうのがついてきます。
emacs_urxvt_client=/path/to/emacs-urxvt-client \
${emacs-urxvt-client} -e emacscliet -t &

のようなシェルスクリプトを書いて適当に起動してください。

emacs-urxvt-client の部分は単純なシェルスクリプトなので、そこに書いてある urxvt の設定を読み込めさえすれば自分が書いたのは使う必要はありません。自分で書きたい人は`urxvt-keybinder-insert`関数を使うとそれ用の設定が挿入されるので使ってみてください。

何が便利か

Emacs は拡張できるのが売りなのに結構空いてるキーバインドがないんですよね、そんななか、ターミナル上の Emacs はさらに使えるキーバインドが制限されるので空いてるキーバインドが足りないという方には便利だと思います。

2015年12月9日水曜日

Emacs の visual-fill-column.el が便利だった

Emacs の org-mode を使うときの便利拡張を見つけてしまったので紹介する。たぶん markdown 書くときも便利だと思う。

何をする拡張か?

buffer 上で長文を適当なところで折り返してくれる拡張です。今は obsolete 扱いだけど、longlines-mode と同じようなことをしてくれる。大雑把な説明だと、auto-fill-mode が、buffer 上で常時発動している感じ。自分は org-mode でブログを書いているけれど、見やすくするのに改行を入れると Blogger の方でスペースに変換されて見づらくなるので toggle-truncate-lines で我慢しながら使っていたがこの拡張のおかげで 70 文字(fill-column 変数で折り返しする文字数を指定できる)でばっちり折り返ししてくれるので非常に助かっている。

設定

インストールは MELPA 経由でできるみたいなので特にそれについては書かないけど、日本語と一緒に使うのにちょっと不満点があったので自分の設定を紹介する。
;; 折り返えしする文字数を指定
;; (デフォルトは 70 というかデフォルトのままでもいいと思う)
(setq fill-column 80)
(defun my-visual-fill-mode (&optional arg)
  "Show filled sentences by visual line mode.
If ARG is non-nil, turn on visual mode stuff."
  (interactive)
  (let ((toggle (or arg (if visual-line-mode 0 1))))
    (visual-line-mode toggle)
    (when visual-line-mode (setq word-wrap nil))
    (visual-fill-column-mode toggle)))
(global-set-key (kbd "おこのみのキーバインドで") 'my-visual-fill-mode)
上の設定の word-wrap の部分が苦労したポイント、自分は pangu-spacing-mode を使っているけれどスペースが入ったタイミングで勝手に折り返されることがあったのでこの設定をいれた。英語しか書かない人は逆にないほうがいい感じに fill してくれる。(英単語が途切れないように) というわけで状況にあわせて適当に設定してみてください。

おわり

sentence-end 変数をいじったりとか syntax-table で"、。"を punctuation に設定してみましたが結局ダメで、今回の設定に落ち着きました。もし英単語をいい感じに折り返してくれて、なおかつ日本語もいい感じに折り返す設定をご存知の方いたらぜひぜひ教えてください!

Terminal 上の Emacs で文字色を見やすく方法(黒背景で半透明)

ターミナル上の Emacs を黒背景で半透明にして使っているのですが、結構最近まで強引に見づらい色をカラーテーマで設定しなおしていたので記事にしてみようと思った。

何が問題か

ターミナル上の Emacs で透過した黒っぽい背景にしていると、たまに見えづらい文字がある。Tmux で色が 256 カラーになっていない場合もあるかもしれないけれど、Emacs が白背景用のデフォルト文字色を見せている場合もある。(Emacs 側で色があっていない場合、コメント文字の色がくらい赤色になり非常にみずらくなる。)

解決法

以下のコードを.emacs とかに貼っつける

(add-hook 'tty-setup-hook
          '(lambda ()
             (set-terminal-parameter nil 'background-mode 'dark)))

tty-setup-hook はターミナルの設定の読み込み終了時に呼ばれるフックで、background-mode->'dark の部分は Emacs に背景が黒ということを設定している。(デフォルトは'light)

2015年5月3日日曜日

xterm 上の Emacs で C-;とかの本来使えないキーバインドを使えるようにする拡張を書いた

2015/12/20 urxvt にも対応しました

たぶん Emacs をターミナルで使う人が少数派の中さらに xterm 上の emacs を使う人用の拡張を書いた。この拡張を使うと Xterm 上の(ターミナル上の) Emacs で本来使えない C-;, C-.キーや C-M、C-S のプレフィックスキーを利用するできるようになる。

仕組み

Xterm の設定で特定のキーバインド(キーシーケンス?)が押された時に、任意のキーシーケンスを出力できるので Emacs 側で受け取ったキーシーケンスを C-M-a とかのキーバインドとして使っています。どのキーシーケンスがあいているかは ECMA-48 というのを参考にした。リンク先の 26 ページに CSI キーのなかで private 用に #x3c, #x3d, #x3e, #x3f が開いているようなので#x3f(=文字)を利用するようにした。

実際後ろの方がから試そうとしたら#x3f(?文字は)すでに xterm が使っているようでうまく行かなかった。この ECMA-48 自体なかなか古い資料(1998)なので、ひょっとしてなんかまずいことしてるんじゃないか若干不安がある。。。(お詳しい方いたらコメントいただけたらうれしいです。)

インストール方法

MELPA からインストールできます。el-get でインストールしたい人は以下のコードをでインストールできるようになるはず(試してない)

(add-to-list 'el-get-sources
 '(:name xterm-keybinder
       :type github
       :pkgname "yuutayamada/xterm-keybinder-el"))

設定 & 使い方

.emacs とかに下の設定を追加してください。

(require ’ cl-lib)
(add-hook
 'tty-setup-hook
 '(lambda ()
    (cl-case (assoc-default 'terminal-initted (terminal-parameters))
      (terminal-init-xterm
       (xterm-keybinder-setup)))))

xterm と emacs を起動するときに-xrm オプションで設定を読み込みます。

#!/bin/sh
# xtermopt に xterm-option へのパスを設定してください。
xtermopt=path/to/this-repository/xterm-option
eval "xterm -xrm `${xtermopt}` -e emacsclient -t -a ''"

起動した Emacs で適当にキーバインドを試してみてください。

debug(自分用のメモ)

下のコードを C-x C-e で評価したあと調べたいキーを押すと Emacs 側でどう受け取られるか調べられる。

(key-description (read-key-sequence-vector ""))

おわりに

GUI 版の Emacs とほぼ同じキーバインドが使えてまぁまぁ便利なので、よかったら使ってください。

2015年3月4日水曜日

Emacs evil の text object について調べた

今年から evil.el という Emacs 内で vim をエミュレートする拡張を使っているけれど、text object が便利そうだったので調べた。

Evil 単品で調べるとあんまり情報が入らないと思い、vim で text object で調べたら、以下のページ詳しく書いてあるようだった。

http://blog.carbonfive.com/2011/10/17/vim-text-objects-the-definitive-guide/

しかしながら、実際 dai(indent object?) なるコマンドを normal state で実行してもなんか動いてる感じがしなかった。

そこで Emacs 内での text-object のキーマップを調べてみた。(最初からこっちを調べればよかった) 以下のコードを scratch バッファとかで実行すると message バッファに出力がでる。

(require 'cl-lib)
(cl-loop with inner = (cdr evil-inner-text-objects-map)
with outer = (cdr evil-outer-text-objects-map)
for (char . func) in (append inner outer)
do (message (format "%c : %s" char func)))

出力結果

o : evil-inner-symbol
t : evil-inner-tag
` : evil-inner-back-quote
" : evil-inner-double-quote
' : evil-inner-single-quote
> : evil-inner-angle
< : evil-inner-angle
} : evil-inner-curly
{ : evil-inner-curly
B : evil-inner-curly
] : evil-inner-bracket
[ : evil-inner-bracket
) : evil-inner-paren
( : evil-inner-paren
b : evil-inner-paren
p : evil-inner-paragraph
s : evil-inner-sentence
W : evil-inner-WORD
w : evil-inner-word

inner の部分が a になっただけでキーバインドも同じなので
Outer text object は省略しました。



出力結果をみるとどうやら、vim と evil の text-object は完全互換というわけではないみたい。(evil-version は evil-git-1def26d で確認しました。)

気になって確認したところ

evil-inner-back-quote ってひょっとして`symbol'のような emacs-lisp 内のドキュメントを扱うのかと思ったけど、ほんとに backquote 同士で囲われてる文字列に対応していた。むしろそういう lisp 内のシンボルの扱いは evil-inner-symbol がうまいこと扱うことができるみたい。(`symbol'のような文字列の中のテキストと lisp コード内の foo-bar のようなシンボルも扱えた)

あっあと、括弧のテキストオブジェクトを扱うときに"(", ")"を押すのがちょっとキーボードから遠いし英語キーボードと日本語キーボードで配置が違うのでキーマップ変えようかなぁと思ってたけど、"b"でも扱えるようで特に設定しないでもいい感じに使えそう。

おわり

まだ指がもつれる感じだけど、テキストオブジェクトの考えかたが非常に面白いと思った。特に terminal で Emacs を使うのであれば C-M-キーの代わりに便利に使えそう。

2015年3月3日火曜日

Emacs から firefox36 で browse-url-firefox が失敗する問題の対処法

いつのまにか、Emacs で browse-url で Firefox が違う URL(ただの google.com のページ)を開くようになっていたので調べたら、Firefox36 で–remote オプションが削除されていた。おそらく Emacs 側ですぐに対処されると思うけれど一応、対応策を書いておく。

ぐぐったら以下のページがみつかりどうやら、url-remote 変数を nil にすればうまいこといくらしい。http://askubuntu.com/questions/590265/clicking-link-in-emacs-no-longer-opens-page-in-browser

というわけで以下のようにした。

(require 'browse-url)
(defadvice browse-url-firefox (around my-ff-fix-remote-option activate)
"Apply firefox version 36 which was removed --remote option."
;; assign nil to use-remote of `browse-url-firefox'
(let ((system-type 'windows-nt))
ad-do-it))
(advice-add 'browse-url-mozilla :override 'browse-url-firefox)

なんか mew でリンク開くと失敗して調べたら browse-url-mozilla で開いてるっぽかったので browse-url-firefox で開くようにしておいた。(同じ引数をとっているので問題ないっぽいし、実際動いた。)

system-type を変更するのは正直きもいが、まぁ一時的だし browse-url-firefox の中だけなので我慢する。。。どうしても嫌な人は、リンク先にあるとおり url-remote の代入部分に nil をいれればいいと思います。(自分は開発版の Emacs なのでこっちのほうがアップデートするとき都合がよかった。)

2015年2月2日月曜日

Emacsでkey-translation-mapを設定した

EmacsでC-x 8でなんかプレフィックスキーがあるのは知ってたが、このkey-translation-mapで数学に関係した文字(だけだはないけど)を入力できるらしい。どこで設定してるのかちょっと探したので、一応記事にしておく。

設定した理由

最近、ターミナル上のEmacsでC-mキーとEnterキーを別々に登録できた。(Linux版窓使いの憂鬱(mayu)とEmacsのevent-apply-modifierを利用した。)ただ、なぜだか謎のタイミングで登録したキーが消えて、代わりに"µ"の文字が入力されてしまった。ここで自分が設定したC-mの代わりのキーがA-mなのだが、key-translation-mapとつながっていておそらく autoload のタイミングで自分が設定したキーを上書きしていた。(っぽい)なので、もしA-XXX keyにキーバインドを登録してそれがいつの間にか消えていたら、このkey-translation-mapを疑ったほうがいいかもしれない。(あんま使う機会ないかもしれないけど)

iso-transl.elファイルで定義されている

Emacsのソースでgit.savannah.gnu.org/emacs/lisp/international/iso-transl.elのなかにあった。探すのうまい人はすぐみつかるんだろうけど、"µ"でgrepしても変な辞書にヒットしたり最初ちょっと???ってなった。

設定

読み込まれるタイミングがよくわからなかったので、with-eval-after-loadでinit_iso-trasl.elに保存した以下のファイルを読み込むようにした。

;; init_iso-transl.el
(require 'iso-transl)
;; unbind A-m key because I'm using this key at global map.
;; (and there are four keybinds of µ)
(define-key key-translation-map (kbd "A-m") nil)

C-x 8は結構長くて押したくないキーなのでminor-mode化した。まぁお好みで、、

(easy-mmode-define-minor-mode
Y/iso-transl-minor-mode "Yuta's iso transl key minor-mode"
:init-value nil :lighter nil :keymap iso-transl-ctl-x-8-map)

(defun Y/iso-transl-toggle-minor-mode ()
"Toggle `iso-transl-ctl-x-8-map' keybinds."
(interactive)
(if Y/iso-transl-minor-mode
(Y/iso-transl-minor-mode 0)
(Y/iso-transl-minor-mode t)))

;; 適当なキーに登録してください
(define-key global-map (kbd "C-0") 'Y/iso-transl-toggle-minor-mode)

おわり

一見このキーマップが便利そうな感じで紹介しているけど、数学の記号が入力したい場合は、 helm-ucs でもっとたくさん候補から選べるのでそこまで便利じゃないかもしれない。

2015年1月28日水曜日

ubuntu14.10 awesome wm環境でプリンタ設定にはまった

Ubuntu14.10を導入してからプリンタの設定をしてなかったので設定した。

自分の環境を書くとUbuntu14.10でwindow managerはawesomeを利用している。だからなんだといわれそうだけど、awesomeだとprinterの設定する項目がGUIでみつからなかったので自分のために記事にしておく。

ドライバーのインストール

自分が使いたいプリンタ用のドライバをインストールする。CanonのMG6120が使いたかったので、 このページこのページ を参考にppaを追加した。

sudo add-apt-repository ppa:michael-gruz/canon-trunk
sudo apt-get update



64ビット環境なので以下をインストールした(自分が必要なドライバを選ぶ)MG6120は6100系のドライバで動いたのは前の環境で知っていたので以下のようにインストールした。

sudo apt-get install cnijfilter-common-64 cnijfilter-mg6100series-64





プリンタの設定

ブラウザでlocalhost:631にアクセスする方法もあるけど、僕はsystem-config-printerコマンドで設定した。locahost:631で設定する場合はadd printerとかで先に管理者用のパスワードを入力しないとfind network printerでプリンタがみつけられなくてはまった。

sudo system-config-printer




なに用のプリンタか

プリンタにいくつか種類があるがnmapコマンドで調べると、ippとかlpdとか推測できる。自分の場合は、515があったのでlpdでprinterを登録したら、印刷できるようになった。

nmap PRINTER_IP_ADDRESS
# result example
# Not shown: 997 closed ports
# PORT STATE SERVICE
# 80/tcp open http
# 139/tcp open netbios-ssn
# 515/tcp open printer
# Nmap done: 1 IP address (1 host up) scanned in 3.93 seconds

エラーメッセージ

上に書いたやりかたに行き着くまでエラーをみながらググっていたが、エラーは以下のようなコマンドでチェックできる。

sudo tail -n 100 /var/log/cups/error_log



2015年1月8日木曜日

Emacs org-modeのちょっと便利な関数

Emacs advent calender用に書いたのですが、エントリーするの遅れて更新してなかった記事です。さてorg−modeですがこのブログを書くのに利用したり何かメモするのに使ったりしてます。で、たくさんありすぎて困るorg-modeの機能ですが僕はよく使う機能はカーソルの位置によっていくつかの機能を切り分けて実行する関数を書いてひとつのキーで利用しています。今回はその便利関数の紹介です。

機能

今回紹介する関数の機能の要約は

  • カーソルがソースブロックテーブル上では、別バッファを開く
  • org-src-edit-bufferでは(上の別バッファのこと)そのバッファを閉じる
  • org-table上では折りたたまれてる内容を展開する
  • *(アスタリスク)のヘッダー行の場合,TODO,DONEなどのラベル選択を出す
  • チェックボックス(-[])ではXと無入力のトグル動作
  • link部分ではlinkの参照
  • 何もマッチしないときは、org-drawerでタンス作成

ちょっと機能がてんこもりで形容するのが難しいので、名前はorg-dwimとしました。(ちなみに DWIM はDo What I Meanの略らしい)

以下がコードです。適当にあなたの.emacsとかに貼りつけてください。(gist版もあるよ)

(defun org-dwim ()
"My convinience function for `org-mode'."
(interactive)
(cond
((org-in-block-p '("src"))
(org-edit-special))
((org-src-edit-buffer-p)
(org-edit-src-exit))
((org-table-p)
(org-table-edit-field 4))
((org-on-heading-p)
(org-todo))
((org-at-item-checkbox-p)
(org-toggle-checkbox))
((and org-return-follows-link
(let ((tprop (get-text-property (point) 'face)))
(or (eq tprop 'org-link)
(and (listp tprop) (memq 'org-link tprop)))))
(org-open-at-point))
(t (org-insert-drawer))))

各機能の説明とこの関数の説明とかをします。

link

下のような形式でURLとそのエイリアスを書くと、そのエイリアスで表示してくれる機能がorg-modeにはありますが、カーソルがそのリンク上にあるとorg-dwimで開くことができます。

ただ、デフォルトでRETキーでリンクに飛べる。のでこの機能はカレーに入っている福神漬のようにあまり意味はありません。(じゃあいれんなよ)

[[URL][ALIAS]]




table

パイプで区切ることでorg-mode上でExcelのセルとカラムのようなことができるますが、使ってると文字がながくなってきて省略したいときがあります。

で、省略したいときは下の<N>のような書き方でNに数字を入れるとその数以上は折りたたんでくれる。

| <3> |  <4> |   <5> |
| 1=> | 12=> | 12345 |



それでorg-dwim関数はカーソルがその場所にあればこの折りたたまれた状態から展開してくれます。(僕のような、キーバインド覚えられない人はここから折りただんだテーブルを展開できなくて詰む)

src block

org-mode上で特定のプログラミング言語を埋めこむことができます。埋めこみ方は下のようにbegin_srcとend_srcで囲みます。(小文字でも大丈夫です)

#+BEGIN_SRC emacs-lisp
(message "hoge")
#+END_SRC



正式名称謎ですが、このbegin_srcとend_srcの間をソースブロックって便宜上よびますね。でこのソースブロックの中で、org-dwimを呼び出すと別バッファが開いてそこでそのプログラミング言語のメジャーモードで編集できます。編集が終わったら、またorg-dwim関数を呼べばもとのorg-modeのファイルへ戻れます。

注意点として、flycheckなどのシンタックスチェッカーがあると問題がある場合もあります。その場合は`(org-src-edit-buffer-p)`関数で場合わけする必要があります。

checkbox

org-modeには以下のような感じで書くチェックボックス機能があります。

- [ ] Todo
- [X] Done


しかしながら、C-c C-x C-bというcheck boxをon, offするキーバインドが覚えられなかったので、今回のorg-dwimに追加しました。

Drawers

org-mode manualみてたらこんな機能があった。

Names of drawers.  Drawers are not opened by cycling on the headline above.
Drawers only open with a TAB on the drawer line itself.



Drawerってタンスって意味らしい、説明のとおりシフト+tabで折り畳み展開を繰り返してもタンスの中身までは展開されない。どれくらい有用かよくわかっていないけどデフォルトの関数がなかったので追加してみた。

書き方

:RESULTS:
たんす
:END:





おわり

あまりorg-mode使いこなせてるわけではありませんが、デフォルトのキーバインド覚えるよりはいくぶんましかと思います。よかったら使ってみてください。

2014年12月31日水曜日

vi.el、Emacsやめるってよ

Emacs newsの24をみてたら、vi.el, vpi.elがObsoleteになるみたい(なった?)ようです。以下のS式をEmacs上で評価するとみれます。

(view-emacs-news 24)

一応コメントを抜き出すと、

* Changes in Specialized Modes and Packages in Emacs 24.5
** Obsolete packages
...
*** vi.el, vip.el (try M-x viper instead)



ということで変わりにviper-modeを使えということらしいです。まぁ使ってる人がいるのか謎のvi modeですが、まだ(require 'vi)で注意はでますがまだ使うことはできました。

なんでこんなこと書いてるかというと、来年は心を入れかえて(Emacsで)vi(っぽい)操作を少しずつ覚えようと思い調べたからです。この記事のメインはEmacsよりのevilの設定なんですが、この Evil: EmacsをVimのごとく使う - 導入編 をみるといろいろ歴史があるんですねー。

さて僕自身はvi(vim)の操作は移動方法と終了方法がわかるくらいで、ギリギリvisudoで設定編集できるくらいなんですがちょっと観光するくらいの気持ちでevil.el挑戦してみました。あまり急にviっぽい操作を入れるとなかなかストレスフルなので、かなりEmacsよりの設定になっています。

Evilの設定

一般的な設定

(require 'evil)

(setq evil-default-cursor 'box ; 'hbar box
evil-normal-state-cursor '("#Ff00ff")
evil-insert-state-cursor '("#4169e1" (bar . 2))
evil-emacs-state-cursor '("#00ced1" (bar . 2))
evil-cross-lines t
;; Do not move eol when normal state
evil-move-cursor-back t)

;; window移動するときcursorを更新
(advice-add 'other-window :after 'evil-refresh-cursor)

Emacsよりのevilにする設定:キーバインドまとめて無効化するのにmykie.el というキーバインド拡張を利用しています。(作者によるステマ)

(require 'cl-lib)
(require 'mykie)
;; Override Evil's keybinds
;; (自分が使わない)一部のEvilキーバインドを無効化する
(cl-dolist (map `(,evil-normal-state-map
,evil-motion-state-map))
;; 以下の設定で指定したキーが無効化され、global-mapのキーが利用され
;; るようになる
(mykie:set-keys map
"C-e" "C-o" "C-r" "C-s" "C-t" "C-w" "C-z" "C-^" "C-="
"M-n" "M-p"))

(setq
;; デフォルトのevilの状態をemacsに(それevil使う意味ry)
evil-default-state 'emacs
;; term-mode or eshell-mode didn't work well in my environment.
;; For more info, see `evil-emacs-state-modes', `evil-insert-state-modes' or
;; `evil-motion-state-modes'.
evil-insert-state-modes nil)

;; insertモードはemacsモードです
(advice-add 'evil-insert-state :override 'evil-emacs-state)

自分の設定を解説すると、最初のdolistの部分はnormalモードとmotionモードの一部のキーでglobal-mapのキーが使いたいので無効化しています。evil-insert-state-modesについては、デフォルトではterm-modeやeshell-modeが入っていましたがこのままだと自分が設定した各モード用のキーバインドが反映されなかったのでnilとして default のstateをemacsとして使っています。

あと最後のevil-insert-stateの設定については、あまりこういうことはしたくないのですがorg-modeでtabキーでorg-tableを広げられなかったり上述のterm-modeやeshellの問題があり、各モードごと設定するのはめんどうかなと思い、このように設定しました。(何かよい解決策あれば教えてください)

InsertモードからNormalモードへの切替え

ESC と C-[ はちょっと押しづらいと感じていて、muhenkanキーに割り当てています。これもmykie.elを利用していて、2回押したらmagitを起動するようにしてます。

(mykie:set-keys global-map
"<muhenkan>"
:default
(if (bound-and-true-p evil-mode)
(call-interactively 'evil-normal-state)
nil)
:repeat magit-status

"C-e"
;; C-u2回押したあと、C-eでevil-modeになる
;; mykieがこんな設定もできるよという例なので、:C-uとregion&C-uはいりません。
:default end-of-line
:C-u eww
:C-u*2 evil-mode
:region&C-u align)

おわり

こんな感じでevil.el使い始めました。ほんとはvi.elが一度も登場しないもやもやとした構成も考えましたがさすがにあれかなぁと思って最初にちょっと書きました。

桐島、部活やめるってよ (本編BD+特典DVD 2枚組) [Blu-ray]
バップ (2013-02-15)
売り上げランキング: 6,195

2014年12月29日月曜日

EmacsでGoogle日本語入力のSKKサーバーを利用するようにした

以前は Ruby製のGoogle日本語入力サーバー を使っていたが、OSを変えたついでに調べたら Golang製のGoogle日本語入力のSKKサーバー があったのでこちらを使うようにした。(どちらもlocalのマシンでサーバー起動して、Google日本語入力APIとやり取りする)

SKKについてあまりわかっていないので、自分のやり方が正しいかよくわからないがとりあえず利用できるようになったので記事にしておく。(自分は辞書含めて全てutf-8で設定しているので、以降の設定もそれようとなっているので適当に読み替えてください)

まずはインストール

Golang製なので


go get github.com/akiym/go-skkserv


これでインストールできる。

作者さんの書いてる例をコピペ&ビルド

コピペしたけど、文字エンコーディングの部分は"utf8"にした。その後、go buildでビルドした。

Emacsの設定

ほんとは設定値をsetqしたら後はskk-server-openでいけそうな気がするけど、(よくわからず)できなかったので、自分は以下のように設定した。

(require 'skk-server)

(setq skk-server-host "0.0.0.0"
skk-server-prog "pass/to/go-serv" ; ビルドしたgo-skkservへのパス
skk-server-portnum 55100)

(defun my/boot-skk-server ()
"Start SKK server."
(unless (skk-server-live-p)
(async-shell-command skk-server-prog (get-buffer-create "*goskk*"))
(setq skkserv-process (skk-open-server-1))
(when (skk-server-live-p)
(set-process-coding-system skkserv-process 'utf-8 'utf-8))))

(defun my/skk-close-server ()
(interactive)
(when (skk-server-live-p)
(skk-disconnect-server)
(kill-process (get-buffer-process "*goskk*"))
(message "Server disconnected")))

(add-hook 'kill-emacs-hook 'my/skk-close-server)

最初文字コードを特に設定せずに利用した場合、文字化けしたので`skk-process-coding-system'の部分を追加したら動くようになった。設定変数でこのあたりなんとかできるのかもしれないけれど、自分が調べたかぎりではeuc-jpに強制的にかわるようだった。(詳しいかたいたらコメントいただければうれしいです。)

上のコードを利用するにはmy/boot-skk-serverをSKKでキーインプットする前に呼び出せばいい。

おわり

ハードコアなSKKユーザーの方には軟弱者と罵られそうですが、SKKを使いつつGoogle日本語入力で補助してもらうのは、なかなか快適です。便利なGoogle日本語入力SKKサーバー(のコード)を公開してくださっているかたたちに感謝です。

Raspberry Piでリモートデスクトップ環境を作った

現在Raspberry PiはHDMI経由でテレビにつなっがっているので、こちらのほうが大画面でみやすいのでRaspberry PiからノートPCのほうにリモートで接続して使用できないかと思い試した。(自分は)あんまりやることではないので、メモとして残す。

結論からいうと、できることはできるけどあんまり快適ではなかったのでたぶん継続しては使わないと思う。

やりかた

リモートデスクトップで調べると、xrdp, remix, x11vnc, tightvncserverとかあるらしい。このページ をみてx11vncを試してみた。

接続されるPC:

sudo apt-get install x11vnc
# マシンのパスワードを保存
x11vnc -storepasswd
# パスワード付きでサーバー起動
x11vnc -usepw -forever

実行すると、メッセージで最後の方に"ホスト名:0"みたいのがでた。

接続するPC(自分の場合Raspbery Pi)

# 確かこんな名前のパッケージだった
sudo apt-get install vncviewer
# sshで接続
ssh 接続されるPC
# 別タブを開いた後,その別タブで(上で出たホスト名を入れる)
vncviewer ホスト名:0

sshで接続する前は、エラーが出て接続できなかった。

書きわすれたがPiはstartxしてから確認した。ログインターミナルの状態では確認していない。

使い勝手

リモートPC側でキーバインドの変更をしているが、Raspberry Piではしていないので(あたりまえだけど)設定したキーバインドが使えなくて違和感を覚えた。あと自分の環境ではそんなにさくさく使えなかった。ただこのあたりPiの性能なのか自分のとこのネットワークが遅いのかよくわからなかった。

おわり

快適じゃないけど、Raspberry Piでリモートで自分のPCをいじるのはちょっと快感だった。Raspberry Piおもしろい。

2014年12月27日土曜日

Raspberry Piの設定をした

クリスマスプレゼントにRaspberry Piをもらったので(ありがとう母!)さっそく設定した。ブログ記事としては、他の人もよくかかれているしとりたてて新しい情報はないので知っている人はあまり見る価値はないです。自分用のメモの意味合いがつよいです。

もらったもの

Raspberry Pi Starter Kitをもらった。なので、

  • Raspberry Pi B+
  • HDMIケーブル
  • 電源ケーブル(micro usb)
  • micro SD card(Noobs入り)

が入っていた。※NoobsはPi用のOSインストーラーです

OS Install

  • Raspberry PiをテレビにHDMIでつなぐ
  • Raspberry Piにmicro SD cardを入れる
  • 電源ケーブルを入れる

電源ケーブルを入れた段階でRaspberry Piが起動するので、後は(Noobs)なのでOSを選択してインストールする。

自分は初Raspberry Piだったので、とりあえずRaspbianにした。

インストール中にユーザー名とパスワードとホスト名を決めたきがする。defaultのユーザー名はpi,パスワードはraspberryだった。デフォルトのパスワードのままだとアレなので変えた。

あと説明の途中で、raspi-configで設定変えれるよって書いてあったのでメモしておく。

Install後にしたこと

若干インストール中のことも入っている気もするが、まぁメモなのでいっか。

update-alternativeコマンドでちょっとデフォルト設定をいじった。エディターnanoからviにした。

sudo update-alternative --all



アップデート&アップグレード

sudo apt-get update
sudo apt-get upgrade



Wifi接続の設定をした。startxコマンドの後,GUIからwifiの設定ぽいっアイコンをクリックした

startx


あとは普通にIDとパスワードを設定した。

固定IPの設定たぶん、Emacsからtrampで接続するので固定IPの設定をした。How to set static address in Raspberry Pi上のリンクを参考に設定した。(リンクはeth0で設定しているが自分がやりたいのは無線なのでwlan0で設定した。)

SSH接続がカクつくSSH接続がカクつくような感じがしたので、ググったRaspberry Pi + Wi-Fi アダプタが異常に遅い問題を解決とりあえず設定したら少し早くなった気がする。(たぶん)

おわり

設定したのこれくらい。(ほんとはEmacsのtrampの設定もしたけど別の記事にする)スターターキットだからOSもすぐインストールできて導入はすごい簡単だった。

Raspberry Pi Model B+ (Plus)
Raspberry Pi Model B+ (Plus)
posted with amazlet at 14.12.29
raspberrypi.org
売り上げランキング: 724

2014年12月22日月曜日

Emacsのcl-lib.elとlexcal-binding: tのエラー回避

最近mykie.elというEmacsのキーバインド拡張をcl-lib対応した。その時に遭遇した問題をメモとして残しておく。(この記事は2014/12/20に書いたので、そのうち修正さる挙動がかわるかもしれません)


cl-libって?

まずcl-libが何だという人向けに説明すると、cl-libはEmacsでもcommon-lisp系の関数を使えるようにする拡張です。loopとかloopとかloopとか(それくらいしかしらない)

たしかEmacs24くらいから正式に導入されたと思いますが、それ以前のEmacserは



(eval-when-compile (require 'cl))

としてclライブラリを使っていました。eval-when-compileの説明をみるとどうやら、コンパイル時評価するようにしていたようです。

詳しい経緯は知らないですが、最近は上記のcl-libを使うほうが主流のようです。


lexcal-baidingって

emacs-lispの変数はダイナミックスコープですが、ファイルの先頭にlexical-binding: tとして追加しておくとそのファイルをレキシカルスコープとして扱ってくれます。



;; some thing ......  -*- lexical-binding: t -*-

問題

んで、mykie.el ですが上の古いclを使って書いてました。去年僕が書いた時はcl-libを使おうとするとwarningが出て直し方がよくわからなかったので、古い方のclでいいやって思ってそのままでしたが、最近このmykie.elパッケージをいじるのにcl-libにしてたらまだワーニングがでたのでいいかげん調べてみました。

最初の問題としては以下のようなcl-loop関数でunused lexical variable my_listと出るようになりました。



;;; this is sample -*- lexical-binding: t -*-
(require 'cl-lib)
(cl-loop with my_list
for str in '(1 2 3)
collect str into my_list
finally return my_list)

上の関数をmacroexpand関数で展開してみると以下のようになりました。



(cl--block-wrapper
(catch (quote --cl-block-nil--)
(let* ((my_list nil)
(--cl-var-- (quote (1 2 3)))
(str nil)
(my_list nil))
(while (consp --cl-var--)
(setq str (car --cl-var--))
(setq my_list (nconc my_list (list str)))
(setq --cl-var-- (cdr --cl-var--)))
my_list)))

なぜかletフォームの中にmy_list nilが2個あるのがわかると思います。というわけで、実際マクロ展開すると使われていない変数として存在するのがわかりました。

じゃあどう書けばいいかっていうと、単純にwith my_listで宣言している部分を消してしまえばいいだけでした。

他のunused variableが出た時のtipsとして、_を変数名につけるとwarningがでなくなるかもしれません。



  •   ;;; this is sample -*- lexical-binding: t -*-
    (require 'cl-lib)
    (cl-loop for (first second) in '((1 . 2) (3 . 4))
    collect first)

    ;; こっちはエラーでない
    (cl-loop for (first _second) in '((1 . 2) (3 . 4))
    collect first)

ただemacs-lispコンパイラーに好き嫌いがあるみたいで、上で紹介したwith文の場合は_ではwarning抑制できませんでした。

あとこれは、あまりおすすめできませんが、with-no-warningsという関数でくくればその中はワーニングが抑制できます。ただ上のwith文は(以下略)

なので、最初は_をちょろっと追加してダメなら、他を試すといった感じでしょうか

あとこんなスーパーおっちょこちょいは僕だけかもしれませんが、古いcl-libが読み込まれているとエラーが出るというケースもあるみたいです。いいかたがあやふやなのはもう古いのは消してしまって確認するのがめんどうという理由ですが、確か古いcl-lib消したらちょっとワーニング変わった気がします。たぶん

でどうやって確認するかですが、M-x list-load-path-shadowsで確認できました。
(僕がみつけたのは、なんかwarningにそれっぽいのがでてたからですが)

こんなかんじの出力でした。



/home/yuta/local/vcs/github.com/yuutayamada/emacs.d/elisp/el-get/cl-lib/cl-lib hides /home/yuta/local/vcs/git.savannah.gnu.org/emacs/lisp/emacs-lisp/cl-lib

おまけ

pcaseでも以下のようにするとunusedワーニングがでました。



(let ((name "おれだよおれおれ"))
(pcase name
(`"foo" "fooだよ")
(`"bar" "barだよ")
(`"piyo" "piyoだよ")
(name (concat name "だよ"))))

一番下のデフォルトで結果を返すところをtにすれば普通にうごきます。


おわり

というわけで、僕がはまったところのネタがつきました。cl-libではまったとき参考になれば幸いです。


Popular Posts

Blogger templates

Blogger news