TIL

Today I Learned. 知ったこと、学んだことを書いていく

2019/03 記録

今月の出来事

  • fish入れようとして失敗した
  • gorilla.vimにいった
    • ujihisaさんにあって、すごいってなった.
  • 実践Vimを少しずつ読もうとして、やめちゃったこと
  • Pythonチュートリアルの本を買って、一通り読んだ
    • 実際にアウトプットするべき。そうしないと身につかない
  • flaskでLINEBot作った
    • pillowで画像加工
    • heroku
  • deniteのSource作成したい
    • Shougoさんにフォローされた
    • 4月になったらやるぞ!!
    • 小さくやっていこう
      • まずはmemobook.nvimを固めていく
  • hugoやろうとしてやめた(deniteのSourceに使えるかもと思ったけど、そこまでガチガチにやらないから)
  • Goやろうとしてやめた
    • 作りたいものがないから
    • Pythonだと、Neovimのプラグインを書けるから楽しい
      • 作りたいものがないとできないのはやばいかも...?
      • 学ぶことを楽しむ。知れることを楽しむくらいじゃないと!
  • Google翻訳をするNeovimのプラグインを作った

やろうと思ってやめたこと

  • fishのセットアップ
  • Goの学習
  • 実践Vimを少しずつやろうと思ってやっていない
    • 本当に小さくでいいからやろう

できたこと

読んだ本

  • チーズはどこへ消えた?
    • 変化に応じて、自分も変わることの重要性
  • 仕事と人生を激変させるなら99.9%アウトプットを先にしなさい
    • 最低限の知識を得たら、すぐに行動する。行動しながら足りないところを学んでいく
    • どんどん行動する
  • ざんねんな努力
    • 小さく初めて、やり始める意志の力を少しずつ小さくしていく
    • SNSで宣言し、やるしかないという状況を作ることで、行動ができる
    • 毎日、少しずつやる。苦痛にならないようなくらいの小さなことでいいから毎日やる。継続することが大事。

やっていること

  • Neovimのプラグイン作り
    • 少しずつVimを楽しんで、学んでいく
  • Linucの勉強

2019年4月にやること

ゴリラ.vim#2に参加した

第2回ゴリラ.vimに参加してきました!

ujihisaさんのライブコーディングが自分にとってはすごい参考になりました。 まず、関数のインターフェースを書く。呼び出しを書く。そして、「関数の実装、QuickRunで実行」を繰り返す。 書いていたのはVim scriptだったけど、Pythonでも同じように書いていけそうです!

UniteとVim shell(?)を使ったvim操作が華麗だった。 Uniteの後続のDeniteというものを使ってみようと思います。

懇親会では、ujihisaさんに「Vimではやらない方がいいこと。また、Vimではなく、IDEを使った方がいいことはありますか?」と質問してみたところ、「Webブラウジングくらい」と言っていました(半分冗談かもしれないですが…)

Vim最強では…!?

moppさんの発表で、社内でvimrcを読み合うという、とても楽しそうなことをしていて、正直、「羨ましい」と思いました。自分の会社でもVim活せねば…

また、気になるキーマッピングが2つありました。

選択範囲での検索

vnoremap / <Esc>/\%V

選択した文字列を指定の文字列で置換

vnoremap <C-R> "hy:%s/\V<C-R>h//g<left><left>

\Vで文字列そのものを検索できるのすごい便利!!!

今回の発表内で何回か「実践Vim」の話が出てきていました。自分はKindle版で買って放置していたので、また読み直してみようと思います!

今回もとても楽しいゴリラのセミナーでした!

次回の開催予定は4/18(木)らしいです!

https://gorillavim.connpass.com/

会場を提供してくださったQuipper Ltd様、ゴリラさん、登壇してくださった方々、楽しい時間を本当にありがとうございました!

また、会場スポンサー、登壇者を大募集しているそうです!

ゴリラ.vim #1に参加してきました

