たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

競プロはじめてから1年ぐらいたった

楽しい

でもつらいときもある

1年ぐらい経ちました

去年のこれぐらいの時期にAtCoderに登録したような気がします。(今使っているアカウントは4月末のコンテストから参加してたので正確な日がわからん)

コンテストには合計で43回参加してるみたいで、レートは水色一歩手前で揺れてますね。こう見ると成長がえっちらおっちらですねこりゃ。
1

コンテスト用のリポジトリはもいい感じ(?)にcommitが増えてきました。
github.com

なので覚えてることとかをせっかくなので書いてみようと思いました。

出会い

同期にICPCへ誘われて始めました。今思えば自分にはちょっとハードルの高い始め方だったようにも感じます。
自分はC#が好きなのでそれでやろうと思っていたんですが、ICPCC#が使えないのでC++でやってました。(早く使えるようになって)

ICPCまでは同期にC++教えてもらったり、ABCに出ていたりしていました。このころはSTLや競プロ的な問題文や解説の言い回しに慣れなくて四苦八苦してた覚えがあります。弊学の競プロサークルでは毎週バチャコンを行い終わった後に解説し合う、というのをやっていましたがみんなの解説が解らなくて例の顔みたいになっていました。

このころはとけてもABCのBまで・・・とかで、ようやくC問題やICPCの過去問の300?問題を読んで長考して解けるぐらいになったころに本番が来てしまってました。

ICPC

自分はA問題を担当しました。Aを解いた後はB,Cをメンバーが解いてる間にDを読んだりしてました。ICPCはチーム戦で、ggれないしPC1台しか使えないしとかで勝手が解らずにぶっ倒れてたことしか覚えてません。

結果は5X位ぐらいだった気がします。

そのあと

ICPCの後はせっかく始めたし、ということで続けていくことにしました。ここからはC#を使いました。C++でやってる時にLINQがあればな~と思うことが多々あったので・・・それなりにC#も速いですし。Visual Studioのインテリセンスがはちゃめちゃ強いですし。

ただジャッジサーバがだいたいmonoなのでこちらが未来のC#を書いてることが結構あるのが辛いところでした。(とくにAOJのやつ)

とりあえずAtCoderのC問題ぐらいがコンテスト中に安定して解けるように目指して過去問埋めをやっていました。まあ色んな所に書いてあるんですが、C問題ともなると競プロ的な知識がないと解けない感じだったので躓いていました。これは9月ぐらいだったと思います(レートのグラフもそうなってますね)

Cがちょっとわかる

C問題がちょこちょこ解けるようになってきたころが10月ぐらいからでした。なにか切っ掛けになるようなことがあった・・・のかは思い出せませんが気づいたらチョットワカルになってました。あえていうなら問題に対して「考えようとする気持ち」が一番高かった気がします。

コンテスト中にCまでは解けるのでD・・・と思って問題をみて無言になるのを繰り返していました。

最近

全然できません。昔聞いていたラジオで、「成長は階段みたいなもんで、なかなか伸びないとき、それは踊り場にいるだけだからもう少し頑張ろうな」って言ってたのを思い出します。完全にそれを感じてます。

400点を安定して解けるようにと思って400点埋めをしたんですが、これがなかなか。
これぐらいになるとやはり必要になる知識の幅が広くなってきます。今ある400を埋めきったところで次のコンテストをクリアできるかっていうとうーん・・・と思ってしまいます。

before
twitter.com

after
twitter.com

これが10月ごろと同じようにまた伸びへ転換してくれればいいんですが・・・!

あと自分の苦手な問題もよくわかってきた気がします。例えば

これですね・・・・こういうなんか・・・算数?みたいな問題が苦手です。算数サボったからかな・・・

偉そうで申し訳ないんですが、AtCoderの最近の問題はまた難しくなった気がします(質が上がったともいう)。
DijkstraやるだけUnion-Findするだけみたいなのは減って、それらを使うためにどうやって状態を減らすかとかが必要な気がします。まあこれが上手く思いつかないんですが

あとは考察が終わっても書くのが遅いのでこれも何とかしないと・・・

これから

やっぱコンテスト中とかに解けないと普通に凹むんですよね。めちゃくちゃ悔しいんですよ。他の人は解いてるのに己は・・・とか
終わった後は解説とか他の人の提出を見て「天才~~~!」とか「次は倒す!」と思うようにしています。ゲームってすぐクリアできても面白くないですからね。

次の1年はとりあえず水色になって、それからはまあその時考えます。

VisualStudioから棒読みちゃんを喋らせるやつ

VisualStudioから棒読みちゃんを喋らせるやつ

VOICEROID買っちゃってました

前々からVOICEROID気になってて、ネット記事とか読み上げてほしいなあ~って思ってたんです
まあでも諭吉さんぐらいはかかっちゃうわけで。「悩む理由が値段なら買え」っていうのはたまに聞きますが、やっぱ考えちゃうんです買った後のこと
別に動画とか投稿しないだろうし(これは大変だって聞くし)、これといった用途も思いつかなかったので伸ばし伸ばしにしてたんです

ところがそんなときAHSからVOICEROID2 紲星あかりが発表されまして
www.ah-soft.comhttp://www.ah-soft.com/voiceroid/akari/

めっちゃかわいいじゃないですか

めっちゃかわいいんです

しかも発売日が誕生日と同じだったんです

買うしかないじゃないですか

で発売日にDL版を購入したんです。で、しゃべらせてみたらスゲー可愛いじゃないですか
毎日いろいろ喋らせてウフフって思ってました

でも、僕オタクなんで
このエディタにコリコリ文字入力させるだけじゃ物足りなくなってきたんですね
シェル芸・・・とかWLSでの重い処理やVisual Studioのビルドとかが終わったらあかりボイスでお知らせしてくれたら嬉しいじゃないですか
嬉しいんですよ
じゃあできるようにしたいじゃないですか

色々調べていたら棒読みちゃんプラグインでVOICEROIDに飛ばせる奴があると
chi.usamimi.info
ch.nicovideo.jp

天才か。危うくまた車輪の再開発をするところだった。
この棒読みちゃんにタスクを投げればプラグインを介してあかりちゃんがしゃべるわけですね

