カテゴリー別アーカイブ: emacs

Termux with Xperia Z4 Tablet + BKB50 + Syncthing

最近使わなくなってきた Xperia Z4 タブレットに、下記の環境を整備して延命する。

  • emacs25
  • markdown と org-mode ファイルを、出先で編集する
  • gitやファイル共有で、他のPCとのファイルの同期をとる

Termuxのインストール

何で今まで知らなかったのか、こんな凄いものを見付けた。

Termuxは、Androidで動く端末(ターミナル)とLinux環境を、非root環境で動かすというもの。

Linux環境にはパッケージマネジメント apt も含まれていて、主だったパッケージは既に用意されているところが素晴しい。

2015年末から開発が始まっていて、この原稿の時点では v0.59 。

2017年ごろから、紹介記事が増えていたようだ。

Termuxの使い方

ターミナル内は、bashそのもの。

標準では表示できる画面は一つだけだが、複数セッションも起動できる。

アプリとしてのTermux自体は、以下の様な操作が出来る。 フォントサイズをピンチ操作で変更できるのは、とても有り難い。

  • タッチ操作でスクロール
  • 長押しでコンテキストメニューが出て、コピーペーストなどが可能
    • Selecting and pasting text.
    • Sharing text from the terminal to other apps (e.g. email or SMS)
    • Resetting the terminal if it gets stuck.
    • Switching the terminal to full-screen.
    • Hangup (exiting the current terminal session).
    • Styling the terminal by selecting a font and a color scheme.
    • Showing this help page.
  • ピンチで拡大・縮小が可能 (Terminalなのに!)
  • 左側からスワイプするとメニューが出て、KEYBOARDとNEW SESSIONの操作が可能
    • 長押しでSESIONのタイトル編集が可能
  • キーボードショートカット
    • Ctrl+Alt + C → Create new session
    • Ctrl+Alt + R → Rename current session
    • Ctrl+Alt + Down arrow (or N) → Next session
    • Ctrl+Alt + Up arrow (or P) → Previous session
    • Ctrl+Alt + Right arrow → Open drawer
    • Ctrl+Alt + Left arrow → Close drawer
    • Ctrl+Alt + F → Toggle full screen
    • Ctrl+Alt + M → Show menu
    • Ctrl+Alt + U → Select URL
    • Ctrl+Alt + V → Paste
    • Ctrl+Alt + +/- → Adjust text size
    • Ctrl+Alt + 1-9 → Go to numbered session

詳細は

キーボードのCapsとCtrlの入れ替え&特殊記号の入力

Google Playからインストールすれば、特にAndoroid本体の設定を加える必要もなく、アイコンから起動してあっさり普通に使用できる。 ただし、AndroidのソフトキーボードはIMEを前提に作られていて直接入力に向かないし、Ctrlキーなどの装飾キーも使い難い。

実用的には、外付けの物理キーボードが必須だ。

今回は、Xperia Z4 Tablet 用のBluetoothキーボード BKB50を使用する。

更に、レイアウトを設定する下記のアプリを使ってCapsとCtrlを入れ替える。これで快適に操作できる。

アプリのページには、下記の様な但し書きがあり、保証外の様子。

Bluetooth接続のキーボードでは未検証です。 恐らく他の(ATOK以外の))IMEでは正常に動作しません。 確認した限りGoogle日本語入力・Simeji・iWnnでは正常に動作しませんでした。

今回は、Androidの日本語入力は使用せず(SKKを使う)、CapsとCtrlの入れ替えだけが目的なので、問題ない。

残念ながら、BKB50では"|"が入力できないのだけれど、 Termuxの機能で補うことが出来る。

左からのスワイプのメニューから、KEYBOARDを選択すると、画面下に記号一覧が出るので、ここから入力することにする。

emacs + git + python のインストール

2018.01.05時点でのバージョンは。

  • python 3.6.4 (標準が python3)
  • emacs 25.3.1
  • git 2.15.1

これだけあれば、使い道はかなりありそうだ。

caskでemacs環境を再構築

emacsの環境をgitとcaskで管理しているので、Termuxでも使用する。

cask install がパッケージをダウンロードする時に失敗することが多いものの、 installを何度か繰り返すと、全てのパッケージのインストールを完了出来た。

Androidのストレージをリンク (不採用)

で、 $HOME/storage に、下記のストレージへのリンクが作られる。

  • ~/storage/shared
  • ~/storage/downloads
  • ~/storage/dcim
  • ~/storage/pictures
  • ~/storage/music
  • ~/storage/movies
  • ~/storage/external

Dropboxでファイル同期 (不採用)

AndroidでDropboxのオフライン機能を使っていれば、下記のフォルダからアクセスできる。

  • ~storage/shared/Android/data/com.dropbox.android/files/hogehoge/foo/bar

ただし、Forumの記事 Got Dropbox to work with Termux!!! によると、全自動で同期とは行かず、いくつかのお作法がある。

  • Termuxでファイルを開く前後で、Dropboxを手動で同期(update/sync)する必要がある
  • ファイルを新規作成する場合は、Dropboxで作成し、予めオフラインファイルとしておく必要がある

