[C#][開発環境]Visual Studioに入れておくと捗る7つのプラグイン

3月末までJava/C#を使ったプロジェクトに参加していたんですが、その時に使ってたVisualStudio 2008周りのプラグインとかをまとめておく。

Visual Studio

AnkhSVN

screenshot
ankhsvn: Subversion Support for Visual Studio

VisualStudio内でSVNを使うためのプラグイン

Eclipseに比べるといろいろ非力だけど仕方ない

CodeRush

https://www.devexpress.com/Products/CodeRush/
CodeRush: IDE Productivity Tools for Visual Studio | DevExpress

リファクタリング系の機能を追加してくれる

  • メソッドの抽出
  • ローカル変数の抽出
  • 変数をvarにしたり、その逆をしたり
Code Compare

screenshot
http://www.devart.com/codecompare/

文字単位まで比較してくれる。

ちょっとEclipseっぽくなる

SonicFileFinder

ファイルを開くのが簡単になる。Eclipseでいうと「リソースを開く」に相当する

screenshot
http://www.jens-schaller.de/sonictools/sonicfilefinder/index.htm

Visula Local History

ローカルの修正を保存してくれる。Eclipseでいうとローカルヒストリー

うっかり、SVNからRevertして失敗したので、入れたけど使う頻度はそんなにない

screenshot
CodePlex Archive

metalscroll

Sublime Textの右に出てくるようなエディタの全体図がだせる。(ミニマップ)
変数をAlt+クリックすることで、参照も分かる。
ただし、意味までは見てないみたいなので、Eclipseのとは違う

※Code Compareと相性が悪い

https://code.google.com/p/metalscroll/
Google Code Archive - Long-term storage for Google Code Project Hosting.

DPack

ファイル内のクラス検索、メソッド検索、プロパティ検索ができるようになる。
クラス検索は初期化が遅いので、大体はSonicFileFinderを使っているので、
メソッド検索しか使わない。

screenshot
DPack - Visual Studio Marketplace

Windowsアプリ(おまけ)

Clover

エクスプローラGoogleChromeっぽいタブにしてくれる

screenshot
http://ejie.me/

Sublime Text2

かゆいところに手が届くエディタ

screenshot
Sublime Text - A sophisticated text editor for code, markup and prose

Oracle SQL Developer

重いけど、結合条件書くのが楽

screenshot
Oracle SQL Developer Downloads

Everything

ローカルファイルなら一瞬で見つけ出してくれる(※ただしファイル名に限る)

screenshot
voidtools

ClipCube

実用性よりもデザインで選んだけど、まあまあ使える

screenshot
Wikispaces

play frameworkのメモ

  • routesファイルのアクションは大文字(ex:GetではなくGET)
  • routesファイルのコントローラーと実装は一致している必要がある
  • Controllerクラスで仮実装としてTODOが使える
  • mvcのフォルダはすべて複数形(controllers,models,views)
  • 当たり前だけど、controllerでmodelを使うときはimportが必要
  • SQLにはUps/Downsのコメントが必須

vimのメモ

  • ~ でカーソル位置の文字の大文字/小文字を変換する
  • gUw で単語を大文字化
  • . で直前の操作の繰り返し

時間や日付の変換

普通プログラム内で時間や日付を扱うと基本はintとかlongになって、それを人間が見やすいようにするには、「H:MM:SS」とか「MM:SS」に変換とかにするんだけど、SimpleDateFormatで変換かだとスレッドセーフじゃないからあーだこーだとか考える必要あるし、それにしたって毎回、同じようなのを書くのかと。

いや、Googleがそんな無駄なことをするはずがない!!
と思って、ドキュメント見てたらあったね「android.text.format.DateUtils」

DateUtils.formatElapsedTime(sec) // 18:02

時間に変換するときは自動で「H:MM:SS」にもしてくれるみたい。便利。

それ以外にも時間・日付をいい感じに変換してくれそうなメソッドがDateUtilsにはたくさんあるみたいなので、SimpleDateFormatを使うよりはいいかもしれない。

他のMedaipPlayerを止める


2012/1/31
下記の方法でも止められるみたいですが、GoogleはAudioManager#requestAudioFocus()の実装を推奨してるみたいなので、本エントリーは参考程度ですね。詳しくはHandling changes in audio output  |  Android Developersを参考にしてください。気が向いたらこれについて書くかもだけど


MediaPlayerを使ってて、ふと他のアプリがMediaPlayerが再生してたらどうやって止めたらいいのか疑問になったので調べてみた。

iPhoneユーザーの視点としては、どの音楽アプリを起動してもそっちが優先して動いて欲しい。要するにそれまで音楽再生をしていたアプリを止めて自分でコントロールしなおしたいわけだ。

標準の音楽再生アプリを調べてみたらbroadcastを投げれば止まるみたい

// 停止ボタンのキーダウン
Intent stopIntent = new Intent();
stopIntent.setAction(Intent.ACTION_MEDIA_BUTTON);
KeyEvent stopDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP);
stopIntent.putExtra(Intent.EXTRA_KEY_EVENT, stopDown);

