【VSCode】Visual Studio Code 0.5.0の新機能まとめ

前書き

またいつの間にかVisual Studio Codeがバージョンアップしていました。そーいや「これからは1ヶ月に1回ペースで更新するよ!」みたいなことがどこかに書いてあったような。

今回は0.5.0になったみたいですね。リリースは奇数でやるってスタンスなのかしらん。

以前0.3.0の機能をまとめたので、今回もまとめてみましょう。

アップデート方法

今回から自動アップデート機能がちゃんと動作するようです。(Linuxではサポートしてない模様。)

なぜか私の環境では一向に機能しなかったので、もっかいインストールしてきました。

新機能

またUpdatesの箇所を適当に訳していきます。

ただし、可能な限り省略するので、必要な情報だと思ったらちゃんと元ドキュメントを読みましょうね…。

要約

  • ファイルの扱い方がアップデートされました。
    • explorerでファイルやフォルダをフィルタできるようになりました。
    • コマンドラインからファイルを開く時に行番号を指定することができるようになりました。
    • 複数のファイルを開く時に既に存在するインスタンスを流用するようになりました。
    • working filesの数を制御できるようになりました。
  • 末尾のwhite spaceを削除するオプションが追加されました。
  • ワークスペース内の検索時に特定のファイルのみを検索できるようになりました。
  • JavaScriptでES6をサポートするようになりました。また、jsconfig.json///による参照の改善、ワークスペース設定の追加などが行われました。
  • 内蔵されているGitに以下の機能が追加されました。
    • 認証プロンプトの表示
    • 複数行のコミットメッセージ
    • 自動フェッチ
  • ユーザ独自のスニペットを作成できるようになりました。また、Dockerfiles、Python、Rustといった言語のスニペットが追加されました。
  • デバッグ機能の強化として、ウォッチ式の追加や、Node.jsのブレークポイント、ソースマップのサポートなどが行われました。
  • 他にも、プロキシのサポートや、MacWindowsでの自動アップデートの提供、細かいバグフィックスが行われました。

ファイル

-r-gの追加

  • コマンドラインにて-r--reuse-window)オプションを使うことで最後にアクティブになったVisual Studio Codeのワークスペースにファイルを追加できるようになりました。存在しないファイル名が指定されていた場合はdirtyなファイルが作成されます。
  • コマンドラインにて-g--goto)オプションを使うことでファイルの行番号を指定することができるようになりました。
    • code -g file1:<line>:<column?> file2:<line>:<column?> file3:<line>:<column?>
    • columnを同時に指定することで位置も指定することができます。
    • 実際の指定例はこんな感じ。

      code -g c:\mycode\HelloWorld.ts:10:17

-r-gは外部ツールからVisual Studio Codeを呼び出す時に便利だよ!とのこと。

コマンドラインから呼び出す際の変更点

複数のファイルパスを渡してもちゃんと一つのインスタンスで開くようになりました。

例えばcode . HelloWorld.tsとすれば、explorerにはカレントディレクトリとHelloWorld.tsが表示されます。(HelloWorld.tsがもしなければdirtyなファイルが作成される)

Macのdockのサポート

既にアクティブになっているdock上のVisual Studio Codeにファイル or フォルダをドロップしたら同じインスタンスで開くようになりました。

エディタのオプション

ファイル検索パターンの文法

Ctrl + Shift + Fで呼び出せるsearchで検索対象 / 非対象とするファイルパターンを指定できるようになりました。

また、settings.jsonに予め非対象とするファイルのパターンを記述しておくことができます。(files.excludesearch.exclude

パターンマッチの文法は以下の通り。

*
1文字以上の一致
?
1文字の一致
**
複数のパスセグメント
{}
グループ指定({**/*.html,**/*.txt}
[]
範囲指定(**/example_[0-9].txt)

末尾white spaceの自動削除

settings.jsonfiles.trimTrailingWhitespacetrueにすると末尾のwhite spaceを自動で削除してくれます。

Working Filesの数のカスタマイズ

settings.jsonexplorer.workingFiles.maxVisibleでWorking Filesの表示数を制御できるようになりました。(デフォルトでは9)

また、explorer.workingFiles.dynamicHeightfalseにすると新しいWorking Fileを操作しても自動で枠のサイズが広がらなくなります。(デフォルトではtrue

ファイル / フォルダの非表示

先述したfiles.excludeに指定したファイル / フォルダは検索結果だけでなくexplorerでも表示されません。

リソースの非表示

files.excludeの高度な使い方。元文章だとわかりにくいので勝手に解説します。

files.excludeはデフォルトだとこんな設定になっています。

"files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true
}

なぜかファイルパターンに対する値がbooleanになっていますね。ここがミソで、このbooleanの部分にexpressionを記述することができます。

例えば「.tsと同名の.jsは非表示とする」なんてことがしたかったらこんなexpressionを書けばOKです。

"files.exclude": {
    "**/*.js": { "when": "$(basename).ts"}
}

このexpressionに関するドキュメントは見当たりませんでした。しっかりしろVSCodeチーム!

検索対象から特定ファイルの除外

search.excludefiles.excludeと同じようなことが記述できます。

今まであったsearch.excludeFoldersはもう使えなくなるし破壊的変更点となるので注意してね、とのこと。

検索対象ファイルの指定

searchの「files to include」にファイル検索パターンが使えるよと言うお話。

JavaScript

破壊的変更

以下の設定は非推奨となるようです。jsconfig.jsonの方でサポートするから使わないでね、とのこと。

  • validate.scope
  • validate.baseUrl
  • validate.target
  • validate.module
  • validate.noLib

ES6のサポート

ECMAScript 6の文法を解釈してくれるようになりました。

ただし、superの参照が上手くいかない(?)らしく、コンパイルエラーが出るなら_surpressSuperWithoutSuperTypeError: [true|false]を使って抑制してくれとのこと。

jsconfig.jsonによるプロジェクト設定

tsconfig.jsonのサブセットとしてjsconfig.jsonを作成することができます。

これにはどのjsファイルを使うかだとか、どのコンパイラを使うかなどを指定することができます。なぜか画像で表示されている例を書き写してみますか。

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs"
    },
    "files": [
        "app.js",
        "model.js"
    ]
}

これを設定しておくことで///による参照が不要になるそうです。

シバンの色付け

#!で始まる行を色付けしてくれるようになりました。これ、シバン(shebang)って言うんですね…。

スニペット

待望のユーザスニペットが導入されました。詳しいドキュメントはこちら

ユーザスニペットの定義

メニューバーのFile | Preferencesに「User Snippets」なる項目が追加されています。

選択するとどの言語のスニペットを定義するか聞かれるので、適当に選びましょう。

で、公式の例はあんまり面白くないので、Visual StudioC#を書いてる時に頻繁に使うpropを定義してみましょう。

{
    "Property": {
        "prefix": "prop",
        "body": "public ${1:int} ${2:MyProperty} { get; set; }",
        "description": "auto Property"
    }
}