さらに棒読みちゃんにはコンソールから棒読みちゃんに発言タスクを投げるやつが同梱されてました。天才じゃん
なのでWLSの重い処理が終わったときにあかりボイスが聞ける最高の環境は出来たんです
ですがVisual Studioのビルド終了時にも喋ってほしいんですよ。けどそんなのないので(システム音を弄る方法はあるが)

自分で作るしかないんですよおおおおおお

VSBouyomi

作った拡張機能の名前はVSBouyomiです。何のひねりもない名前ですが

github.com
アイコンとかほしいんですけどなんも思いつかなかった・・・

Visual Studio Market上に公開しようと思ったんですがなんかエラーがでてできませんでした。泣こう

VSBouyomiの機能

VSBouyomiはタイトルに書いた通り、Visual Studioから棒読みちゃんを喋らせる拡張機能です
Visual Studioのいくつかのイベントが発生したときに任意の文字列を棒読みちゃんへ送ることができます。今のバージョンでは棒読みちゃんのパラメータを弄ることはできません VisualStudioから棒読みちゃんへは棒読みちゃん側が用意してくれているTCP通信機能を使っています

インストール

  1. GitHubからリポジトリをクローン。もしくはvsixをダウンロードしてくる
    1. クローンしたならお手持ちのVisual Studioでビルドして下さい
  2. ビルドしたvsixもしくは、ダウンロードしたvsixをダブルクリックしてVisual Studioにインストールする

使い方

インストールされたVisual Studioツールバーを右クリックします。すると
toolbar
VSBouyomi Activateという項目があると思うのでクリック

ツールバーにボタンが追加されます
button
このボタンが押されるとVSBouyomiが有効になり、もう一度押すと無効化されます。あとはVSBouyomiが勝手にやります

設定

初期設定ではビルドが成功したときに「ビルド成功です」とだけ言いますが、これを変えたいときもあると思います
そういう時は[ツール]=>[オプション]からVSBouyomiの設定を開きます

option1

各設定項目の詳細は以下です

ネットワーク設定

項目 説明
IPアドレス 棒読みちゃんIPアドレスです
ポート番号 棒読みちゃんのポート番号です

棒読みちゃんTCP通信するときに使うパラメータです。デフォルトでは127.0.0150001が入っています

発言内容設定

どれがどのときに発言する内容なのかは項目を見てもらえばわかると思うので割愛です。ここではその詳細設定を書きます

option2

発言内容はbool値とstringの組み合わせでできています

項目 説明
すぐに? イベントが発生したら棒読みちゃんにたまっているタスクを取り消して直ぐに読み上げるかどうかです
テキスト 読ませたいテキストを入力します。空白の場合は読み上げを行いません

この程度のシンプルな設定にしたのは 細かい設定はVOICEROIDとプラグイン側でやれよ と思ったからです
最初は拾えるイベントは拾えるだけ拾って発言できるタイミングを増やしたり、WPFを使ったイケイケな設定画面とかも作っていたんですがだんだん 「いるんかこれ・・・」 となってしまったので全部バイバイしました

これでVisual Studioがあかりちゃんの声でしゃべるようになったので他の痛IDE拡張と組み合わせれば

ide