// Broadcast発行
sendOrderedBroadcast(stopIntent, null, new BroadcastReceiver() {
	@Override
	public void onReceive(Context context, Intent intent) {
		// 停止ボタンのキーアップ
		Intent i = new Intent();
		i.setAction(Intent.ACTION_MEDIA_BUTTON);
		KeyEvent stopUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP);
		i.putExtra(Intent.EXTRA_KEY_EVENT, stopUp);
		
		// Broadcast発行
		sendOrderedBroadcast(i, null);
	}
}, null, 0, null, null);

KEYCODE_MEDIA_STOPではなくKEYCODE_MEDIA_PLAY_PAUSEも試してみたけど、名前からわかるとおり再生/停止を切り替えるので、うまく使うのはめんどくさい。

やってる内容としてはウィジットの振りをしてBroadcastを投げてるイメージであってると思う。
一回目のIntentは停止ボタンのキーダウン。
sendOrderedBroadcast()内での二回目のIntentは停止ボタンのキーアップ。

キーダウンだけでいけるかと思っていたら、長押しの処理のために両方見ていてキーアップのBroadcastを投げないと、次のキーアップのイベントを受け付けてくれないようだ。

ちなみにsendOrderedBroadcast()*1の動作が良くわかっていないまま使ってるので、誰か詳しい人教えてくれるとうれしい。

まとめ

音楽プレイヤーがウィジットを持っていて、ACTION_MEDIA_BUTTONのインテントフィルターを使っていれば、どのプレイヤーでも止まるはず。
それぞれのサービスを使う必要もない(標準のはそもそも公開されていないし)ので、Intentサイコーってことだね

*1:sendOrderedBroadcast()を使わないと"RuntimeException():BroadcastReceiver trying to return result during a non-ordered broadcast"が発生する

Uriクラスのテストクラス

Uriクラスのメソッドで毎回混乱するから、テストメソッドを書いた。

public void testUri() {
	Uri uri = Uri.parse("content://anony@com.limelabo:77777/person/1?history=10#name");
	
	assertEquals("//anony@com.limelabo:77777/person/1?history=10", uri.getSchemeSpecificPart());
	assertEquals("anony@com.limelabo:77777", uri.getAuthority());
	
	assertEquals("content", uri.getScheme());
	assertEquals("anony", uri.getUserInfo());
	assertEquals("com.limelabo", uri.getHost());
	assertEquals(77777, uri.getPort());
	
	assertEquals("/person/1", uri.getPath());
	assertEquals("1", uri.getLastPathSegment());
	assertEquals("history=10", uri.getQuery());
	assertEquals("name", uri.getFragment());
	
	assertEquals(2, uri.getPathSegments().size());
	assertEquals("person", uri.getPathSegments().get(0));
	assertEquals("1", uri.getPathSegments().get(1));
	
	assertEquals("10", uri.getQueryParameter("history"));
	assertEquals(1, uri.getQueryParameters("history").size());
	assertEquals("10", uri.getQueryParameters("history").get(0));
}

Problem 14

Problem 14 - PukiWiki

// コラッツ問題用の関数
def col(n:Long):Long = n match {
  case 1 => 1
  case x if x % 2 == 0 => x / 2 
  case x if x % 2 == 1 => 3 * x + 1 
}

// 初期値から上記の関数を1になるまで適用したListを作成
def c(n:Int):List[Long] = {
  def _c(m:Long, l:List[Long]):List[Long] = {
    if (m == 1) {
      return 1::l                                                          
    }
    _c(col(m), m::l)
  }
  _c(n, Nil)
}

// 100万未満の数列数
val l = (1 until 1000000).map(c(_).size)

// 0始まりなので、調整のために+1
l.indexOf(l.max) + 1

末尾関数を使ってる部分があんまりきれいじゃない気がする。
もう少しスマートになりそうな気配がある

Problem 28

GDDでこれ系の問題を解くのが面白いことに気付いたのと、Scalaの勉強のために最近Eulerをといている。
これ絶対あとで解けなくなるってのを残しておこう。

一応、ネタバレ注意ですね。

Problem 28 - PukiWiki

// 次の対角線上の数字への増加分
val l = 1 :: ((1 to 1001).filter(_%2==0).map(c=>List(c,c,c,c)).flatten.toList)
// lを元に実際の体格洗浄の数字を作った値の合計
l.zipWithIndex.map(t=>l.take(t._2+1).sum).sum

変にこった作りな気がする。
これくらいなら力づくで解くようなプログラムを書きたい。