Cscope

この間の三島Haskellで@karky7にcscopeを教えてもらったので、朝からいじっていたのだけどetagsとの違いがよく分からなかった。規模がでかいとこっちのほうがいいのだろうけど、.emacsにいちいち書かないといけないのが面倒くさそうだなと思ったが、virtualenvで作った仮想環境のlibを登録してしまえばいいのかなぁ。

Sass x SyntaxCheck x Linting = Emacs & Flymake

Sass+Comapss用にEmacsをいじっていった結果、Flymakeによるリアルタイム構文チェックまでたどり着いて快適になった。livereloadを組み合わせるとさらによい。

  • scss --checkによるコンパイルチェック(エラー検出)
  • scss-lintによるLinting

更新を検知してリアルタイムに上のチェック、エラーがあれば該当行が赤く染まる。カーソルを該当行にのせると何がいけないのかがミニバッファに表示されるのでエラーが把握しやすい。

ちなみに下のスクリーンショットでは29行目にカーソルを合わせていて、「セレクタは一行に一つづつ書きなさい」とpythonのimportみたいなことを言われている。

flymake scss

install

こんな感じだったと思う。

gem install sass
gem install compass
gem install scss-lint

scsscheckers

scss --checkとscss-lintを実行するスクリプトを用意する。ついでにflymake-cursorに対応させるために出力をいじるが、scss --checkの場合は--traceをつけると偶然にもflymake-cursorの書式に対応するので必要な一行目だけを出力させている。

#!/usr/bin/env python

from subprocess import Popen, PIPE
import sys

for arg in sys.argv[1:]:
    if arg.endswith(".scss"):
        file = arg

p1 = Popen(["scss", "--compass", "--trace", "--check", file],
           stdin=PIPE, stdout=PIPE, stderr=PIPE)

stdout, stderr = p1.communicate()
print  stderr.split("\n")[0]

p2 = Popen(["scss-lint", file],
           stdin=PIPE, stdout=PIPE, stderr=PIPE)

stdout, stderr = p2.communicate()
print stdout.replace(" - ", ": ")

Emacs

scssコマンドをscsscheckersコマンドに変更するためにscss-sass-commandを上書きする。

;;; http://d.hatena.ne.jp/CortYuming/20120110/p1#20120110f1
(defun my-css-electric-pair-brace ()
  (interactive)
  (insert "{")(newline-and-indent)
  (newline-and-indent)
  (insert "}")
  (indent-for-tab-command)
  (previous-line)(indent-for-tab-command)
  )

(defun my-semicolon-ret ()
  (interactive)
  (insert ";")
  (newline-and-indent))

