header

2013年10月14日月曜日

Emacsで英語の文章書くのに便利なgrammar.elを導入した

Emacswikiで grammar.el の紹介記事をみて、これはいいと思い導入しました。
英語の文章の間違ったところをハイライトして教えてくれる。ただインストー
ルするのにちょっと苦労したので記事として残しておこうとおもいます。
(僕がC++とかmakeに詳しくないだけかもしれないですが…)

Snapshot

Installation

Ubuntu12.02をつかっていますが、aptでインストールできるlink-grammarでは
間違った箇所のハイライトをよけいなところまでしていたので、最新のものを
インストールすることをおすすめします。

cd ~/
mkdir -p grammar
cd grammar
# download link-grammar
svn co http://svn.abisource.com/link-grammar/trunk link-gram

link-grammarのビルド
README をみるのが一番いいとおもいますが、一応自分の例を書いておきます。
(pacoについては ここ とか参考になるかもしれません。)

sh autogen.sh
CC=clang CXX=clang++ ./configure --disable-java-bindings && make
sudo paco -D make install
sudo ldconfig

僕はel-getを利用しているので下のように設定したあと

(push '(:name grammar
:type svn
:url "http://bcui-emacs.googlecode.com/svn/trunk/grammar")
el-get-sources)

M-x el-get-install grammarでインストールしました。

普通にsubversionでインストールするには下のような感じ


svn co http://bcui-emacs.googlecode.com/svn/trunk/grammar

grammar.elを使うにはgrammar.ccをコンパイルする必要がありますが、添付の
makefileではうまくコンパイルできませんでした。(僕は…)
なので以下のような感じでコンパイルしました。(autorg というところで
grammar.elをコンパイルしていたのでそれを参考にしました。)

#!/bin/bash # -*- coding: utf-8; mode: sh; -*-
# GRAMMAR_DIR=grammar.elがあるディレクトリを指定してください
GRAMMAR_DIR=${HOME}/.emacs.d/el-get/grammar
# LINK=link-grammarがあるディレクトリ指定してください
LINK=${HOME}/grammar/link-gram

if test -d ${GRAMMAR_DIR}; then
LG=${LINK}/link-grammar
LIBLINK=${LG}/.libs/liblink-grammar.a
cd ${GRAMMAR_DIR}
# clangがなければg++でも行けると思います(未確認)
clang++ -O3 grammar.cc -I${LINK} -I${LG} ${LIBLINK} -o grammar
fi

コンパイルが終わったらgrammar.elの設定