prefixスニペットを呼び出す時の文字列、descriptionはそのまんまスニペットの説明です。

bodyで実際にスニペットを定義します。${id:text}はタブストップです。idに数値、textにデフォルト値を指定しておくとベネです。また、bodyは配列を受け取るので、複数行を定義することもできます。

Git

ぶっちゃけ機能追加 / 改善するよりVSCodeからgitのコマンドを直接叩けるようにしてほしいんですが。

認証プロンプト

「なんかVSCodeのGitが動かないんだけど…。」→「認証を求められている場所で固まってる」ってパターンがあまりにも多かったらしいので追加されました。

毎回毎回入力するのが面倒だったらgit configで設定してくれよな!とのこと。

複数行のコミットメッセージ

コミットメッセージ入力中にEnterを押すことで改行されるようになりました。送信する場合はCtrl + Enterだそうです。

複数ファイルの選択

git addする時に複数ファイルを選択できるようになりました。今までなかったのが不思議。

自動フェッチの制御

自動でフェッチするかどうかをドロップダウンで選択できるようになりました。

デバッグ

launch.json生成の改善

launch.jsonを生成する時にpackage.jsonmain属性を見るようにしたそうです。

ウォッチ式

ウォッチ式が追加されました。

って言うか…今までなかったんですね。未だにVSCodeのデバッグは使ったことないです。

デバッグ中のコード編集

流石にホット・コード置換は無理だけど、デバッグ中にコードが編集されたら自動でデバッガが再起動するようにしたとのこと。

Node.jsのブレークポイント改善

コールバックのようなクロージャの中にブレークポイントが置かれた場合、呼び出された行と実際に実行している行を表示するようになりました。

ブレークポイントのアクティブ / 非アクティブ化

ブレークポイントのアクティブ / 非アクティブが簡単に切り替えられるようになりました。

JavaScriptのソースマップ

生成(あるいはコンパイル)されたJavaScriptの元ソースが見つからない場合、接続設定(launch configuration)に記述されているoutDirから探すようになりました。

また、インラインで書かれたソースマップもサポートされるようになりました。(インラインで書かれたソースは無理、とのこと。)

Minifiedのデバッグ

圧縮 / 難読化されたJavaScriptでもデバッグできるようになりました。

その他諸々

出力への切り替え

Ctrl+Shift+Uで簡単にOutputを見ることができるようになりました。

OS XWindowsでの自動アップデート

私は機能しませんでした。

プロキシのサポート

package/project/bower.jsonでHTTP通信をする際、以下のどちらかの方法でプロキシを経由できるようになりました。

  • VSCode起動前に環境変数http_proxyhttps_proxyに値をセットする。
  • user settingsのhttp.proxyに値をセットする。

プロキシサーバへの認証(ID / パスワード)なんかはこんな風に指定することができます。VSCodeとは全く関係ない豆知識です。

http://{Username}:{Password}@{ProxyHost}:{PortNumber}

細かいバグフィックス

今回のアップデートに関わるissueが挙げられています。

  • 16480: Git push/pull not working
  • 16782: Fonts Are Blurry
  • 17223: SourceMap debugging doesn't work with inlined source map
  • 17079: Poor Scrolling in Explore Sidebar

まとめ

いやはや、まだまだ未完成度合いがすごいですね。

【Android】ブラウザからの Intent の送信とアプリがインストールされてない場合のフォールバック

2018/12/01 追記

前書き

ここ半年ほどコードよりも日本語を書く仕事がメインになっていて、それはそれは退屈かつシビアなものだったのですが、最近はまたちょこちょこコードを書く仕事をしています。楽しいです。

色々な都合から以前のように一日に何本も記事を書いたりはできないんですが、現状、一ヶ月に一本ペースになってしまっているので、一週間に一本ぐらいのペースにしたいですね。

で、今回はタイトルの通り、Android のブラウザから Intent を送信する方法と、対応するアプリがインストールされていない場合のフォールバック方法について解説します。

Intent を送信するのは至極簡単なんですが、フォールバックは中々厄介です。

アプリ側でその Intent を受信する方法は以前書いたので、今回は特に説明しません。リンクぐらいは貼っておきますが。

outofmem.hatenablog.com

outofmem.hatenablog.com

Intent の送信方法

Chromeの資料にさらっと書かれています。syntaxの箇所を引用してみましょう。

HOST/URI-path // Optional host
#Intent;
   package=[string];
   action=[string];
   category=[string];
   component=[string];
   scheme=[string];
end;

例がないとわかりにくいですね。アプリ側はこんな AndroidManifest.xml だとします。

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="hoge.fuga.piyo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="4"
        android:targetSdkVersion="10" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity android:name="hoge.fuga.piyo.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name="hoge.fuga.piyo.IntentActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="hogefuga" android:host="piyo"/>
            </intent-filter>
        </activity>

    </application>

</manifest>

上記の例で設定した IntentActivity の intent-filter に引っかかるようにするためには、このような URI を用意してあげます。

intent://piyo#Intent;package=hoge.fuga.piyo;action=view;category=browsable;scheme=hogefuga;end;

また、一応こんな URI でも呼べますが、今はあまり推奨されていないようです。action や category も指定できませんしね。

hogefuga://piyo

アプリがインストールされていない場合のフォールバック

どちらかと言うと、これが本題。

「Web からネイティブアプリを Intent で起動させたい!」と言う要件。当然あると思います。

が、先ほどの例でのhogefuga://piyoなんて URI だと、ネイティブアプリがインストールされていない端末では「ページが見つかりません」なんてつれないことを言われてしまいます。

ってなわけで、「インストールされていなかったら別のページに移動させたい!」となることも多いでしょう。どーやってやるかを解説していきます。

package を指定してインストールされていなかったら Google Play に飛ばす

Intent の URI でわざわざ package を指定していましたが、あれがフォールバックそのものになります。

Android 君は対象となる intent-filter が見つからないと自分で「インストールされてないっぽいから Google Play に飛ばすか!」とやってくれます。ありがたいですね。Google Play における各アプリのインストール画面はパッケージ名をクエリとして持っている(例えば Twitter ならcom.twitter.android)ため、このような芸当ができるわけですね。ありがたいことです。

が、この方法、何らかの事情で Google Play に公開していないアプリでは何の意味もありません。

むしろ意味なく Google Play に飛ばしてしまうので、野良アプリの場合は URI から package の指定を外しておいた方がいいです。(それでも Intent 自体は動いてくれます。)

S.browser_fallback_url を指定する

先ほどのドキュメントを読み返してみると、S.browser_fallback_urlと言う最早そのまんまな名前のパラメータに関する記述があります。

指定方法も簡単で、エンコード済みの URI を渡すだけです。先ほどの URI から package を外して S.browser_fallback_url を指定してみましょう。例えば、http://hoge.fuga.piyo/app-install.htmlなんて場所に飛ばしたければこんな感じです。