コード書いてる時もワクワクですね!(立ち絵はMtU氏のものです

今後のうんぬん

この間TypeScriptを触ることがあったのでVSCodeへVSBouyomiを移植してもいいかなあと思っています。まあ気が向いたらですね

VisualStudioの設定ダイアログを作る

またVSIX

ほぼ備忘録になってる
まぁぼくは忘れやすいのでOKOK

それにしてもsurface3みたいなスペックだと実験インスタンス起動するのに時間かかってつらい

Visual Studioの設定ダイアログを作る

メニューバーの[ツール][オプション]で開くやつ正式名称はわからない・・・

d1
こういうやつ

これを自分の作ったVSIX用に作る

参考はここ

Creating an Options Page

プロジェクトを作る

今回は空のVSPackageに作っていく。自分のVSIXに実装するときは新しくVSPackageを追加する必要はない

まずは[ファイル]-[新規作成]-[プロジェクト]-[Visual C#]-[Extensibility]-[VSIX Project]を選んでプロジェクトを作る

できたらソリューションエクスプローラーで右クリックして[追加]-[新しい項目]
d2

Visual Studio Packageを選ぶ

d2

テンプレートが展開されるまでちょっと待つ

実装する

ダイアログページを作るにはSystem.ComponentModel名前空間が必要なのでusingする

using System.ComponentModel;

次にオプションで設定したい値を持ってるクラスを作る。今回はOptionDialogクラスにした。ネーミングセンス・・・・

public class OptionDialog : DialogPage {

}

このクラスにはDialogPageクラスを継承する必要があるのに気を付けよう

次にPackageクラスを継承してるクラスに属性を追加する。たぶんこのVSIXはオプションページがありますよ~~~ってことなんだと思うたぶん

/*他の属性は略*/
[ProvideOptionPage(typeof(OptionDialog),"Test Dialog","General",0,0,true)]
public sealed class Dialog : Package {
    /*略*/
}

d2

ちなみにこの属性の引数はこんな感じらしい。categoryNameはオプションウィンドウのサイドバーの項目で、pageNameはその下の全般とかのことっぽい

今のままだと設定したい項目が0なので追加していく今回はIntを1つもたせることにした

public class OptionDialog : DialogPage {
    [Category("かてごりー")]
    [DisplayName("ひょうじめい")]
    [Description("せつめい")]
    public int Num { get; set; }
}

DialogPageではプロパティとかにした値がそのまま設定項目として表示される。XmlとかJsonシリアライズしたりするのと似ていてちょっとうれしかった

実は実装はこれで終わりで、あとはビルドするだけでちゃんと動くのだ!最高!

d2

プロパティにつけていた属性の意味は上の画像と照らし合わせればわかると思う。これは僕も驚いたところだけど、これ値を変えてから再起動しても値が変更されたままになる。どこに書き出しているかはリファレンスをちゃんと読んでないのでわからない(読む気もない)。まあとにかく簡単である

xmlに書き出してみる

xmlファイルの準備

こういうのはjsonとかxmlに書き出しておきたいっていうのがあります(あります)
なので今回はxmlに書き出すのを目標にしてみる

まずはソリューションエクスプローラーからxmlを追加しておく。そして一度自力で書くか、適当なコンソールアプリケーションを書いてこのxmlを書いておく。書くのはOptionDialogクラスと同じようなプロパティを持ったクラスをシリアライズしたやつ。こういう時にC#インタラクティブが便利だと思うんだけどXmlSerializerがroslynでは死ぬのでダメだった・・・ざんねん・・・
なので自分はいつも以下みたいなのを書いてる。面倒

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ConsoleApp2 {
    class Program {
        static void Main(string[] args) {
            var path = @"c:\users\user\source\repos\TestDialog\TestDialog\Resources\config.xml";
            var xml = new XmlSerializer(typeof(Store));
            using(var sw=new StreamWriter(path, false, Encoding.UTF8)) {
                xml.Serialize(sw, new Store { Num = 0 });
            }
        }

    }
        public class Store {
            public int Num { get; set; }
        }

}

追加したxmlはプロパティウィンドウでビルドアクションをコンテンツに、Include in VSIXをTrueにしておくこと。これが分からなくてINF分失った

Load/Saveイベント

またイベントの話だけどダイアログが開かれたとき、または閉じられたときにLoadとSaveが行われる。DialogPageにはこれをするLoad/SaveSettingsToStorageメソッドがあるのでオーバーライドしてやるといい

パスの取得

さっきビルドした拡張機能がどこにインストールされてるのか探してみたらC:\Users\USER\AppData\Local\Microsoft\VisualStudio\15.0_29065328Exp\Extensions\xztaityozx\TestDialog\1.0にあった。上の設定をしていればこの下にxmlも置かれるのでこのパスが分からないといけない。でもユーザー名とか変わるし決め打ちはできないのでどうにかして実行中に取得したい

ggっていたらドンピシャなstackoverflowを見つけた
stackoverflow.com

CodeBase?ってやつを取得すると実行中のファイルがわかるっぽい
そしてどうやらPackageクラスにも同じような値が入っているらしいけど何階層か上までしかわからなかったのでダメだった

なのでこんな風にかいた

public class OptionDialog : DialogPage {
    [Category("かてごりー")]
    [DisplayName("ひょうじめい")]
    [Description("せつめい")]
    public int Num { get; set; }

    public string Path {
        get {
            var codebase = typeof(Dialog).Assembly.CodeBase;
            var uri = new Uri(codebase, UriKind.Absolute);
            return System.IO.Path.GetDirectoryName(uri.LocalPath) + "\\Resources\\config.xml";
        }
    }

    public override void LoadSettingsFromStorage() {

        using (var sr = new StreamReader(Path, Encoding.UTF8)) {
            var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Store));
            var config = (Store)xmlSerializer.Deserialize(sr);
            this.Num = config.Num;
        }
    }

    public override void SaveSettingsToStorage() {
        var config = new Store {
            Num = this.Num
        };
        using (var sw = new StreamWriter(Path, false, Encoding.UTF8)) {
            var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Store));
            xmlSerializer.Serialize(sw, config);
        }
    }
}
public class Store {
    public int Num { get; set; }
}

これでxmlに書き出せるようになったのでVSIX中の任意の場所から同じようにxmlにアクセスすれば色々できてうれしい

それでは最後にソースコードをはって終わります

using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.Win32;
using System.ComponentModel;
using System.IO;
using System.Text;

namespace TestDialog {
    /// <summary>
    /// This is the class that implements the package exposed by this assembly.
    /// </summary>
    /// <remarks>
    /// <para>
    /// The minimum requirement for a class to be considered a valid package for Visual Studio
    /// is to implement the IVsPackage interface and register itself with the shell.
    /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
    /// to do it: it derives from the Package class that provides the implementation of the
    /// IVsPackage interface and uses the registration attributes defined in the framework to
    /// register itself and its components with the shell. These attributes tell the pkgdef creation
    /// utility what data to put into .pkgdef file.
    /// </para>
    /// <para>
    /// To get loaded into VS, the package must be referred by &lt;Asset Type="Microsoft.VisualStudio.VsPackage" ...&gt; in .vsixmanifest file.
    /// </para>
    /// </remarks>
    [PackageRegistration(UseManagedResourcesOnly = true)]
    [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About
    [Guid(Dialog.PackageGuidString)]
    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")]
    [ProvideOptionPage(typeof(OptionDialog),"Test Dialog","General",0,0,true)]
    public sealed class Dialog : Package {
        /// <summary>
        /// Dialog GUID string.
        /// </summary>
        public const string PackageGuidString = "3e22428e-3305-4a4b-9c3e-11c54c2bef28";

        /// <summary>
        /// Initializes a new instance of the <see cref="Dialog"/> class.
        /// </summary>
        public Dialog() {
            // Inside this method you can place any initialization code that does not require
            // any Visual Studio service because at this point the package object is created but
            // not sited yet inside Visual Studio environment. The place to do all the other
            // initialization is the Initialize method.
        }

       #region Package Members

        /// <summary>
        /// Initialization of the package; this method is called right after the package is sited, so this is the place
        /// where you can put all the initialization code that rely on services provided by VisualStudio.
        /// </summary>
        protected override void Initialize() {
            base.Initialize();
        }

       #endregion
    }

    public class OptionDialog : DialogPage {
        [Category("かてごりー")]
        [DisplayName("ひょうじめい")]
        [Description("せつめい")]
        public int Num { get; set; }

        public string Path {
            get {
                var codebase = typeof(Dialog).Assembly.CodeBase;
                var uri = new Uri(codebase, UriKind.Absolute);
                return System.IO.Path.GetDirectoryName(uri.LocalPath) + "\\Resources\\config.xml";
            }
        }

        public override void LoadSettingsFromStorage() {
            
            using (var sr = new StreamReader(Path, Encoding.UTF8)) {
                var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Store));
                var config = (Store)xmlSerializer.Deserialize(sr);
                this.Num = config.Num;
            }
        }

