Quantcast
Channel: SourceChord
Viewing all 153 articles
Browse latest View live

VisualStudio Codeにejsのシンタックスハイライトを追加する

$
0
0

VSCode 0.9.1で、言語のシンタックス定義を追加できるようになりました。
ということで、ejs用の定義を追加してみました。

GitHubで探してみたら、ejs用のtmLanguageファイルを公開してくれてる方がいます↓
https://github.com/samholmes/EJS.tmLanguage

このファイルを元にして、yoのジェネレータを使ってejsのシンタックス定義ファイルを生成してみます。

yo codeでジェネレータを立ち上げて、
EJS.tmLanguageファイルを指定し、その後の入力項目を以下のように適当に入力します。 f:id:minami_SC:20151016002152p:plain

出来上がったフォルダ一式を、「%USERPROFILE%.vscode\extensions」にコピペします。
こうしておくと、VSCodeでejs形式のファイルを開くと、自動でEJSとして判定し、シンタックスハイライトが適用されるようになります。
f:id:minami_SC:20151016002200p:plain

自分は普段Node.js使うときはejsで書いてたので、こうやって自動でシンタックスハイライトしてくれるようになってメッチャ便利♪


TypeScript+Electronでデスクトップアプリを作ってみる

$
0
0

最近あちこちでElectronを使ったアプリが出てきたり、入門記事もちらほら見かけるようになってきました。
流行りものには乗っておこうということで、Electronをちょろっと使ってみました。
Electron

JavaScriptでの入門は、良質な記事がネット上に多々あるので、 ここではTypeScriptを使ってElectronアプリを作ってみたいと思います.

サンプルコード一式は、以下に置いておきました。
GitHubからcloneした後、npm installしてnpm startすれば実行できます。

準備

Node.jsがインストールされていて、npmが使える状態を前提としてます。
自分はNode.js v4系を使ってますが、v0.12系でも同じようにできるかと思います。

プロジェクトの作成

まずは適当にフォルダ作ってnpm initしてpackage.jsonを作ります。

electronのインストール

続いてelectronを--save-devでインストールします。

npm install electron-prebuilt --save-dev

TypeScriptコンパイラ

続いてTypeScriptコンパイラもインストールします。
一応、開発環境のバージョンも構成管理できるように、グローバルなtscではなく、プロジェクト内にtscをインストールしておきます。

npm install typescript --save-dev

この、プロジェクト配下にインストールしたtscを使うので、コンパイルなどのコマンドはnode_modules\\.bin\\tscと呼び出します。
グローバルにインストールしたコンパイラを使う場合には、このコマンドをただのtscと読み替えて進めてください。

tsconfig.jsonの作成

TypeScriptのコンパイル時に使う設定をtsconfig.jsonに用意します。
プロジェクトのルート(package.jsonなどがあるのと同じ階層)に、tsconfig.jsonというファイルを以下の内容で作ります。

tsconfig.json

{"compilerOptions": {"target": "es5",
        "module": "commonjs",
        "sourceMap": true},
    "exclude": ["node_modules",
        "dist"]}

設定の内容はおおまかに以下のような感じです。

  • node_modulesは各種外部ライブラリのフォルダなのでコンパイル対象外
  • distというフォルダもコンパイル対象外(まだdistフォルダは作ってませんが、後でリリース物の出力場所としてこの名前のフォルダを作ります。)
  • 「files」プロパティを省略してるので、「exclude」の内容に一致するパス以外のすべての.tsファイルがコンパイル対象になります。

これでnode_modules\\.bin\\tscというコマンドでプロジェクト一式のコンパイルをする準備ができました。

tsdを使って型定義ファイルを用意

tsdのインストール

npmから以下のコマンドでtsdをグローバルにインストールします。
もうグローバルにインストールしてるような場合はここの手順はスキップ。

npm install tsd -g
型定義ファイルの取得

electron用の型定義ファイルを取得します。

DefinitelyTypedのページを見てみると、他のライブラリの型定義ファイルとは異なり、なぜかelectronのディレクトリには、型定義ファイルがやたらたくさんあります。
https://github.com/borisyankov/DefinitelyTyped/tree/master/github-electron
rendererプロセスと、mainプロセス用にわかれてるような感じですが、両方取得するとipcモジュールの定義が重複してエラーになってしまうので、ここではmainプロセス用の型定義のみ取得してます。

これ、うまくやる方法ないのかなぁ。それともmainプロセスとrendererプロセスは別々にコンパイルしたほうがいいのだろうか・・・ この辺はまだまだお悩み中・・・

tsd init
tsd query github-electron-main -rosa install

作ってみる

これで準備が整ったので、ここからelectronを使ったアプリ作成に入ります。

ボタンを押したらalert表示するだけのサンプル

エントリポイントの作成

プロジェクトのルートフォルダに、main.tsというファイルを作ります。
そして、package.jsonに以下のようなプロパティを追加します。

{// 省略"main": "main.js",
  // 省略}

package.jsonのmainプロパティに書かれているjsファイルがアプリのエントリポイントとなります。

main.tsは以下のとおり。

import app = require('app');
import BrowserWindow = require('browser-window');
require('crash-reporter').start();

// メインウィンドウの参照をグローバルに持っておく。var mainWindow: GitHubElectron.BrowserWindow = null;

// すべてのウィンドウが閉じられた際の動作
app.on('window-all-closed', function() {// OS X では、ウィンドウを閉じても一般的にアプリ終了はしないので除外。if (process.platform != 'darwin') {
    app.quit();
  }});