intent://piyo#Intent;action=view;category=browsable;scheme=hogefuga;S.browser_fallback_url=http%3a%2f%2fhoge%2efuga%2epiyo%2fapp%2dinstall%2ehtml;end;

で、やってみると本当に飛ばしてくれます。最新版の Chrome なら。

この方法は非常にスマートなんですが…その…Chrome が対応したのが本当に最近で、今年の 3 ~ 4 月頃にリリースされた新機能だったりします。(細かいバージョンはちゃんと調べていません…。)

一応 Android の WebView も Chromium を使っていることには間違いないので、そのうち対応されるんでしょうが、現状では常に Chrome を最新版にしていてなおかつ普段のブラウジングも Chorome しか使わない人にしか機能しません。つまり、実質使えないってことですね。

JavaScript を書いてどうにかする

こうなったら JavaScript だ!ってことで、頑張って書いてみました。

function fallbackApp(uri, fallbackUri) {
    // 起動する瞬間の時間を取得しておく
    var startTime = new Date().getTime();

    // 普通にlocation.hrefにuriを渡すとその後操作できないので
    // window.openを使って開く
    var w = window.open(uri, "intent");

    setTimeout(function() {
        if(w) {
            // ブラウザに処理が戻ってきたタイミングの時間を取得する
            var endTime = new Date().getTime();

            // アプリが起動しようとしまいと、ブラウザに処理が戻ってきた
            // タイミングでここのsetTimeoutは動く。
            // そこで、起動時と起動後の時間の差分をとって無理矢理判定する。
            // (そうしないと、アプリが起動したのにフォールバックしてしまう。)
            if((endTime - startTime) < 3000)) {
                w.location.href = fallbackUri;
            }
        }
    }, 1000); // ここの時間は多分もっと短くても良い。
              // 1秒だと「ページが表示されませんでした」っぽいエラーが普通に見えてしまう。
}

見てもらえばわかる通り、相当な力技です。

Intent のための URI はどう頑張っても same origin policy に反するので(そもそも scheme が違うんだから打つ手がない)、このように setTimeout で逃げるしかありませんでした。せめてw.documentあたりが取得できればまた違ったのでしょうが…。

2015/12/11 追記:標準ブラウザでのフォールバック

上記のスクリプトですが、Chrome では動くものの、Android の標準ブラウザでは動作しません…。

試行錯誤の結果、更なるパワープレイで対処できました。

// intentを飛ばすためのa要素を作成し、bodyにappendする
var a = document.createElement("a");
a.href = url;
a.target = "_blank"; // 同ウィンドウ内でアプリを開くとフォールバックしないので無理矢理別ウィンドウに…
var body = document.getElementsByTagName("body")[0];
body.appendChild(a);

// a要素のクリックイベントをぶったたく
var e = document.createEvent("MouseEvents");
e.initMouseEvent(
  "click",
  true,
  true,
  window,
  0,
  0,
  0,
  0,
  0,
  false,
  false,
  false,
  false,
  0,
  null
);
a.dispatchEvent(e);

// 一定時間内にアプリが起動しなかったらフォールバック
setTimeout(function() {
  var endTime = new Date().getTime();
  if (endTime - startTime < 3000) {
    window.location = fallbackUrl;
  }
}, 1000);

こうすると別ウィンドウでは「ページが見つかりません」みたいな表示がされ、リンク元のウィンドウでフォールバック、というあんまりイケてない感じにできます。文句は Google に言ってください。

まとめ

そんなわけで、Intent の送信は簡単なんですが、フォールバックさせるのは死ぬほどしんどいよ、と言うお話でした。

参考

【PowerShell】他プロセスの実行方法まとめ

2018/11/22 追記

以下の修正を行いました。

  • ちゃんとシンタックスハイライトを適用しました。
  • 呼び出し元のプロセスに標準 / エラー出力をリダイレクトする方法を追記しました。
  • 一部のリンクが 404 を返すようになったので削除しました。

前書き

何だかんだで最近 PowerShell を書く機会が増えまくっています。まぁ中身はほとんど C#なんですが。

で、全部 C#で書いてもいいんだけど、外部ツール使えば一瞬みたいなものもあるので、そう言うものはなるべくそっちでやってしまいたいです。特に zip 関連の処理。

シェルってぐらいなんだからそれぐらい簡単にできるでしょー?と思っていたら大分ハマったので色々とメモしておきます。

実行例

引数で受け取ったフォルダのサブフォルダ内にある zip ファイルをC:\Program Files\7-Zip\7z.exeで解凍する、みたいなパターン。7z.exe にパスは通していない状態。

コマンドはxコマンドを使います。

大体こんなコードになります。Get-ChildItem?何のことかよくわからないですね…。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
    }
}

普通に実行する

何をもって普通と呼ぶのかですが、こんな風にすりゃ呼べるんじゃねーの?と普通は思います。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root, "*7z")) {
        # ここで7zipを使って解凍したい
        $7zexe x -o$root $7zFile
    }
}

$root$7zFileにスペースが入っていたりするとやっぱりダメなので、安全性を鑑みてこのようにするのがベストでしょう。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        & $7zexe x -o"$root" "$7zFile"
    }
}

ちなみにこの&Invoke-Expressionエイリアスです。まぁわざわざInvoke-Expressionなんて長ったらしいコマンドを書く必要は皆無なので tips として覚えておきましょう。

また、似たようなコマンドレットにInvoke-Itemがありますが、使える範囲が非常に狭いので覚えなくていいです。(既定のプログラムで txt 開きたいとかのケースだと使えるけど…。)

また、$?を使うことで直前のコマンドが成功したかどうかを boolean で取得できるので、こんなこともできます。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        & $7zexe x -o"$root" "$7zFile"

        if($?) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

Start-Processを使う

他の方法としてはStart-Processコマンドレットを使用する必要があります。 System.Diagnostics.Process::Startみたいなもんだと思えば OK です。

Start-Processのパラメータ

色々と引数がありますが、頻繁に使うのはこのあたりでしょうか。

パラメータ 用途
-FilePath 実行ファイルのパス。パス内にスペースが入っているとキレられるので、ダブルクオーテーションでくくってやる必要がある。
-ArgumentList 実行ファイルへ渡す引数。一応String[]を受け付けるが、普通に一個のStringを渡す方が安全。
-NoNewWindow プロセス実行時に別ウィンドウを立ち上げない。-WindowStyleとは併用不可。
-PassThru 実行するプロセスのオブジェクトを生成してくれる。デフォルトではオフなので、戻り値が欲しい時は必須のパラメータとなる。後述。
-Wait 指定したプロセスの実行が完了するまで PowerShell が待っていてくれる。
-WindowStyle プロセスを実行する際のウィンドウサイズを指定。規定値はNormal-NoNewWindowとは併用不可。

-WindowStyleに指定可能な値

-WindowStyleには以下の値を設定することができます。内容は読んで字の如く。

  • Normal
  • Hidden
  • Minimized
  • Maximized

Start-Processでのプロセス実行例