        public override void SaveSettingsToStorage() {
            var config = new Store {
                Num = this.Num
            };
            using (var sw = new StreamWriter(Path, false, Encoding.UTF8)) {
                var xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(Store));
                xmlSerializer.Serialize(sw, config);
            }
        }
    }
    public class Store {
        public int Num { get; set; }
    }
}

Visual Studioのビルド成功時にメモ帳を起動する

VisualStudioのビルド成功時にメモ帳を起動する

おいVSIX

Visual Studio拡張機能を少しずつ作ってる。なんもわからん

開発対象にしてるのはVS2017

Visual Studioのビルド成功時にメモ帳を起動する

今回はビルド成功時に発火するイベントを用いて色々するやつ。ビルド成功したときにメモ帳が出て何がうれしいんだ?って感じだけど分かりやすい例としてね

めちゃくちゃ分かりやすいリファレンス(怒)はここ
BuildEventsClass Class

OnBuildDone/Beginイベント

OnBuildDoneはビルドが終了したときに発火するイベントで、OnBuildBeginはビルドが始まったときに発火するイベント。まあそのままですね

この二つに登録できるメソッドは第一引数にvsBuildScope列挙型と第二引数にvsBuildAction列挙型を持ってるやつだけ。つまり以下みたいなやつ

private void OnBuildDoneEvent(vsBuildScope scope,vsBuildAction action){
    //なんかの処理
}

vsBuildScope 列挙型はリファレンスによると Represents the scope of the build. らしい。ふーんなるほどねすべて理解した。それとvsBuildAction列挙型は同リファレンスによるとRepresents the type of build action that is occurring, such as a build or a deploy action.らしい。なるほどなるほど

こういうのはインテリセンス見たほうがはやいんですよ

buildevent2.PNG

vsBuildScopeはどうやらバッチビルドなのかソリューションのビルドなのかプロジェクトのビルドなのかを示してるらしい。そのままだったw

buildevent3.PNG

vsBuildActionはどんなビルドだったのかが分かるらしい。これもそのままだったw ていうかよくみたらビルドメニューのドロップダウンと一緒だった

buildevent4.PNG

OnBuildProjConfigDone/Beginイベント

こいつらはOnBuildDone/Beginとほぼ同じタイミング(こっちのが先)で発生するが、ソースコードが変更されたなどでビルドし直さないといけないときにしか発生しない。つまり

buildevent1.PNG

こんな風にビルド時[出力ウインドウ]に正常終了が出てる時しか発火しない。1文字もソースを変更せずにビルドしたときは変更不要になるのでこのイベントは起きない

これに登録できるメソッドは引数が結構多いから下を見てくれ

private void OnBuildProjConfigDoneEvent(
                    string Project,
                    string ProjectConfig,
                    string Platform,
                    string SolutionConfig, 
                    bool   Success
) {
        //挟みこみたい処理
}

割と引数の名前が分かりやすいので何が入ってるかわかる。個人的に重要だと思ってるのは最後のbool値。変数名からわかると思うけどSuccessにはビルドが成功したかが入ってる。今回はこれがtrueの時にメモ帳を起動すればOKということ

というわけでビルド成功時にメモ帳を起動したいなら

private void OnBuildProjConfigDoneEvent(
                    string Project,
                    string ProjectConfig,
                    string Platform,
                    string SolutionConfig, 
                    bool   Success
) {
    if(!Success) return;
    new System.Diagnostics.Process { 
        StartInfo = { 
            FileName = "notepad.exe" 
        } 
    }.Start();
}

たぶんこんな感じになる

イベントハンドラを登録する

作ったメソッドをイベントハンドラとして登録して実際に動かしたい

上4つのイベントはEnvDTE.BuildEventsインターフェイスにあるのでそれをどこからか探してくる必要がある。これにはPackageクラスを継承しているクラスでGetService()メソッドをつかってEnvDTE.DTEインターフェイスを取得してそこから~~・・・・・文章書くのも難しいのでコードを張るね

protected override void Initialize() {
    var dte = (DTE)GetService(typeof(DTE));    //<--DTEインターフェイス取得
    //dteを辿って OnBuildProjConfigDoneにハンドラ登録する。
    dte.Events.BuildEvents.OnBuildProjConfigDone+=OnBuildProjConfigDoneEvent;
}

VSIXを作るとコンストラクタの代わりに上みたいなメソッドを書くのでそこで登録すればいいと思うんだけど、実はこれではダメなんですよ

BuildEventsを持っておかないとダメ

ぼくもこれで動くと思ってたがうんともすんとも言わなくて泣いた。でも色々調べてたら下のにたどり着いた

social.msdn.microsoft.comhttps://social.msdn.microsoft.com/Forums/vstudio/en-US/33ab218f-3e7b-4dd9-b2a2-d5df04fefa6f/why-is-onbuilddone-event-not-firing?forum=vsx

どうやらPackageクラスの継承先で参照を持ってないとダメらしい。VS2017のテンプレで作成したなら{ProjectName}Package.scってソースだ(たぶん)

なので

public BuildEvents BuildEvent {get;set;}
protected override void Initialize() {
    var dte = (DTE)GetService(typeof(DTE));    //<--DTEインターフェイス取得
    //dteを辿ってBuildEvents取得
    this.BuildEvents=dte.Events.BuildEvents;
    //はい
    this.BuildEvents.OnBuildProjConfigDone+=OnBuildProjConfigDoneEvent;
}

これでOK

img

おっ起動したな

OnBuildDoneのときもメモ帳起動したい

今のままだとソースが変更されていて、新たにビルドしたときしかメモ帳が起動しないのは簡単にわかると思う。
ぼくは変更不要の時もメモ帳起動してほしかったのでOnBuildDoneにも登録したかったけど二重起動しちゃうし、そもそもOnBuildDoneは失敗時にも発火するのでダメ!ぼくは成功時だけがいいの!

まあでもこれはboolをフィールドに持っていれば済む話で

private bool lastStatus = true;

private void OnBuildDoneEvent(vsBuildScope sc,vsBuildAction ac){
    if(lastStatus) WakeNotepad();
}

private void OnBuildProjConfigDoneEvent(/* 略 */){
    lastStatus=Success;
}