app.on('ready', function() {// 新規ウィンドウ作成
  mainWindow = new BrowserWindow({ width: 800, height: 600 });

  // index.htmlを開く
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたら、ウィンドウへの参照を破棄する。
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

BrowserWindowのインスタンスを作り、loadUrlするとウィンドウを開くことができます。

型定義ファイルを使いTypeScriptで書いているので、コード補間も効くので快適にコーディングできます。
electronの各種モジュールやメソッドがうろ覚え状態なので、呼び出せるメソッドの候補などが出てくれるのは特に助かります。
f:id:minami_SC:20151019000726p:plain

表示内容の作成

続いて、main.jsから開かれるindex.htmlとこのページから読み込むindex.jsを作ります。
それぞれのファイルの内容は以下のとおり。
index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><scriptsrc="index.js"></script></head><body><h1>Hello World!</h1><hr/><buttononclick="hello()">Show Message</button></body></html>

index.ts

function hello(){alert('hello');
}

画面にはHello World!!と表示され、ボタンが一つ表示されているだけです。
このボタンを押すと、index.tsのhelloメソッドが呼ばれ、「hello」とだけ書かれたメッセージボックスが表示されます。

アプリの起動

アプリを起動するには、以下のようにelectron.exeに対し、実行対象のフォルダのパスを渡すことで起動できます。

node_modules\.bin\electron .

package.jsonがあるプロジェクトのルートがカレントディレクトリになってる場合には、「.」の指定でOK。

f:id:minami_SC:20151019000743p:plainこんな風に、ボタンを押したらメッセージボックスが表示されます。

electronのdialogモジュールを使ってダイアログを表示してみる

せっかくなので、もう少し手の込んだことをしてみます。
先ほどはjavascriptのalertメソッドを使ってダイアログの表示をしてましたが、 今度はelectronのdialogモジュールを使ってやってみます。

electronのプロセスについて

dialogモジュールを使う前に、electronのアプリの実行プロセスについてさらっと解説。

electronのアプリは複数のプロセスで動作します。
プロセスは、BrowserProcessとRendererProcessの2種類があります。 エントリポイントとなるmain.tsはBrowserProcessで動作し、BrowserWindow.loadUrlで開かれたウィンドウのhtmlからロードされるindex.tsなどはRendererProcessで動作します。

↓のドキュメントなどにも書いてありますが、BrowserProcessとRendererProcessで使えるモジュールが異なっているので、今書いているスクリプトがどちらのプロセスなのかを意識しておく必要があります。
http://electron.atom.io/docs/v0.34.0/

これからダイアログ表示に利用しようとしているdialogモジュールはBrowserProcess用のモジュールのため、RendererProcessで動作しているindex.tsからはそのままでは利用できません。

RendererProcess側から、BrowserProcessのモジュールを使いたい場合には、require('remote').require(・・・・)という感じで、remoteを経由してrequireします。

index.tsを以下のように修正します。

index.ts

var remote = require('remote');
var app = remote.require('app');
var BrowserWindow = remote.require('browser-window');
var dialog = remote.require('dialog');

function hello(){var options = {
        title: 'ダイアログのタイトル',
        type: 'info',
        buttons: ['OK', 'Cancel'],
        message: 'メッセージ',
        detail: 'hello'};
    var win = BrowserWindow.getFocusedWindow();
    dialog.showMessageBox(win, options);
}

※補足
github-electron-rendererの型定義ファイルを読み込んでいないので、RendererProcessの方ではTypeScriptでの型情報が利用できてません。。。
github-electron-mainとgithub-electron-rendererの両方を同時に使おうとするとコンパイルエラーになるので。。。 そのため、ここではrequireの結果をvarで受けて使っています。

ここまでの修正で、こんな風にelectronのdialogモジュールを使ったメッセージボックス表示ができました。
f:id:minami_SC:20151019000757p:plain

全体の動作のイメージは↓みたいな感じです。
f:id:minami_SC:20151019000807p:plain

もうちょい扱いやすくしてみる

開発時にもっと便利にコンパイル/実行できるように、npm経由で実行できるようにしたり、VSCodeから簡単に呼び出せるようにしてみます。

この辺は自分の開発スタイルに合わせてお好みの方法を取捨選択してもらえればよいかと。

package.jsonを使って起動

これで、npm run buildとやればビルドでき、npm startとするとアプリを起動できるようになります。
またnpm startでアプリを起動する前にはビルド処理も行うようになります。

package.json

{// 省略"scripts": {"build": "tsc",
    "prestart": "npm run build",
    "start": "electron ."},
  // 省略}

VSCodeから呼び出す

ビルド設定

tasks.jsonを以下のようにしておくと、VSCodeから「Ctrl+Shift+B」でビルドできるようになります。

tasks.json

{"version": "0.1.0",
    // The command is tsc. Assumes that tsc has been installed using npm install -g typescript"command": "node_modules\\.bin\\tsc",
    // The command is a shell script"isShellCommand": true,
    // Show the output window only if unrecognized errors occur."showOutput": "silent",
    "args": ["-p", "."],
    // use the standard tsc problem matcher to find compile problems// in the output."problemMatcher": "$tsc"}
VSCodeから起動する設定

launch.jsonを以下のように書くと、VSCodeからF5で起動できます。
ただし、「OpenDebug process has terminated unexpectedly」というエラーが表示され、デバッガが正常に起動できません。
以下のページでも同じような現象の報告があります。
http://www.mylifeforthecode.com/a-better-way-to-launch-electron-from-visual-studio-code/
https://code.visualstudio.com/Issues/Detail/19279
デバッガの動作は、今後のアップデートとかいろんな情報が出てくるのを待ったほうがいいかな。

launch.json

{"version": "0.1.0",
    // List of configurations. Add new configurations or edit existing ones."configurations": [{// Name of configuration; appears in the launch configuration drop down menu."name": "Launch Electron App",
            // Type of configuration."type": "node",
            // Workspace relative or absolute path to the program."program": "main.js",
            // Automatically stop program after launch."stopOnEntry": false,
            // Command line arguments passed to the program."args": [],
            // Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace."cwd": ".",
            // Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH."runtimeExecutable": "node_modules\\.bin\\electron",
            // Optional arguments passed to the runtime executable."runtimeArgs": [],
            // Environment variables passed to the program."env": {},
            // Use JavaScript source maps (if they exist)."sourceMaps": false},
        {"name": "Attach",
            "type": "node",
            // TCP/IP address. Default is "localhost"."address": "localhost",
            // Port to attach to."port": 5858,
            "sourceMaps": false}]}

アプリのパッケージング

最後に、アプリをexeファイルとしてパッケージングしてみます。
パッケージングには、electron-pacakgerというモジュールを使います。

以下のコマンドでインストール

npm install electron-packager --save-dev

npmのscriptにパッケージング用のスクリプトを追加

npmのスクリプトでexe化できるようにしてみます。
package.jsonに以下のようなスクリプトを追加します。 package.json

{// 省略"scripts": {"build": "tsc",
    "prestart": "npm run build",
    "start": "electron .",
    "pack": "electron-packager . sample --out=dist --arch=x64 --platform=win32 --version=0.34.0 --overwrite --prune --ignore=dist --ignore=typings"},
  // 省略}

これで、npm run packと実行すると、distフォルダにパッケージングした一式のフォルダが出来上がります。
distフォルダの中身は以下のようになります。sample.exeを実行すると先ほどのアプリが起動します。 f:id:minami_SC:20151019000922p:plain

補足

  • --out
    • 出力先のディレクトリを指定
  • --ignore
    • パッケージに含めないフォルダを指定
    • ただし、このプロパティで特に指定しなくても、node_modules以下のelectron-prebuildやelectron-packagerは除外されます。
  • --prune
    • パッケージにする際に、devDependenciesのフォルダを含めないようにする

ここまでざっと見てみましたが、思ってたより簡単にできました。
最初の準備はちょっと面倒だけど、一度ひな形を作っておけば、サクっと作れそうですね。

Visual Studio Codeの地味に便利な「コンソールで開く」ショートカット

$
0
0

f:id:minami_SC:20151020225628p:plain

Open New Command Prompt

ショートカットキーは「Ctrl+Shift+C
こんなショートカットあったんですね。

VSCodeでフォルダを開いているときに、このコマンドを実行すると開いてるフォルダのパスをカレントとしてコマンドプロンプトを表示してくれます。

どの階層のファイルを編集している時でも、常にルートのフォルダをカレントにしてコンソールを開きます。
なので、Node.jsを使ってるときはpackage.jsonのあるフォルダをVSCodeで開いていると、「Ctrl+Shift+C」ですぐにnpmの各種コマンドを実行できるようになります。

Node.jsを使った開発をしてると、「npm install ・・・」やら「npm start」などなど、コンソールを多用するのでこのショートカットはメッチャ便利。

Electronでアプリのメニューを作る

$
0
0

今度は、Electron+TypeScriptなアプリにメニューを追加してみます。

Electronのアプリで使えるメニューには、ウィンドウ上部(Macの場合ディスプレイの上)に表示されるアプリケーションメニューと、画面右クリック時に表示されるコンテキストメニューの2種類のものがあります。

Electronを使ってそれぞれ順番に作っていってみます。

参考

公式ドキュメントの↓あたりを参考にいろいろやってみます。
http://electron.atom.io/docs/v0.34.0/api/menu/
http://electron.atom.io/docs/v0.34.0/api/menu-item/

以下では、前回の↓サンプルコードをベースに色々やってみました。
TypeScript+Electronでデスクトップアプリを作ってみる - SourceChord

アプリケーションメニューの作成

メニューをつけるには、Menuモジュールを利用します。
このモジュールはBrowserProcess用のモジュールなので、RendererProcessから利用する場合には、remote.require('Menu')とする必要があります。

アプリ全体のメニューを設定する

アプリのエントリポイントとなるmain.tsでメニューの設定をしてみます。

まずは、Menu.buildFromTemplateメソッドで、メニューの項目などを作成します。
そして、作ったメニューをMenu.setApplicationMenuメソッドの引数に渡すと、メニューをつけることができます。

main.ts

import app = require('app');
import BrowserWindow = require('browser-window');
import Menu = require('menu');
require('crash-reporter').start();

// メインウィンドウの参照をグローバルに持っておく。var mainWindow: GitHubElectron.BrowserWindow = null;

var menu = Menu.buildFromTemplate([{
    label: 'File',
    submenu: [{label: 'New File'},
      {type: 'separator'},
      {label: 'Save'},
      {label: 'Save As...'},
      {type: 'separator'},
      {label: 'Exit', click: onExit}]},
  {
    label: 'Edit',
    submenu: [{label: 'Copy', accelerator: 'CmdOrCtrl+C'},
      {label: 'Paste', accelerator: 'CmdOrCtrl+V'},
    ]},
  {
    label: 'Help',
    submenu: [{label: 'About'}]},
]);

Menu.setApplicationMenu(menu);

// すべてのウィンドウが閉じられた際の動作
app.on('window-all-closed', function() {// OS X では、ウィンドウを閉じても一般的にアプリ終了はしないので除外。if (process.platform != 'darwin') {
    app.quit();
  }});

app.on('ready', function() {// 新規ウィンドウ作成
  mainWindow = new BrowserWindow({ width: 800, height: 600 });

  // index.htmlを開く
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたら、ウィンドウへの参照を破棄する。
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});


function onExit(){
  app.quit();
}

f:id:minami_SC:20151027010940p:plain

こんな風にちゃんとメニューが表示されました。

このメソッドを使ってメニューをつけた場合、BrowserWindow側で別途メニューの設定をしていない限り、すべてのウィンドウについて、ここでセットしたメニューが表示されるようです。

指定したウィンドウにメニューをつける

BrowserWindowクラスのsetMenuというメソッドでもメニューをつけることができます。
こうすると、setMenuメソッドを呼び出したウィンドウについてだけメニューをつけられるみたい。

  mainWindow = new BrowserWindow({ width: 800, height: 600 });
  mainWindow.setMenu(menu);

コンテキストメニューの作成

続いてコンテキストメニューを作ってみます。

ウィンドウ上を右クリックしたときの'contextmenu'イベントのタイミングでポップアップ表示をします。 UI上のイベントを拾うので、今度はRendererProcessからメニュー表示をしてみます。

コンテキストメニューも、前述のアプリケーションメニューと同じように、まずはMenu.buildFromTemplateメソッドでMenuクラスのインスタンスを作ります。

コンテキストメニューとして表示するには、Menu.popupメソッドを呼び出します。
引数には、ポップアップを表示させるウィンドウを指定します。

index.ts

var remote = require('remote');
var app = remote.require('app');
var BrowserWindow = remote.require('browser-window');
var Menu = remote.require('menu');

var menu = Menu.buildFromTemplate([{label: 'すべて選択'},
  {type: 'separator'},
  {label: 'Copy', accelerator: 'CmdOrCtrl+C'},
  {label: 'Paste', accelerator: 'CmdOrCtrl+V'}]);

window.addEventListener('contextmenu', function (e) {
  e.preventDefault();
  menu.popup(remote.getCurrentWindow());
}, false);

f:id:minami_SC:20151027010949p:plain

その他

メニューを自動で隠す設定

アプリケーションメニューでは、BrowserWindowクラスのsetAutoHideMenuBarというメソッドを使うと、メニューを自動で隠すようにすることができます。
Altを押すとメニューが出てきます。そしてフォーカスが外れると自動で隠れます。

mainWindow.setAutoHideMenuBar(true);

そんなに頻繁には使わないかもしれないけど、ウィンドウの領域を極力広く使いたいようなケースでは使うこともあるのかな。

Visual Studio Code 0.9.2が出てました

$
0
0

VSCodeの0.9.2が出てたので早速更新してみました。

https://code.visualstudio.com/updates
http://blogs.msdn.com/b/vscode/archive/2015/10/26/visual-studio-code-0-9-2-or-how-many-squares-do-you-see.aspx

公式ブログとアップデート情報にそれぞれ記載がありますが、TypeScriptの言語サポート機能で不具合があり、TypeScriptのコードをタイピングしたときに動作が遅くなったり、アプリがクラッシュしたりすることがあったようです。

たしかに、自分の環境でも、TypeScriptいじってると、たびたびモッサリすることがありました。
PCの調子悪くなってきたのかな~位に思ってたら、こんな不具合があったんですね。

てことで、VSCode 0.9.1使ってる人は更新しておくと捗るかと思います。

Electronでコマンドライン引数を受け付ける方法

$
0
0

ちょろっとメモだけ。

process.argvのプロパティで、コマンドライン引数を取得できます。
これはElectronではなく普通にNode.jsの仕様ですね。

ただし注意すべき点がひとつ。
このアプリ起動時のコマンドライン引数ですが、BrowserProcessから実行した場合はのみちゃんと取得できます。

RendererProcessは文字通り、別プロセスでの実行となるので、当然といえば当然ですが。。。
RendererProcessで取得しようとすると、process.argvは以下のような値になってしまいます。
f:id:minami_SC:20151101180350p:plain

コマンドライン引数を付けて実行

electronコマンドで実行するときに引数を追加すると、コマンドライン引数としてBrowserProcessに渡されます。
また、electron-packagerで作ったバイナリファイルに引数をつけて実行しても同じ結果となります。

以下のように、package.jsonのstartスクリプトに引数を追加してみると、コマンドライン引数が渡されるようになります。

{// 省略"scripts": {"build": "tsc",
    "prestart": "npm run build",
    "start": "electron . sample"},
  // 省略}
コマンドライン引数の確認

BrowserProcessのスクリプトに以下のように書いて実行してみると、コマンドライン引数が渡されてるのを確認できます。
main.ts

// コマンドライン引数をコンソールに表示
console.dir(process.argv);

Node.js 5.0をインストールしてみました

$
0
0

つい先日4.0が出たばかりと思っていたら、もう5.0が出ました。
ただし5.0はLTS版ではないので、Node.jsの公式ページは以下のように、LTSの4系と5.0の両方がトップページに表示されるようになってます。

f:id:minami_SC:20151101221847p:plain:w300
Node.js

ちなみに、Node.js 5.0.0での変更点はこんな感じ。
https://github.com/nodejs/node/blob/v5.0.0/CHANGELOG.md

個人的に特に大きな変更点はコレ!!

  • npm 3系へのアップデート

node.jsにバンドルされているnpmのバージョンが上がりました。

npm3系については、以前こんなニュースがありましたが、それがNode.jsの標準として搭載されました。
http://www.infoq.com/jp/news/2015/07/npm
http://www.infoq.com/news/2015/06/npm

npmのv3系では、モジュールの依存関係の管理方法が変わりました。
今までみたいに、フォルダ階層があっという間に深くなってしまうのを避けるような構造になっています。

今までのnpmは、あるモジュールをインストールした際に、そのモジュールが依存する別のモジュールをxxxx/node_modules/yyyy/node_modules・・・と入れ子構造で管理していましたが、v3.0からは依存するモジュールもフラットに展開して管理するようになってます。
これによって、依存モジュールのツリー構造による、とてつもなく深い階層ができにくくなっています。
また、今までは各ライブラリが依存するモジュールはそのライブラリのフォルダ以下の階層に別々に持っていたので、あちこちで大量に重複するファイルが出てました。
これもフラットに持つことで重複は少なくなるっぽいです。

厳密にバージョン指定されてて、別々のバージョンを持たなきゃいけない場合にどうなるのか、とか、まだ動作を把握できてない部分もありますが、Windows環境のNode.jsユーザーとしては、これは非常にうれしい変更点です。

Node Tools for Visual Studioを使ってVS上でNode.js開発をしてると、MAX_PATH超えるとビルドに失敗するようになって、デバッガも動かせなくなったり、、、
と、かなり踏んだり蹴ったりな状態になってしまってたので、これはとても助かります。

npm2系とnpm3系でのインストール動作の違い

てことで、Node.js4.0をインストールしてた環境と、Node.js5.0をインストールした環境のそれぞれで、以下のコマンドでexpressをインストールして違いを見てみます。 npm install express --save

Node.js4.0(npm2系)での動作

node_modulesフォルダは、以下の画像のようにexpressフォルダが一個できてるだけです。
f:id:minami_SC:20151101221913p:plain

Node.js5.0(npm3系)での動作

npm3系の環境では、以下のようにnode_modulesフォルダにはexpressで使っているモジュールがフラットに展開されて保管されます。
f:id:minami_SC:20151101221922p:plain

こんな風に大量にフォルダができますが、npm uninstall express --saveとかやってアンインストールすると、これらのexpressが依存してたモジュールを含めすべて削除されます。
イイ感じですね♪

Electronのプロセス間の通信

$
0
0

MainProcess(BrowserProcess)とRendererProcess間の通信方法についてメモ。

プロセス間の通信方法は何通りかありますが、順番に見ていきます。

remoteモジュール使ってMainProcess側としてモジュールを読み込む方法

remote経由でのrequire。これもある意味プロセスをまたいだ処理、ということで。。

MainProcess用のモジュールをRendererProcessから使いたい時や、重たい処理をするコードをreqireするときに使ったりします。
今までも普通に書いてたけど、こういうヤツです。

index.ts(RendererProcessのコード)

var remote = require('remote');
var app = remote.require('app');
var BrowserWindow = remote.require('browser-window');

remote.require(xxxx)とすると、そのモジュールはMainProcess側のプロセスで動作します。
また、こうすることで、「app」や「browser-window」のようなMainProcess用のモジュールも、RendererProcessから利用することができるようになります。

RendererProcess⇒MainProcessへの通信(ipcモジュール)

今度はより汎用的なプロセス間の通信をしてみます。
まずはRendererProcessで何かの操作をしたら、そのタイミングでMainProcessに通知してみます。

RendererProcessとMainProcessの間で汎用的なプロセス間通信を行うには、「ipc」モジュールを利用します。
ipcモジュールでRendererProcess⇒MainProcessの通信をするときには、同期/非同期の二通りの通信方法が用意されてます。

非同期な通信

非同期な通信では、送信側からでipc.sendメソッドでメッセージを送り、受信側ではipc.onでハンドラを登録してメッセージ受信時の動作を定義します。

こんな感じ。
ここでは、htmlで適当にボタンを用意しておき、onclickでhello()メソッドを呼ぶようにしておきます。
そして、hello()メソッドでは、Renderer⇒Mainへとasync-messageというメッセージを送り、Mainプロセスでは処理が完了したら、RendererProcessへasync-replyというメッセージで処理の完了を通知しています。

送信側

index.ts(RendererProcessのコード)

var ipc:any = require('ipc');

function hello(){
    ipc.send('async-message', 'ping');
}// MainProcessでの処理完了通知をハンドルするため
ipc.on('async-reply', function(arg) {alert(arg);
});
受信側

main.ts(MainProcessのコード)

ipc.on('async-message', (event, arg) => {
  console.log(arg);
  event.sender.send('async-reply', 'pong');
});

同期的な通信

同期的な通信を行う場合、MainProcess側での処理が完了するまでRendererProcessがブロックされてしまうため、基本的に非推奨となってます。
なので、あまり使うことはないかと思いますが、一応使い方をメモだけしときます。

同期通信では、処理の完了の返し方が違うので注意。
MainPrcessでevent.returnValueプロパティに値をセットするだけで、同期通信の完了通知となります。

index.ts(RendererProcessのコード)

var ipc:any = require('ipc');

function hello(){var result = ipc.sendSync('sync-message', 'ping');
    alert(result);
}

main.ts(MainProcessのコード)

ipc.on('sync-message', (event, arg) => {
  console.log(arg);
  event.returnValue = 'pong';
});

MainProcess⇒RendererProcessへの通信(webContents.sendメソッド)

今度はMainProcessからRendererProcessへとメッセージを送ってみます。
例えば、MainProcessでメニューとか作った時に、メニューのclickイベントでRendererProcess側に何かメッセージを送って、処理をする、といった場面で使えるかと思います。

RendererProcessへメッセージを送るには、目的のBrowserWindowのインスタンスのwebContentsプロパティを取得し、webContents.sendメソッドでメッセージを送ります。
受信側は、先ほどの例と同じようにipc.onで受け付けます。

また、この通信方法では、同期的な通信はサポートされておらず、非同期な通信のみサポートされています。
同期的な処理はデッドロックの原因になったり、なにかと問題を起こすので、同期通信は非サポートとのこと。

送信側

sendメソッドで送るだけ。RendererProcessに何か引数をつけて通知することもできます。 main.ts(MainProcessのコード)

  mainWindow.webContents.send('menu-clicked', 'メッセージの引数');
受信側

onで登録するコールバック関数には、sendで指定した引数が渡ってきます。 index.ts(RendererProcessのコード)

ipc.on('menu-clicked', (msg) => {alert(msg);
});

サンプル

こんな内容のサンプルです。

  • MainProcessでアプリケーションメニューを作る
  • そのメニューの項目をクリックしたら、クリックした項目に応じたメッセージをRendererProcessに通知
  • RendererProcess側では、メッセージを受け取ったら、その内容をalertで表示

f:id:minami_SC:20151103123441p:plain:w300

全体のコードはこんな感じ。

main.ts(MainProcessのコード)

import app = require('app');
import BrowserWindow = require('browser-window');
import Menu = require('menu');
import ipc = require('ipc');
require('crash-reporter').start();

// メインウィンドウの参照をグローバルに持っておく。var mainWindow: GitHubElectron.BrowserWindow = null;

var menu = Menu.buildFromTemplate([{
    label: 'File',
    submenu: [{label: 'New File', click: () => onMenuClicked('New File')},
      {label: 'Save', click: () => onMenuClicked('Save')}]},
  {
    label: 'Edit',
    submenu: [{label: 'Copy', click: () => onMenuClicked('Copy')},
      {label: 'Paste', click: () => onMenuClicked('Paste')},
    ]}]);
Menu.setApplicationMenu(menu);

// すべてのウィンドウが閉じられた際の動作
app.on('window-all-closed', function() {// OS X では、ウィンドウを閉じても一般的にアプリ終了はしないので除外。if (process.platform != 'darwin') {
    app.quit();
  }});