と言うわけで、先ほどの処理を行うならこんな感じですね。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in$cDirectory::GetDirectories($args[0])) {
  foreach($7zFile in $cDirectory::GetFiles($root,"\*7z")) {
    #ここで 7zip を使って解凍したい
    $arg = "x -o`"$root`" `"$7zFile`""
    Start-Process -FilePath $7zexe -ArgumentList $arg -Wait -NoNewWindow
  }
}

ただこの方法、標準出力 / エラー出力を取得することが出来ません…。

-PassThru を使って更に細かい制御を行う

先述した通り、-PassThruオプションをつけるとプロセスのオブジェクトを作成してくれます。

具体的には、System.Diagnostics.Processが取得できます。

Processに含まれるプロパティExitCodeを見ることで処理結果からその後の処理を分岐させることが可能です。

$nIO = "System.IO" 
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        $arg = "x -o`"$root`" `"$7zFile`""
        $proc = Start-Process -FilePath $7zexe -ArgumentList $arg -Wait -NoNewWindow -PassThru
        
        if($proc.ExitCode -eq 0) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

他にもWaitForExitメソッドあたりを使ってタイムアウトの制御なんかもできます。(当然-Waitオプションをはずさないと意味ないですが)

System.Diagnostics.Processを使う

え?PowerShell の文法なんか覚えられない?じゃあ C#書いたら?

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]
$nDiagnostics = "System.Diagnostics"

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        $arg = "x -o`"$root`" `"$7zFile`""
        $proc = New-Object "$nDiagnostics.Process"
        $psi = New-Object "$nDiagnostics.ProcessStartInfo"

        $psi.FileName = $7zexe
        $psi.Arguments = $arg
        $psi.UseShellExecute = $false
        $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden

        $proc.StartInfo = $psi

        $proc.Start()
        $proc.WaitForExit()

        if($proc.ExitCode -eq 0) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

とまぁ、見ていただくとわかるんですがすげー冗長です。シェルとは何だったのか。

ただ、Start-Processとは違ってSystem.Diagnostics.ProcessStartInfoをこちらで用意できるので、標準出力 / エラー出力をごにょごにょし放題です。

呼び出し元のプロセスと同じ標準出力 / エラー出力にリダイレクトさせるだけなら、以下のプロパティをtrueにすれば OK です。

また、この記事Process.OutputDataReceivedの設定方法などが詳細に解説されていますので、興味ある人はどうぞ。私はスクリプトのためにそこまでしないタイプの人間なので紹介だけにとどめておきます。

まとめ

PowerShell 使いにくい。

参考

【VSCode】Visual Studio Code 0.3.0の新機能まとめ

前書き

いつの間にかVSCodeが0.3.0にバージョンアップしていました。

「0.2.0は?」とか「起動時に毎回やってる自動アップデートチェックとは一体何だったのか」とか色々思うことはあるんですが、気が付かなかったことにしましょう。0.2.0は色々あったみたいですが、見なかったことにしましょう。

アップデート方法

再インストールしてください。

C:\Users\{UserName}\AppData\Local\Code\app-0.3.0にまるっと新しいものがインストールされます。日本語フォントを適用するためにcssを直接いじってたりすると強制的に元に戻されてしまいますが、app-0.1.0に元のソースやバイナリがそのまま残っているので、適当にマージしましょう。

新機能

Updatesに色々書かれているので、適当に翻訳していきます。

新しいキーバインド

色々な要望を受けてデフォルトのキーバインドを改善したようです。

  • Ctrl+Oでネイティブなファイル選択ダイアログが出るようになりました。各所から強い要望があったそうです。
    • VSCodeのファイル選択ダイアログ(コマンドパレットっぽいあれ)はCtrl+P⌘Pに変更したようです。「今の主要なエディタだとCtrl+Pで開くほうがトレンドだから!」と言い訳がましいことが書いてあります。
  • Visual Studioと同じくF12で定義にジャンプできるようになりました。(Ctrl+F12から変更)
  • Macでファイルの先頭/末尾への移動がCmd+UpCmd+Downで行えるようになりました。
  • コードのフォーマットを⇧⌥Fで行えるようになりました。(WindowsだとShift+Alt+FLinuxだとCtrl+Shift+Iで元々できました)

起動時の引数

存在しないファイルが引数で渡されたら新規ファイルを作成するようになりました。

(正確には「VSCodeで保存すると初めて作成されるDirtyなファイル」とのこと。)

code mynewfile.js

また、複数のファイルやディレクトリを引数で渡すことである程度最初からWorking Spaceを作れるようになりました。

code c:\myfolder1 c:\myfolder2 c:\myapp\program.cs

最後に、前回のセッション内容を復元しないで起動できるように-n--new-window)と言うオプションが追加されました。

code -n

コード編集

複数選択

  • Ctrl+D⌘D)を押すことでカーソル上の単語を選択、選択中に同コマンドを押すことで次に現れる同単語も選択できるようになりました。
  • Ctrl+K → Ctrl+D⌘K → ⌘D)で同単語を選択しつつカーソルを移動させることもできます。
  • 検索ボックス(Ctrl+F)が開いた状態で上記コマンドを入力すると即座に検索単語になります。
  • Ctrl+U⌘U)でカーソルの位置をアンドゥできるようになりました。
  • Ctrl+Alt+UpMac:⌥⌘↑, Linux:Ctrl+Meta+Up)とCtrl+Alt+DownMac:⌥⌘↓, Linux:Ctrl+Meta+Down)を使うことで複数選択しながらページを移動できます。

コメント

  • Ctrl+K → Ctrl+C⌘K → ⌘C)で選択行をコメントアウトできるようになりました。
  • Ctrl+K → Ctrl+U⌘K → ⌘U)で選択行のコメントを外せるようになりました。
  • 元々Ctrl+/⌘/)で行コメントの切り替えができたんですが、選択文字列内の空白行(ホワイトスペースのみ含む)では何も追加/削除しないようになりました。
  • 同じく、ブロックレベルのコメント切り替えであるShift+Alt+AMac:⇧⌥A, Linux:Ctrl+Shift+A)でも選択行の内容を見るようになりました。

インデント

空白行でTabを押したらちゃんと前行を見て必要な分だけインデントしてくれるようになりました。

選択範囲の拡張/縮小

Shift+Alt+Left^⇧←)とShift+Alt+Right^⇧→)を使って選択範囲の拡張/縮小が行えるようになりました。

どんなイメージかはgif動画があるんでそれを見てください。

禁則処理

settings.jsoneditor.wrappingIndentと言うプロパティが追加されました。指定できる値は以下の通りです。

  • none
  • same(これがデフォルト)
  • indent

長い文章が入力されるとそれぞれこんな感じになります。

    #none
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat."

    #same
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
    , sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat."
    
    #indent
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
        , sed do eiusmod tempor incididunt ut labore et dolore magna
        aliqua. Ut enim ad minim veniam, quis nostrud exercitation
        ullamco laboris nisi ut aliquip ex ea commodo consequat."