昨日、ゴリラ.vim #1に参加してきました。

https://gorillavim.connpass.com/event/119276/

ゴリラさんのvimへの熱意が伝わってきました。

ゴリラさんが、

「mattnさんみたいになります」

と宣言していたのかすごい印象的でした!

自分も、ゴリラさんみたいに行動力ある人になりたい。じゃなくて、行動力がある人になるぞ!

発表では、自分の知らないvimを見ることが出来たので、楽しめました!

また、発表中にQuickRunを使っている方がいて、コードがあんなに簡単に実行できていて、発表を見ながら感動してました! 早速インストールして、使ってます!!

懇親会では、TwitterGitHubで見るすごい方々と直接お話させたいただくことが出来ました。

懇親会で、ほかの方が「vimは最高のREPL。vimscriptを書いたら、そのままエディタが実行してくれるんだよ?」って、言っていて、「たしかに」って納得してしまいました。

また、会場を貸してくださった株式会社ディー・エヌ・エー様さん、主催者のゴリラさん、登壇してくださった方々、とても楽しい勉強会をありがとうございました!!

次回の日程が決まっているそうなので、立ち見でもいいので参加したいと思います!!

https://gorillavim.connpass.com/event/121394/

会場スポンサー、登壇者を大募集していそうです!!

文字列からクラスのインスタンスを生成 - VB.NET

例) ProjectName.Personインスタンスを生成したい

生成対象のクラス(ProjectName.Person)

Public Class Person
    Public name As String

    Public Sub New()
        Me.name = "hoge"
    End Sub

    Public Sub New(ByVal name As String)
        Me.name = name
    End Sub
End Class

生成するメインモジュール

Module Module1

    Sub Main()
        Dim personType As Type = Type.GetType("ProjectName.Person")
        ' 引数なしのコンストラクタ
        Dim personConstructor As ConstructorInfo = personType.GetConstructor(Type.EmptyTypes)
        ' Stringの引数を持つコンストラクタ
        Dim personConstructor2 As ConstructorInfo = personType.GetConstructor(New Type() {GetType(String)})

        Dim personClassObject As Object = personConstructor.Invoke(New Object() {})
        Dim personClassObject2 As Object = personConstructor2.Invoke(New Object() {"太郎"})

        Debug.Print(personClassObject.name)
        Debug.Print(personClassObject2.name)
    End Sub

End Module

出力結果

hoge
太郎

ポイント

  • Type.GetType()でクラスの生成
  • {Type}.GetConstructor()でコンストラクタの生成
    • 引数なしの場合、Type.EmptyTypes
    • 引数ありの場合、Typeインスタンスを生成し、渡す
  • {ConstructorInfo}.Invoke()インスタンスの生成

参考文献

頭に来てもアホとは戦うな! を読んで

読み終わったから、アウトプットする

Before

  1. 他人にどう思われるかを気にして、行動していた
  2. 自分はできる人だと思いこんでいた

気づき

1. 他人にどう思われるかは気にせずに行動してみる

他人からどう見られるかは、人生の最後から逆算すればどうでもいい途中経過

人生の終りがあると考えると、やりたいことは今すぐにすべき。

他人にどう思われようと構わずにやりたいことをやるべき。

つまらない意地とかプライドは人生で全く意味のないこと

2. 等身大の自分を知るために、行動する。そして、等身大にあった目標を立てる

等身大の自分を知ること(自分を見失わないこと)

常に等身大の自分を見つめて、それに基づいた正しい目標を設定し、成長していく

自分の力を過信しない。たまたま、なにか成功したからと言って、調子に乗らない。それはただの途中経過で、目標はその先にある

3. 気まずいときこそ、コミュニケーションを取る

これがこの本を読んで一番の収穫

もし、気まずいときにコミュニケーションをしないと、事態は悪化するしかなくなってしまう。
お互いに最悪のシナリオで深読みし合うしかなくなる