(add-to-list 'auto-mode-alist '("\\.\\(scss\\|css\\)\\'" . scss-mode))
(add-hook 'scss-mode-hook 'ac-css-mode-setup)
(add-hook 'scss-mode-hook
          (lambda ()
            (define-key scss-mode-map "\M-{" 'my-css-electric-pair-brace)
            (define-key scss-mode-map ";" 'my-semicolon-ret)
            (setq css-indent-offset 2)
            (setq scss-sass-command "~/bin/scsscheckers")
            (setq scss-compile-at-save nil)
            ))

(load-library "flymake-cursor")

補足

ここ二週間くらい試したこと

おまけ

Flask+Sass-bootsrap+Coffeescriptなサイトを作っていて、Python,CoffeeScript,Sass全てに対してFlymakeがサポートしてくれるのでつまんないtypoとかのミスで時間をムダにすることがなくなった。

これを機会にWebデザイナー系のヒトもEmacsに入門すると楽しいと思いますよ!

FlymakeでSass+Compassのチェックをおこなう

こまるわーとか書いたんだけど、別件でscssのオプション調べてたら--compassっていうcompass用のオプション見つけたので、これを加えればいける。

scss-modeのソース調べたらscss-sass-optionsにオプション渡せばいいっぽいので、setqした。

(add-hook 'scss-mode-hook
          (lambda ()
            (define-key scss-mode-map "\M-{" 'my-css-electric-pair-brace)
            (define-key scss-mode-map ";" 'my-semicolon-ret)
            (setq css-indent-offset 2)
            (setq scss-sass-options '("--compass"))
            (setq scss-compile-at-save nil)
            (flymake-mode t)
            ))

あとはConfigulation Errorでしょっちゅう死ぬので以下の設定は追加しておいたほうがよい。

(defadvice flymake-post-syntax-check (before flymake-force-check-was-interrupted)
  (setq flymake-check-was-interrupted t))
(ad-activate 'flymake-post-syntax-check)

参考

CompassとFlymakeを一緒に使うとSyntax checkerがはしらなくて困る

Emacsでscss-modeを使う

解決した 13.03.12


インストールは普通にlist-packageで。

設定はscss-mode設定 / 牌語備忘録を参考にして、rbenvで入れたscssにパスを通しておいた。

scssを普通に使っているぶんにはなかなか快適だけど、Compassと一緒に使うと困る。

何が困るのか?

例えばcompassのblueprintを使いたい場合、importのところでコケる。

scss

自分でscss叩いてみると

$ scss --check sass/screen.scss
Syntax error: File to import not found or unreadable: blueprint/reset.

importできてないっていうエラー。まぁcompassで挿入されるから実体がないのはしょうがないけど、scss --checkでエラーが発生したところで終了するのも困る。全てのエラーを補足するようになっていればいいのにと思ったりもするが。flymakeの意味無いじゃん。

compassコマンドのほうに構文チェック用のオプションないかなぁと見てみても、作成されたcssのバリデーターくらいしか用意されていないみたいだ。createした時にファイルを用意してくれるオプションでもいいんだけど。

というわけで、他のCompass使いの人達はどうやって構文チェックしているんだろうか?

検索かけてもほとんどヒットしないんだよなぁ

etagsを再帰的に使うにはeshellから**/*.pyとするだけだった

etagsに再帰的に探索するオプションがないので面倒くさかったんだが、eshellを使えば解決することが分かって快適になった。

例えばFlaskだったらM-x eshellでeshellを立ちあげて、flaskのディレクトリで

etags **/*.py

と打てばよい。

etags_emacs

eshellは常に一つ立ちあげておこうかな。

hsktagsでHaskellでもタグジャンプ

@karky7に教えてもらったEmacsのタグジャンプでRedmineの中を探索するのが楽になったが、etagsはHaskell対応していない。

これは困ったとフグったところ、hasktagsをみつけて解決。

hakyllのソースで

hasktags -e .

ってやってTAGSファイルを作ったら、Emacsでタグジャンプできる。

Emacsでタグジャンプ

昨日Gentoo Linuxの布教活動に来ていた@karky7にEmacsのタグジャンプの便利さを教えてもらったので、僕もちょっと使ってみようかなと。

ちょうどredmineの中を読んでいるのでappディレクトリで

etags */*.rb */*/*.rb

と打つとTAGSファイルができて(etags -f rb -Rとか叩けないんだろうか?)タグジャンプができるようになるのでM-.で探索しつつM-*で元の場所に戻るということが簡単にできるようになっていい感じ。

RoRみたいなフレームワークは行きつ戻りつすることが多いのでタグジャンプを使えばコードを追いかける効率が上がりそうだ。anythingとかhelmでも使えるようなのであとで設定してみる。

三島Haskell無名関数の会#1が面白かった

皆様お疲れ様でした。Emacsの設定ネタでやたらと時間が取られてしまったが、Emacsの素晴らしさが伝えられたかなーと。キーバインドなんて些細なことですよ、みんな左手の小指を鍛えて快適なEmacsライフをおくりましょう!

init.elはこれを参考にしてください。

todo

virtualboxでGentoo Linuxを入れてみる。

次回

fay-langの話とか、もう少しハンズオン的なyesod(wikiを作るくらいの)ネタをやれればいいかなという感じ。

次回は三島でやって、懇親会を鈴木屋でやりたい。

参加者

C-sで検索をかけた時にC-x C-xで検索開始位置に戻れる(Emacs)

Emacs RocksのEpisode 01: From var to thisを見ていて、C-sすると自動的に検索開始時点の位置がマークされることを知った。

ということはC-x C-xで戻れるってことじゃないかと。

他にはexpand-regionってのが便利そうだったので、入れた(list-packagesで選択できる)。

AlloyでのiPhoneアプリ開発にCoffeeScriptを使う

犬が早朝から吠えたので4時に叩き起こされたが、タイムラインを追いかけていたらAlloy with CoffeeScript のお誘いというこれは!というエントリがあがっていたので、早速誘われてみた。尚、jsとcoffeeは一緒のディレクトリに置いておくのが好みなので@k0sukeyのオリジナルなjmkに変更をくわえてあります。

ストップウォッチをつくる

Titanium Mobile iPhone/Androidアプリ開発入門のストップウォッチを参考にしました。

ProductName Titanium Mobile iPhone/Androidアプリ開発入門―JavaScriptだけで作る
小澤 栄一
秀和システム / 2520円 ( 2012-02 )


本書ではui.jsという1つのファイルで完結していますがAlloyのようなMVCフレームワークを使ったほうがコードの見通しは良くなると思います。

雛形をつくる

$ titanium create stopwatch # 対話でターゲットデバイスやapp-id設定
$ cd stopwatch
$ alloy new # alloyのひな形作成
$ alloy generate jmk

coffeeがコンパイルされるようにする

stopwatch/app/alloy.jmkを以下のように書きなおす。これでapp/controller のcoffeeファイルはalloy compileでコンパイルされるようになります。

task("pre:compile", function(event,logger) {
    var wrench = require("wrench"),
    fs = require("fs"),
    path = require("path"),
    controller_root = event.dir.controllers,
    coffee = require("coffee-script");

    wrench.readdirSyncRecursive(controller_root).forEach(function(controller){
    if (controller.match("coffee$")) {
        fs.writeFileSync(
        path.join(controller_root,controller.replace("coffee", "js")),
        coffee.compile(
            fs.readFileSync(path.join(controller_root, controller)).toString(),
            { bare: true }));
    }
    });
});

task("post:compile",function(event,logger){
});

alloyの開発

あとは普通に。

app/views/index.xml

<Alloy>
    <TabGroup>
        <Tab id="tab1" icon="dark_clock.png" title="ストップウォッチ">
            <Window id="window1" title="ストップウォッチ">
                <Label id="label">
          00:00:00.000
                </Label>
        <Button id="button">
          Start
        </Button>
            </Window>
        </Tab>
        <Tab id="tab2" icon="dark_info.png" title="使い方">
            <Window id="window2" title="使い方">
          <WebView url="howto.html">
          </WebView>
            </Window>
        </Tab>
    </TabGroup>
</Alloy>

/app/styles/index.tss

{"Window": {
  "barColor": "#000",
  "backgroundColor": "#000"
},
"Tab": {
  "backgroundColor": "#000"
},
"#label": {
  "color": "#fff",
  "width": "auto",
  "height": "auto",
  "font": {
    "fontSize": 40,
    "fontWeight": "bold"
  }
},
"#button": {
  "color": "#000",
  "width": 150,
  "height": 40,
  "bottom": 30
}}

webview用のhtmlは /app/assets/iphone/howto.htmlに

<html>
    <head>
        <title>使い方</title>
    </head>
<body>
    <h1>使い方</h1>このサンプル
は<a href="http://www.amazon.co.jp/dp/479803231X">Titanium Mobile
iPhone/Androidアプリ開発入門</a>のストップウォッチのサンプルをAlloyで
書きなおしてみたものです。
<img src="http://ec2.images-amazon.com/images/I/41jDZ5IY01L._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA300_SH20_OU09_.jpg"/>
</body>

興味を持ったら購入して読んでみるとよいと思いますよ。

</html>

最後にcoffeeをapp/controllers/index.coffeeに

started =false
intervalID = null

startStopwatch = ->
  $.label.text = "00:00:00.000"
  startTime = new Date()

  _updateTimer = ->
    u_sec = 1000
    u_min = 60 * u_sec
    u_hour = 60 * u_min
    now = new Date()
    diff = now - startTime

    hour = Math.floor(diff/u_hour)
    min = Math.floor((diff - hour*u_hour)/u_min)
    sec = Math.floor((diff - hour*u_hour - min*u_min)/u_sec)
    msec = diff / u_sec
    $.label.text = ("0" + hour).slice(-2) + ":" +
                   ("0" + min).slice(-2) + ":" +
                   ("0" + sec).slice(-2) + "." +
                   ("00" + msec).slice(-3)

  intervalID = setInterval(_updateTimer, 3)
  return

$.button.addEventListener 'click', -> 
  if started
    clearInterval(intervalID)
    $.button.title = "Start"
    started = false
  else
    startStopwatch()
    $.button.title = "Stop"
    started = true
  return

$.index.open()

実行

$ alloy run

alloy_stopwatch

Let's Enjoy!