デバッグ機能

正直、VSCodeのデバッグ機能って使ったことないんですが…。

ドキュメントもちゃんとアップデートされているので、よくわからなかったらそっちも読んでください。

  • 接続時の設定(launch.json)としてruntimeArgsが追加されました。Node.jsやMonoにコマンドライン引数を渡す時に便利だそうです。
  • Linuxではデバッグ開始時に入出力をサポートするterminalを自動で開くようにしたそうです。
  • TypeScriptのデバッグ時にJavaScriptのsource mapと連携できるようになりました。接続時の設定でsourceMapstrueにすると使えるようです。
  • program属性にTypeScriptファイルを明示できるようになりました。
  • TypeScriptファイルからsource mapを生成してくれるようになりました。
  • 現在のセッションで開いていないフォルダ内のコードもデバッグできるようになりました。
  • 例外が発生したらその場所を赤く表示するようになりました。

この他にも多数の改善が行われています。UNCパス上のファイルをデバッグできるようになっていたりとか、MonoのF#(!)をデバッグできるようになっていたりだとか。

…って言うか、WindowsC#はいつサポートされるんですかね?

タスク

新たに三つのproblem matcherが追加されました。JSHintESLintの結果を受け取れるようになっています。

  • $jshint-stylish
  • $eslint-compact(※元文章では$eshint-compactとなっているが、Taskのドキュメントを読む限り誤記だと思われる。)
  • $eslint-stylish

また、ESLintのように複数行にまたがって取得する情報が展開されるものをどうにかするためにMulti Line Problem Matcherなるものも用意されました。

Taskの機能そのものより、ドキュメントの整備具合が大幅に向上したって感じです。がっつりtask.jsonを書くならSchema for tasks.jsonに一度は目を通しておきましょう。

言語対応状況

  • Rustの色分けとブラケットに対応。
  • TypeScript version 1.5に対応。
  • JavaScriptのvalidationのon/offを切り替えるプロパティが追加されました。主にJSHintを使う人向け。
    • javascript.validate.semanticValidation
      • 型はboolean。未使用変数が存在するとかのエラーを通知
    • javascript.validate.syntaxValidation
      • これもboolean。ブラケットが閉じてないとかのエラーを通知
  • HTMLで自動でタグを閉じてくれるようになりました。

CJK wrapping

今度は自然言語のお話。CJKとは「Chinese-Japanese-Korean」とのこと。左記の言語で禁則処理をきちんと行うようになりました。

また、変換を確定した時に変な挙動になるのも直ったみたいです。

…が、ファイル内に日本語が含まれているとOmniSharpがおかしくなるのは直ってない模様。Windowsだけなのかなー。って言うかこれはRoslynの問題な気もする。でもScriptCSは大丈夫だしなぁ…。

ファイル比較

コマンドパレットからファイル比較が簡単にできるようになりました。Files: Compare Opened File Withで可能です。

パスのコピー

Explorerペインで右クリックした時にパスをコピーできるようになりました。

現在開いているパスのコピーはコマンドパレットのFiles: Copy Path of the Active Fileで可能です。

Close Folder

メニューバーのFileか、コマンドパレットからClose Folderを選択することで現在開いているフォルダを閉じることができるようになりました。

ファイルエンコーディング

何だかんだで今回一番の目玉。UTF-8以外のエンコーディングに対応しました。

デフォルトではUTF-8のままですが、settings.jsonfiles.encodingを修正することで変更できます。

ちなみに文字コードの自動判別とかは一切ないです。ダメじゃん。

設定

VSCodeあるあるとして「setting.jsonの内容を自動補完で書いたせいで最後に,がついて怒られる」と言うのがあるんですが、これを無視してくれるようになりました。

まぁでも、怒りっぱなしなんですけど。

UNCパスのサポート

前から思ってたんだけど、VSCodeチーム、Windowsのこと嫌いだよね?

Working filesの監視

フォルダを開いていなくてもWorking files内のファイルは変更を監視するようになりました。

32bit版Linuxへの対応

対応したそうです。(雑)

まとめ

とまぁ、色々「どーなってんじゃい!」みたいなところが少しずつ修正されています。

次回は自動アップデートがちゃんと意味をなしてくれるといいですね!(皮肉)

【PowerShell】PowerShellでC#っぽいスクリプトを組むときの覚書

前書き

こう、「超単純だしC#なら10分ぐらいで書けるんだけど手作業でやると恐ろしく時間がかかる」みたいな作業ってあるじゃないですか。

そう言うのは最近ScriptCSで書いてるんですけど、あれの弱点って「どんな端末でも実行できるわけではない」なんですよね。.NET 4.5以上が必須だし、そもそもScriptCS自体がない。

Windows Server上での作業だとか、メインで使っているのとは別の開発端末での作業とか、「こいつ叩けば一発っすよ。」と鼻をほじりながら誰かに渡したりするようなスクリプトを書きたいときにはどうしても別の方法を考えなきゃいけません。

ってなると、じゃあbatでも書く?ってなるんですが、あれを書くエネルギーって本当にもったいないじゃないですか。デバッグは大変だし、文法はクソだし、文法はクソだし、文法はクソだし。

System.IO.PathとかSystem.IO.Directoryとかが使えればこんなの一発なのに…!ついでにSystem.DateTimeとかもあったら完璧なのに…!と思ったら、さっさとPowerShellで書くことにしました。

この文章の対象読者

PowerShellの文法を覚えるのは面倒だけどC#っぽいことができるスクリプトを書きたい人

下準備

PowerShellの環境を準備する

準備と言っても、Windows 7Windows Server 2008 R2からは標準搭載です。XPは標準搭載ではないですが、Windows Updateで取得できます。まぁ、XPなんて流石にもう使ってないと思うんですが…。使ってないですよね?

そんなわけで、今ならbatと同じぐらいの感覚で「これ使って」とばらまくことが可能です。実際に書いてる人を全然見たことがありませんが。

IDEの準備をする

PowerShellをインストールすると勝手にPowerShell ISEなる統合開発環境がくっついてきます。

…が、ver.1~2は「PowerShellシンタックスを綺麗に色分けしてくれるちょっと重いエディタ」でしかないです。(デバッグ機能はあるけども)

ver.3以降はインテリセンスが使えるので、可能であればアップデートしてきましょう。可能でなければ、頑張るだけです。

実際に書いてみる

オブジェクトを作る

New-Objectと言うコマンドレットがコンストラクタのかわりです。

ドキュメントには色んな引数が書いてありますが、基本的にはこんな感じでOKです。

$l = New-Object System.Collections.Generic.List[string]

New-Object 名前空間.型名って感じですね。ジェネリクス<T>ではなく[T]になります。

引数を渡すことも当然可能です。複数ある場合は,でOK。

$l = New-Object System.Collections.Generic.List[string](20)

プロパティをセットすることもできますが、インテリセンスが効かないのでオススメしません。