コミュニケーションを取らないと、この深読みの負のループに入ってしまい、相手の何気ない行為にも、悪気のある行為であると思いこんでしまい、最終的には衝突してしまう。

最低限のコミュニケーションを取り、相手に敵意はないことを伝えて、これ以上関係を悪化させないようにする

Neovim内で使うpythonをpyenvのアクティブなものにする - Neovim

g:python3_host_progに値をセットする(Python3の場合)

g:python3_host_progに値をセットすると、neovim内で実行するpython3を指定できる

pyenvのアクティブなPythonを使うようにするには、以下のように~/.config/nvim/.init.vimに書く

let g:python3_host_prog = system('type pyenv &>/dev/null && echo -n "$(pyenv root)/versions/$(cat $(pyenv root)/version | head -n 1)/bin/python" || echo -n $(which python)')



メモ書き

:checkhealthしたときのメッセージ

## Python 3 provider (optional)
  - INFO: `g:python3_host_prog` is not set.  Searching for python3 in the environment.

:help g:python3_host_progしてみた

PYTHON PROVIDER CONFIGURATION ~
                        *g:python_host_prog*
                        *g:python3_host_prog*
Program to use for evaluating Python code. Setting this makes startup faster.
Also useful for working with virtualenvs.  >
    let g:python_host_prog  = '/path/to/python'
    let g:python3_host_prog = '/path/to/python3'

Pythonコードを評価するためのプログラム。 これを設定すると起動が速くなります。

virtualenvsでの作業にも便利です。

.vimrcに以下の記述を追加する

参考文献

prompt-toolkitで検索ツールバーの実装と、インクリメンタル検索の実装した - Python

いろいろやって、できたから、まとめてみる

ソースはGistにあげた

https://gist.github.com/tamago324/806aac08455412d06b48b7022f5b660f

2018-11-16 00:21:49 編集:カレントバッファで検索結果の移動をするように変更

単純な検索機能を実装する

まずは、単純な検索を実装する

  • /で検索の文字入力開始
  • ?で検索の文字入力開始(逆順に検索)
  • Enterで検索実行
  • c-cで検索入力中止
  • 検索文字が0文字になったら、検索入力中止
  • nで次の検索位置
  • Nで逆順に次の検索位置

今は、ReadOnlyの想定で作ったから、nとかNとか入力できないのは気にしない

from prompt_toolkit.application import Application
from prompt_toolkit.application.current import get_app
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.filters import Condition, is_searching
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.key_binding.bindings import search
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.widgets.toolbars import SearchToolbar


text = "\n".join([str(i) for i in range(100)])

# vi_mode=Trueとすると`/`と`?`で表示されるようになる
search_toolbar = SearchToolbar(vi_mode=True)
control = BufferControl(
    Buffer(document=Document(text), read_only=True),
    search_buffer_control=search_toolbar.control,
)


# ウィンドウ
body = HSplit([Window(control), search_toolbar])

# キーバインディング
kb = KeyBindings()


@kb.add("q")
def _(event):
    event.app.exit()


# 検索ツールバーの文字が空になったかどうか
@Condition
def search_buffer_is_empty():
    " Returns True when the search buffer is empty. "
    return get_app().current_buffer.text == ""


kb.add("/")(search.start_forward_incremental_search)
kb.add("?")(search.start_reverse_incremental_search)
kb.add("enter", filter=is_searching)(search.accept_search)
kb.add("c-c")(search.abort_search)
kb.add("backspace", filter=search_buffer_is_empty)(search.abort_search)