You will need to go into Dropbox and manually update/sync the files before and after you open them in Termux. I also discovered if you want to create a new file you will need to use Dropbox to create it and set it as an offline file before you open it to edit in Termux if you want Dropbox to sync it.

普段使いには、やや面倒。

とは言え、gitで管理する程でもない個別のファイルはDropboxの様な方法が便利。

代りに、Syncthingを使って自宅のMac上のファイルと同期がとれる様にする。

Syncthingでファイル同期: Macの設定

Macには、homebrewからインストールする。

アプリケーションから syncthing-bar を実行すると、 Syncthingが常駐する。 タスクバーの syncthing-bar から [http://127.0.0.1:8084/](OpenUI) を選択して設定画面を出して、必要な情報を確認しておく。

  • デバイスID: 設定画面のメニューから IDを表示 を選ぶ
  • 共有フォルダー: 設定画面の フォルダーを追加 で設定する

Syncthingでファイル同期: Termuxの設定

Termuxで使うので、Google Playのアプリ版ではなく、 apt からCUIでインストールする。

常に使う予定はないので、サービスの設定はしない。 必要な時に、裏のTermuxターミナルで syncthing を実行する。

標準では 127.0.0.1:57562 で、Macと時と同じ設定画面が表示されるので、Mac同様に共有したい設定を加える。

  • デバイスID: 起動メッセージの中に "MY ID"(デバイスID)という行
  • (共有フォルダー: 設定画面の フォルダーを追加 で設定する) ☆必要なら

Syncthingでファイル同期: 接続テスト

最初の接続がやや煩雑。 MacとTermuxの設定画面に、それぞれからの接続確認メッセージが出るので、適宜許可を出せば同期が始まる。 その際、(多分無関係な)"近くにあるデバイス"も同時に表示されるので、自分のデバイスIDとフォルダIDに間違いないか確認する。

一度同期が始まれば、Dropboxに近い感覚でファイルが同期される。

少し意地悪なテストをしてみた結果は、以下の通り。

  • 編集がコンフリクトした場合は、ファイルが複数に分かれる (Dropboxと同じ動作)
  • ファイル編集時には、他のデバイス上のファイルがロックされるが、タイムラグがやや大きい
  • そのタイムラグの間に複数の編集を加えると、どちらかの編集が消えることがある

この様な動作なので、複数人で同時にアクセスする様な使い方には向いていないが、一人で作業する分には問題にならない程度だろう。

gitを使ったプロジェクト同期のテスト

自分のリポジトリからcloneして、commit出来ることを確認した。 これなら、ちょとしたコーディングには十分使える。

ドキュメント作成するには、ややSKKの反応が遅いのが気になる。 入力は出来ているのだが、表示の遅延が大きくて、ややとまどう。

emacsの補間系のパッケージを減らすと改善するかも知れない。 おいおい試してみる。

まとめ

  • Termuxを使えば、Androidタブレットで簡易版ではない本物emacsが割と実用的に動作する
  • しかも、emacsに限らず通常使いそうなパッケージを簡単に追加することができる
  • 実際に、gitとSyncthingを使ったプロジェクト・ファイル同期の環境を作り、動作を確認した
  • 物理キーボードにない特殊記号は、termuxのソフトキーボードで解決できる

Macbook Proを持ち運ぶ機会が少し減るかも知れないくらいの完成度だ。

emacs 25.1 で org2blogを使って WordPress に投稿するには

以前から気になっていた org2blog を emacs-25.1.1 で動かそう。 という話。

(この記事はemacs-25+org2blogで投稿しました)

org2blog / README.org を参考に、packageから org2blog をインストールして、以下の様に設定。

(require 'org2blog-autoloads)
(setq org2blog/wp-blog-alist
   '(("wordpress"
      :url "http://***.somof.net/****"
      :username "****"
      :password "****"
      :wp-latex nil
      :wp-code t
      )))

早速試してみるとワーニングが出たので、追加で htmlize の新しいバージョンを手動でインストールした。

これでログイン(org2blog/wp-login)まで出来るようになったけれど、投稿(org2blog/wp-post-buffer)が出来ない。

エラーメッセージは、こんな感じ。



error in process sentinel: url-http-create-request: Multibyte text in HTTP request: POST /xmlrpc.php HTTP/1.1




error in process sentinel: Multibyte text in HTTP request: POST /xmlrpc.php HTTP/1.1

雰囲気、文字コードか改行コードの問題の様。 org2blogが呼び出している gzipコマンドを Apple製からGNU製に変えてみたけど、症状は変わらず。

仕方ないので org2blogのソースを追ってみたところ、エラーの発信源は emacsに添付されている url-http.el だった。 なんと、 emacs 自身のコード側に問題があったのだった。

url-http-create-request関数の中に、こんなコードが紛れていた。

;; Bug#23750
(unless (= (string-bytes request)
           (length request))
  (error "Multibyte text in HTTP request: %s" request))
(url-http-debug "Request is: \n%s" request)