#意味不明なコードだ…。
$l = New-Object System.Collections.Generic.List[string](20) -Property @{Capacity=30}
$l.Capacity
# => 30

静的メソッドを呼び出す

[名前空間.型名]::メソッドで呼び出せます。

$tuple = [System.Tuple]::Create("hoge", 0)
$tuple.Item1
# => hoge
$tuple.Item2
# => 0

usingっぽいことをする

今までの例を見てもらえればわかるんですが、いちいち名前空間を書くのが結構面倒くさいです。(ISE ver.3以降であればインテリセンスである程度補完できますが…。)

PowerShellの文法にはC#のusingに該当するシンタックスはありませんが、近いことはできます。

# 名前空間を文字列で保持しておく
$nGeneric = "System.Collections.Generic"

# New-Objectの際に型名を文字列で渡す
$l = New-Object "$nGeneric.List[string]"
$l.Add("hoge")
$l.Add("fuga")
$l

# => hoge
# => fuga

静的メソッドを呼ぶ場合はもう一手間必要です。

$nIO = "System.IO"

# デフォルトで読み込まれていないアセンブリならロードしておく必要がある
#[Reflection.Assembly]::LoadWithPartialName($nIo)

# Typeにキャストする
$cPath = "$nIO.Path" -as [type]

$cPath::GetFileName("C:\test.txt")
# => test.txt

どちらもインテリセンスが効かなくなってしまうんですが、F8で選択した文字列だけを実行できるので、usingっぽいところだけを適宜実行すればOKです。

もうちょっと実践的なことをする

ファイルの退避処理

例えば、C:\TMP配下の.txtファイルをC:\TMP\backにタイムスタンプ(yyyymmdd)をつけて格納する、みたいな処理。

C:\TMP
│  fuga.txt
│  hoge.txt
│  piyo.png
│
└─back

これだけの処理ですがbatでやろうとすると結構面倒です。dirでtxtだけとってきて…batのforってどう書くんだっけ…日付の書式ってどう書くんだっけ…と嫌になってきます。

ここは.NETの力を借りましょう。どんどん借りましょう。

$baseDir = "C:\tmp"
$today = [datetime]::Today.ToString("yyyyMMdd")

foreach($file in (dir ($baseDir + "\*.txt"))) {
    
    # バッククオートを使うと改行できる
    $destFile = $baseDir + "\back\" + [System.IO.Path]::GetFileNameWithoutExtension($file) `
                    + "_" + $today + ".txt"

    copy $file $destFile
}

インテリセンスを使いつつ大体3分ぐらいで書けました。

また、当然のことですがPowerShellではパスが通ってるコマンドならいくらでも使用可能です。(dirとかcopyとかmoveとかはPowerShellのaliasで色々構文が変わってしまっていますが…。)コマンドの構文が思い出せなかったら.NETのAPIでやっちゃえばいいです。

それに加えて制御構文としてforeachswitchwhileなんかも当然のように使えます。もうbatを使う理由なんて一つもないですね。

もういっそ全処理をAdd-Typeでぶちこむ

ここまで読んでも「いやでもやっぱPowerShellクソ面倒でしょ。C#最高でしょ。」と思った人にオススメの方法があります。

PowerShell ver. 2から追加されたAdd-Typeと言うコマンドレットがあるんですが、.NETのDLLやソースをPowerShellで使えるようにしてくれます。コードをインラインで書いてもOKです。

# 文字列を@でくくるとヒアドキュメントになる
Add-Type @"
using System;

public class Test {
    public static void Exec(string arg) {
        Console.WriteLine(arg);
    }
}
"@

[Test]::Exec("hello world")
# => hello world

「やりたいことを全部C#で書く⇒PowerShellでAdd-Typeする⇒適当に呼び出す」とするだけでPowerShellの記述は、まぁおおよそ3行ぐらいですみます。やりましたね!

ちなみにこれ、-Languageを指定することでVB.NETでもいけます。VBおじさんにも優しい!やりましたね!

Add-Type -Language VisualBasic @"
Public Class Test
    Public Shared Sub Exec(ByVal args As String)
        System.Console.WriteLine(args)
    End Sub
End Class
"@

[Test]::Exec("hello world")
# => hello world

また、なぜかJScriptも読み込めます。何の因果かJavaScriptを習得してしまったWebデザイナーにも優しい!やりましたね!