(require 'grammar)
(setq grammar-program-name "作成したgrammarへのパス")
;; 黒背景だとデフォルトの色はみずらかったので変更
(set-face-attribute 'grammar-error-face nil
:background "#Ff6347"
:foreground "#000000")
(define-key grammar-mode-map (kbd "C-M-g") nil)
(global-set-key (kbd "C-\]") 'grammar-check)

上の設定だとC-]でそのポイントより前の grammar チェックをおこなってくれ
ます。デフォルトだとC-M-gにgrammar-checkをバインドしてくれるので消しています。

下の設定はgrammar-modeの間は, '.?' を押したタイミングで
grammar-checkを呼び出すようにしています。書いてからきずいたけど
grammar-delay-commandってやつで設定するのがgrammar.elの普通の使い方の
気がしてきた。
でも英語の文章書いてて文が完結するのが".?"のタイミングだと思うからこ
れでいいや。(自分が後悔しないための必死の言い訳。。。)
ちなみにlink-grammarをインストールするとコマンドラインからlink-parser
コマンドも使えるようになってこれで、どんな感じにパースするかみれる。

(eval-when-compile (require 'cl))
(defconst my/grammar-default-sentence-end ".?\"!。ぁ-んァ-ン")
(defvar my/grammar-sentence-end-local nil)

(defun* my/grammar-check (&optional (sentence ""))
(interactive)
(unless (bound-and-true-p my/grammar-sentence-end-local)
(my/grammar-set-sentence-end))
(let ((sentence-end
(format "[%s%s]" my/grammar-sentence-end-local sentence)))
(grammar-check)))

(defun my/grammar-check-auto ()
(when (and (bound-and-true-p grammar-mode)
(not (bobp))
(case (char-before)
(46 t) ; dot
(63 t)) ; question
(case major-mode
(org-mode (not (org-in-src-block-p)))
(t t)))
(if (not (bound-and-true-p my/programming-mode)
(my/grammar-check)
(my/grammar-check-for-programming))))

(defun my/grammar-set-sentence-end ()
(setq-local my/grammar-sentence-end-local
(format "%s%s"
my/grammar-default-sentence-end
(replace-regexp-in-string " " "" comment-start))))

(defun my/grammar-check-for-programming ()
(lexical-let ((current-face (nth 1 (text-properties-at (1- (point))))))
(when (or (equal 'font-lock-string-face current-face)
(equal 'font-lock-comment-face current-face))
(my/grammar-check))))

(defadvice self-insert-command
(around ad-check-grammar-automatically activate)
ad-do-it
(my/grammar-check-auto))

プログラミングしている時の文字列の入力やコメントの入力時にも使えるように、
my/grammar-check-for-programming関数がありますが、そんなにつかってない
ので動作は期待しないでください。。。
もし使いたい場合は下のようにして、モードフックごとに
my/programming-mode変数が設定されるようにしてください。

(defvar programing-hooks
'(emacs-lisp-mode-hook
ruby-mode-hook))

(loop for hook in programing-hooks
do (add-hook hook
'(lambda ()
(setq-local my/programming-mode t))))

終わり

とりあえずこんな感じでつかっています。三単現のsとか複数系とか自分の忘
れやすいところを気づかせてくれるので結構便利と思います。

Land of Lisp

2013年10月11日金曜日

EmacsでのScala用の設定を公開してみる

Emacs上でのScala関係の設定がたまってきたので公開してみる。
いい設定があったらおしえてください。他にもこの辺りが参考になるかもしれません。

eMacsでscaLaを書く準備
EmacsでつくるScala開発環境 後編(ENSIME)

設定

scala-mode2利用している。

(require 'scala-mode2)
(add-to-list 'auto-mode-alist
'("\\.\\(scala\\|sbt\\)\\'" . scala-mode))

個人的な設定,,,日本語キーボードだけどmayu(窓使いの憂鬱)で英語配列にしているのでコロンがシフトを押さないといけないため入れかえる。Rubyとかのほとんどセミコロンを使わない言語で利用してもいいかも

;; Reverse ; and :
(let ((map scala-mode-map))
(define-key map (kbd ";") (lambda () (interactive) (insert ":")))
(define-key map (kbd ":") (lambda () (interactive) (insert ";"))))

Buffer上のコードを実行するのに関数をつくった。
apt-get install scalaでscalaコマンドの-eオプションを使えるのが条件
あとpopwinも必要。さりげにRubyとPerlにも対応している。

(require 'popwin)
(defun my/execute-from-current-file (&optional statement)
"Execute current buffer's program."
(interactive)
(lexical-let*
((original-buffer (current-buffer))
(code (shell-quote-argument (or statement (buffer-string))))
(program (case major-mode
(ruby-mode "ruby -e ")
(cperl-mode "perl -e ")
(scala-mode "scala -e ")))
(command (concat program code))
(buffer (get-buffer-create "*execute program*")))
(save-current-buffer
(popwin:popup-buffer
buffer :stick t :width (/ (frame-width) 2) :position :right)
(erase-buffer))
(start-process
"emacs-program" buffer "/bin/sh" "-c" command)
(switch-to-buffer-other-window original-buffer)))

(define-key scala-mode-map (kbd "C-c C-c") 'my/execute-from-current-file)

自動的にクラス名とか型名の最初の一文字を大文字にする。

;; Capitalize type word automatically
(defun my/scala-capitalize-auto ()
(when (equal major-mode 'scala-mode)
(lexical-let*
((current-face (nth 1 (text-properties-at (1- (point)))))
(type-face-p
(lambda () (equal font-lock-type-face current-face)))
(anonymous-func-type-p
(lambda ()
(and
(string-match "^ ?+def " (thing-at-point 'line))
(equal "=" (char-to-string (char-before (- (point) 3))))
(equal ">" (char-to-string (char-before (- (point) 2)))))))
(bracket-p
(lambda ()
(and (string-match "\\[" (char-to-string (char-before (1- (point)))))
(string-match "]" (char-to-string (char-after (point))))))))
(when (and (not (bobp))
(not (equal font-lock-string-face current-face))
(or (funcall type-face-p)
(and (not (equal font-lock-constant-face current-face))
(or (funcall anonymous-func-type-p)
(funcall bracket-p)))))
(let ((case-fold-search nil))
(unless (string-match "[A-Z]" (word-at-point))
(capitalize-word -1)))))))

(defadvice self-insert-command
(around ad-capitalize-type-word-in-scala activate)
ad-do-it
(my/scala-capitalize-auto))

multi-term上でのsbtの以下の挙動を修正する。

  • C-hで文字がきえない
  • C-aで行の頭に戻れない

パッケージにしたので、el-getとかで適当にダウンロードしてください。

cd somewhere
git clone https://github.com/yuutayamada/sbtp.git

sbtp-prompt-string変数はsbtコマンドを実行したあとの"> "とかの文字を
設定してください。(デフォルトで"> "なので 変更してなければ必要ありません)
2013/10/05 追記:
起動が遅いのでsbtのconsoleから利用するようにしました。
コマンドを実行するとEmacsのstart-processでsbt consoleを起動します。
起動後sbtp-console-sendでミニバッファから入力またはリージョン選択して
いればそのリージョンを実行します。
sbt-console-send-lineコマンドはその行を評価します。print文を使わなくても
res1: ~~ とかなんとかでて評価されるます。
sbtp-lang変数はデフォルトではLANG変数が設定されます。
もし日本語の表示がおかしい場合は設定するとなおるかもしれません。
C-uを押してから各sbt-consoleコマンドを実行すると、 :reset をしてからコ
マンドを実行します。
(ensimeでもC-c C-v sでensime-sbt-switchというコマンドがありますが、これ
はensime必須なので)

(require 'sbtp)
(setq sbtp-prompt-string "> "
sbtp-lang "ja_JP.UTF-8")
(define-key term-raw-map (kbd "C-a") 'sbtp-begging-of-line)
(define-key scala-mode-map (kbd "C-c C-p") 'sbtp-console-send)
(define-key scala-mode-map (kbd "C-c C-l") 'sbtp-console-send-line)

ensime 関係:

.ensime があったら自動でコネクトする

(require ensime)
(setq ensime-auto-connect 'always)
(add-hook 'scala-mode-hook '(lambda ()
(when (my/file-exists-p ".ensime")
(ensime-scala-mode-hook))))

(defun my/file-exists-p (file)
"Search file recursively until home directory"
(let* ((filename (concat "./" file))
(home "~/")
(home-p (lambda (dir1 filename)
(equal
(expand-file-name dir1)
(expand-file-name
(file-name-directory filename))))))
(while (not (or (file-exists-p filename)
(funcall home-p home filename)))
(setq filename (concat "../" filename)))
(when (file-exists-p filename)
(expand-file-name filename))))

Error箇所にジャンプする。popup packageが必要です

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

(defvar my/ensime-current-error-number 0
"A number already searched error")

(defun my/ensime-goto-next-error ()
(interactive)
(when (equal major-mode 'scala-mode)
(lexical-let*
((errors (ensime-all-notes))
(convert-error-format
(lambda (err)
(loop for i from 0 to (length err) by 2
for key = (nth i err)
for value = (nth (1+ i) err)
if (< i (1- (length err)))
collect (cons key value))))
(converted-err-list
(loop for error in errors
for formatted-error = (funcall convert-error-format error)
if (equal buffer-file-name (assoc-default :file formatted-error))
collect formatted-error))
(move
(lambda (err-list)
(let* ((err (nth my/ensime-current-error-number err-list))
(err-point (1+ (assoc-default :beg err))))
(goto-char err-point)
(popup-tip (assoc-default :msg err)
:point err-point))))
(save-err-point
(lambda ()
(setq-local my/ensime-current-error-number
(if (equal my/ensime-current-error-number
(1- (length converted-err-list)))
0
(1+ my/ensime-current-error-number))))))
(when converted-err-list
(funcall move converted-err-list)
(funcall save-err-point)))))

終わり

Scalaのコード書くのにIntelliJとかIDEのほうがよさそうだけど、Emacsしか
使うきがないので仲間を増やすために設定を公開してみました。
何かナウい設定があったらおしえてください。


Emacsから org-mode で Blogger に記事を送るbpe.elがタグに対応しました。

googleコマンドをみてたら–tagsオプションがあったので指定できるように
しました。それとupdate時にbpe:use-real-post-when-updating変数にtを設定
することで、ドラフトではなくそのまま更新するようにしました。
既に利用されているかたは(もしいたら)、githubから利用しているとおもうので、
git pullしてConfiguratinの項の設定を加えてください。これからインストールしたい方は
melpaにも登録してみたので、M-x list-packagesコマンドからbpeを探してイ
ンストールできます。

  • そもそも bpe.el って、、、
    タイトルにはさらっと書いてますが、Emacsの olg-mode 形式のファイルから
    googleの Blogger にHTMLエクスポートしたものを送るプログラムです。

Requirement

googlecl というパッケージを利用しているので最初にインストールする必要が
あります。Ubuntuでは以下のようにインストールできました。

sudo apt-get install googlecl

Installation

Melpa からインストールする場合は M-x package-install bpe でインストールできます。GitHubからクローンしたい場合は ここから インストールできます。

Configuration

以下の設定を.emacsなどの設定ファイルに貼り付けてください。
bpe:lang変数は$LANG変数を参照するので最設定しないと文字ばけするかもし
れません。bpe:use-real-post-when-updating変数は記事をアップデートする
ときにドラフトではなくそのままポストします。(default nil)
bpe:no-ask変数はnon-nilだと更新時のy/nの問い合わせを出ないようにします。

(require 'bpe)
(setq bpe:account "your mail address on google blogger")
(setq bpe:blog-name "your blog name")
(setq bpe:no-ask t)
(define-key org-mode-map (kbd "C-c C-p") 'bpe:post-article)
;; Do not attach --draft option if updating
(setq bpe:use-real-post-when-updating t)
;; For Japanese, default is $LANG environment variable.
(setq bpe:lang "ja_JP.UTF-8")

Usage

.org形式のファイルを開いて以下のコメント行を貼り付けます。

#+TITLE: How to post my blog from Emacs and org-mode?
#+OPTIONS: toc:nil \n:nil num:nil
#+TAGS: Emacs Blog
#+AUTHOR: author-name

OPTIONSは必要はありませんが、toc(table of contents)の部分が表示される
のが嫌な場合は書いておいたほうがいいです。
TITLE行はブログのタイトルになり、TAGSはブログのタグになります。
(これが今回の追加した機能)

ポストするにはM-x bpe:post-articleコマンドか設定の項で入れたキーバイン
ドでできます。C-uを押してから実行した場合は同じ名前の記事を削除してから
投稿します。

使用環境

僕はOrg-mode 8.1.1(maint branch)を使用しています。
古いバージョンのorg-modeを利用していてもし動かなかった場合は、

(defadvice bpe:export-html
(around ad-use-old-export-func activate)
(bpe:export-html-old-version))

で動くかもしれません。(確認はしてないけど前は動いていたので)

問題

googleのBloggerサービスがHTML内に改行が入っていると自動で改行をいれてし
まうので、対処としてHTMLをminifyするコード(perlのパッケージを利用してる
だけ)を書きましたが,,,
org-mode内で<p></p>要素などの最初と最後に改行をいれていて、もうminifyす
るとかそんな問題じゃなかった。
というわけで現在はHTML出力したものに正規表現で改行を置換しています。な
ので文書内に<p>\nのような部分があった場合は改行が削除されてしまいます。


Popular Posts

Blogger templates

Blogger news