private void WakeNotepad() => new System.Diagnostics.Process { StartInfo = { FileName = "notepad.exe" } }.Start();

上にも少し書いたけどOnBuildDoneOnBuildProjConfigDoneより後に発火するのでこうやって書ける

これをそれぞれのイベントに登録すればおわり!
BuildEventsを持っておかないとだめっていう罠にどっぷりハマって死んでいたけど、これが分かってしまえば他のイベントでも同じようにすることになるのでやった~~~という感じですね

ちなみに他のイベントをまとめたクラスを作っておくとPackageクラスから参照を渡すだけでいいので楽です

今回はここまで

Visual Studioの拡張機能のテンプレすらビルドできない

VSIXこのやろう

年の瀬にこのやろう

プロジェクトがビルドできない

色々片付いたのでちょっとなんか作ろうと思って、いつもお世話になっておりますVisual Studio拡張機能でも作ろうかとテンプレート使って作成したプロジェクトが・・・・ビルドできない・・・・!ビルドしたら「no resource file set the resource merger」ってだけ出て終わる・・・!つらい・・・!!!環境はVS2017Community 15.5.2

テンプレートすらビルドできないのか僕はと思いつつggってたら全然情報がないことないこと。そもそもVisual Studio拡張機能についての記事すら少なくてくるしい。えいごの記事は目がつかれるし

あ~でもそういえばなんか生成時に 「Key.snkが見つかりません」 とか出てたなあ

Key.snkってなんやねん

アセンブリ署名したときにできるキーペアファイルらしい
https://msdn.microsoft.com/ja-jp/library/6f05ezxy(v=vs.110).aspxmsdn.microsoft.com

Visual Studio拡張機能を作るときはプロジェクト生成時にこれが作られる・・・ハズだけどC:\ProgramData\Microsoft\Crypto\RSA\MachineKeysにアクセス権がないとこれが上手く作れず死亡する。以下が参考
http://blog.sorceryforce.net/?p=912blog.sorceryforce.net

画像は面倒なので貼らないけど無事ビルドできた

早く寝ないとプリキュアがみれない

第32回シェル芸勉強会大阪サテライトに参加した

正規表現ムズい

2017年12月2日に開催された第32回シェル芸勉強会の大阪サテライトに参加してきたのでその時の感想と自分の解答を日記します
techplay.jp

午前中

perl正規表現第3回目
「はあ今日ここでぼくの命の輝きも終わりかあ」と会場ついたときには思いましたが、講師の方がすごくわかりやすく教えてくれたので延命できた
perl正規表現がDFSで実装されてるので遅いという話はとてもおもしろかった

その他も強力な正規表現のオンパレードで確かにこれを習得すればシェル芸力が跳ね上がりそう...(永遠に無理)

午後

「今回の問題はヤバい」とTwitterで見ていたのでめっちゃくちゃ身構えて行きましたがいつもより時間内に解けた問題が多かったのでうれC
問題と想定解答は以下にあるよ
【問題と解答】jus共催 第32回全くインスタ映えしないシェル芸勉強会

Q1

echoされた10までの数字列に含まれない奴を歯抜けにして縦に出力する問題。のっけからパズル

僕の答え

echo 14679|grep -o .|diff - <(seq 1 10) -y|awk '{print $1}'|tr -d '>'

diff-yで左右にどーんとすればいいかなーと思って素直に
競プロでいう「はい」って感じの解法だった。はい

Q2

Q1の出力で歯抜けになっているところをa,b,c....と埋めていく問題

僕の答え

echo 14679|grep -o .|comm - <(seq 1 9)|cut -f3|awk 'BEGIN{c=97}{if($1==""){printf "%c\n",c++}else{print $1}}'

前問の答え合わせのときに知ったcommコマンドを使ってみた。diffの表示がわかりやすい版見たいな感じだ
問題の解答はawkprintfaから順番に出していくだけになった。awkゴリゴリ
これも割とやさしい

Q3

/etc/servicesから素数TCPポート番号をもつサービスだけ取り出す問題。でたよ素数
シェル芸で素数といえばfactorを使って素因数分解の結果を得た後、awkでフィールド数を数える方法があまりにも有名

#素数だろうか?
echo 17 | factor | awk 'NF==2{print}'

これを使ってポート番号が素数かどうか判定してechoすれば良さそうということで以下が僕の答え

僕の答え

cat /etc/services | grep /tcp|awk '{print $1" "$2}'|sed 's|/tcp||g'|while read L;do x=$(echo $L|awk '{print $2}'); [ "$(echo $x|factor|awk 'NF==2{print}')" != "" ] && echo "$L"; done|awk '{print $1}'

うーんゴリゴリwhile read LINE;
後で気づいたけどreadは二つでもフィールドを読めるのでx=の部分はいらなかった

Q4

入力

136
725
948

9
7
4
1
2
8
3
5
6

に変換する問題。読解がちょっと難しいけど、9から斜めに出力していくということ

僕の答え

頭のいい解答が思いつかなかったのでちょっとセコい方法で

cat ./nums.txt |xargs|tr -d ' '|python -c "x=input();l=[6,3,7,0,4,8,1,5,2];
for i in l:
    print(x[i])
"

3x3の入力をxargstrで1列に整形してから6,3,7,0,4,8,1,5,2の順番に出力した出力自体は何でもよかったけどpythonを使った
ワンラインじゃないけど....いいでしょたぶん....
こんなんじゃなく賢いやり方をみると「ほぉぉ〜〜」ってなるのがシェル芸勉強会のおもしろい所の1つだとおもいます

Q5

テキストファイルからウムラウトだけを抽出する問題。なんやこれ....
ちなみにウムラウトってのは文字の上に点々がついてるアレ
時間内に解けたのはここまで

僕の答え

cat ./umlaut.txt |xargs|tr -d ' '|csharp -e 'foreach(var c in Console.ReadLine().Where(x=>x>=196&&x<12450)) Console.WriteLine(c)'

ウッ...!C#!方針としてはアスキーコードを見てある範囲内ならウムラウトだとするようにしたWhereで削ってWriteLineするだけ
csharpコマンド楽しいのでぜひインストールしよう

Q6