今使っているemacsは、リリース版の emacs 25.1.1 なのだけど、たまたま出来たてのバグを踏んでしまったらしい。

request(XML-RPCのXMLそのもの)の文字数とバイト数が一致しない場合にエラーを返す、多分デバッグ用のコードなのだけど、 ユーザーには意味がないので、とりあえず削除することにする。

こんな風に、initファイルに追加。

(advice-add 'url-http-create-request :override
            'url-http-create-request-debug)
(defun url-http-create-request-debug (&optional ref-url)
  "Create an HTTP request for <code>url-http-target-url', referred to by REF-URL."
  (let* ((extra-headers)
         (request nil)
         (no-cache (cdr-safe (assoc "Pragma" url-http-extra-headers)))
         (using-proxy url-http-proxy)
         (proxy-auth (if (or (cdr-safe (assoc "Proxy-Authorization"
                                              url-http-extra-headers))
                             (not using-proxy))
                         nil
                       (let ((url-basic-auth-storage
                              'url-http-proxy-basic-auth-storage))
                         (url-get-authentication url-http-proxy nil 'any nil))))
         (real-fname (url-filename url-http-target-url))
         (host (url-http--encode-string (url-host url-http-target-url)))
         (auth (if (cdr-safe (assoc "Authorization" url-http-extra-headers))
                   nil
                 (url-get-authentication (or
                                          (and (boundp 'proxy-info)
                                               proxy-info)
                                          url-http-target-url) nil 'any nil))))
    (if (equal "" real-fname)
        (setq real-fname "/"))
    (setq no-cache (and no-cache (string-match "no-cache" no-cache)))
    (if auth
        (setq auth (concat "Authorization: " auth "\r\n")))
    (if proxy-auth
        (setq proxy-auth (concat "Proxy-Authorization: " proxy-auth "\r\n")))

    ;; Protection against stupid values in the referrer
    (if (and ref-url (stringp ref-url) (or (string= ref-url "file:nil")
                                           (string= ref-url "")))
        (setq ref-url nil))

    ;; We do not want to expose the referrer if the user is paranoid.
    (if (or (memq url-privacy-level '(low high paranoid))
            (and (listp url-privacy-level)
                 (memq 'lastloc url-privacy-level)))
        (setq ref-url nil))

    ;; url-http-extra-headers contains an assoc-list of
    ;; header/value pairs that we need to put into the request.
    (setq extra-headers (mapconcat
                         (lambda (x)
                           (concat (car x) ": " (cdr x)))
                         url-http-extra-headers "\r\n"))
    (if (not (equal extra-headers ""))
        (setq extra-headers (concat extra-headers "\r\n")))

    ;; This was done with a call to </code>format'.  Concatenating parts has
    ;; the advantage of keeping the parts of each header together and
    ;; allows us to elide null lines directly, at the cost of making
    ;; the layout less clear.
    (setq request
          (concat
             ;; The request
             (or url-http-method "GET") " "
             (url-http--encode-string
              (if using-proxy (url-recreate-url url-http-target-url) real-fname))
             " HTTP/" url-http-version "\r\n"
             ;; Version of MIME we speak
             "MIME-Version: 1.0\r\n"
             ;; (maybe) Try to keep the connection open
             "Connection: " (if (or using-proxy
                                    (not url-http-attempt-keepalives))
                                "close" "keep-alive") "\r\n"
                                ;; HTTP extensions we support
             (if url-extensions-header
                 (format
                  "Extension: %s\r\n" url-extensions-header))
             ;; Who we want to talk to
             (if (/= (url-port url-http-target-url)
                     (url-scheme-get-property
                      (url-type url-http-target-url) 'default-port))
                 (format
                  "Host: %s:%d\r\n" host (url-port url-http-target-url))
               (format "Host: %s\r\n" host))
             ;; Who its from
             (if url-personal-mail-address
                 (concat
                  "From: " url-personal-mail-address "\r\n"))
             ;; Encodings we understand
             (if (or url-mime-encoding-string
                     ;; MS-Windows loads zlib dynamically, so recheck
                     ;; in case they made it available since
                     ;; initialization in url-vars.el.
                     (and (eq 'system-type 'windows-nt)
                          (fboundp 'zlib-available-p)
                          (zlib-available-p)
                          (setq url-mime-encoding-string "gzip")))
                 (concat
                  "Accept-encoding: " url-mime-encoding-string "\r\n"))
             (if url-mime-charset-string
                 (concat
                  "Accept-charset: "
                  (url-http--encode-string url-mime-charset-string)
                  "\r\n"))
             ;; Languages we understand
             (if url-mime-language-string
                 (concat
                  "Accept-language: " url-mime-language-string "\r\n"))
             ;; Types we understand
             "Accept: " (or url-mime-accept-string "*/*") "\r\n"
             ;; User agent
             (url-http-user-agent-string)
             ;; Proxy Authorization
             proxy-auth
             ;; Authorization
             auth
             ;; Cookies
             (when (url-use-cookies url-http-target-url)
               (url-http--encode-string
                (url-cookie-generate-header-lines
                 host real-fname
                 (equal "https" (url-type url-http-target-url)))))
             ;; If-modified-since
             (if (and (not no-cache)
                      (member url-http-method '("GET" nil)))
                 (let ((tm (url-is-cached url-http-target-url)))
                   (if tm
                       (concat "If-modified-since: "
                               (url-get-normalized-date tm) "\r\n"))))
             ;; Whence we came
             (if ref-url (concat
                          "Referer: " ref-url "\r\n"))
             extra-headers
             ;; Length of data
             (if url-http-data
                 (concat
                  "Content-length: " (number-to-string
                                      (length url-http-data))
                  "\r\n"))
             ;; End request
             "\r\n"
             ;; Any data
             url-http-data))
    ;; Bug#23750
    ;;(unless (= (string-bytes request)
    ;;           (length request))
    ;;  (message "   text byte %d vs %d length" (string-bytes request) (length request)))
      ;;(message "===============================")
      ;;(error "Multibyte text in HTTP request: %s" request))
    (url-http-debug "Request is: \n%s" request)
    request))

これで、無事 org2blogから投稿できるようになった。

そのうち解決されるだろうけれど、それまではこれで凌ごう。

emacs helm find-fileの設定を整理

emacsとhelmののアップデートで、
find-fileの動きが大分変わってしまったので修正する。

|—————-+———————————————|
| 関数 | いろいろ |
|—————-+———————————————|
| find-file | 標準の補完リストがバッファになり |
| | 操作がacejumpみたくなった (acejumpの機能?) |
| helm-find-file | TAB補完の設定が効かなくなった |
| | その代り → を使え、と言うことらしい |
|—————-+———————————————|

両方をしばらく使ってみたけれど、
どちらも、find-fileとしては、おせっかい過ぎる感じがする。

滅多に使わないコマンドを探す様な場合はhelmは最高だけども、
find-fileする時は目的のファイル名が頭の中にある訳なので、
候補が大量に出てきても有難味が薄いのだ。

emacs標準機能に慣れるのも良いかと、しばらく素で使ってみたけれど、
helm-miniと補完操作が違うのは、やっぱり気持悪い
そうは言っても helm I/Fが便利だし、補完操作は揃えておきたい。

|—————-+———————————————|
| 関数 | 操作方法 |
|—————-+———————————————|
| find-file | 水平リスト, ace-jump的選択 |
| | TAB: 補完 (複数候補があると確定しない) |
| | C-BS: 直前の単語削除 |
| helm-find-file | helm I/F、垂直リスト、Action込み |
| | →: 補完 (複数候補があっても何か確定できる) |
| | C-l: 直前の単語削除 |
| | TAB: Actionの選択 |
| | C-j,C-z: 昔のTABの様な動作 (多分) |
|—————-+———————————————|

補完キーがカーソルになっているのは、 lynxスタイルというものらしい。

#+BEGIN_SRC lisp
(defcustom helm-ff-lynx-style-map t
“Use arrow keys to navigate with helm-find-files'.
You will have to restart Emacs or reeval
helm-find-files-map’
and `helm-read-file-map’ for this take effect.”
:group ‘helm-files
:type ‘boolean)
#+END_SRC

ただ、これを nil にしても、TABキーは元に戻らない。

昔のTAB相当の機能 helm-execute-persistent-action は
C-jとC-zに割り当てられている。

そもそもActionなんて使わないぜ!という男の中の男は。

#+BEGIN_SRC lisp
(define-key helm-map (kbd “TAB”) ‘helm-execute-persistent-action)
#+END_SRC

とすれば簡単で良い。

僕は女々しいので、今後はC-jとC-zを使うことにする。

find-filesとhelm-miniの動作がちょっと違うのが
もやっとするけど、慣れられそうな範囲だと思う。

emacs helm の補完情報(ソース)を切り替えるキー操作

helmは、殆どの場合、タブキーで補完してくれるので、
操作方法を覚える必要はあまりない。

だけど、覚えなくて良いせいで
たまに補完の情報源を切り替えたい時に、
毎回検索することになる。

#+BEGIN_SRC lisp
;; helm-20160321.959:
./helm-files.el:409: (define-key map (kbd “<M-left>”) ‘helm-previous-source)
./helm-files.el:410: (define-key map (kbd “<M-right>”) ‘helm-next-source))
#+END_SRC

カーソルキーの左右で切り替えられるみたいだ。

これで、ソースを recentf から buffers-list に
さくっと切り替えられる。

きっと
また忘れるだろうな。

emacs helm の設定を整理

2016/03/24 現在のhelmの初期状態が、
変更していた自分好みと殆ど同じになったので
設定を見直した。

#+BEGIN_SRC lisp
;; ————————————————————————
;; @ helm
(require ‘helm-config)
(require ‘helm-command)
;;(require ‘helm-descbinds)

;; 体感速度向上
;;(setq helm-idle-delay 0.2)
;;(setq helm-input-idle-delay 0.2)

;;(setq helm-candidate-number-limit 200)
(setq helm-mini-default-sources ‘(helm-source-recentf
;;helm-source-files-in-current-dir
helm-source-buffers-list
;;helm-source-buffer-not-found
))
(helm-mode 1)

;; Helm KeyBind
(define-key global-map [remap find-file] ‘helm-find-files)
(define-key global-map [remap occur] ‘helm-occur)
(define-key global-map [remap list-buffers] ‘helm-buffers-list)
(define-key global-map [remap dabbrev-expand] ‘helm-dabbrev)
(global-set-key (kbd “M-x”) ‘helm-M-x)

;;; helmで変更したい/したくないコマンド
;;(add-to-list ‘helm-completing-read-handlers-alist ‘(find-file . nil))
;; ‘((describe-function . helm-completing-read-symbols)
;; (describe-variable . helm-completing-read-symbols)
;; (describe-symbol . helm-completing-read-symbols)
;; (debug-on-entry . helm-completing-read-symbols)
;; (find-function . helm-completing-read-symbols)
;; (disassemble . helm-completing-read-symbols)
;; (trace-function . helm-completing-read-symbols)
;; (trace-function-foreground . helm-completing-read-symbols)
;; (trace-function-background . helm-completing-read-symbols)
;; (find-tag . helm-completing-read-with-cands-in-buffer)
;; (ffap-alternate-file . nil)
;; (tmm-menubar . nil)
;; (find-file . nil)
;; (execute-extended-command . nil))

;; 自動補完を無効にする
;;(custom-set-variables ‘(helm-ff-auto-update-initial-value nil))

;; C-hでバックスペースと同じように文字を削除
;;(define-key helm-read-file-map (kbd “C-h”) ‘delete-backward-char)

;; TABで任意補完。選択肢が出てきたらC-nやC-pで上下移動してから決定することも可能
;;(define-key helm-read-file-map (kbd “TAB”) ‘helm-execute-persistent-action)

;; helm
;; minibuffer で C-k を押すと先頭から丸ごと削除され、kill ring に追加されないのを解決
;; → 今は不要
;;(setq helm-delete-minibuffer-contents-from-point t)
;;(defadvice helm-delete-minibuffer-contents (before helm-emulate-kill-line activate)
;; “Emulate `kill-line’ in helm minibuffer”
;; (kill-new (buffer-substring (point) (field-end))))

#+END_SRC

migemoの不具合から、macのemacsをgit-HEADから25.0.50に戻してみたり

Windows上で快適に使っている emacs-w64 は、 アップデートする毎、動作が機敏になってきていたので、 割と頻繁に追従していた。

それがある時から、不調になりがちになった。

emacs-w64 自体のバージョンは 25.0.x なのだが 25.1.x を目指した変更が外のパッケージに不具合を起こす様だ。

良い機会なので、もう使っていない古いパッケージを整理した結果、 むしろサクサク動く様になって、快適快適… と思いきや。

  • migemoが動かない。
  • helmの挙動が、変わってしまう。
  • moccur が無くなった?

helmの方は、症状が深刻ではないし、 helm自体の更新が速いので、直に元に戻るだろう。

migemo/cmigemoは、もう枯れたパッケージだし、 そんなに更新頻度が高くないので、なんとか設定で回避したい。

migemo と emacs25.1.x

emacs25.1.x で isearch.elに変更があったために、 migemo.elと辻褄が合わなくなっている様だ。

Warning (bytecomp): ‘isearch-word’ is an obsolete variable (as of 25.1); use ‘isearch-regexp-function’ instead.

なので、

(setq search-default-regexp-mode nil) ;; emacs25.1

とすれば、まずは動作する。

追記

2016年03月24日現在、 isearch.elの実装がしょっちゅう変更されている様で、 ちょいちょい対応する必要がありそう。

macbook上のemacsは、 git HEAD で問題なくmigemoが動作する様になっている。

cygwinのcmigemoを使う emacs-w64 では、 問題なく使えるのは 2015年10月頃のバージョンみたいだ。

homebrewのemacsを25.0.50に戻す方法

Formula/emacs.rb を見ると、25.0-dev が良さげ。

brew reinstall emacs --devel --with-cocoa --with-rsvg --with-imagemagick

で、一応 25.0.xに戻せるのだけれど、 isearch.el は既にemacs25.1.x相当のものに置き換わってしまっていた。

むむむ。

そういう事なら、最新版にしておこう。と言う場合は。

brew reinstall emacs --HEAD --use-git-head --with-cocoa --with-rsvg --with-imagemagick

cygwinのファイルアクセスが遅い件:解決編

もうmagit無しではemacsでコーディングできない体になってしまった。 さらに便利を求めて git-gutter-fringe+ をインストールしたところ、 Macではもう最高の使い心地。

だけども。 これをCygwinとntemacsで使うと、しょっちゅうプチフリーズしてしまう。 Cygwinのファイルアクセスが異常に遅いせいなのだけれど、 仕事上Cygwin環境は必須だし、git-gutterは手放したくないし。

いくら便利でも、作業中に30秒も固まられると、さすがに我慢できない。 いい加減、ちゃんとCygwinに対策をしなければ…

と言う訳で。

Cygwinの起動やファイルアクセスが遅くて怪しい場合に

CygwinのFAQサイト を検索してみた。

以下、Cygwinのページから引用。

4.2. Starting a new terminal window is slow. What’s going on?

There are many possible causes for this.

~snip~

For almost all its lifetime, Cygwin has used Unix-like /etc/passwd and /etc/group files to mirror the contents of the Windows SAM and AD databases. Although these files can still be used, since Cygwin 1.7.34, new installations now use the SAM/AD databases directly.

To switch to the new method, move these two files out of the way and restart the Cygwin terminal. That runs Cygwin in its new default mode.

~snip~

For the AD case, it can be slower than the old method, since it is trading a local file read for a network request. Version 1.7.35 will reduce the number of AD server requests the DLL makes relative to 1.7.34, with the consequence that you will now have to alter /etc/nsswitch.conf in order to change your Cygwin home directory, instead of being able to change it from the AD configuration.

If you are still experiencing very slow shell startups, there are a number of other things you can look into:

One common cause of slow Cygwin Terminal starts is a bad DNS setup. This particularly affects AD clients, but there may be other things in your Cygwin startup that depend on getting fast answers back from a network server.

~snip~

Another cause for AD client system is slow DC replies, commonly observed in configurations with remote DC access. The Cygwin DLL queries information about every group you’re in to populate the local cache on startup. You may speed up this process a little by caching your own information in local files. Run these commands in a Cygwin terminal with write access to /etc:

getent passwd $(id -u) > /etc/passwd getent group $(id -G) > /etc/group Also, set /etc/nsswitch.conf as follows:

passwd: files db group: files db

~snip~

Either in addition to the previous item or instead of it, you can run cygserver as a local caching service to speed up DC requests.

~snip~

A less preferable option is to create a static read-only cache of the authentication data. This is the old-fashioned method of making Cygwin integrate with AD, the only method available in releases before 1.7.34. To do this, run mkpasswd and mkgroup, then put the following into /etc/nsswitch.conf to make Cygwin treat these files as the only sources of user and group information:

passwd: files group: files

~snip~

If none of the above helps, the best troubleshooting method is to run your startup scripts in debug mode. Right-click your Cygwin Terminal

~snip~

4.3. Why is Cygwin suddenly so slow?

If suddenly every command takes a very long time, then something is probably attempting to access a network share. You may have the obsolete //c notation in your PATH or startup files. Using //c means to contact the network server c, which will slow things down tremendously if it does not exist.

要するに、ドメインで使っている会社のPCで遅くなる原因は。。。

  1. cygwinを 1.7.35 以降の最近のバージョンにする (古いのは遅い)
  2. DNSのIPアドレスが間違っていると、長い待ちがおこる
  3. ドメインじゃないなら、 /etc/passwd と /etc/group を消すと良いかも(知れない)
  4. ドメインなら、ドメインコントローラの返事が遅いのかも
    • その場合、passwd/group をキャッシュして高速化できる
    • cygserverでドメンインキャッシュサーバをたててみても良いぞ
    • そもそもドメインにアクセスするの辞めちゃえば? (ADが更新しても知らんけど)
  5. それでもダメならデバッグモードで起動してみな
  6. ひょっとして ‘//c’ とか書いてない?

DNSが関係しているのは分かっていたけど、 会社のドメインコントローラが遅いとは疑っていなかった。 Windowsでは困ったことないし。

でもやってみよう。

まずはバージョン確認

以下のどちらかで確認できる。

uname -a
cygcheck -c cygwin

2.2.0 だったので、問題なし。

/etc/passwd と /etc/group の削除

cygwinでドメインに関係するような事はしないし、 むしろ悪さしそうなので、まず削除して様子をみてみた。

数時間使ってみて、酷いフリーズは経験しなかったけれど、 プチフリーズが解決したかと言うと、ちょっと分からない。

AD情報のキャッシュ化

ドメインの情報を削除するのも危険な気がしたので、 一応キャッシュしておいて、様子をみてみた。

ドメイン情報のキャッシュは、こうしてとれる。

getent passwd $(id -u) > /etc/passwd
getent group $(id -G) > /etc/group

その後、 /etc/nsswitch.conf を編集して、 ADにアクセスするより先にキャッシュ(files)を見るように変更する。

passwd: files db
group:  files db

正直、これも良くなったのか悪くなったのか分からない。

そもそもドメイン情報を使わないようにする

いくつか試してみた結果、 /etc/passwd と /etc/group を削除してしまうことにした。

実はこの状態でも、ドメインでアクセス管理しているネットワークサーバの ファイルにアクセスできたのだった。しかも今迄よりもサクサクと。(汗)

まだ、たまにフリーズはするものの (キャッシュはあった方が良いのかも知れない)、 全体的にファイルアクセスが軽快になった。

無くて良いものは、無い方が良い。 この状態で、またしばらく使ってみようと思う。

org-mode で WordPress の記事を書きたい その3 スタイル追加

とりあえず、手元の emacs で書いた org-mode の記事を、 そのまんま WordPress の載せられるようになったけれど、 見た目があまりにも素気ないので、スタイルシートを追加してみる。

HTMLはともかく、デザインっぽい css には縁がなく、サッパリ分らない。 とりあえず、人様のを パクってきて 参考にしてみよう。

とその前に。 WordPressが勝手に追加したHTMLタグを削除しておく。

まずは WordPress 標準の HTML タグを排除する

remove_filter で、余計なフィルタを削除する事までは分かっている。 削除するフィルタは ‘wptexturize’、’wpautop’、’wp_richedit_pre’ あたりで十分そうだ。

ただ、どの資料や先人のブログを見ても、remove_filter を functions.php に 記述するように、とある。

今回のプラグインでも、呼び出される時に同時に remove_filter を行なうと、 とりあえず想定通りの動作はした。

無駄はあるかも知れないけれど、まぁ良いか。

プラグインに挿入したのは、こんなコード フィルタの存在確認は特に必要ないようだし、 このプラグインでは画面の種類まで気にする必要がないので、 今は、これで必要十分。

remove_filter('the_title', 'wptexturize');   // タイトルの記号を実態文字化する
remove_filter('the_content', 'wptexturize'); // 記事の記号を実態文字化する
remove_filter('the_excerpt', 'wptexturize'); // 抜粋の記号を実態文字化する
remove_filter('the_title', 'wpautop');       // タイトルの自動整形を無効にする
remove_filter('the_content', 'wpautop');     // 記事の自動整形を無効にする
remove_filter('the_excerpt', 'wpautop');     // 抜粋の自動整形を無効にする
remove_filter('the_editor_content', 'wp_richedit_pre'); // 改行とBRのあつかい

WP-Markdown や JP Markdown のソースコードを見てみると、 上と同じコードがないし、それぞれ違う実装方法を選んでいるみたいだ。

WP-markdownでは

./wp-markdown.php:79:  remove_filter( 'bbp_new_reply_pre_content', 'bbp_code_trick',  20 );
./wp-markdown.php:80:  remove_filter( 'bbp_edit_reply_pre_content', 'bbp_code_trick',  20 );
./wp-markdown.php:81:  remove_filter( 'bbp_get_form_reply_content', 'bbp_code_trick_reverse',  10 );
./wp-markdown.php:85:  remove_filter( 'bbp_new_topic_pre_content', 'bbp_code_trick', 20 );
./wp-markdown.php:86:  remove_filter( 'bbp_edit_topic_pre_content', 'bbp_code_trick', 20 );
./wp-markdown.php:87:  remove_filter( 'bbp_get_form_topic_content', 'bbp_code_trick_reverse', 10 );
./wp-markdown.php:91:  remove_filter( 'content_save_pre', 'balanceTags', 50 ); //Remove balanceTags and apply after MD -> HTML
./wp-markdown.php:125: if ( remove_filter( 'content_save_pre', 'wp_filter_post_kses' ) ) {

jetpack-markdownでは

./markdown/easy-markdown.php:137: remove_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ), 10, 2 );
./markdown/easy-markdown.php:138: remove_filter( 'edit_post_content', array( $this, 'edit_post_content' ), 10, 2 );
./markdown/easy-markdown.php:139: remove_filter( 'edit_post_content_filtered', array( $this, 'edit_post_content_filtered' ), 10, 2 );
./markdown/easy-markdown.php:141: remove_filter( '_wp_post_revision_fields', array( $this, '_wp_post_revision_fields' ) );
./markdown/easy-markdown.php:143: remove_filter( 'content_save_pre', array( $this, 'preserve_code_blocks' ), 1 );
./markdown/easy-markdown.php:161: remove_filter( 'pre_comment_content', array( $this, 'pre_comment_content' ), 9 );
./markdown/easy-markdown.php:238: $this->kses = remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' ) && remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
./markdown/easy-markdown.php:568: remove_filter( 'wp_revisions_to_keep', '__return_false', 99 );

WordPressのどこを勉強すれば、こういう方法を思いつくのかな?

せめてソースコードのスタイルシートは綺麗に

さて、問題のスタイルシート。 WordPressのHTMLタグを取り除いたので、ひとまず見られる位になったので、 もう少し華やかにしてみたい。

出来るだけ楽をしたいので デザインに自信ないので、出回っている物を流用しよう。

検索すると、 Highlight.js と SyntaxHighlighter が見付かった。 軽量で扱い易そうな Highlight.js を有り難く使わせて頂こう。

javascriptの設置と登録

Highlight.js は、名前の通り javascript なので、 どこかのサーバに置いて、 WordPress に教えてあげる必要がある。

そこではたと困るのが、プラグインのフォルダを知る方法。 探してみると、それっぽいのが結構色々みつかる。

Highlight.js から zenburn.css を選んだとすると。 こんな感じ?

wp_enqueue_script('org2html-highlight', plugin_dir_url( __FILE__ ) . 'script/highlight.pack.js');
wp_enqueue_style('org2html-style', plugin_dir_url( __FILE__ ) . 'style/zenburn.css');

動く以前に、何か怒られた。

login_enqueue_scripts hooks. Please see Debugging in WordPress for more information. (This message was added in version 3.3.) in ... /wp-includes/functions.php on line 3622

検索してみると、一旦関数にして add_action で登録しろって事らしい。 なので、それっぽく書き直してみよう。

function my_enqueue_scripts() {
    wp_enqueue_script('org2html-highlight', plugins_url('script/highlight.pack.js', __FILE__ ));
    wp_enqueue_style('org2html-style', plugins_url('style/zenburn.css', __FILE__ ));
}
add_action('wp_enqueue_scripts', 'my_enqueue_scripts');

あと、本文の方に javascript の実行部分を追加して、作業完了。

$html .= '<script>hljs.initHighlightingOnLoad();</script>';

おぉ〜 良い感じになった。

想定外の文字が意外に多くて、時々パーサが失敗してるけど… まぁ、良いか。そのうち直そう。

emacsのorg-mode で WordPress の記事を書きたい

org-mode で書いた記事を、そのまま WordPress に投稿したい。

方法は、大きく分けて二つある。

– org-mode で HTMLに変換してからコピペする
– org-mode の書式を解釈する WordPress のプラグインを新たに作る

org-mode側でHTMLに変換する方法は、
WordPressの記事一覧が酷い事になるのが目に見えている。

いつかは画像も自動で組込みたいし、
後者の、プラグインを新たに作るのが良さそう。

車輪の再発明ぽくてイヤだけど、自分で使う目的だし、
自由が効く方が良いか。

問題はむしろ、PHPの開発経験が全く無いこと。

orgのテーブルを変換するプラグインは小さかったので、
一旦pythonで書いてから、本番サーバ上でPHPに移植する
という、恐しい開発方法だったけど。

今回は、ちゃんとテスト環境をそろえて開発したい。

テーブルプラグインの開発では、
WP-MarkDown の不具合(バグの様な仕様)で、
保存する度に記事を壊されて無駄に時間がかかってしまった。

WP-MarkDown とはオサラバして、スッキリ開発したい。

で。

対応したいタグは、こんなもの。

– 段落タイトル 3段階
– 段落
– コード
– テーブル
– 引用
– 段落
– 強調/イタリック
– リンク
– リスト
– *インライン画像
– (入れ子リスト)
– (番号リスト)

これだけ変換するには、
テーブルプラグインの構造では間に合わないので、
きちんと文章を構文解析する必要がある。

それに、ちゃんとしたテスト環境を作ってから開発したいし
新調した MacBookPro に合わせて、CI環境を再構築しないと…

emacs magitでソース管理

cygwin上のemacsから使い易い gitクライアントが無かったので、
Windowsでの開発では、ソースの編集はemacsでやっていても、
バージョン管理には TortoiseGit を使っていた。

TortoiseGit は GUIが上等なので、それはそれで便利なのだけど、
いちいちマウスを持つのが面倒なので、
編集に関わる作業は全部emacsの中で連続してやってしまいたい。

で、 magit を使うことにした。

今迄 emacs内でgitを触りたくなかったのは
cygwinのファイルアクセスが異常に遅いのが理由なのだけど、
最新のemacs-win64(25.0.50)とmagitの組み合わせなら何とかなる範囲。

で、インストール。

一旦、magitをGitHubからダウンロードしたものの、
中のドキュメントを見たら、 emacsのパッケージからインストールできる、
という事だったので、そっちに方針変更。

ドキュメント内では、 Melpa と Marmalade のパッケージが説明されていたけど、
結局、 Elpa 内の magit を使うことにした。

使用している git は 2.5.0、emacsは25.0.50 なので、
動作条件は満しているものの、 emacsがHEADのせいか、
こういう状況だった。

  • Melpa は、パッケージ自体に問題がちょいちょい起こるのでリストから外している
  • Marmalade の Magit は、バージョンが 1.2 だったけど、エラーで動作せず
  • Elpaの Magit は、バージョンが 0.8.1 で、かなり古いけど、問題なく動作する

Elpaのパッケージは更新されそうにないので、
そのうち GitlHub の Magit 2.1.0 に乗り換えるかも知れない。

で、Magitの使用方法は、とても簡単。

で、今のソースの更新状況が表示される。

これが emacs に出るのが本当に嬉しい。
うっかり編集や、気の迷いでチョット修正したのを忘れてしまう、
という、本当におバカなミスを防いでくれる。

TortoiseGit だと気付くタイイングが大分後になってしまうし、
そもそも作業が億劫なので、こまめに commit しなくなるから
gitの有難味が、ちょっとそがれてしまう。

emacs の magit-status 画面で普段使う機能は以下の通り。

  • s でファイルを一つ add
  • S 全ファイルを全てadd(git add -A)
    • 実際には C-u S とする
  • c コミット
  • u addの取消
  • l ログ一覧表示
  • L ログ一覧詳細表示

Macでの作業は、基本個人のローカル運用なので、コレで十分。

Windowsの開発案件で必要な pull/push/merge などは、
今のところ TortoiseGit を使っている。
外部と関わる重要作業は、GUIがしっかりしていた方がちょっと安心なので。