app.on('ready', function() {// 新規ウィンドウ作成
  mainWindow = new BrowserWindow({ width: 800, height: 600 });
  // index.htmlを開く
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたら、ウィンドウへの参照を破棄する。
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

function onMenuClicked(itemName: string){// クリックされた項目の情報を、RendererProcessに通知
  mainWindow.webContents.send('menu-clicked', itemName);
}

index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><scriptsrc="index.js"></script></head><body><h1>Hello World!</h1><hr/></body></html>

index.ts(RendererProcessのコード)

var ipc:any = require('ipc');
ipc.on('menu-clicked', (msg) => {alert(msg + ' clicked!!');
});

Electronで各種ダイアログ表示

$
0
0

今度はElectronのdialogモジュールを使い、いろいろなダイアログ表示をしてみます。

↓のドキュメントを参考にやってみます。
http://electron.atom.io/docs/v0.34.0/api/dialog/

dialogモジュールを使うと、メッセージボックスの表示や、ファイルを開く、ファイルを保存、などのダイアログ表示ができます。
このモジュールでは以下のようなメソッドが用意されています。

dialog.showOpenDialog([browserWindow][, options][, callback])
dialog.showSaveDialog([browserWindow][, options][, callback])
dialog.showMessageBox([browserWindow][, options][, callback])
dialog.showErrorBox(title, content)

このうち、shorErrorBox以外の3つは、若干の違いはありますが呼び出し方は似た感じ。
メソッドの引数には以下のようなものを渡します。

  • browserWindow: ダイアログの親となるウィンドウ
  • options: オプション
  • callback: コールバック関数

もう一個の、showErrorBoxは、ダイアログに表示するタイトルと本文を設定するだけのシンプルなものです。

てことで、順番にこれらの使い方を見ていきます。

ファイル操作系のダイアログ

まずはファイル系のダイアログ。
これらのメソッドでは、実行環境のOSに応じたダイアログ表示をしてくれます。
こういうos標準のダイアログを使ったり、ファイル操作などが普通にできるってのもいいですね。

showOpenDialog・・・ファイルを開くダイアログ

saveOpenDialogというメソッドで、ファイルを開く/フォルダを開くダイアログを表示できます。
メソッドシグネチャはこんな感じ↓

dialog.showOpenDialog([browserWindow][, options][, callback])

optionsプロパティには以下のような要素を設定します。

optionsの設定内容

プロパティ名内容
titleダイアログのタイトルを設定
defaultPathダイアログを開いたときの初期表示状態のパスを設定
filtersファイル選択時のフィルタ設定。
propertiesその他いろいろ細かな設定

filterプロパティには、こんな風にファイル選択時のフィルタ設定をします。

filters: [{ name: 'JPEG File', extensions: ['jpg', 'jpeg']},
    { name: 'TIFF File', extensions: ['tif', 'tiff']},
    { name: 'All Files', extensions: ['*']}]

propertiesには、以下の要素を配列で指定します。
createDirectoryの内容は、ドキュメント見ただけではちょっとわかりませんでした。。。orz

  • openFile : ファイルを選択するダイアログにする。
  • openDirectory : ディレクトリ選択ダイアログにする。
  • multiSelections : 複数選択できるようにするか設定
  • createDirectory : ・・・

こんな風に複数の項目を指定できます。

properties: ['openFile', 'multiSelections']

使い方

var win = remote.getCurrentWindow();
var options = {
    title: 'タイトル',
    filters: [{ name: 'JPEG File', extensions: ['jpg', 'jpeg']},
        { name: 'All Files', extensions: ['*']}],
    properties: ['openFile', 'createDirectory']};

dialog.showOpenDialog(win, options);

showSaveDialog・・・ファイルを保存ダイアログ

こちらも使い方はだいたい同じです。
ただし、こちらのoptionsプロパティにはpropertiesの設定はありません。

かんたんなコード例だけメモ。
使い方

var win = remote.getCurrentWindow();
var options = {
    title: 'タイトル',
    filters: [{ name: 'JPEG File', extensions: ['jpg', 'jpeg']},
        { name: 'All Files', extensions: ['*']}]};

dialog.showSaveDialog(win, options);

メッセージボックス系のダイアログ

showMessageBox・・・メッセージボックス

続いてメッセージボックス。
alertメソッドで出すようなのとは違い、いろいろと表示をカスタマイズできるので、何かと使いどころはありそうです。

プロパティ内容
typeメッセージボックスのタイプを設定する。(info, 'warning'のいずれかを文字列で指定)
buttonsメッセージボックスのボタンを設定。文字列の配列として設定します。
titleタイトルを設定する
messageメッセージを設定
detailメッセージボックスの詳細メッセージを設定
iconダイアログに表示するアイコン画像を設定。

こんな風に使います。

function showMessageBox() {var win = remote.getCurrentWindow();
    var options = {
        type: 'info',
        buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
        title: 'タイトル',
        message: 'メッセージ',
        detail: '詳細メッセージ'};
    
    dialog.showMessageBox(win, options);
}
buttonsプロパティについて

buttonsプロパティは、表示するボタンの定義を文字列の配列として定義します。

この時の注意として、「OK」や「Cancel」などのような文字列を設定したときの動作が特殊っぽいので注意が必要です。

自分のWindows環境で動かしてみると、
「OK」「Cancel」「Yes」「No」の文字列を指定した場合は、ダイアログ下部に並んだボタンに表示され、それ以外の文字列を指定したボタンは、ダイアログ中に並びます。

例えばこう書くと

var win = remote.getCurrentWindow();
var options = {
    type: 'info',
    buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
    title: 'タイトル',
    message: 'メッセージ',
    detail: '詳細メッセージ'};

dialog.showMessageBox(win, options);

↓こんな風になります。
f:id:minami_SC:20151105005111p:plain

この辺のbuttonsプロパティの動作については、特にドキュメントにも書かれていないので、ちょっとよくわからん部分。。。

showErrorBox・・・エラーダイアログ

最後はエラーダイアログ。
エラーダイアログを表示するためのメソッドです。

アプリの通常の動作としてはあまり使わないかもしれませんが、覚えておくと、デバッグ用にお手軽で便利かも。
ブラウザのalertメソッドが使えない、MainProcess側でちょろっとalertの代わりに使ったりできるかも知れません。

dialog.showErrorBox("タイトル", "本文");

呼び出すとこんな感じのダイアログが表示されます。
f:id:minami_SC:20151105005144p:plain

サンプル

ボタンを押すと、これらの4種類のダイアログ表示をするサンプルです。

f:id:minami_SC:20151105005155p:plain:w350

MainProcess、RendererProcessはそれぞれこんな感じのコード。

main.ts(MainProcessのコード)

import app = require('app');
import BrowserWindow = require('browser-window');
require('crash-reporter').start();

// メインウィンドウの参照をグローバルに持っておく。var mainWindow: GitHubElectron.BrowserWindow = null;

// すべてのウィンドウが閉じられた際の動作
app.on('window-all-closed', function() {// OS X では、ウィンドウを閉じても一般的にアプリ終了はしないので除外。if (process.platform != 'darwin') {
    app.quit();
  }});

app.on('ready', function() {// 新規ウィンドウ作成
  mainWindow = new BrowserWindow({ width: 800, height: 600 });
  // index.htmlを開く
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたら、ウィンドウへの参照を破棄する。
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><scriptsrc="index.js"></script></head><body><h1>Dialog Module Test</h1><hr/><buttononclick="showOpenDialog()">Open Dialog</button><buttononclick="showSaveDialog()">Save Dialog</button><buttononclick="showMessageBox()">Message Box</button><buttononclick="showErrorBox()">Error Box</button></body></html>

index.ts(RendererProcessのコード)

var remote = require('remote');
var dialog = remote.require('dialog');

function showOpenDialog() {var win = remote.getCurrentWindow();
    var options = {
        title: 'タイトル',
        filters: [{ name: 'JPEG File', extensions: ['jpg', 'jpeg']},
            { name: 'All Files', extensions: ['*']}],
        properties: ['openFile', 'createDirectory']};
    
    dialog.showOpenDialog(win, options);
}function showSaveDialog() {var win = remote.getCurrentWindow();
    var options = {
        title: 'タイトル',
        filters: [{ name: 'JPEG File', extensions: ['jpg', 'jpeg']},
            { name: 'All Files', extensions: ['*']}]};
    
    dialog.showSaveDialog(win, options);
}function showMessageBox() {var win = remote.getCurrentWindow();
    var options = {
        type: 'info',
        buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
        title: 'タイトル',
        message: 'メッセージ',
        detail: '詳細メッセージ'};
    
    dialog.showMessageBox(win, options);
}function showErrorBox() {
    dialog.showErrorBox("タイトル", "本文");
}

同期/非同期呼び出しの切り替え

これらのダイアログボックス系のメソッドは、コールバックが設定されていない場合は同期的な呼び出し、コールバック関数が設定された場合は非同期処理をします。

同期的な呼び出し

同期的に呼び出す場合は、ダイアログの実行結果をメソッドの戻り値として取得できます。

var result = dialog.showOpenDialog(win, options);
alert(result);
非同期な呼び出し

非同期に呼び出す場合は、コールバック関数の引数にダイアログの実行結果が渡ってきます。

dialog.showOpenDialog(win, options, (ret) => {alert(ret);
});

WPF向けにRelativePanelなどを実装したライブラリ~UniversalWPF~

$
0
0

↓のブログを読んでいて知りました。

こんなコントロールを作ってくれてる方がいたんですね!!
WPF用にRelativePanelやSplitViewを作ってくれてます。スバラシイ!!

準備

今のところNugetパッケージはないので、GitHubからクローンしてきてビルドして作ったdllをプロジェクトの参照に加えて使います。

↓を見ると、もうしばらくの間はNugetパッケージを作らずにこのままのスタイルで開発を予定のようです。 https://github.com/dotMorten/UniversalWPF/issues/3
それまでは、自分でビルドしてdllを参照して使いましょう。

使ってみる

てことで、ちょろっと使ってみます。

RelativePanel

<Window x:Class="WpfApplication1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:WpfApplication1"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="525"Height="350"mc:Ignorable="d"><RelativePanel><Rectangle x:Name="origin"Width="100"Height="100"Fill="Blue"RelativePanel.AlignHorizontalCenterWithPanel="True"RelativePanel.AlignVerticalCenterWithPanel="True"Stroke="Black" /><Border Width="70"Height="70"Background="Cyan"RelativePanel.Below="origin"RelativePanel.RightOf="origin" /></RelativePanel></Window>

f:id:minami_SC:20151107134306p:plain:w350

SplitView

SplitViewはまだ開発段階とのことですが、使ってみるとこんな感じ。

<Window x:Class="WpfApplication1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:WpfApplication1"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="525"Height="350"mc:Ignorable="d"><Grid><SplitView x:Name="splitView"DisplayMode="Inline"IsPaneOpen="{Binding IsChecked,                                        ElementName=toggleSwitch,                                        Mode=TwoWay}"OpenPaneLength="150"PaneBackground="LightGray"PanePlacement="Left"><SplitView.Pane><StackPanel><TextBlock Text="Item1" /><TextBlock Text="Item2" /></StackPanel></SplitView.Pane><Grid Background="Beige"><ToggleButton x:Name="toggleSwitch"Width="70"Height="24"Content="Show" /></Grid></SplitView></Grid></Window>

f:id:minami_SC:20151107134318p:plain:w350

CompactOverlayやCompactInlineなどのモードや、PanePlacement="Right"はまだ対応してないみたい。

まだ粗削りな段階ですが、今後がとても楽しみなライブラリです。

Electronで作ったウィンドウの各種設定など

$
0
0

ElectronのBrowserWindowクラスで作ったウィンドウの設定などについてメモ。

BrowserWindowクラスのAPIは↓にまとまってますが、よく使いそうなのをメモしときます。 http://electron.atom.io/docs/v0.34.0/api/browser-window/

ウィンドウの位置/サイズに関するメソッド

setFullScreen(flag: boolean)

ウィンドウのフルスクリーン化をします。
setKiosk(flag)メソッドでも同じようにフルスクリーンになります。

setAspectRatio(adpectRation[, extraSize])

これはmacのときだけ使えるみたい。
ウィンドウのアスペクト比を指定できるそうです。
自分はwin環境しか持ってないので、コレはスキップ。

setBounds/getBounds

以下のメソッドで、ウィンドウの位置とサイズを設定できます。

setBounds(options)

optionsには、x,y,width,heightのプロパティを持ったオブジェクトを渡すことで、ウィンドウの位置やサイズを指定します。
また、現在のウィンドウ位置は、getBoundsメソッドで取得できます。

setPosition(x, y)/getPosition()

ウィンドウの表示位置を設定/取得できます。

  mainWindow.setPosition(10, 10);
  console.log(mainWindow.getPosition());
setSize(width, height)/getSize()

同じような感じで、現在のウィンドウのサイズを設定/取得できます。

center()

ウィンドウを、ディスプレイの中央に移動します。
これは結構便利かも。

ウィンドウの最大サイズ/最小サイズなど

以下のメソッドで、ウィンドウの最大サイズの設定/取得と最小サイズの設定/取得ができます。

setMinimumSize(width, height)
getMinimumSize()

setMaximumSize(width, height)
getMaximumSize()

その他

setResizable(resizeable)/isResizeable()

ウィンドウのリサイズ有効/無効の設定などができます。

setAlwaysOnTop(flag)

こんな風にすると、常に最前面に表示できます。
ちょっとしたツールを作るときとかに、こういうオプションを活用できるかも。

mainWindow.setAlwaysOnTop(true);

ウィンドウのタイトル取得/設定

setTitle(title)/getTitle() タイトルの文字列の取得/設定ができます。

mainWindow.setTitle("Window Title");

ただし、RendererProcessで表示しているhtmlのページでtitleタグの指定があると、そっちが優先でウィンドウのタイトルに設定されてるっぽい。

setSkipTaskbar(skip)

setSkipTaskbar(true)とすると、タスクバーにアプリのアイコンを表示しなくなります。

VSCode 0.10.1の新機能・変更点

$
0
0

先日のMSのオンラインイベントConnect();で、とうとうβリリースの発表がありました。
今回も、新機能や各種変更点をまとめておきます。

Connect(); // 2015 | Channel 9

f:id:minami_SC:20151121212619p:plain:w300

拡張機能への対応

今回の目玉は何といってもコレ!!
とうとう拡張機能により、VSCodeへの機能追加ができるようになりました!!

拡張機能はそろそろ来る頃かなぁ、、と予想はしてたのですが、大きなサプライズがありました。
なんとVSCode用の拡張機能マーケットプレイスまでできました♪

↓からいろいろな拡張機能を探すことができます。
https://marketplace.visualstudio.com/#VSCode

VSCodeのコマンドパレットから、拡張機能の検索/インストール済みの一覧表示など、一通りの操作ができるようになっています。

拡張機能の検索

まずは、拡張機能の検索とインストールをしてみます。

Ctrl+Shift+Pを押してコマンドパレットを開き、「Extensions」と入力すると、拡張機能関連の項目が表示されます。
f:id:minami_SC:20151121212715p:plain

ここで「Extensions: Install Extension」を選ぶと、マーケットプレイスのギャラリーから、インストールできる拡張機能の一覧が表示されます。
打つのがめんどいときは、「ext install」でもOK。

f:id:minami_SC:20151121212723p:plain

こんな風にインストールできる拡張機能が一覧表示されます。
この状態から、続けてキーワードなどを入力すると絞り込み検索ができます。

このリストから拡張機能を選んでインストールできます。
インストールした拡張機能は、以下のディレクトリに保存されます。

  • Windows環境
    • %USERPROFILE%.vscode\extensions
  • Mac/Linux環境
    • $HOME/.vscode/extensions

お試しで、↓の拡張機能をインストールしてみたけどこれはイイ感じ!!
https://marketplace.visualstudio.com/items/stevencl.addDocComments
関数定義の部分を選択して、「Add Doc Comments」というコマンドを実行すると、関数コメントをつけてくれます。

インストール済み拡張機能一覧の確認

インストール済みの拡張機能一覧を表示するには、コマンドパレットから「Extensions: Show Installed Extensions」というコマンドを実行します。
f:id:minami_SC:20151121212826p:plain

マーケットからインストールしたものも、自分で作成してextensionsフォルダに直接置いたものもどちらもリストアップされます。
また、インストール済みの拡張機能のアップデートやアンインストールもこのUIからできます。

拡張機能の作成

v0.9.1でテーマ作成やシンタックスハイライト定義の作成用にyoのジェネレータが用意されましたが、このジェネレータで拡張機能の雛型を作れるようになりました。
f:id:minami_SC:20151121212859p:plain:w350

https://code.visualstudio.com/docs/extensions/overview
割としっかりとドキュメントが用意されてるんで、yoで雛型を生成してドキュメント読みながらいじればいろいろ作れそうです。

この辺はまた近いうちに少しずつドキュメントを読んでみようかと思います。

VSCodeのオープンソース

今回のバージョンアップのもう一つの目玉!!
VSCodeがオープンソースになりました。

GitHubの↓のリポジトリで公開されてます。

デバッガの改善

デバッガ実行中のコンテキストメニューの追加機能

値を確認したい変数を選択してコンテキストメニューを表示すると、「Debug: Evaluate」「Debug: Add to Watch」という項目が表示されるようになりました。
f:id:minami_SC:20151121212932p:plain

これらのメニューから、デバッグコンソールでの値の確認や、ウォッチウィンドウへの追加を素早く行えます。

Node.jsデバッグ時のコンソール

今までは、デバッグを開始すると別ウィンドウでコンソールが開かれて、そのコンソール内でNode.jsの実行がされてました。
V0.10.1からは、デフォルトではこんな風にVSCode内のDebugConsole領域で実行されるようになります。
f:id:minami_SC:20151121212947p:plain:w450

別ウィンドウのコンソールで実行

launch.jsonexternalConsole: trueというプロパティを追加しておくと、別ウィンドウのコンソールで実行するようになります。
f:id:minami_SC:20151121212955p:plain:w450

デバッグコンソールの表示改善

こんな風にエラー発生時の出力の、エラー発生箇所のファイルにリンクが張られるようになってます。
f:id:minami_SC:20151121213015p:plain:w350

エラーのある行に素早く移動できて便利になるかも。
ただしTypeScriptで書いてるときは、コンパイル後のJavaScriptの方に移動します。
ソースマップで対応付けて移動してくれると嬉しいんだけどなぁ。

その他細かい点

他にも以下のような変更点があります。

  • コードスニペット作成用に、yoのジェネレータの機能追加
  • シンタックスハイライトの改善
    • v0.9.1でシンタックスハイライトの定義を追加できるようになってましたが、追加した言語向けのシンタックスハイライト表示が改善されました。
  • launch.jsonやtask.json環境変数が使えるようになった
  • PHP向け機能
    • PHPのlinterが変わったり、いろいろ変更あるみたい。自分はPHPはやってないので、ココはスキップ。
  • ワークスペースごとに、使用するTypeScriptのバージョンを変えられるようになった
  • Diffの表示方法切替
    • GitHubのDiff表示みたいな、最近よく見かけるスタイルのDiff表示ができるようになりました。
    • diffEditor.renderSideBySide: falseという設定をsettings.jsonに加えることで、表示方法の切り替えができます。 f:id:minami_SC:20151121213028p:plain

Electron 0.35.0以降での変更点

$
0
0

久しぶりにelectronのドキュメントやらリポジトリやら見てたら、結構変わってたのでφ(..)メモメモ。

とりあえず、これを書いてる現時点では、0.35.2が最新となっています。
で、以前Electronで遊んでた時のバージョン(0.34.x)から色々と変更点があるので、それらをメモしときます。

0.35.0の変更点は以下のリンクから。
https://github.com/atom/electron/releases/tag/v0.35.0

APIのUrlという部分はURLに変更

各種メソッドなどで、○○Urlなどとなっていた部分が、○○URLというように、大文字での表記に変わりました。 古いメソッド名も、まだ動作していますが、duprecatedとなっているので近いうちに使えなくなるかと思います。

loadUrlメソッドも、以下のような書き方に変わりました。

mainWindow.loadURL('file://' + __dirname + '/index.html');

electronモジュール

BrowserWindowやMenuモジュールなどなど、electronのAPIは今までは別々のモジュールに定義されてました。

これらをすべて統合したelectronモジュールが追加されています。
今までのBrowserWindowやMenuモジュールなどもelectronモジュール内に含まれています。
require('electron').BrowserWindowという風に書いて利用できます。

一応、今まで通りrequire('browser-window')とかやっても使えるみたいです。
ですが、ドキュメントなどではこのelectronモジュールを使った書き方に変わってるので、今後はこっちを使ったほうがいいのかも。

ipcモジュールの名前変更

以前までは、Mainプロセス用ipcモジュールと、Rendererプロセス用のipcモジュールがありました。
どちらもrequire('ipc')と書いてインポートしてましたが、そのスクリプトがMainプロセスで実行されるか、Rendererプロセスで実行されるかにより、読み込まれるモジュールが変わるという仕様でした。

これが、electronモジュール内に定義された「ipcMain」「ipcRenderer」という名前の別々のクラスとなりました。
また、今までのipcモジュールはduprecatedとなっています。

今後は以下のように使うみたい。

// Mainプロセスの場合
const ipcMain = require('electron').ipcMain;

// Rendererプロセスの場合
const ipcRenderer = require('electron').ipcRenderer;

TypeScriptで使う場合、今までは同名のipcモジュールが重複して存在し、うまいこと型定義ファイルが書けない状態でした。
今回の変更は、TypeScriptの型定義ファイルを作る上でもメリットありそうです。

TypeScript用の型定義ファイル

TypeScript関係でもう一点。
この辺のモジュール変更には、DefinitelyTypedの型定義がまだ追いついていません。

https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/github-electron

だれか、型定義修正して上げてくれる人いないかなぁ。とか他力本願で待機中。

自分で型定義書いてみようかな。。。

VSCodeのデバッガとの連携

今まで、VSCodeからelectronのアプリのデバッグ実行をしても、ブレークポイントなどが効かず、デバッグ実行できませんでした。

VSCodeのバージョンアップで変わったのか、electronのバージョンアップで変わったのか、どちらかわかりませんが、、
以下のように、launch.jsonを書いておくと、VSCodeのデバッガから起動して、ちゃんとデバッガでの動作ができるようになりました。

f:id:minami_SC:20151129130855p:plain

これで、electronのmainプロセスのデバッグが捗りそうです。

launch.json

{"version": "0.2.0",
    "configurations": [{"name": "Launch Electron App",
            "type": "node",
            "request": "launch",
            "program": "main.js",
            "stopOnEntry": false,
            "args": [],
            "cwd": ".",
            "runtimeExecutable": "node_modules\\.bin\\electron.cmd",
            "runtimeArgs": ["--nolazy"],
            "env": {},
            "externalConsole": false,
            "sourceMaps": false,
            "outDir": null},
        {"name": "Attach",
            "type": "node",
            "request": "attach",
            "port": 5858
        }]}

2015年の技術系アドベントカレンダーで気になるものメモ

$
0
0

自分が色々見て回るためにメモしときます。

いつも通りC#とか.net/Win系のカレンダーと、Web系の話題なテーマを主に読むつもり。
自分は今年Web系のことをちょこちょこやってたので、JavaScriptやらNode.js絡みなどを多めにピックアップ。

気になったものをひたすら列挙しただけだから、全部読もうとするとすごく消化不良を起こしそう・・・
でも、やっぱ気になるから、一応φ(..)メモメモ

探すときはこちらから

http://qiita.com/advent-calendar/2015
http://www.adventar.org/
http://gihyo.jp/news/info/2015/12/0101

リンク集

言語系

C# Advent Calendar 2015 - Qiita
TypeScript Advent Calendar 2015 - Qiita
C++ Advent Calendar 2015 - Adventar
初心者 C++er Advent Calendar 2015 - Adventar
JavaScript Advent Calendar 2015 - Qiita
JavaScript stage 0,1,2,3 Advent Calendar 2015 - Qiita
F# Advent Calendar 2015 - connpass

Win/.net系

ASP.NET Advent Calendar 2015 - Qiita
Windows & Microsoft技術 基礎 Advent Calendar 2015 - Qiita
Microsoft Azure Advent Calendar 2015 - Qiita
WindowsAPI(Win32API) Advent Calendar 2015 - Adventar
コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiita

PowerShell Advent Calendar 2015 : ATND

Visual Studio / Visual Studio Code Advent Calendar 2015 - Qiita

クロスプラットフォーム開発

Electron Advent Calendar 2015 - Qiita
Xamarin Advent Calendar 2015 - Qiita
ハイブリッドアプリ Advent Calendar 2015 - Qiita
Qt Advent Calendar 2015 - Qiita
一人React Native Advent Calendar 2015 - Qiita

JavaScript関連

AngularJS Advent Calendar 2015 - Qiita
Angular 2 Advent Calendar 2015 - Qiita
knockout.js Advent Calendar 2015 - Qiita
Vue.js Advent Calendar 2015 - Qiita
React.js Advent Calendar 2015 - Qiita

RxJS Advent Calendar 2015 - Qiita
bouzuya&#39;s RxJS Advent Calendar 2015 - Adventar

Yeoman Advent Calendar 2015 - Adventar

Node.js関連

Node.js Advent Calendar 2015 - Qiita
Node.js その2 Advent Calendar 2015 - Qiita
Meteor Advent Calendar 2015 - Qiita
Sails.js Advent Calendar 2015 - Qiita

その他Web系

Bootstrap Advent Calendar 2015 - Qiita
Office UI Fabric Advent Calendar 2015 - Qiita
Web API Advent Calendar 2015 - Qiita
HTML5 Advent Calendar 2015 - Qiita

仮想DOM/Flux Advent Calendar 2015 - Qiita
CSS昔話 Advent Calendar 2015 - Adventar
SVG Advent Calendar 2015 - Adventar

Web系ってくくりも辺だけど・・・
Git Advent Calendar 2015 - Qiita

その他グラフィック系

この辺は余裕があれば見てみるつもり。

OpenCV Advent Calendar 2015 - Qiita
Data Visualization Advent Calendar 2015 - Qiita
WebGL Advent Calendar 2015 - Qiita
WebVR Advent Calendar 2015 - Qiita

Processing Advent Calendar 2015 : ATND
vvvv Advent Calendar 2015 - Qiita

phina.js Advent Calendar 2015 - Qiita

ちょっと興味あるもの

言語

RustとかGoとか、ちょろっと触ってみたい。

Rust Advent Calendar 2015 - Qiita
Go Advent Calendar 2015 - Qiita
Go その2 Advent Calendar 2015 - Qiita
Go その3 Advent Calendar 2015 - Qiita

デバイス系

オンリーロンリーWindows Phone / Windows 10 Mobile Advent Calendar 2015 - Adventar
Windows Phone / Windows 10 Mobile Advent Calendar 2015 - Adventar

Oculus Rift Advent Calendar 2015 - Qiita
RICOH THETA Advent Calendar 2015 - Qiita
おうちハック Advent Calendar 2015 - Qiita
ロボット Advent Calendar 2015 - Qiita
Raspberry Pi Advent Calendar 2015 - Qiita

学術系/文章系/その他

アルゴリズム Advent Calendar 2015 - Qiita
オブジェクト指向 Advent Calendar 2015 - Qiita
ヒューマンコンピュータインタラクション論文紹介 Advent Calendar 2015 - Qiita
技術英語や翻訳 Advent Calendar 2015 - Qiita
言語実装 Advent Calendar 2015 - Qiita
技術系文章 Advent Calendar 2015 - Adventar
LT(ライトニングトーク) Advent Calendar 2015 - Adventar

グラフ探索アルゴリズム Advent Calendar 2015 - Qiita
Machine Learning Advent Calendar 2015 - Qiita

ElectronでCSS Grid Layout Moduleを使ってちょっと未来のレイアウト方法を先取りしてみる

$
0
0

この記事はElectron Advent Calendar 2015 - Qiita2015の8日目の記事です。

今回の記事のサンプルコードは↓コチラ。
https://github.com/sourcechord/electron-gridlayout-sample

目次

前置き

CSSでのレイアウトって難しいですよね。。。

自分は今まで主に.net系のデスクトップアプリ開発をやってきましたが、ここ最近Web系の開発に手を出してみて、色々と勝手の違うCSSでのレイアウトにずいぶんと苦労しました。

XAML系のプログラミングだったらGridパネル、Androidの開発でのGridLayoutというような、いい感じにグリッドレイアウトを実現するためのものが現在のCSSにはありません。

なんで、よくあるこういうHoly Graylレイアウトを作るのにこんな苦労しなきゃいかんのか・・・と、ずいぶん頭を抱えてきました。

CSS Grid Layout Module Level 1

ですが、CSSでもグリッドレイアウトを定義するための仕様の策定が進んでいます。
CSS Grid Layout Module Level 1

CSS Grid Layout Module Level 1」では、平面上をグリッドに分割して、任意の位置に要素を配置をしていくことができます。
この手のレイアウトはデスクトップアプリのようなUIのレイアウトととても相性がいいです。

また、MediaQueryと組み合わせてレスポンシブにUIのレイアウトを切り替えるのも行いやすく、まさにElectronでアプリ作る時にはバッチリ相性のよいレイアウト方法だと思います。

CSS Grid Layoutの各ブラウザの対応状況

この「CSS Grid Layout Module Level1」ですが、2015年12月現在の対応状況は以下のような状態です。
f:id:minami_SC:20151208233257p:plain:w350
Can I use... Support tables for HTML5, CSS3, etc

Webサイトの作成などでは、当然使えるわけない!!って状況ですね。

対応状況について補足
  • IE10以降やEdgeは部分的な対応となっていますが、以下のような状況です
    • -ms-のベンダープレフィックスが必要
    • ↓の古い仕様への対応(現在策定中の仕様とは少し異なるもの)
      Grid Layout
  • ChromeFirefoxでは、拡張フラグを指定することで、実験的な機能として利用できます。
    • Chromeで使うためには
      現在Chromeは、標準ではこのレイアウトに対応していませんが、拡張フラグをONにすることで、実験的な機能として有効になります。
      f:id:minami_SC:20151208233319p:plain:w350

Chromiumを内部で使用するElectronのアプリでも、同様のフラグをONにすることでこの機能が使えるようになります。

メリット・デメリット?

現時点で標準になっていない機能(まだWorkingDraftの段階)なので、もちろんデメリットやリスクもあったりすると思います。
今後仕様が変わったりしても追従していく覚悟も必要ですし、まだ実装されていない部分や、不具合に遭遇する可能性も多々あると思います。
それに、学習するための情報もまだまだ少なめです。

ですが、レイアウトがこれだけシンプルで自由自在にできるようになるので、デメリットやリスクを補って余りある十分なメリットがあるのでは、という気がしています。

CSS Grid Layoutを使ってみる

参考サイト

CSS3 Grid Layoutの使い方については、下記ページでサンプルを交えて非常に詳しく説明してくれてます。
Grid by Example
今回はこれを参考に色々やってみます。

言葉の定義

まずは、Gridレイアウトで出てくる言葉の定義についてザックリと解説します。
Gridの中の、行や列/セルを表す単位は以下のようになっています。

  • Grid Line
    この図で赤い線を引いている部分は、column 2のLineとなります。
    f:id:minami_SC:20151208233339p:plain:w350

  • Grid Track
    Grid中の1列or1行をまとめて指す単位がTrackです。
    f:id:minami_SC:20151208233348p:plain:w350

  • Grid Cell
    Grid中の特定の1コマを指定する単位がCellです。
    f:id:minami_SC:20151208233357p:plain:w350

  • Grid Area
    このように、複数のセルを矩形にまとめたGrid中の特定の領域を示す単位です。
    f:id:minami_SC:20151208233406p:plain:w350

Chromiumの拡張フラグを設定する

Electronでは、以下のappendSwitchというメソッドChromiumで使用する拡張フラグの設定ができます。
http://electron.atom.io/docs/v0.35.0/api/app/#app-commandline-appendswitch-switch-value

このメソッドを使って「試験運用版のウェブプラットフォームの機能」のオプションを有効にします。
以下のメソッドをMainプロセスのスクリプトに追記します。

App.commandLine.appendSwitch("--enable-experimental-web-platform-features");

これで準備OK。

単純なグリッドレイアウト

実際にGridを使ってレイアウトをやってみます。
まずは単純な配置から。

こんな感じのhtmlを用意します。
グリッドレイアウトを行うためのwrapperのdivを作り、その中にシンプルにdivを並べただけのものです。

<divclass="wrapper"><divclass="box">A</div><divclass="box">B</div><divclass="box">C</div><divclass="box">D</div><divclass="box">E</div></div>

gridレイアウトをする領域の定義

Gridレイアウトを行う領域に対して、display: gridというプロパティを指定します。

  • gridの分割数を定義
    gridの分割数は、grid-template-columns/grid-template-rowsという二つのプロパティで、Gridの分割数やサイズを指定します。
    ここでは、100px、150px、100pxという順番で3つの列と、高さが自動で計算される行を2つ定義します。

wrapperクラスの定義はこんな風になります。

.wrapper{display: grid;
      grid-template-columns: 100px150px100px;
      grid-template-rows: autoauto;
    }

設定する単位について
グリッドのサイズは、pxやem、remなどの指定方法の他に、以下のような方法が用意されています。 * auto
auto指定をすると、auto指定をした行/列のサイズは、実際にその行/列に配置された要素のサイズに合わせて決定されます。 * fr
グリッドのサイズを、配置可能な余白のサイズから比率で指定します。
(↓のように○○frなどといった感じで指定します。)

grid-template-columns: 1fr 2fr;

こうすると、幅が1:2になるように、二つの列を定義できます。

グリッド上に自動で流し込む場合

先ほど定義した2行3列のグリッドの領域内に複数の要素を入れてみます。

.wrapper{display: grid;
      grid-template-columns: 100px150px100px;
      grid-template-rows: autoauto;
    }.box{background-color: #444;
      color: #fff;
      border-radius: 5px;
      border: 2pxsolidblack;
      padding: 20px;
      font-size: 150%;
    }
<divclass="wrapper"><divclass="box">A</div><divclass="box">B</div><divclass="box">C</div><divclass="box">D</div><divclass="box">E</div></div>

こんな風に定義したグリッドに順番にdiv要素が流し込まれていきます。
f:id:minami_SC:20151208234444p:plain:w300

流し込む方向の指定

grid-auto-flowというプロパティを使うことで、自動で要素をグリッドに流し込む際に、行/列どちらの方向に順に流し込むかを指定できます。

.wrapper{display: grid;
      grid-template-columns: 100px150px100px;
      grid-template-rows: autoauto;
      grid-auto-flow: column; /*列方向に順に並べていくよう指定*/}

https://github.com/sourcechord/electron-gridlayout-sample/blob/master/view/flow_direction.htmlf:id:minami_SC:20151208234455p:plain:w300

グリッド上の特定の位置へ配置

今度は、htmlに定義した順に流し込むのではなく、cssでグリッド上の特定の位置を指定して配置してみます。 グリッド上の配置位置を指定するには、以下の4つのプロパティで、row/culumnの開始位置と終了位置を指定します。 * grid-row-start * grid-row-end * grid-column-start * grid-column-end

特定のセルに配置
.a{
      grid-row-start: 1;
      grid-row-end: 2;
      grid-column-start: 2;
      grid-column-end: 3;
    }

f:id:minami_SC:20151208233513p:plain:w300

複数のセルにまたがった配置

こんな風に、複数のセルにまたがって配置することもできます。

.b{
      grid-row-start: 2;
      grid-row-end: 3;
      grid-column-start: 2;
      grid-column-end: 4;
    }

f:id:minami_SC:20151208233519p:plain:w300

ショートハンド

gridの定義方法、配置方法ともに、簡潔に記述するためのショートハンドが用意されています。

  • グリッド定義のショートハンド
    f:id:minami_SC:20151208233435p:plain

  • 配置位置指定のショートハンド
    f:id:minami_SC:20151208233457p:plain

Z-Indexの指定

z-indexプロパティを指定することで、要素のが重なった際の順序指定ができます。
htmlに定義した順ではなく、このz-indexプロパティの値の大きい方を前面に表示することができます。

https://github.com/sourcechord/electron-gridlayout-sample/blob/master/view/z_index.html
f:id:minami_SC:20151208234558p:plain:w250

複雑なレイアウト

今度はもう少し複雑な例として、よくあるHolyGrail的なレイアウトを作ってみます。
htmlは↓みたいに、シンプルなものを用意しておきます。

<divclass="wrapper"><divclass="box header">header</div><divclass="box left">left</div><divclass="box content">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati debitis nemo excepturi voluptatibus magnam fugit officia, ut, dicta, animi inventore quidem aliquam adipisci vitae perspiciatis id autem maiores asperiores dolores!</div><divclass="box right">right</div><divclass="box footer">footer</div></div>

続いて、cssを書いていきます。
全体を、3×3のグリッドに分割します。

.wrapper{display: grid;
      width: 100%;
      height: 100%;
      grid-template-columns: 150px3fr 1fr;
      grid-template-rows: auto1fr auto;
      padding: 10px;
    }

配置は、こんな感じ。
ヘッダーやフッター領域は複数のセルからなるエリアを指定して、こんな形にしています。

.header{/*↓grid-areaで書く場合はこんな感じ*//*grid-area: 1/1/2/4;*/
      grid-row: 1;
      grid-column: 1 / span 3;
    }.left{/*grid-area: 2/1/3/2;*/
      grid-row: 2;
      grid-column: 1;
    }.content{overflow: auto;
      /*grid-area: 2/2/3/3;*/
      grid-row: 2;
      grid-column: 2;
    }.right{/*grid-area: 2/3/3/4;*/
      grid-row: 2;
      grid-column: 3;
    }.footer{/*grid-area: 3/1/4/4;*/
      grid-row: 3;
      grid-column: 1 / span 3;
    }

f:id:minami_SC:20151208234704p:plain:w350
わかりやすいですね。

grid-template-areasを使って、AA風にレイアウトを定義

grid-template-areasプロパティを使うと、アスキーアートっぽく文字列でレイアウトの定義を行いつつ、エリアに名前を付けることができます。

先ほどのHolyGrail的なレイアウトの例を、grid-template-areasプロパティを使って書き直してみます。
grid-template-areasというプロパティを使い、グリッドの各セル/エリアに名前を付けていきます。
スペースで区切られた各文字列が一つのセルとなり、隣り合う同名のセル同士が一つのエリアとなります。

.wrapper{display: grid;
      width: 100%;
      height: 100%;
      grid-template-columns: 150px3fr 1fr;
      grid-template-rows: auto1fr auto;
      grid-template-areas: 
          "header header header""left  content right""footer footer footer";
      padding: 10px;
    }

配置するときは、grid-areaプロパティにエリア名を指定するだけ。

.header{
      grid-area: header;
    }.left{
      grid-area: left;
    }.content{overflow: auto;
      grid-area: content;
    }.right{
      grid-area: right;
    }.footer{
      grid-area: footer;
    }

レイアウト結果は同じなので、htmlのソースとキャプチャ画像は省略します。
こうしてみると、「ココの領域は開始位置がcolumn1で、spanは・・・」などと考えずに、直感的にレイアウトできると思います。
この発想はなかった。。。なるほどなぁ、って感じの仕様です。

メディアクエリを併用しレスポンシブなレイアウト

メディアクエリと組み合わせることで、レスポンシブなレイアウト切替も簡単に実現できます。 先ほどの例と同じレイアウトですが、ウィンドウサイズをリサイズして幅を550px以下にすると、縦に一列に並んだスマホ向けっぽいレイアウトになります。 f:id:minami_SC:20151208234757p:plain:w300

.wrapper{display: grid;
      width: 100%;
      height: 100%;
      grid-template-columns: auto;
      grid-template-rows: auto;
      padding: 10px;
    }.box{background-color: #444;
      color: #fff;
      border-radius: 5px;
      border: 2pxsolidblack;
      padding: 20px;
    }@media (min-width: 550px) {
      .wrapper {
        grid-template-columns: 200px3fr 1fr;
        grid-template-rows: auto minmax(min-content, 1fr) auto;
        grid-template-areas: 
            "header header header""left  content right""footer footer footer";
      }.header{
        grid-area: header;
      }.left{
        grid-area: left;
      }.content{
        grid-area: content;
      }.right{
        grid-area: right;
      }.footer{
        grid-area: footer;
      }}

サンプル

今回の全サンプルをまとめたプロジェクトを↓に置いておきました。
sourcechord/electron-gridlayout-sample · GitHub
メニューから項目を選ぶことで、ページ表示が切り替わります。
また、メニューから選択 or 「Ctrl+Shift+I」のショートカットキーでDev Toolsが出てきます。
Dev Toolsの各種パネルで色々と動きを確認することができるかと思います。
f:id:minami_SC:20151208233530p:plain:w300

まとめ

以上、駆け足でしたが、CSS Grid Layout Module Level1を使ってElectronのアプリのレイアウトをしてみました。
実際に動かしてみると、こんなシンプルな記述で思い通りにレイアウトできる、CSS Grid Layout Moduleの威力を実感できるかと思います。

この機能をブラウザ上で気軽に使えるようになるのは、まだまだ遠い未来かもしれません。
しかし、Electronを使った開発であれば、そんな未来の世界を少し先取りして体験することができます。
あとは、この機能が気兼ねなくブラウザでも利用できるようになる日が早く来ることを願うばかりです。

明日はsoedaさんです。
よろしくお願いします♪


Visual Studio Codeのinsider向けリリースをゲットする方法

$
0
0

この記事はVisual Studio / Visual Studio Code Advent Calendar 2015の22日目の記事です。

最近何かと話題のVSCodeですが、そんなVSCodeが好きでたまらない人向けな、VSCodeの自動更新に関する小ネタです。

VSCodeでは、自動更新に関する設定をいじることで、以下のようなことができます。

  • insidersチャンネル新しいバージョンの更新を一足先に受け取る
  • 自動更新をオフにして、現在使ってるバージョンのままにする

VSCodeの更新について

VSCodeは、およそ1か月に1度の頻度でアップデートが行われています。
新しいバージョンの配布が始まると、こんな風にエディタ上に通知が来て更新できるのは、VSCodeを使ってる方々にはご存じの通りかと思います。
f:id:minami_SC:20151222231259p:plain

insidersチャンネルでの先行リリース

VSCodeにはinsider向けに一足先に更新を配布するための手段が提供されています。
この設定をしていると、VSCodeのstable版が一般に配布されるよりちょこっと(数日~1週間程度?)速く、次のバージョンの更新を受け取ることができます。
ちょうど、Windows10のinsider programなんかと同じような感じですね。

先月のConnect();でVSCode 0.10.1がリリースされ、0.10.2→0.10.3とバグフィックスがリリースされました。
そして今月の19日には0.10.5がリリースされています。
この間0.10.3と0.10.5の間に、0.10.5での更新内容を一足先に試してみるための0.10.4というバージョンがあり、12/14頃からinsider向けにリリースされていました。
f:id:minami_SC:20151222231405p:plain:w300

こんな風に配布されるinsider向けの先行リリースですが、今回の0.10.5のアップデートから設定方法が簡単になり、ユーザーのsettings.jsonを編集するだけで設定できるようになりました。
また、リリースノートやFAQページでもinsiderチャネルの更新の受け取り方が明記されました。

insiderチャネルの設定をする

VSCode 0.10.5以降でのinsiderチャネルの設定方法

設定方法は、次のFAQページに書かれているとおりです。
https://code.visualstudio.com/Docs/supporting/FAQ#_how-can-i-test-prerelease-versions-of-vs-code

FileメニューのPreferences→User Settingsを開き、以下のようなプロパティ設定を追記します。
f:id:minami_SC:20151222231414p:plain:w250

settings.json

{// Configure the update channel to receive updates from. Requires a restart after change."update.channel": "insiders"}

こうしておくと、insider向けリリースの配布が開始されたときに、通常の更新と同じような通知がVSCodeのエディタ上に表示されるようになります。

0.10.5より前のバージョンでの設定方法

ちなみに、0.10.5より前のバージョンでは、若干異なった方法でinsiderチャネルの設定をしていました。
今後は使うことはないでしょうが一応、過去の経緯のメモということで。

以下のパスにある、storage.jsonというファイルを編集します。

  • Windows環境
    • %APPDATA%/Code
    • C:\Users\[ユーザー名]\AppData\Roaming\Code・・・←こんな感じのパス
  • Mac環境
    • ~/Library/"Application Support"/Code

このstorage.jsonの中の、updateChannelのプロパティをinsidersにすることで、insiderチャネルの設定ができます。

{"updateChannel": "insiders",
    "lastKnownKeybindings": {"workbench.action.files.newUntitledFile": "Ctrl+N",
        "workbench.action.files.openFile": "Ctrl+O",
        // 以下略//   :

0.10.5からは上に書いたユーザーのsetting.jsonで設定ができるようになったので、この設定方法はもう使わなくてよくなりそうですね。

insiderチャネルの設定方法の変化について

この自動更新の設定は、GitHubリポジトリを見てみると、以下のようなコードで実装されています。
コミットログなども追ってみると、何となく実装の概要はつかめるかと思います。
vscode/update-manager.ts at ed139191d6d17eeca9e9034f49f733e52bbdd8e6 · Microsoft/vscode · GitHub
allow to set the update channel from settings · Microsoft/vscode@ed13919 · GitHub

現時点の実装では、以下のように設定値を参照するようです。

  1. まずUserSettingsのsettings.jsonを参照
  2. そこにupdate.channelの記述がなければ、storage.jsonの内容を確認
  3. どちらもなければデフォルト値(stable)とする。

で、この部分のコードにコメントが書かれてますが、storage.jsonを使った設定方法は、いくつか先のバージョンで削除するつもりのようです。
ですので、既にstorage.jsonでinsiderチャネルの設定をしていた方は、今のうちにsettings.jsonでの設定に変えておいたほうが良いかと思います。

こうやって、修正点や変更内容についての実装をコードを見て確認できるのは、OSSならではの楽しさですね!!

元のstableのバージョンに戻す場合

上記の方法で一度insider channelの新しいバージョンにした後、「やっぱ元のバージョンに戻したい!!」ってなった時には、settings.jsonupdate.channelプロパティを以下のように戻すことで、元のstableバージョンの更新が降ってくるようになります。

{// Configure the update channel to receive updates from. Requires a restart after change."update.channel": "stable"}

普段のバージョンアップ時と同じような通知が出てくるので、指示に従いアップデートしてVSCodeを再起動すると以前のstable版がダウンロードされて元のバージョンに戻すことができます。

※補足
今までのstorage.jsonを使ったinsiderチャネルの変更をしてた頃は、stableに戻すことで最後のstable版に戻せることは確認しています。
settings.jsonで設定するように変わってからは、まだinsiderチャネルでのリリースがないので、この辺の動作は実際に動かして確認できていません。が、まぁおそらく大丈夫でしょう。

自動更新をオフにする

今度は逆に自動更新をオフにする方法。

ここのドキュメントによると、先ほど書いたstorage.jsonupdateChannelプロパティをnoneとすることで、自動更新を無効にできるようです。

storage.json

{"updateChannel": "none",
    "lastKnownKeybindings": {"workbench.action.files.newUntitledFile": "Ctrl+N",
        "workbench.action.files.openFile": "Ctrl+O",
        // 以下略//   :

注意点
このstorage.jsonを編集するときは、すべてのVSCodeのインスタンスを終了しておく必要があります。
VSCode終了時に各種設定をこのファイルに書き込んでいるようで、VSCodeを起動したままこのファイルを編集すると、VSCode終了のタイミングでファイルの内容を上書きされてしまいます。

なので、このjsonファイルの編集はVSCode以外のエディタで編集してください。

自動更新オフの使いどころ

現在使ってるバージョンのまま使い続けたい場合や、新しいバージョンが出ても、不具合報告などがある程度出て落ち着くころまで様子見をしておきたい、という時に使えそうです。
ちなみにVSCode 0.10.5では、JIS配列のキーボードを使ったOS X環境ではアプリ起動時にクラッシュする、という不具合報告なども出てます。
慎重派な方は、普段はこの設定をしておいて、少し様子を見てからstableに設定を戻してアップデートする、という使い方もアリかもしれません。

自動更新オフの設定方法の補足

現時点でのドキュメントでは、上記のようなstorage.jsonを用いた設定方法が記載されています。
しかし、VSCodeの実装を見てみる限り、UserSettingsのsettings.json"update.channel": "none"と書けばオフにできるのでは、と思います。

この辺はドキュメントの修正がまだされてないだけなのかな?

最後に

ここに書いた方法は、VSCode0.10.5の時点での設定方法です。
この手の各種設定方法は、今後のバージョンアップに伴い変わる可能性もありますのでご注意を。。。

また、insiderチャネルでの更新は、stableとしてリリースする前の状態のモジュールなので、それなりのリスクはあるかもしれません。
やってみる場合には、VSCode関係の設定ファイル類を一通りバックアップして何かあってもいい状態にしておき、不具合を踏む覚悟とともに挑んでみることをお勧めします。

Visual Studio Code 0.10.5の新機能・変更点

$
0
0

今月も定例のアップデートがありました。
ちょっと時間が経ってしまいましたが、今回も更新内容を一通りメモっておきます。

あと、0.10.5ではMac環境&JIS配列キーボードを使用した環境でクラッシュするって不具合がありましたが、その修正をした0.10.6というバージョンがMac向けにリリースされてます。
https://code.visualstudio.com/Updates

今回のリリースでは、前回リリース時の拡張機能のような目玉となる大きな変更点はありませんが、細かいけど痒いとこに手が届く感じな修正がいっぱい入ってます。

また、今回の更新では「Communities Contributes」という括りで、GitHubでコミュニティから届いたプルリクを受けての修正が多数入ってるのも印象的です。
VSCodeをOSS化したことによる効果がさっそく現れている感じで、今後のバージョンアップも楽しみになりますねw

insiderチャネルでのアップデート

VSCodeのinsiderチャネルでの更新を受け取る方法がドキュメントに明記されるようになりました。また、settings.jsonでお手軽にinsiderチャネルでの更新の設定ができるようになりました。

更新方法の制御については以下にまとめてます。

テキスト検索など

  • ^や$、^$などを、正規表現での検索で仕様できるようになった
  • 文字列置換の置換結果に、\n\tが使えるようになった

検索・置換のショートカット

テキスト検索関連のショートカット動作が少し変わりました。

Ctrl+Fを押すとFindのテキストボックス、Ctrl+Hを押すとReplaceのテキストボックスにフォーカスが移るようになりました。 f:id:minami_SC:20151228142620p:plain

その他各種検索のショートカット

ショートカット内容
Alt+C検索・置換時に、大文字と小文字を区別するかどうかを切替
Alt+R正規表現で検索するかどうかを切替
Alt+W検索文字の部分一致ではなく、単語単位でのマッチをするかどうか切替
Ctrl+↓検索のテキストボックスから、エディタ本体側へとフォーカスが移動する。

その他、エディタ関連のキーボード・ショートカット

他にも色々と便利なショートカットが追加されています。

カーソル位置を保持したスクロール

以下のショートカットで、カーソル位置はそのままにして、1行分上下にスクロール、1ページ分上下にスクロールできます。

  • Ctrl+↑
  • Ctrl+↓
  • Ctrl+PageUp
  • Ctrl+PageDown

VisualStudioと似た感じの動作ですね。
(PageUp/PageDownの動きは若干異なりますが。)

1行選択

Ctrl+Iで現在のカーソルがある位置の、行全体を選択するようになりました。

その他

  • settings.jsonのデフォルト値変更
    • editor.insertSpacesのデフォルト値をtrueに変更
    • editor.tabSizeのデフォルト値を4に変更
  • editor.cursorBlinkingという設定を追加
    • カーソルの点滅動作を制御
    • blink, visible, hiddenから選択
    • hiddenにすると、カーソルを非表示にできるけど、使い道がイマイチよくわかりません。。。w
  • ショートカットキーの定義に利用できるキーが増えた
    • F13~F19までのファンクションキーを用いたショートカット定義ができるようになった
    • テンキーの0~9の数字や、テンキー側の+, -などの各種記号を用いたショートカット定義ができるようになった

非USのキーボードレイアウト環境向けの改善

斜め読みしかしてないですが、ざっと以下のような感じ。

  • VSCodeでは、UI上にショートカットキーの表示をする際には、今までUS配列上の文字列で表示していた
  • 今回の修正で、キーボードショートカットのUI表示時には、実行環境のキーボードレイアウトに合わせたキー表示をするようにしたとのこと

ドキュメントにはフランス語環境での例とかが書いてありました。
この辺の事情はあまりよくわからないので省略。
フランス語のキーボードレイアウトって少々特殊なんですかね。

ショートカット定義を入力するウィジェット

前述のフランス語環境などの、特殊な環境用にショートカット定義を補助するウィジェットを追加したようです。

keybindings.jsonを編集してるときに、Ctrl+K Ctrl+Kと入力すると、以下のような画面が出てきます。
f:id:minami_SC:20151228142647p:plain

ここで、定義したいショートカットキーを実際に入力すると、以下のようにショートカット定義のスニペットが入力されるようです。
各言語でのキーボードの表示と、VSCode内部でのショートカット定義をするkeybindings.jsonでの定義の食い違いを吸収するために、こういうUIを追加したみたい。

QuickOpenの改善(←Ctrl+Pでファイル開くヤツ)

VSCodeでは、Ctrl+Pのショートカットで、以下のようなUIが出て、ファイル名を指定して特定のファイルを開くことができます。
f:id:minami_SC:20151228142705p:plain

この、開くファイルを検索する際の動作で、以下のようにいい感じに検索するための仕様が付け加えられました。

  • /\などを含む、フォルダ指定での検索ができるようになった
  • fuzzy search
    • こんな風に、ファイル名中の単語区切りの頭文字だけ省略して入力しても、検索結果に含まれます。
    • 例えばrmと打つと、README.mdというファイルが引っかかる、という感じ。 f:id:minami_SC:20151228142715p:plain

言語サポート

  • JavaScript
    • ES6がデフォルトになった
    • 今までは、VSCodeでES6のサポートを有効にするには、jsconfig.jsonを用意してcompilerOptions.targetプロパティを設定をする必要がありました。
    • v0.10.5からはデフォルトでES6が有効になっています。
    • PromiseSet, Map, String.startsWithなどのES6の各種機能が、デフォルト状態でもコード補完で出てくるようになってます。
  • TypeScript
    • TypeScriptのLanguage Serviceが1.7.5になった
  • JSX

拡張機能関連の修正・変更点

Extension Galleryへの接続で、プロキシ設定が反映されるようになった。

VSCodeは、以下の設定をUser or workspace単位の設定としてjsonファイルに書いておくことで、VSCodeが行う各種通信で、プロキシサーバー経由での通信を行うように設定することができます。

{
    "http.proxy": "http://・・・・"
}

しかし、今までのバージョンでは、Extension Galleryへの通信にこのプロキシ設定が反映されておらず、プロキシ設定が必要な環境では、ギャラリーからの拡張機能のインストールができない状態でした。

0.10.5からは、このギャラリーからの拡張機能インストールにプロキシ設定が反映されるようになったようです。

ただし、0.10.5で自分も試してみたところ、まだうまく接続できません。
以下のissuesを見ても、同様の問題が起きてる人が多数いるようです。 https://github.com/Microsoft/vscode/issues/69ギャラリーへの接続はまだ問題ありそうなので、今後の修正を期待しておきましょう。

Outdatedな拡張機能の列挙機能

コマンドパレットから、Extensions: Show Outdated Extensionsというコマンドを打つと、新しいバージョンが配信されている拡張機能を列挙してくれます。
f:id:minami_SC:20151228142725p:plain

今後、色々な拡張機能がバージョンアップしていったら、色々と使う場面も増えるのかな。

その他拡張機能

  • deactevatedイベントの追加
    • VSCode終了時に、deactivatedイベントが拡張機能側に通知されるようになりました。
    • アプリ終了時に、拡張機能側で何かしたい場合に使えるかな
  • 拡張機能で発生した問題がステータスバーに表示されるようになった

Git関連

Scoped Git Services

VSodeで開いてるフォルダが、gitのルートディレクトリではなく、サブフォルダを開いてる時でも、git連携機能が動作するようになりました。

sample
├─.git
├─project1
│     package.json
│        :
└─project2
       package.json
          :

こんなフォルダ構成で、sampleフォルダのルートに.gitフォルダがある状態でproject1 フォルダをVSCodeで開いても、ちゃんとgitの構成が認識されます。

Gitステータスバー

git関連の表示や同期処理を行うためのボタンが付いたステータスバー表示が追加になってます。

その他

  • 拡大率の設定
    • 環境設定で拡大率を設定しておけるようになりました。キーボードショートカットのCtrl++、とかで設定した拡大率はアプリ終了後は保持されませんが、ここのjsonファイルで設定した値は、ずっと保持されます。
    • window.openFIleInNewWindow
      • 今まで、window.openInNewWindowというプロパティ名だったもの。目的を適切に表すように、プロパティ名が変更になりました。
  • EmmetがJSXやTSXの中でもサポートされるようになった
  • Debug Console
    • デバッグコンソールで文字列を表示する際に、ウィンドウ右端で改行してラップ表示するようになった
  • ブレークポイントの表示改善 *以下のようにブレークポイントの表示が変わるようになった
    (たぶん、グレー枠だけの表示が今回追加になった部分)
  • JSON Schemaの関連付けを行う拡張機能の作成ができるようになった
  • ↓二つはあんま詳細な内容を見れてないので省略
    • Language Server Extensions
    • Debug Adapter Development

electron環境でknockout.jsを使ってみる

$
0
0

そういえば、ブログにメモしてなかったので、改めてφ(..)メモメモ
knockout.jsをelectron環境で使う手順についてメモしときます。

準備

プロジェクトの雛型

以前↓で書いた、Electron+TypeScriptなプロジェクトのテンプレートを雛型に利用します。
sourcechord/electron-typescript-sample · GitHub

まずは、このプロジェクト一式をcloneしてローカルに置いたところから始めます。

git clone https://github.com/sourcechord/electron-typescript-sample.git

knockout.jsのインストール

以下のコマンドで、npmからknockout.jsをインストールします。

npm install knockout --save

続けて、tsdを使って型定義ファイルをインストールします。

tsd install knockout -rosa

これで準備OK。

knockout.jsの読み込み

それでは、さっそくknockout.jsを使うために、ライブラリを読み込んでみます。
普通にブラウザ上からknockout.jsを使うときは、こんな風に<script>タグで読み込みをしていたと思います。 (↓node_modulesフォルダ内のファイルを直接指定する場合)

<scripttype="text/javascript"src="node_modules/knockout/build/output/knockout-latest.js"></script>

electronでknockout.jsを使う時には、このように<script>タグを使ったロードももちろんできます。

ですが、electron環境では、node.jsのモジュールシステムが利用できるので、CommonJSスタイルでのrequireができます。
ということで、こんな風に、javascript側から直接knockout.jsのスクリプトを普通にrequireして読み込むこともできます。
(ES6スタイルのimportで使う方が今風ですね。)

import ko = require('knockout');
//import * as ko from 'knockout';   // ES6スタイルのimportをする場合はこちら

browserifyやらWebPackやらのモジュール管理システムを使わずとも、直接node_module内のライブラリをrequireして使えるってのがなんか新鮮です。
scriptタグではなく、require/importで書いておけば、後々でWebPack使ってバンドルしたい、というときにもそのまま移行できそうです。

使ってみる

テキストボックス1つ作り、そこに入力した文字列をボタン押下時にalert表示するだけ、という単純なサンプルを作ってみます。
f:id:minami_SC:20160110161701p:plain:w350

ページの定義

やってることは↓だけです。 * index.jsを読み込む * inputタグ/buttonタグを配置 * ↑のタグに対してknockout.jsのデータバインドを色々設定

html側からは、knockout.jsの読み込みはしていません。

index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><scriptsrc="index.js"></script></head><body><h1>Knockout.jsのテスト</h1><hr/><span>名前:</span><inputtype="text"data-bind="value: name"></input><buttondata-bind="click: showName">Show Name</button></body></html>

viewmodelクラスの作成

nameプロパティと、nameを表示するためのshowNameメソッドを持ったVMクラスを作り、onloadイベントでVMの設定をしているだけです。
また、knockout.jsはこのindex.ts側からimpoteしています。

index.ts

import * as electron from 'electron'; 
import{remote} from 'electron'; 
const app = remote.app;
const BrowserWindow = remote.BrowserWindow;
const dialog = remote.dialog;

import * as ko from 'knockout';

class SampleViewModel{public name: KnockoutObservable<string>
    = ko.observable<string>();
    
    public showName() {alert(`こんにちは、${this.name()}さん`);
    }}window.onload = () => {var vm = new SampleViewModel();
    ko.applyBindings(vm);
};

とりあえず今回はここまで。

fs-extraを使ったファイル/フォルダ操作

$
0
0

Node.jsには、ファイル操作関係を行うfsモジュールというのが標準で用意されてます。

ですが、こいつは微妙にかゆいとこに手が届かないです。。

  • フォルダを再帰的にコピーすることができない
  • フォルダを再帰的に作成することができない。
    • ⇒入れ子になった階層構造のフォルダを一気に作ることができない
  • などなど

そんなファイル/フォルダ操作をちょろっと便利にしてくれる、fs-extraというライブラリがあるので使ってみました。

使い方

以下のコマンドでインストール。

npm install fs-extra --save

このfs-extraモジュールは、node.js標準のfsモジュールと同等のメソッドも提供してます。
なので、今までvar fs = require('fs');としてた部分を、var fs = require('fs-extra');と差し替えても使えるように作られてるみたい。

よく使いそうなパターンを少しメモしておきます。

深い階層のフォルダを一気に作成
var fs = require('fs-extra');

fs.mkdirs('H:\\Test\\Test\\Test\\Test\\Sample', function (err) {if (err) return console.error(err)
  console.log("success!")
});

深い階層のフォルダも一気に作れます。
標準のfsモジュールでは、複数階層のフォルダを一度に作れないため、再帰的にフォルダ作成をするメソッドを自分で用意したりしないといけませんでした。
自分で作るよりは、こういうのに任せた方が間違いがなくていいですね。

フォルダを再帰的にコピー
var fs = require('fs-extra');

fs.copy('H:\\Test\\Test\\copy_test\\src', 'H:\\Test\\Test\\copy_test\\dst', function (err) {if (err) return console.error(err)
  console.log("success!")
});

これで、普通にフォルダを再帰的にコピーできます。
入れ子になったフォルダツリーも一気にコピーできて便利!!

コピー時のフィルタリング
var fs = require('fs-extra');

//var filter = /.txt$/i;var filter = function (s) {return s.split('.').pop() !== 'txt'}
fs.copy(コピー元のパス, コピー先のパス, filter,function (err) {if (err) return console.error(err)
  console.log("success!")
});

コピー時に、正規表現や、関数を指定してフィルタリングすることができるようです。
が、試してみたところ、正規表現でのフィルタリングは上手く動きませんでした。。。
使い方が悪いのか、バグなのか。
ちょっとお悩み中・・・

GitHubへお引越し

$
0
0

ふと思い立って、昔作ってCodePlexに上げてたものをGitHubにお引越ししました。
(とはいっても、たいしたものは作ってませんが・・・)

以前XAMLアドベントカレンダーに書いた、↓のやつもお引越し。
WPF4.5の新機能~「イベントのマークアップ拡張」で、イベント発生時のコマンド呼び出しをスッキリ記述する~ - SourceChord

ちなみに、ちょこちょこと修正入れていて、アドベントカレンダーに書いたときにあった以下のような不具合も一通り直してます。

  • バインディングのコレクション操作パスの記法に対応してない
  • DataContextの変更に追従できてない

ここ1年くらい、個人的なちょっとしたツール類の作成にコレを使ってみてますが、割と使い勝手は悪くないな、と感じています。

UWPの{x:Bind}によるイベントへのバインドみたいな処理が、WPFでもどうしても使いたい、って時にはこんな手もありかなぁ、と。

Viewing all 153 articles
Browse latest View live