誰かのTwitterをターゲットにして新しい投稿がある度に端末上に「んほぉ!」と出力する問題。なんやこれ....なんやこれ...
曰く急に生徒がこなくなったときこれがあれば生きてるかどうか分かるらしい...ホンマか

この問題は時間内に解けなかったので解答はなし。w3mですくれいぴんぐ?して総ツイート数を比較するらしい
wgetで同じことしようとしてたがうまく抽出できず...!無念!!

Q7

縮小をする画像処理アルゴリズムワンライナー化問題。普通にスマートなやり方はない
C#でゴリゴリやればできると思うけどめっちゃ長くなって読みにくいしバグらせるしモウダメ...となってるうちに時間切れ

Q8

満身創痍で挑むラスト問題はカタカナや漢字が行頭にくるようなワンライナーを考える問題。
ただし「シェル芸」みたいなものは1つの単語としてカウントすること。なんやのこれ...

午前中に覚えたperl正規表現\p{Hiragana}\p{Han}\p{Katakana}を使ってやるだけかと思ったが「シェル芸」を一塊にできず時間切れ。なんやこれ

LT

今回もLTまで参加させてもらった。毎回「ほえ〜〜〜」となる話とかが多くて楽しい

発表者の紹介とかは上のYoutubeにお任せします★

一番目はinterdiffというコマンドの紹介
最初はdiffのバイナリのdiffをとる話なのかと思って「何を言ってるんだ...」と思ったけどそうじゃなくてよかった。まともな人でよかった
diffの意味分からん表示じゃなくてわかりやすくdiffをとってくれるのですごい便利という話だった

二番目は僕
bindを使って危険シェル芸をするはなしをした


難読化のつもりで始めたけどそうならなかったのでこうなった(?)

三番目は非公開でとのことだったので詳細は話せないけどふとした瞬間にシェル芸を発動できる素敵な話だった
次のLTでは準備万端でお話ししていただけるらしいので超楽しみだ

四番目はsedで寿司を回すお話だった
何が起きているのか分からなかったけどsedマスターの発表者が解説してくれたのでわかった(わからない)
sedってすごいなあ...という気持ちで支配されたLTだった

まとめ

今回もはちゃめちゃでおもしろかった。シェル芸自体は去年の今頃に存在を知り、今年の6月ごろに勉強会に初参加させていただいた新参者なのでまだまだ精進するぞと言う気持ち

また機会があれば参加したいな〜と思っています。よろしくお願いいたします。

お前らのWSLはそれじゃダメだ

OIT Advent Calendar 2017!!!

2023/10/12 追記 この記事は2017年現在のものなので、今は参考にしないほうがいいと思います

この記事は、 OIT Advent Calendar 2017の1日目の記事です
adventar.org

わーいあどべんとだー

OIT Advent Calendar が今年もやってきた!
募集を観測してから1秒でアクセスし1秒1日目に予約してやったぜ

因みに去年も1日目だったんですよ~
adventar.org

ていうかもう12月?はやくない?

本題

Bash on Windowsが2016年の4月に来たときめちゃくちゃ嬉しかったことを覚えています

それからしばらく経った2017年の10月末にWindows10のFall Creators Updateがきました。BoWの名称はWindows Subsystem for Linux(WSL)へと変わり、正式版になったことでWindows上でシェル芸をするときの選択肢が増えましたね。非常に嬉しいです

自分はSurface3を持ち運び用にしてますが容量の都合とかでデュアルブートするのしんどいし、なによりWSLは破壊してもすぐなおせるところがいいですよね!最高!

でも

ターミナルエミュレータがイケてない

BoWだった時も思ってたんですけどぉ…Windows環境ってぇ…
ほんッとターミナルがイケてない!

イケてない

  • イケてないお前らのWSL
    omaerawls

僕は違いますよ! - イケてるぼくのWSL
bokunowls
やった~~~~~かっこいい~~~~~WSLしゅき~~~~!

もうひとつ mate-on-wsl
Ubuntu MATE on WSL
同じやり方でmate-sessionだって起動する

DEほどの機能がいらなければawesomeみたいなウインドウマネージャーを起動すればいいね awesome-on-wsl

これで楽しいWSL生活!

環境構築

材料

  • Fall Updateした後のWindows10
    • めっちゃじかんかかった
  • Windows向けX server
    • 今回はVcXsrvを使用。Xmingがいいならそっちでもいいけど解説はないよ
  • WSL
    • ストアから落とそう
  • ggる力
    • 目の前の箱はおもちゃか?

VcXsrvのインストール

sourceforge.net
特にインストールするときにggった覚えがないのでポチポチでインストールできるハズ・・・

WSLの用意

OpenSUSEとかもあるけど今回は普通にUbuntuを使う
Microsoft StoreでUbuntuと検索すればすぐ出てくるからインストールする

終わればスタートの最近追加されたものの項目にUbuntuが出てくるだろうからそれをクリック。みつからないならCortanaにUbuntuどこですかって聞こう
whereisubuntu

クリックしたらインストールの続きが始まるので少し待つ、それが終わるとユーザー名とパスワードを聞かれるので入力。好きなのでいいと思うよ

少し上のお前らのWSLになったら 定番のアップデートをする

sudo apt update && sudo apt upgrade -y

思ったより時間はかからないと思うぜ!

この先は自分の好きなように選んでほしい、DEやWMはいらんから端末だけほしい!とかDEごとほしい!とか自分のニーズに合わせてインストールしよう。全部やると時間かかるよ

日本語化

WSLになってからデフォだとえいごだからJP語にする。したい人はしたらいいぼくはする

sudo apt install language-pack-ja
sudo update-locale LANG=ja_JP.UTF-8

端末だけ使う

インストール

好きな端末を選べばいいと思うけど、ここではgnome-teminalをインストールする

sudo apt install -y gnome-terminal uim-fep uim-anthy dbus-x11

(2017/12/07 誤字ってたので修正)

gnome-terminalと一緒にuimをインストールして日本語入力できるようにする
日本語入力する予定がないならuim系はインストールしなくてもOK
dbus-x11は・・・知らん・・・ないと動かなかった
ここが結構時間かかるので気長に待ちましょう

終わったらuimの設定を書く