$obj = (Add-Type -Language JScript -MemberDefinition @"
    static function exec(args) {
        // 流石にJScriptでConsole.WriteLineは無理っす…。
        return args
    }
"@ -Name "Test" -PassThru)[1]

Write-Host $obj::exec("hello world")
# => hello world

JScriptの例で-MemberDefinitionなるものを使いましたが、これを使えばC#でもいちいちクラスの宣言等が不要になります。

$obj = Add-Type -MemberDefinition @"
public static void Exec(string arg) {
    Console.WriteLine(arg);
}
"@ -Name "Test" -PassThru

$obj::Exec("hello world")
# => hello world

更にコードが短くなりました!もう怖いものなしですね!どんどんC#書きましょう!

まとめ

中々PowerShellおじさんに怒られそうな内容になりました。っていうか内容がペラッペラなので、何か思いついたらどんどん追記していきます…。

ともかく、PowerShellの文法をほとんど知らなくてもここまでやりたい放題できるので、ちょっとしたスクリプトをbatなんてゴミで作るぐらいならどんどん活用していきましょう。

参考

【Git】最低限やっておきたい.gitconfig

前書き

個人用メモなので他の人がどうしてるのかは知りませんが。復旧したり新しい環境で再設定したりするのが結構だるいんですよね…。

なんだか最近こんな記事ばっかりですね。

aliasで強制的に--no-pagerをつける

いきなり.gitconfigとは全く関係無いですが、pager使いたかったら自分で指定する方がストレスフリーなのでaliasを設定しておきます。

私はNyaosを仕事でもプライベートでも使っているので_nyaに記述。コマンドプロンプトを使ってる?知らんがな。

alias git=git --no-pager

前提知識

Gitのconfigファイルは三種類あります。どれか一つだけ修正して「なんか動かねーぞ!」と慌てる前にgit config --listを使って覚えのない設定で上書きされていないか確認しましょう。

git configでのオプション場所
--system (Gitがインストールされているディレクトリ)\etc\gitconfig
--global %USERPROFILE%.gitconfig
--local リポジトリの.git内のconfig

また、どんな設定ができるかはここに書いてありますが、正直読んでも全然わかりません。

systemレベルの設定

editorをvimにしたりとか、diffツールWinMergeにしたりとか。後はgrepにcolor設定したりとか。

alias以外はデフォルト以上のことはしないようにします。面倒だし。

[core]
    symlinks = false
    autocrlf = false
    editor = vim
[color]
    diff = auto
    status = auto
    branch = auto
    interactive = true
    grep = auto
[pack]
    packSizeLimit = 2g
[help]
    format = man
[http]
    sslCAinfo = /bin/curl-ca-bundle.crt
[diff]
    tool = WinMerge
    guitool = WinMerge
[difftool "WinMerge"]
    prompt = false
    path = C:/Program Files/WinMerge/WinMergeU.exe
    cmd = \"C:/Program Files/WinMerge/WinMergeU.exe\" -e -ub -dl \"Theirs Files\" -dr \"Mine  Files\" \"$REMOTE\" \"$LOCAL\"
    trustExitCode = false
[rebase]
    autosquash = true

aliasはこんな感じ。

[alias]
#各短縮形
st = status
cm = commit
br = branch -a
ad = add
co = checkout
wc = whatchanged
sh = show
ft = fetch

#オレオレ便利コマンド
diffd = difftool -d
cancel = reset --soft HEAD^
history = log --graph --date=iso --pretty=format:'%Cgreen%h %cd %Cblue%cn %Creset%s'
stat = log --stat
unstage = rm --cached
merged = branch --merged
no-merged = branch --no-merged

globalレベルの設定

最低限userだけ入ってればいいでしょみたいなスタンス。

色んな人が使う端末ならsystemの大部分はこっちに持ってきた方がいいんでしょうけど。

[user]
    name = tumbling-dice
    email = xxxxx@gmail.com

localレベルの設定

好きにしたまえ。

後書き

メモでした。

【VSCode】WindowsでVisual Studio CodeをそこそこまともなC#開発環境にするまでの手順まとめ

2018/11/22追記

この記事は3年以上前に書かれたものです。

現在では最早何の役にも立たない記事ですので、お帰りください。

前書き

超絶お久しぶりです。最近はくっそ忙しいです。忙しすぎて趣味的なコードを書く暇もありません。最近白髪が生え始めました。実績解除ですね。

さて、お仕事で使っているPCがあまりにもクソスペックすぎることは以前お話したんですが、最近わけあってVisual Studio 2013 ExpressをインストールしようとしたらHDD容量が足りないとか言う2015年とは思えない理由でダメでした。まぁ空き容量が2GBしかないし。.NET Framework 4.5.2 Developer Packすら入らないし。

そこで最近登場したVisual Studio Code、あれを使ってみようかなと。あわよくばScriptCsのコードもバリバリ書けるIDEにしておきたいなと思ったので、そのために準備した内容を書き留めておきます。

まぁなんと言うかですね。Windowsで無理に使うぐらいならVisual Studio 2015なりなんなりを入れた方が100倍便利です。現状だとC#デバッグすらできません。準備も結構大変です。私のようにやむにやまれぬ事情があるか、とりあえず使ってみたい人向けです。

Visual Studio Codeのインストール

公式サイトから落としてきてください。

Windows版だとC:\Users\{username}\AppData\Local\Code内に本体が置かれます。普通にProgram Filesに置いてくれよ…。

(2015/11/27追記)v0.8.0からインストール先を選べるようになりました。

Node.jsのインストール

Visual Studio CodeのインテリセンスはOmniSharpと呼ばれる技術で動いています。これはNode.jsを使ってローカルサーバを立て、そのサーバに対してPOSTするとRoslynが解析して使用可能な候補を返すと言う、理論上どんなエディタでも使用可能な仕組みです。

(2015/11/27追記) OmniSharp自体がサーバとしての機能を持っているのでNode.jsは関係ないです。(最近OmniSharpで遊び始めて気が付いた)

そのため、Node.jsがないとどうやってもインテリセンスが動かない…ってことは多分ないんですが(一応node.exeも同梱されてるし)、npmから色々なパッケージを持ってくることで開発が更に捗るので、インストールしてなかったらインストールしてきましょう。

インテリセンスを使うための準備

Visual Studio CodeでOmniSharpが起動する条件は以下の二つのどちらかを満たしている場合のみです。

  • ワーキングスペース内に*.sln(と、*.csprojとか*.vbprojとか)があり、Visual Studioがインストールされていること。
  • ワーキングスペース内にASP.NET 5用のproject.jsonがあること。

と言うわけで、Visual Studioを既にインストールしている方。おめでとうございます。既存のプロジェクトをVisual Studio Codeで開き、15~30分ほど遊んだ後、普段から使っているVisual Studioに戻りましょう。

多分、本当はVisual Studioなしでもどうにかすれば動くとは思うんですが、そもそもソリューションファイルを頑張って自作すること自体が恐ろしく面倒ですし、自分でシコシコとcsprojを書くのはあまりにも苦痛です。

ASP.NET 5のproject.jsonの方は比較的準備が簡単なので、今回はこちらの解説をしていきます。

ASP.NET 5の実行環境を整える

Visual Studio CodeでASP.NET 5を使うためのドキュメントがあるので、基本的にはこれを読んで一通りやればOKです。一応要点だけ解説します。あくまで要点なのでちゃんと元ドキュメントは読みましょうね。

まずはDNXをインストールします。これは.NET Execution Environmentの略で、その名の通り「.NETの実行環境」です。マイクロソフトが頑張ってMacLinuxでも.NET Frameworkで書かれたwebアプリケーションを動かせるようにしてくれました。もちろんWindowsでも動きます。

ASP.NETGitHubインストール手順があるので、黙々とインストールしてきてください。Upgrading DNVMと書かれていますが、後で諸々全部ついてくるのでご安心を。ちなみに「Visual Studio 2015をインストールするのが一番早い」とのことです。そっすか。

DNVMのパスが通っていることが確認できたらdnvm upgradeを実行しましょう。これにてDNXのインストールは完了です。

空プロジェクトをコマンドラインで作成できるようにする

次のステップです。ASP.NET 5の空プロジェクトをコマンドラインで生成するための諸々のツール・モジュールをnpm経由でインストールします。

ドキュメントにもあるように、以下のコマンドを実行するだけです。普段からNode.jsをバリバリ使ってる人は既にインストールしてそうなものもあるので適宜欲しい物を取ってきて下さい。

npm install -g yo grunt-cli generator-aspnet bower

ちなみにyoことyeomanWindowsだとyodoctorなるものが引っかかってインストールできないことがあるみたいなので、ダメだった場合はGitHubから適当にcloneしpackage.jsonから下記記述をまるっと消してしまいましょう。

「Gitなんか入れてねぇ」とぬかす人もいるかもしれませんが、Bowerを使うためにどのみち必要なのでこれを機にインストールしてきてください。

"scripts": {
        "test": "grunt",
        "postinstall": "node ./scripts/doctor",
         "postupdate": "node ./scripts/doctor"
},

消し終わったらコマンドプロンプトでカレントディレクトリをyoのプロジェクトに移した後、npm i -gを実行すればOKです。

とりあえず空プロジェクトを作る

DNXとyoとgenerator-aspnetをインストールしたらやっと準備完了です。空プロジェクトを作りましょう。

と言ってもコマンドプロンプトからyo aspnetと叩くだけです。後はConsole ApplicationかClass Libraryあたりを選択し、自動生成されたディレクトリでdnu restoreを実行すれば不思議な力によって謎のパッケージがNuget経由でインストールされ、なんだかよくわからないjsonが新たに生成され、Visual Studio Codeでそのディレクトリを開くとOmnisharpが動くようになっているはずです。お疲れ様でした。

project.jsonの中身を書き換える

と、それだけで済めばよかったんですが、もう一手間かけないといけません。

yo経由でClass Libraryのプロジェクトを作った場合、最初のproject.jsonはこんな風になっています。

{
    "version": "1.0.0-*",
    "dependencies": {},

    "frameworks": {
        "dnx451": {
            "dependencies": {}
        },
        "dnxcore50": {
            "dependencies": {
                "System.Runtime": "4.0.20-*"
            }
        }
    }
}

これをとりあえずこうします。

{
    "version": "1.0.0-*",
    "dependencies": {},

    "frameworks": {
        "dnx451": {
            "frameworkAssemblies": {
                "System": "",
                "System.Core": "",
                "System.Xml.Linq": "",
                "System.Data.DataSetExtensions": "",
                "Microsoft.CSharp": "",
                "System.Data": "",
                "System.Xml": ""
            }
        }
    }
}

上記のように変更した後、もう一度dnu restoreしましょう(コマンドパレットでrestoreと入力してもOK)。今度こそお疲れ様でした。これであなたはようやくまともな開発環境を一つ手に入れました。

project.jsonの役割と参照設定

本筋から大きくそれてしまうのですが、今後もproject.jsonはメンテしていくことになるので、簡単に解説しておきます。詳しい情報はドキュメントにたくさん書いてあるので一読しておきましょう。

project.jsonはcsprojとほぼ同様の内容を記述することができます。有名所で言えば参照設定、ビルドイベントとかですね。

実はrestoreコマンドを実行したdnu(DNX Utility)にはcsprojをproject.jsonに変換するコマンドも用意されていますが、Visual Studioをインストールしないと手に入らないようなMSBuild.exeを使うらしいので特に説明しません。

今回何を消して何を追加したかはこの辺が参考になると思います。

がっつり削除したdnxcore50の部分は、物凄く雑に言うと、「OSを問わずどんな環境でも動かすために必要なassemblyとそのバージョン」です。対してdnx451frameworkAssembliesは「GACに登録されているであろうassembly」です。本当に超絶雑な説明なので鵜呑みにしないように。

dnxcore50で使えるライブラリは、現状、かなりの制限があります。(Webアプリケーションで使うって意味では必要十分なんでしょうが。)

Visual Studio Codeくんはdnxcore50dnx451の両方でコンパイルできないと知ると「dnxcore50の方で参照設定が足りてないと思うんですけど(名推理)」と容赦のないエラーを吐き出すため、もういっそdnxcore50は定義しなくていいです。dnx451だけにします。ついでに普通にConsole ApplicationやClass Libraryのプロジェクトを作った時に定義される参照設定を入れておきます。

ただこのままだとyo aspnetする度にproject.jsonを直す必要があるため、generator-aspnetのtemplates内にあるproject.jsonも適当に直しておきましょう。

「自分で作ったDLLは参照設定に入れられないの?」と思った人もいると思います。一応できますが、プロジェクトのNugetパッケージ化が必要です。

後はdependencies内に名前とバージョンを書けば適当にNugetから取ってきてくれます。例えば、SgmlReaderの最新版を使いたかったら、こんな感じです。

{
    "version": "1.0.0-*",
    "dependencies": {
        "SgmlReader": "1.8.11"
    },

    "frameworks": {
        "dnx451": {
            "frameworkAssemblies": {
                "System": "",
                "System.Core": "",
                "System.Xml.Linq": "",
                "System.Data.DataSetExtensions": "",
                "Microsoft.CSharp": "",
                "System.Data": "",
                "System.Xml": ""
            },
            "dependencies": {
                "SgmlReader": "1.8.11"
            }
        }
    }
}

フォルダ構成はこうなります。

(root)
│  .gitignore
│  Class1.cs
│  project.json
│  project.lock.json
│              
└─packages
    │  
    └─SgmlReader.1.8.11
        │  SgmlReader.1.8.11.nupkg
        │  
        └─lib
            ├─2.0
            │      SgmlReaderDll.dll
            │      
            └─4.0
                    SgmlReaderDll.dll

コンソールアプリケーションを実行する

dnx [path] runでコンソールアプリケーションを実行可能です。コマンドパレットにも登録されているのでわざわざコマンドプロンプトを開く必要はないです。

exeファイルにビルドとかはできません。dnuにビルドコマンドはあるんですが、dllファイルになってしまいます。

Visual Studio Codeからビルドできるようにする

dnu build [path]とすることで対象のプロジェクトをdllファイルにビルドできます。が、Visual Studio Codeにはこのコマンドが登録されていないので、自分で作ります。

コマンドパレットでtaskと入力し、「Tasks: Configure Task Runner」を選択しましょう。自動でワーキングスペース内にtasks.jsonが生成されます。

後はこんな風にしておけばOKです。

{
    "version": "0.1.0",
    "command": "dnu", 
    "showOutput": "always", // 出力内容を必ず表示
    "isShellCommand": true, // 外部のツールかどうかの設定
    "isBuildCommand": true, // ビルドコマンドフラグ これをtrueにするとCtrl + Shift + Bでビルドできる
    "args": ["build"]
}

このtasks.json、複数のタスクが登録できると思うじゃないですか。だって「tasks」ですよ?そんなもん100%できると思うじゃないですか。なぜか一つしか登録できません。gulpを使うとできるみたいなことが書いてありますが、その、なんていうか、何なんでしょうね…。

おまけ - フォントの変え方

デフォルトだと日本語フォントが中華フォントになってしまいます。流石につらぽよなので変えたいところです。まぁでも、日本語のコメントを入力したら突然OmniSharpが死んだりするので、そもそも日本語を書かないことをオススメしますが。

方法1:settings.jsonをいじる

メニューバーのFile -> Preferences -> User Settingsから変えることができます。

選択すると自動でsettings.jsonを開いてくれるので、こんな感じのものを書いて保存すればOKです。

// Place your settings in this file to overwrite the default settings
{
    "editor.fontFamily": "適当な日本語フォント"
}

方法2:native.main.cssをいじる

方法1だと全部日本語フォントになってしまいます。英数字はConsolasで、日本語は別フォントで、としたい場合は、大元のcssをいじるしかありません。

ここを参考にC:\Users\{username}\AppData\Local\Code\app-0.1.0\resources\app\client\vs\monaco\ui\workbench\native\native.main.css内のfont-familyを検索し、よきにはからって下さい。

勿論他の要素をいじることもできるので参考サイトのように自分だけのオタク臭い開発環境を整えるのも一興でしょう。ただまぁ、アップデートかかったら即死ぬと思いますが。

(2015/11/27追記) v0.5.0ぐらいから構成が変わってnative.main.cssが消滅しました。ただまぁ、cssで設定していることには変わりないので、自力で修正自体は可能です。

参考