diff options
Diffstat (limited to 'content/posts/2021-10-02')
7 files changed, 252 insertions, 252 deletions
diff --git a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml index 7f5fc66..3dbb8ff 100644 --- a/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml +++ b/content/posts/2021-10-02/cpp-you-can-use-keywords-in-attributes.xml @@ -16,16 +16,16 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/94090937bcf860cfa93b">https://qiita.com/nsfisis/items/94090937bcf860cfa93b</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> - <simpara> + </para> + <para> タイトル落ち。まずはこのコードを見て欲しい。 - </simpara> + </para> <programlisting language="cpp" linenumbering="unnumbered"> <![CDATA[ #include <iostream> @@ -50,24 +50,24 @@ ]]> </programlisting> <blockquote> - <simpara> + <para> コンパイラのバージョン $ clang++ –version Apple clang version 11.0.0 (clang-1100.0.33.8) Target: x86_64-apple-darwin19.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin - </simpara> - <simpara> + </para> + <para> コンパイルコマンド (C17指定) $ clang –std=c++17 hoge.cpp - </simpara> + </para> </blockquote> - <simpara> + <para> この記事から得られるものはこれ以上ないので以下は蛇足になる。 - </simpara> - <simpara> + </para> + <para> 別件で cppreference.com の <link xl:href="https://en.cppreference.com/w/cpp/language/identifiers">identifier のページ</link> を読んでいた時、次の文が目に止まった。 - </simpara> + </para> <blockquote> <itemizedlist> <listitem> @@ -81,53 +81,53 @@ </listitem> </itemizedlist> </blockquote> - <simpara> + <para> キーワードでも属性として指定する場合は非キーワードとして使えるらしい。 実際にやってみる。 - </simpara> - <simpara> + </para> + <para> 同サイトの <link xl:href="https://en.cppreference.com/w/cpp/keyword">keywords のページ</link> から一覧を拝借し、上のコードが出来上がった (C++17 においてキーワードでないものなど、一部省いている)。 大量の警告 (unknown attribute `〇〇' ignored) がコンパイラから出力されるが、コンパイルできる。 - </simpara> - <simpara> + </para> + <para> 上のコードでは <literal>[[using]]</literal> をコメントアウトしているが、これは <literal>using</literal> キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。 - </simpara> + </para> <programlisting language="cpp" linenumbering="unnumbered"> <![CDATA[ // using の例 [[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文 ]]> </programlisting> - <simpara> + <para> C++17 の仕様も見てみる (正確には標準化前のドラフト)。 - </simpara> - <simpara> + </para> + <para> 引用元: <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4">https://timsong-cpp.github.io/cppwp/n4659/dcl.attr#grammar-4</link> - </simpara> + </para> <blockquote> - <simpara> + <para> If a keyword or an alternative token that satisfies the syntactic requirements of an identifier is contained in an attribute-token, it is considered an identifier. - </simpara> + </para> </blockquote> - <simpara> + <para> 「<literal>identifier</literal> の構文上の要件を満たすキーワードまたは代替トークンが <literal>attribute-token</literal> に含まれている場合、<literal>identifier</literal> とみなされる」とある。どうやら間違いないようだ。 - </simpara> - <simpara> + </para> + <para> ところで、代替トークン (alternative token) とは <literal>and</literal> (<literal>&</literal>) や <literal>bitor</literal> (<literal>|</literal>) などのことだが、<literal>identifier</literal> の構文上の要件を満たさないような代替トークンなどあるのか? 疑問に思って調べたところ、代替トークンという語にはダイグラフも含まれるらしい (参考: <link xl:href="https://timsong-cpp.github.io/cppwp/n4659/lex.digraph">同ドラフト</link>) - </simpara> + </para> <itemizedlist> <listitem><literal><%</literal> → <literal>{</literal></listitem> <listitem><literal>%></literal> → <literal>}</literal></listitem> @@ -136,11 +136,11 @@ <listitem><literal>%:</literal> → <literal>#</literal></listitem> <listitem><literal>%:%:</literal> → <literal>##</literal></listitem> </itemizedlist> - <simpara> + <para> 「<literal>identifier</literal> の構文上の要件を満たさないような代替トークン」はこれらが当てはまると思われる。 - </simpara> - <simpara> + </para> + <para> 調べた感想: 字句解析器か構文解析器が辛そう - </simpara> + </para> </article> diff --git a/content/posts/2021-10-02/python-unbound-local-error.xml b/content/posts/2021-10-02/python-unbound-local-error.xml index 7cf9b1a..bb44a47 100644 --- a/content/posts/2021-10-02/python-unbound-local-error.xml +++ b/content/posts/2021-10-02/python-unbound-local-error.xml @@ -16,19 +16,19 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/5d733703afcb35bbf399">https://qiita.com/nsfisis/items/5d733703afcb35bbf399</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> - <simpara> + </para> + <para> 本記事は Python 3.7.6 の動作結果を元にして書かれている。 - </simpara> - <simpara> + </para> + <para> Python でクロージャを作ろうと、次のようなコードを書いた。 - </simpara> + </para> <programlisting language="python" linenumbering="unnumbered"> <![CDATA[ def f(): @@ -40,22 +40,22 @@ f() ]]> </programlisting> - <simpara> + <para> 関数 <literal>g</literal> から 関数 <literal>f</literal> のスコープ内で定義された変数 <literal>x</literal> を参照し、それに 1 を足そうとしている。 これを実行すると <literal>x += 1</literal> の箇所でエラーが発生する。 - </simpara> + </para> <blockquote> - <simpara> + <para> UnboundLocalError: local variable `x' referenced before assignment - </simpara> + </para> </blockquote> - <simpara> + <para> local変数 <literal>x</literal> が代入前に参照された、とある。これは、<literal>f</literal> の <literal>x</literal> を参照するのではなく、新しく別の変数を <literal>g</literal> 内に作ってしまっているため。 前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。<literal>var</literal> を変数宣言のための構文として擬似的に利用している。 - </simpara> + </para> <programlisting language="python" linenumbering="unnumbered"> <![CDATA[ # 注: var は正しい Python の文法ではない。上記参照のこと @@ -70,9 +70,9 @@ g() ]]> </programlisting> - <simpara> + <para> 当初の意図を表現するには、次のように書けばよい。 - </simpara> + </para> <programlisting language="python" linenumbering="unnumbered"> <![CDATA[ def f(): @@ -83,8 +83,8 @@ g() ]]> </programlisting> - <simpara> + <para> <literal>(*)</literal> のように、<literal>nonlocal</literal> を追加する。これにより一つ外側のスコープ (<literal>g</literal> の一つ外側 = <literal>f</literal>) で定義されている <literal>x</literal> を探しに行くようになる。 - </simpara> + </para> </article> diff --git a/content/posts/2021-10-02/ruby-detect-running-implementation.xml b/content/posts/2021-10-02/ruby-detect-running-implementation.xml index 18548c2..9b59202 100644 --- a/content/posts/2021-10-02/ruby-detect-running-implementation.xml +++ b/content/posts/2021-10-02/ruby-detect-running-implementation.xml @@ -15,29 +15,29 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791">https://qiita.com/nsfisis/items/74d7ffeeebc51b20d791</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> - <simpara> + </para> + <para> Ruby という言語には複数の実装があるが、それらをスクリプト上からどのようにして programmatically に見分ければよいだろうか。 - </simpara> - <simpara> + </para> + <para> <literal>Object</literal> クラスに定義されている <literal>RUBY_ENGINE</literal> という定数がこの用途に使える。 - </simpara> - <simpara> + </para> + <para> 参考: <link xl:href="https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_ENGINE.html">Object::RUBY_ENGINE</link> - </simpara> - <simpara> + </para> + <para> 上記ページの例から引用する: - </simpara> + </para> <programlisting language="shell-session" linenumbering="unnumbered"> <![CDATA[ $ ruby-1.9.1 -ve 'p RUBY_ENGINE' @@ -48,14 +48,14 @@ "jruby" ]]> </programlisting> - <simpara> + <para> それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 - </simpara> - <simpara> + </para> + <para> <link xl:href="https://stackoverflow.com/a/9894232">What values for RUBY_ENGINE correspond to which Ruby implementations?</link> より引用: - </simpara> + </para> <blockquote> <table> <thead> @@ -100,20 +100,20 @@ </tbody> </table> </blockquote> - <simpara> + <para> なお、この質問・回答は 2014年になされたものであり、値は変わっている可能性がある。MRI (aka CRuby) については執筆時現在 (2020/12/8) も <literal>'ruby'</literal> が返ってくることを確認済み。 - </simpara> - <simpara> + </para> + <para> この表にない主要な処理系として、https://mruby.org[mruby] は <literal>'mruby'</literal> を返す。 - </simpara> - <simpara> + </para> + <para> <link xl:href="https://github.com/mruby/mruby/blob/ed29d74bfd95362eaeb946fcf7e865d80346b62b/include/mruby/version.h#L32-L35">mruby 該当部分のソース</link> より引用: - </simpara> + </para> <programlisting language="c" linenumbering="unnumbered"> <![CDATA[ /* diff --git a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml index 00afc01..64851fc 100644 --- a/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml +++ b/content/posts/2021-10-02/ruby-then-keyword-and-case-in.xml @@ -16,26 +16,26 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/787a8cf888a304497223">https://qiita.com/nsfisis/items/787a8cf888a304497223</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> + </para> <section xml:id="tl-dr"> <title>TL; DR</title> - <simpara> + <para> <literal>case</literal> - <literal>in</literal> によるパターンマッチング構文でも、<literal>case</literal> - <literal>when</literal> と同じように <literal>then</literal> が使える (場合によっては使う必要がある)。 - </simpara> + </para> </section> <section xml:id="what-is-then-keyword"> <title><literal>then</literal> とは</title> - <simpara> + <para> 使われることは稀だが、Ruby では <literal>then</literal> がキーワードになっている。次のように使う: - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ if cond then @@ -45,11 +45,11 @@ end ]]> </programlisting> - <simpara> + <para> このキーワードが現れうる場所はいくつかあり、<literal>if</literal>、<literal>unless</literal>、<literal>rescue</literal>、<literal>case</literal> 構文がそれに当たる。 上記のように、何か条件を書いた後 <literal>then</literal> を置き、式がそこで終了していることを示すマーカーとして機能する。 - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ # Example: @@ -77,18 +77,18 @@ </section> <section xml:id="why-then-is-usually-unnecessary"> <title>なぜ普段は書かなくてもよいのか</title> - <simpara> + <para> 普通 Ruby のコードで <literal>then</literal> を書くことはない。なぜか。次のコードを実行してみるとわかる。 - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ if true puts 'Hello, World!' end ]]> </programlisting> - <simpara> + <para> 次のような構文エラーが出力される。 - </simpara> + </para> <literallayout class="monospaced"> <![CDATA[ 20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n' @@ -98,40 +98,40 @@ ...f true puts 'Hello, World!' end ]]> </literallayout> - <simpara> + <para> 二つ目のメッセージは無視して一つ目を読むと、<literal>then</literal> か <literal>;</literal> か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。 - </simpara> - <simpara> + </para> + <para> ポイントは改行が <literal>then</literal> (や <literal>;</literal>) の代わりとなることである。<literal>true</literal> の後に改行を入れてみる。 - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ if true puts 'Hello, World!' end ]]> </programlisting> - <simpara> + <para> 無事 Hello, World! と出力されるようになった。 - </simpara> + </para> </section> <section xml:id="why-then-or-linebreak-is-needed"> <title>なぜ <literal>then</literal> や <literal>;</literal> や改行が必要か</title> - <simpara> + <para> なぜ <literal>then</literal> や <literal>;</literal> や改行 (以下 「<literal>then</literal> 等」) が必要なのだろうか。次の例を見てほしい: - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ if a b end ]]> </programlisting> - <simpara> + <para> <literal>then</literal> も <literal>;</literal> も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。 この例は二通りに解釈できる。 - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価 @@ -148,28 +148,28 @@ end ]]> </programlisting> - <simpara> + <para> <literal>then</literal> 等はこの曖昧性を排除するためにあり、条件式は <literal>if</literal> から <literal>then</literal> 等までの間にある、ということを明確にする。 C系の <literal>if</literal> 後に来る <literal>(</literal>/<literal>)</literal> や、Python の <literal>:</literal>、Rust/Go/Swift などの <literal>{</literal> も同じ役割を持つ。 - </simpara> - <simpara> + </para> + <para> Ruby の場合、プログラマーが書きやすいよう改行でもって <literal>then</literal> が代用できるので、ほとんどの場合 <literal>then</literal> は必要ない。 - </simpara> + </para> </section> <section xml:id="then-in-case-in"> <title><literal>case</literal> - <literal>in</literal> における <literal>then</literal></title> - <simpara> + <para> ようやく本題にたどり着いた。来る Ruby 3.0 では <literal>case</literal> と <literal>in</literal> キーワードを使ったパターンマッチングの構文が入る予定である。この構文でもパターン部との区切りとして <literal>then</literal> 等が必要になる。 (現在の) Ruby には formal な形式での文法仕様は存在しないので、yacc の定義ファイルを参照した (yacc の説明は省略)。 - </simpara> - <simpara> + </para> + <para> <link xl:href="https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986">https://github.com/ruby/ruby/blob/221ca0f8281d39f0dfdfe13b2448875384bbf735/parse.y#L3961-L3986</link> - </simpara> + </para> <programlisting language="yacc" linenumbering="unnumbered"> <![CDATA[ p_case_body : keyword_in @@ -200,25 +200,25 @@ ; ]]> </programlisting> - <simpara> + <para> 簡略版: - </simpara> + </para> <programlisting language="yacc" linenumbering="unnumbered"> <![CDATA[ p_case_body : keyword_in p_top_expr then compstmt p_cases ; ]]> </programlisting> - <simpara> + <para> ここで、<literal>keyword_in</literal> は文字通り <literal>in</literal>、<literal>p_top_expr</literal> はいわゆるパターン、<literal>then</literal> は <literal>then</literal> キーワードのことではなく、この記事で <literal>then</literal> 等と呼んでいるもの、つまり <literal>then</literal> キーワード、<literal>;</literal>、改行のいずれかである。 - </simpara> - <simpara> + </para> + <para> これにより、<literal>case</literal> - <literal>when</literal> による従来の構文と同じように、<literal>then</literal> 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる: - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ case x @@ -243,10 +243,10 @@ end ]]> </programlisting> - <simpara> + <para> ところで、<literal>p_top_expr</literal> には <literal>if</literal> による guard clause が書けるので、その場合は <literal>if</literal> - <literal>then</literal> と似たような見た目になる。 - </simpara> + </para> <programlisting language="ruby" linenumbering="unnumbered"> <![CDATA[ case x diff --git a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml index 7c19fc5..5902450 100644 --- a/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml +++ b/content/posts/2021-10-02/rust-where-are-primitive-types-from.xml @@ -15,19 +15,19 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/9a429432258bbcd6c565">https://qiita.com/nsfisis/items/9a429432258bbcd6c565</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> + </para> <section xml:id="intro"> <title>前置き</title> - <simpara> + <para> Rust において、プリミティブ型の名前は予約語でない。したがって、次のコードは合法である。 - </simpara> + </para> <programlisting language="rust" linenumbering="unnumbered"> <![CDATA[ #![allow(non_camel_case_types)] @@ -52,42 +52,42 @@ struct str; ]]> </programlisting> - <simpara> + <para> では、普段単に <literal>bool</literal> と書いたとき、この <literal>bool</literal> は一体どこから来ているのか。rustc のソースを追ってみた。 - </simpara> + </para> <blockquote> - <simpara> + <para> 前提知識: 一般的なコンパイラの構造、用語。<literal>rustc</literal> そのものの知識は不要 (というよりも筆者自身がよく知らない) - </simpara> + </para> </blockquote> </section> <section xml:id="code-reading"> <title>調査</title> - <simpara> + <para> 調査に使用したソース (調査時点での最新 master) - </simpara> - <simpara> + </para> + <para> <link xl:href="https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98">https://github.com/rust-lang/rust/tree/511ed9f2356af365ad8affe046b3dd33f7ac3c98</link> - </simpara> - <simpara> + </para> + <para> どのようにして調べるか。rustc の構造には詳しくないため、すぐに当たりをつけるのは難しい。 - </simpara> - <simpara> + </para> + <para> 大雑把な構造としては、<literal>compiler</literal> フォルダ以下に <literal>rustc_*</literal> という名前のクレートが数十個入っている。これがどうやら <literal>rustc</literal> コマンドの実装部のようだ。 - </simpara> - <simpara> + </para> + <para> <literal>rustc</literal> はセルフホストされている (= <literal>rustc</literal> 自身が Rust で書かれている) ので、<literal>bool</literal> や <literal>char</literal> などで適当に検索をかけてもノイズが多すぎて話にならない。 しかし、お誂え向きなことに <literal>i128</literal>/<literal>u128</literal> というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って <literal>git grep</literal> してみる。 - </simpara> + </para> <literallayout class="monospaced"> <![CDATA[ $ git grep "\bi128\b" | wc # i128 @@ -100,10 +100,10 @@ 3563 23577 294659 ]]> </literallayout> - <simpara> + <para> 165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。 - </simpara> + </para> <literallayout class="monospaced"> <![CDATA[ $ git grep "\bi128\b" @@ -112,10 +112,10 @@ ... ]]> </literallayout> - <simpara> + <para> <literal>rustc_resolve</literal> というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。 - </simpara> + </para> <programlisting language="rust" linenumbering="unnumbered"> <![CDATA[ /// Interns the names of the primitive types. @@ -152,21 +152,21 @@ } ]]> </programlisting> - <simpara> + <para> これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、 - </simpara> + </para> <blockquote> - <simpara> + <para> All other types are defined somewhere and possibly imported, but the primitive ones need special handling, since they have no place of origin. - </simpara> + </para> </blockquote> - <simpara> + <para> とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。 - </simpara> + </para> <programlisting language="rust" linenumbering="unnumbered"> <![CDATA[ /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. @@ -192,27 +192,27 @@ } ]]> </programlisting> - <simpara> + <para> 関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。 <literal>if ns == TypeNS</literal> のブロック内では、<literal>primitive_type_table</literal> (上記の <literal>PrimitiveTypeTable::new()</literal> で作られた変数) に含まれている識別子 (<literal>bool</literal>、<literal>i32</literal> など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。 - </simpara> - <simpara> + </para> + <para> なお、<literal>ns</literal> は「名前空間」を示す変数である。Rust における名前空間はC言語におけるそれとほとんど同じで、今探している名前が関数名/変数名なのか型なのかマクロなのかを区別している。この <literal>if</literal> は、プリミティブ型に解決されるのは型を探しているときだけだ、と言っている。 - </simpara> - <simpara> + </para> + <para> 重要なのは、これが <literal>resolve_ident_in_lexical_scope()</literal> の最後に書かれている点である。つまり、最初に挙げたプリミティブ型の識別子は、「名前解決の最終段階で」、「他に同名の型が見つかっていなければ」プリミティブ型として解決される。 - </simpara> - <simpara> + </para> + <para> 動作がわかったところで、例として次のコードを考える。 - </simpara> + </para> <programlisting language="rust" linenumbering="unnumbered"> <![CDATA[ #![allow(non_camel_case_types)] @@ -224,17 +224,17 @@ } ]]> </programlisting> - <simpara> + <para> ここで <literal>main()</literal> の <literal>bool</literal> は <literal>struct bool</literal> として解決される。なぜなら、プリミティブ型の判定をする前に <literal>bool</literal> という名前の別の型が見つかるからだ。 - </simpara> + </para> </section> <section xml:id="outro"> <title>まとめ</title> - <simpara> + <para> Rust のプリミティブ型は予約語ではない。名前解決の最終段階で特別扱いされ、他に同名の型が見つかっていなければ対応するプリミティブ型に解決される。 - </simpara> + </para> </section> </article> diff --git a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml index 4e3f187..7e0dd2e 100644 --- a/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml +++ b/content/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre.xml @@ -15,69 +15,69 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/79ab4db8564032de0b25">https://qiita.com/nsfisis/items/79ab4db8564032de0b25</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> + </para> <section xml:id="tl-dr"> <title>TL; DR</title> - <simpara> + <para> 違いはない。ただのエイリアス。 - </simpara> + </para> </section> <section xml:id="code-reading"> <title>調査記録</title> - <simpara> + <para> Vim の autocmd events には似通った名前のものがいくつかある。大抵は <literal>:help</literal> に説明があるが、この記事のタイトルにある2つを含めた以下のイベントには、その違いについて説明がない。 - </simpara> + </para> <itemizedlist> <listitem><literal>BufRead</literal>/<literal>BufReadPost</literal></listitem> <listitem><literal>BufWrite</literal>/<literal>BufWritePre</literal></listitem> <listitem><literal>BufAdd</literal>/<literal>BufCreate</literal></listitem> </itemizedlist> - <simpara> + <para> このうち、<literal>BufAdd</literal>/<literal>BufCreate</literal> に関しては、<literal>:help BufCreate</literal> に - </simpara> + </para> <blockquote> - <simpara> + <para> The BufCreate event is for historic reasons. - </simpara> + </para> </blockquote> - <simpara> + <para> とあり、おそらくは <literal>BufAdd</literal> のエイリアスであろうということがわかる。他の2組も同様ではないかと予想されるが、確認のため vim と neovim のソースコードを調査した。 - </simpara> + </para> <blockquote> - <simpara> + <para> ソースコードへのリンク <link xl:href="https://github.com/vim/vim/tree/8e6be34338f13a6a625f19bcef82019c9adc65f2">vim (調査時点での master branch)</link> <link xl:href="https://github.com/neovim/neovim/tree/71d4f5851f068eeb432af34850dddda8cc1c71e3">neovim (上に同じ)</link> - </simpara> + </para> </blockquote> <section xml:id="code-reading--vim"> <title>vim のソースコード</title> - <simpara> + <para> 以下は、autocmd events の名前と内部で使われている整数値とのマッピングを定義している箇所である。見ての通り、上でエイリアスではないかと述べた3組には、それぞれ同じ内部値が使われている。 - </simpara> - <simpara> + </para> + <para> <link xl:href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L85-L86</link> - </simpara> + </para> <programlisting language="c" linenumbering="unnumbered"> <![CDATA[ {"BufAdd", EVENT_BUFADD}, {"BufCreate", EVENT_BUFADD}, ]]> </programlisting> - <simpara> + <para> <link xl:href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97</link> - </simpara> + </para> <programlisting language="c" linenumbering="unnumbered"> <![CDATA[ {"BufRead", EVENT_BUFREADPOST}, @@ -85,9 +85,9 @@ {"BufReadPost", EVENT_BUFREADPOST}, ]]> </programlisting> - <simpara> + <para> <link xl:href="https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105">https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105</link> - </simpara> + </para> <programlisting language="c" linenumbering="unnumbered"> <![CDATA[ {"BufWrite", EVENT_BUFWRITEPRE}, @@ -98,13 +98,13 @@ </section> <section xml:id="code-reading--neovim"> <title>neovim のソースコード</title> - <simpara> + <para> neovim の場合でも同様のマッピングが定義されているが、こちらの場合は Lua で書かれている。以下にある通り、はっきり <literal>aliases</literal> と書かれている。 - </simpara> - <simpara> + </para> + <para> <link xl:href="https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124">https://github.com/neovim/neovim/blob/71d4f5851f068eeb432af34850dddda8cc1c71e3/src/nvim/auevents.lua#L119-L124</link> - </simpara> + </para> <programlisting language="lua" linenumbering="unnumbered"> <![CDATA[ aliases = { @@ -115,10 +115,10 @@ }, ]]> </programlisting> - <simpara> + <para> ところで、上では取り上げなかった <literal>FileEncoding</literal> だが、これは <literal>:help FileEncoding</literal> にしっかりと書いてある。 - </simpara> + </para> <literallayout class="monospaced"> <![CDATA[ *FileEncoding* @@ -130,9 +130,9 @@ </section> <section xml:id="outro"> <title>まとめ</title> - <simpara> + <para> 記事タイトルについて言えば、どちらも変わらないので好きな方を使えばよい。あえて言えば、次のようになるだろう。 - </simpara> + </para> <itemizedlist> <listitem> <literal>BufAdd</literal>/<literal>BufCreate</literal> @@ -159,10 +159,10 @@ </itemizedlist> </listitem> </itemizedlist> - <simpara> + <para> ところでこの調査で知ったのだが、<literal>BufRead</literal> と <literal>BufWrite</literal> は上にある通り発火するタイミングが「後」と「前」で対称性がない。可能なら <literal>Pre</literal>/<literal>Post</literal> 付きのものを使った方が分かりやすいだろう。 - </simpara> + </para> </section> </article> diff --git a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml index f919301..cf1013a 100644 --- a/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml +++ b/content/posts/2021-10-02/vim-swap-order-of-selected-lines.xml @@ -15,13 +15,13 @@ </revision> </revhistory> </info> - <simpara> + <para> この記事は Qiita から移植してきたものです。 元 URL: <link xl:href="https://qiita.com/nsfisis/items/4fefb361d9a693803520">https://qiita.com/nsfisis/items/4fefb361d9a693803520</link> - </simpara> - <simpara> + </para> + <para> <hr/> - </simpara> + </para> <section xml:id="tl-dr"> <title>TL; DR</title> <programlisting language="vim" linenumbering="unnumbered"> @@ -36,69 +36,69 @@ </section> <section xml:id="version"> <title>バージョン情報</title> - <simpara> + <para> <literal>:version</literal> の一部 - </simpara> + </para> <blockquote> - <simpara> + <para> VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Jan 26 2020 11:30:30) macOS version Included patches: 1-148 Huge version without GUI. - </simpara> + </para> </blockquote> </section> <section xml:id="existing-solution"> <title>よく紹介されている手法</title> <section xml:id="existing-solution--external-commands"> <title><literal>tac</literal> / <literal>tail</literal></title> - <simpara> + <para> <literal>tac</literal> や <literal>tail -r</literal> などの外部コマンドを <literal>!</literal> を使って呼び出し、置き換える。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h v_! - </simpara> + </para> </blockquote> - <simpara> + <para> <literal>tac</literal> コマンドや <literal>tail</literal> の <literal>-r</literal> オプションは環境によって利用できないことがあり、複数の環境を行き来する場合に採用しづらい - </simpara> + </para> </section> <section xml:id="existing-solution--global-command"> <title><literal>:g/^/m0</literal></title> - <simpara> + <para> こちらは外部コマンドに頼らず、Vim の機能のみを使う。<literal>g</literal> は <literal>:global</literal> コマンドの、<literal>m</literal> は <literal>:move</literal> コマンドの略 - </simpara> - <simpara> + </para> + <para> <literal>:global</literal> コマンドは <literal>:[range]global/{pattern}/[command]</literal> のように使い、<literal>[range]</literal> で指定された範囲の行のうち、<literal>{pattern}</literal> で指定された検索パターンにマッチする行に対して、順番に <literal>[command]</literal> で指定された Ex コマンドを呼び出す。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h :global - </simpara> + </para> </blockquote> - <simpara> + <para> <literal>:move</literal> コマンドは <literal>[range]:move {address}</literal> のように使い、<literal>[range]</literal> で指定された範囲の行を <literal>{address}</literal> で指定された位置に移動させる。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h :move - </simpara> + </para> </blockquote> - <simpara> + <para> <literal>:g/^/m0</literal> のように組み合わせると、「すべての行を1行ずつ 0行目(1行目の上)に動かす」という動きをする。これは確かに行の入れ替えになっている。 - </simpara> - <simpara> + </para> + <para> なお、<literal>:g/^/m0</literal> は全ての行を入れ替えるが、<literal>:N,Mg/^/mN-1</literal> とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。 - </simpara> + </para> <programlisting language="vim" linenumbering="unnumbered"> <![CDATA[ command! -bar -range=% @@ -106,36 +106,36 @@ \ <line1>,<line2>g/^/m<line1>-1 ]]> </programlisting> - <simpara> + <para> これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。 - </simpara> + </para> </section> </section> <section xml:id="problem-of-global-command"> <title><literal>:g/^/m0</literal> の問題点</title> - <simpara> + <para> <literal>:global</literal> コマンドは各行に対してマッチングを行う際、現在の検索パターンを上書きしてしまう。<literal>^</literal> は行の先頭にマッチするため、結果として全ての行がハイライトされてしまう。<literal>'hlsearch'</literal> オプションを無効にしている場合その限りではないが、その場合でも直前の検索パターンが失われてしまうと <literal>n</literal> コマンドなどの際に不便である。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h @/ - </simpara> + </para> </blockquote> </section> <section xml:id="solution"> <title>解決策</title> <blockquote> - <simpara> + <para> [2020/9/28追記] より簡潔な方法を見つけたので次節に追記した - </simpara> + </para> </blockquote> - <simpara> + <para> 前述した <literal>:Reverse</literal> コマンドの定義を少し変えて、次のようにする: - </simpara> + </para> <programlisting language="vim" linenumbering="unnumbered"> <![CDATA[ function! s:reverse_lines(from, to) abort @@ -147,54 +147,54 @@ \ call <SID>reverse_lines(<line1>, <line2>) ]]> </programlisting> - <simpara> + <para> 実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 - </simpara> - <simpara> + </para> + <para> この理由は、ユーザー定義関数を実行する際は検索パターンが一度保存され、実行が終了したあと復元されるため。結果として検索パターンが <literal>^</literal> で上書きされることがなくなる。 - </simpara> - <simpara> + </para> + <para> Vim のヘルプから該当箇所を引用する (強調は筆者による)。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h autocmd-searchpat - </simpara> - <simpara> + </para> + <para> <emphasis role="strong">Autocommands do not change the current search patterns.</emphasis> Vim saves the current search patterns before executing autocommands then restores them after the autocommands finish. This means that autocommands do not affect the strings highlighted with the `hlsearch' option. - </simpara> + </para> </blockquote> - <simpara> + <para> これは autocommand の実行に関しての記述だが、これと同じことがユーザー定義関数の実行時にも適用される。このことは <literal>:nohlsearch</literal> のヘルプにある。同じく該当箇所を引用する (強調は筆者による)。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h :nohlsearch - </simpara> - <simpara> + </para> + <para> (略) This command doesn’t work in an autocommand, because the highlighting state is saved and restored when executing autocommands |autocmd-searchpat|. <emphasis role="strong">Same thing for when invoking a user function.</emphasis> - </simpara> + </para> </blockquote> - <simpara> + <para> この仕様により、<literal>:g/^/m0</literal> の呼び出しをユーザー定義関数に切り出すことで上述の問題を解決できる。 - </simpara> + </para> </section> <section xml:id="solution-revised"> <title>解決策 (改訂版)</title> <blockquote> - <simpara> + <para> [2020/9/28追記] より簡潔な方法を見つけたため追記する - </simpara> + </para> </blockquote> <programlisting language="vim" linenumbering="unnumbered"> <![CDATA[ @@ -203,16 +203,16 @@ \ keeppatterns <line1>,<line2>g/^/m<line1>-1 ]]> </programlisting> - <simpara> + <para> まさにこのための Exコマンド、<literal>:keeppatterns</literal> が存在する。<literal>:keeppatterns {command}</literal> のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。 - </simpara> + </para> <blockquote> - <simpara> + <para> :h :keeppatterns - </simpara> + </para> </blockquote> </section> </article> |