@kb.add("n", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position

@kb.add("N", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        ~search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position


app = Application(layout=Layout(body), key_bindings=kb, full_screen=True)

app.run()

ptkのソースのprompt_toolkit.key_binging.key_bingings.vi.load_vi_search_bindingsとか、サンプルとかがすごい参考になった

https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/prompt_toolkit/key_binding/bindings/vi.py#L1815-L1853

https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/examples/full-screen/text-editor.py#L250-L255

実装手順

SearchToolBarインスタンスつくって、BufferControlsearch_buffer_controlに作ったインスタンスcontrolを渡す。(検索ツールバーの紐付け?)

search_toolbar = SearchToolbar(vi_mode=True)
control = BufferControl(
    Buffer(document=Document(text), read_only=True),
    search_buffer_control=search_toolbar.control,
)

/で前方検索の開始

kb.add("/")(search.start_forward_incremental_search)

enterで検索実行

kb.add("enter", filter=is_searching)(search.accept_search)

nNで次の検索結果に移動

@kb.add("n", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position

@kb.add("N", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        ~search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position

2018-11-16 00:21:49 編集

current_buffer = get_app().current_bufferにすることで、カレントバッファで検索結果の移動ができるようになる

これで一通りの検索ができるようになった!

実装するときにつまづいたこと

次の検索結果への移動の実装方法がわからなかった

これは、サンプルのtext_editorを見たら書いてあったから、参考にした

https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/examples/full-screen/text-editor.py#L250-L255

def do_find_next():
    search_state = get_app().current_search_state

    cursor_position = text_field.buffer.get_search_position(
        search_state, include_current_position=False)
    text_field.buffer.cursor_position = cursor_position

search_stateを反転させれば、逆に検索もできることをどこかで知って、それも使った。

filters.is_searchingがなんなのかよくわからなかった

いろいろ調べた結果、検索中で、検索対象のコントロールがカレントコントロールの場合、Trueになるってことがわかった

prompt_toolkit.filters.app.is_searchingに以下のように書いてあった

@Condition
def is_searching():
    " When we are searching. "
    app = get_app()
    return app.layout.is_searching

prompt_toolkit.layout.layout.Layout.is_searchingを見てみる

    @property
    def is_searching(self):
        " True if we are searching right now. "
        return self.current_control in self.search_links

prompt_toolkit.layout.layout.Layout.search_linksとは

class Layout(object):
    def __init__(self, container, focused_element=None):
        ...
        # Map search BufferControl back to the original BufferControl.
        # This is used to keep track of when exactly we are searching, and for
        # applying the search.
        # When a link exists in this dictionary, that means the search is
        # currently active.
        self.search_links = {}  # search_buffer_control -> original buffer control.

Map Search BufferControlを元のBufferControlに戻します。 これは、正確にいつ検索しているかを追跡し、検索を適用するために使用されます。 この辞書にリンクが存在する場合、検索が現在アクティブであることを意味します。

検索している時には、get_app().layout.search_linksに検索対象のBufferControlが格納されるから、is_searchingではinで調べる

search_linksを調べてみた

こんな感じのdictになっている

  • Key: SearchBufferControlで、検索文字入力用のSearchBufferControl
  • Value: BufferControlで、検索対象のBufferControl

検索文字列入力中は、current_controlSearchBufferControlになる。search_links[current_control]とすると、それに紐づく検索対象のBufferControlが返される

そのため、is_searchingは、検索文字列を入力しているかどうかということ。(検索ツールバーが表示されているかどうか)

nNが検索文字列入力中に打てなくなってしまった

@kb.add('n')みたいに書いちゃうと、検索するときに、nが打てなくなってしまった。。。そのため、以下のようにする

@kb.add('n', filter=~is_searching)
@kb.add('N', filter=~is_searching)

こうすることで、検索文字を入力していないときのみ、nNのKeyBindingが有効になる

インクリメンタル検索を実装する

検索文字入力中にもハイライト(インクリメンタル検索, incremental search)したかったから、やってみた

from prompt_toolkit.application import Application
from prompt_toolkit.application.current import get_app
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.filters import Condition, is_searching
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.key_binding.bindings import search
from prompt_toolkit.layout.containers import HSplit, Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.styles import Style
from prompt_toolkit.widgets.toolbars import SearchToolbar
from prompt_toolkit.layout.processors import (
    ConditionalProcessor,
    DisplayMultipleCursors,
    HighlightIncrementalSearchProcessor,
    HighlightSearchProcessor,
    HighlightSelectionProcessor,
)

text = "\n".join([str(i) for i in range(100)])

all_input_processors = [
    # 検索モードではないときだけハイライト
    ConditionalProcessor(HighlightSearchProcessor(), ~is_searching),
    HighlightIncrementalSearchProcessor(),
    HighlightSelectionProcessor(),
    DisplayMultipleCursors(),
]

# vi_mode=Trueとすると`/`と`?`で表示される様になる
search_toolbar = SearchToolbar(vi_mode=True)
control = BufferControl(
    Buffer(document=Document(text), read_only=True),
    search_buffer_control=search_toolbar.control,
    preview_search=True,
    include_default_input_processors=False,
    input_processors=all_input_processors,
)


# ウィンドウ
body = HSplit([Window(control), search_toolbar])

# キーバインディング
kb = KeyBindings()


@kb.add("q")
def _(event):
    event.app.exit()


@Condition
def search_buffer_is_empty():
    " Returns True when the search buffer is empty. "
    return get_app().current_buffer.text == ""


kb.add("/")(search.start_forward_incremental_search)
kb.add("?")(search.start_reverse_incremental_search)
kb.add("enter", filter=is_searching)(search.accept_search)
kb.add("c-c")(search.abort_search)
kb.add("backspace", filter=search_buffer_is_empty)(search.abort_search)


@kb.add("n", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position

@kb.add("N", filter=~is_searching)
def _(event):
    search_state = get_app().current_search_state
    current_buffer = get_app().current_buffer

    cursor_position = current_buffer.get_search_position(
        ~search_state, include_current_position=False
    )
    current_buffer.cursor_position = cursor_position


style = Style([("incsearch", "fg:ansibrightyellow reverse")])

app = Application(layout=Layout(body), key_bindings=kb, full_screen=True, style=style)

app.run()

シンプルな検索との違いは

  • Processorのリストを作っている
  • BufferControlのコンストラクタへの引数を追加
  • IncSearch用のスタイルを用意

Processorのリストを作る

all_input_processors = [
    # 検索モードではないときだけハイライト
    ConditionalProcessor(HighlightSearchProcessor(), ~is_searching),
    HighlightIncrementalSearchProcessor(),
    HighlightSelectionProcessor(),
    DisplayMultipleCursors(),
]

何も指定しなくても、デフォルトでこの4つは生成されるが、HighlightSearchProcessorが、デフォルトのままだと検索文字列入力中にもハイライトされてしまうため、(1回目の検索結果が2回目のIncSearchのハイライトの邪魔になる)ConditionalProcessorで検索中はハイライトしないようにした

BufferControlのコンストラクタへの引数を追加

以下の3つを追加した

  • preview_search=True
    • IncSearchの有効化
  • include_default_input_processors=False
    • input_proecssorsで渡したPrcessorのみを有効にしたいため、False
  • input_processors=all_input_processors
    • 適用するProcessorのリストを渡す

IncSearch用のスタイルを用意

style = Style([("incsearch", "fg:ansibrightyellow reverse")])

IncSearch中には、styleincsearchというclassがつくため、それ用のスタイルを定義して、Applicationに渡しておく。

ドキュメントに書いてあった

https://python-prompt-toolkit.readthedocs.io/en/stable/pages/reference.html#prompt_toolkit.layout.processors.HighlightIncrementalSearchProcessor

増分検索を強調表示するために使用される検索条件を強調表示します。 スタイルクラス 'incsearch'がコンテンツに適用されます。

重要:これは、BufferControlにpreview_search = Trueフラグを設定する必要があります。 そうしないと、検索中にカーソル位置が検索一致に設定されず、何も起こりません。

実装してみて

ドキュメントとソースをたくさん読んでて、少しずつわかっていくのがなんか楽しかった。あと、動いたときの嬉しさ半端ない