cat << EOF > ~/.uim
(define default-im-name 'anthy)
(define-key generic-on-key? '("<Control> "))
(define-key generic-off-key? '("<Control> "))
EOF

これでgnome-terminalを使っているときに、Ctrl+Spaceで日本語入力の切り替えができるようになった
もしここを変えたいとかなら<Control>の部分を書き換えればOK!
一応情報置いときますね
github.com

もしかしたらXMODIFIRESを設定しないとダメかもしれない

export XMODIFIRES=@im=uim

自分の場合はしなくもOKだった。これってxtermとかだといるのかな?

起動テスト

とりあえず起動するか確かめる

  • VcXsrvの起動
    • CortanaにVcXsrvどこですかって聞いて起動する
    • タスクトレイに下図赤丸のアイコンがあればOK!
      • vcxsrv
  • gnome-terminalの設定
    • 下のようなコマンドを入力する
export DISPLAY=:0.0
gnome-terminal -e uim-fep
#上がダメなら
dbus-launch gnome-terminal -e uim-fep
#それでもだめなら
sudo service dbus start && dbus-launch gnome-terminal -e uim-fep

たいていの場合1つ目で起動する・・・dbusを感覚で使っているので細かいことは解らないけどserviceの起動まではしなくていいはず

ちょっと待つと起動すると思う

起動したら

毎回起動時にexportするのはだるいので少しVBとPSスクリプトを書くと楽になると思う

  • wsl-terminal.vbs
Set ws = CreateObject("Wscript.Shell")
ws.run "powershell -NoProfile -ExecutionPolicy Unrestricted .\launch.ps1",0,false
  • launch.ps1
ubuntu.exe -c "gnome-terminal --display=:0.0 -e uim-fep"

ファイル名なんかは適当でいいけど 「同じ場所に置くこと」「vbsの方に書いてあるps1ファイルの名前」 だけは気を付けること
二つ作るのはめんどい!って人はVBの方に纏めちゃってもいいんじゃないかなpowershell -c 'command'みたいな感じに

作ったら vbsの ショートカットを作る
vbsshortcuts

これをWindowsC:\Users\USER\AppData\Roaming\Microsoft\Windows\スタートメニュー\プログラムに置く! これでスタートメニューに登録されるので、ピン止めするなりすれば起動が簡単になるよ

後はショートカットのアイコンをIconfinderなんなりから探してきて
www.iconfinder.com

ショートカットのプロパティのアイコンの変更から好きなアイコンを選べば素敵な環境の出来上がり!やったね
term-icon

ここでショートカットにショートカットキーを割り当てておけばいつものようにCtrl+Alt+Tで起動できてワクワクドキドキ

あとは好みで配色を変えて楽しんでね
github.com

同じやり方で別の端末をインストールすれば、↑のコマンド群のgnome-terminalの部分を置き換えると同じように起動すると思う
因みに自分はTilixが好き
gnunn1.github.io

DEを起動したい

DEってのはDesktop EnvironmentのことつまりUnityとかKDEみたいなデスクトップ環境。どうでもいいけどenvironmentってスペル難しい

先に行っておくとDEはちょっと不安定で、フルパワーで使えなかったりTabBackSpaceを押すとたまに爆発(後述)したりするから注意。とはいえVMじゃない?のにVM感?が味わえて楽しいのでオヌヌメ
当然DE内ならGTKとかのテーマも使えるから
Windowsの見た目、嫌いじゃないけど飽きたよ」
という人にもオヌヌメ

それじゃあ自分の好きなDEを選んでやってみよう。今回はMATEデスクトップをインストールする
ubuntu-mate.org

インストール
sudo apt install mate-desktop-environment-extras ubuntu-mate-core ubuntu-mate-desktop -y

さすがにDEともなるとインストールに時間がかかる。それを見越して軽量なMATEにしたけどうむむという感じ
もしかすると単純にmase-sessionを起動するだけならmate-desktopをインストールするだけでいいの・・・・かなあ?
上のコマンドだけしか試したことがないので是非いろいろ試して教えてほしい

起動テスト
  • VcXsrvの起動
    • CortanaにXLaunchどこですかって聞いて起動する。アイコンがVcXsrvと同じなのでちょいとややこしい
    • 下図3枚のように設定して
    • xlaunch-1
    • xlaunch-2
    • xlaunch-3
    • 完了を押す。ここでコンフィグを保存しておけばこの設定でVcXsrvを起動するショートカットみたいなのが作れるので毎回設定しなくてよくなる。
      • ぼくは保存してるけど毎回設定して起動してる・・・もうだめかもしれない
    • タスクトレイに下図赤丸のアイコンがあればOK!
      • vcxsrv
  • mate-sessionの起動
export DISPLAY=:0.0
mate-session

めっちゃログが流れた後VcXsrvにMATEデスクトップが表示される。エラーも表示される
mate-error

きみはほうこくしてもほうこくしなくてもいいぞ。ぼくはしない

起動したら

terminalだけのときと同じように起動スクリプトを作っておけば楽になる
ほぼおんなじで二度手間だけど

  • mate-on-wsl.vbs
Set ws = CreateObject("Wscript.Shell")
ws.run "powershell -NoProfile -ExecutionPolicy Unrestricted .\launch-mate.ps1",0,false
  • launch-mate.ps1
ubuntu.exe -c "mate-session --display=:0.0"

後の手順はterminalのときと同じ、DEの方はテーマを変えたりするだけ、どこまでできるかわからないけど大抵のことはできると思う

備考
  • 日本語入力
    • 日本語環境に設定しててもMozcが最初からないので自力でMozcを入れるかuim-fepで代用するといいよ。僕は後者
  • ターミナルTabBackSpaceを押すと画面がちらつく
    • どんまいです。ぼくもよくわからないけど何度かVcXsrvごと再起動するとなおる
    • タイミング的に音の鳴るときな気がするからターミナルのベルを切ると発生しないかもしれない。自分はこうしてからあんまり遭遇してない

ウィンドウマネージャーを起動する

WMだけを起動する場合もDEとほぼ同じ・・・というか同じ手順をすればいいよ
これは結構安定しているのかも

ここではawesomeをインストールする

awesome wm

github.com
いわゆるウインドウマネージャーってやつ。Archとか使ってる人がよくこういうのを色々試してる印象

awesome は設定範囲が広い、X の次世代型ウィンドウマネージャです。非常に高速に動作で、拡張性があり、GNU GPLv2 でライセンスされています。 Arch Wiki

らしい。次世代型かぁ・・・!惹かれますね

インストール

もちろんaptでインストールできるんですが、このUbuntuは16.04なのでawesomeのバージョンがちょっとふるい(v3.5.9)
最新はv4.2なのでそっちをインストールしたいなあ・・・
github.com
というかこれが使いたい

ビルドしてもいいんですが面倒なのでaptにまかせたいな~~とlaunchpad探してたら
launchpad.nethttps://launchpad.net/~klaus-vormweg/+archive/ubuntu/awesome

ありました
手順は書いてあるので二度手間ですがコピペ用にどうぞ?

sudo add-apt-repository ppa:klaus-vormweg/awesome  &&  sudo apt update  && sudo apt install -y awesome

インストールが終わったらDEのときと同じ設定でVcXsrvを起動してから

export DISPLAY=:0.0
awesome
#もしくは
awesome --display=:0.0

で起動します

GTK Themeを適用したい

これは主にターミナルだけのやつ
ここまで僕のやることを素直に受け入れてきた人はおそらくウインドウのタイトルバーがWindowsのままだったり、Defaultの色が白背景だったりでちょっとイケてない(白背景をDisってるわけじゃない)
じつはVcXsrvみたいなXserverを使った場合でも有志が作ったGTK Themeを適用出来たりできなかったりする
GTK2.0なのかGTK3.0なのか、タイトルバーを上書きしてるのかとかで適用範囲は変わる・・・と思う
この辺の難しいことは解らないので誰か教えてほしいかも

自分の場合は先述のようにTilixを使ってるのでGTK+ 3のテーマなら使える
Tilixはタイトルバーを上書きしてるのでそこもThemeの適用範囲になる。やったね

というわけで目指すのはこれ
gtkthemetilix

好きなテーマを探す

たぶんgnome-lookで探すのがいい。というかここしかしらない
www.gnome-look.org

ぼくはこれ
github.comhttps://github.com/LinxGem33/OSX-Arc-Darker
別にOSXが好きとかじゃないけど、黒系ならカッコいいし、人気だし、使いたくなるからこれを使ってる。後インストールが楽

テーマをインストールする

基本的にはダウンロードしてきたやつを/usr/share/themes/に置けばOKのはずなんだけど上手くいったためしがないんだ・・・ごめんよ
OSX-Arcのように丁寧にパッケージが用意されてるならそれ展開すればいいでしょう
以下はその手順

mkdir ~/tmp && cd tmp
wget https://github.com/LinxGem33/OSX-Arc-Darker/releases/download/v1.4.5/osx-arc-collection_1.4.5_amd64.deb
sudo dpkg --install ./osx-arc-collection_1.4.5_amd64.deb && rm ./osx-arc-collection_1.4.5_amd64.deb

テーマを適用してアプリケーションを起動する

developer.gnome.org
ここみたらどうやらGTK+3だとGTK_THEMEに適用したいテーマ名を書くだけで良しなにしてくれるらしきことが書いてあった
なので

GTK_THEME=OSX-Arc-Shadow tilix

とすればテーマが適用されてTilixが起動する
テーマの名前は/usr/share/themes/lsすればわかるよ

GTK2だと~/.gtkrc-2.0を書く必要がある
テーマだけをあてるなら

echo 'gtk-theme-name="BlackMATE"' > ~/.gtkrc-2.0 #BlackMATEのところに好きなテーマの名前を書く

としたあと

mate-terminal

すればOK、たぶんタイトルバーはWindowsのままだと思うけどドロップダウンメニューとかはテーマが適用されてるはず
gtkthemetilix
こんな感じになってるんじゃないかな?

タイトルバーに関しては適用される方がいいのかは正直解らない、Tilixはタイトルバーが上書きされて見た目はハッピーだけど最大化ボタンが死ぬので大きくするときが面倒になる

それと一応.gtkrc-2.0でフォントの設定とかもできるけどその辺はここでは書かない・・・(ggって)

解像度とか

なんか少しぼやけるときは下記を参考にDPI設定をするといいかもしれない
qiita.com
surface3ではぼやけてたからDPI設定したら綺麗になった(というより見た目が小さくなった)

WindowsLinuxを同時に使いたいなら

WindowsLinuxを同じPCで共存させる方法ってのは、マシンスペックに余裕のある人はVM、HDDに余裕のある人ならデュアルブートとかだったけど、そのどちらもないSurface3だとこのWSLはすごくありがたい、ubuntu側からならwindows見えるし

他にもwubiuefiを使って簡単にデュアルブートしたりとか、X2GoつかったりDockerコンテナにSSHしてX11フォワーディングするとかいろいろあるので試したいなあって思ってます
github.com
www.youtube.com
qiita.com

まとめ

正直なところライトな使い方をするならcmdとかpowershellから使うだけでいい。けどtmuxとかマルチバイトでずれたりするしイケてないよねってことでこれをしばらく試していた(Fall Update以降はcmdでもずれなくなった・・・?)

参考になる記事が沢山あったので色々試してたらDEまで起動してちょっとびっくりしたし、いかに自分がLinuxを雰囲気で使ってるのかっていうのも解った。雰囲気じゃなくて完璧に使えるようになるのはむり・・・あきらめたくないけどむり

自分はgnome-terminalが起動した時点で「勝った!」と思ったのでこれ以上のことをあんまり調べていないんですが・・・
win
飛び跳ねながらいろいろ設定してたらだんだん重くなってきてsurfaceではpowerline-daemon起動してても重いという状況なのでちょっと整理したいな~なんて

自分はこういう設定で運用してるよ!とかGoodな情報があればぜひ教えてもらいたいです

それではよいWSLライフを

参考

mjhd.hatenablog.com
www.hiroom2.comhttps://www.hiroom2.com/2017/07/27/ubuntu-1604-mate-ja/
Arch Linux JP Project
qiita.com