From 6dedddc545e2f1930bdc2256784eb1551bd4231d Mon Sep 17 00:00:00 2001
From: nsfisis
#include <iostream>
-
-[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]
-[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]
-[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]
-[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]
-[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]
-[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]
-[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]
-[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]
-[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]
-[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]
-[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]
-[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]
-[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]
-// [[using]]
-int main() {
- std::cout << "Hello, World!" << std::endl;
-}
+ #include <iostream>
+
+[[alignas]] [[alignof]] [[and]] [[and_eq]] [[asm]] [[auto]] [[bitand]]
+[[bitor]] [[bool]] [[break]] [[case]] [[catch]] [[char]] [[char16_t]]
+[[char32_t]] [[class]] [[compl]] [[const]] [[const_cast]] [[constexpr]]
+[[continue]] [[decltype]] [[default]] [[delete]] [[do]] [[double]]
+[[dynamic_cast]] [[else]] [[enum]] [[explicit]] [[export]] [[extern]] [[false]]
+[[final]] [[float]] [[for]] [[friend]] [[goto]] [[if]] [[inline]] [[int]]
+[[long]] [[mutable]] [[namespace]] [[new]] [[noexcept]] [[not]] [[not_eq]]
+[[nullptr]] [[operator]] [[or]] [[or_eq]] [[override]] [[private]]
+[[protected]] [[public]] [[register]] [[reinterpret_cast]] [[return]] [[short]]
+[[signed]] [[sizeof]] [[static]] [[static_assert]] [[static_cast]] [[struct]]
+[[switch]] [[template]] [[this]] [[thread_local]] [[throw]] [[true]] [[try]]
+[[typedef]] [[typeid]] [[typename]] [[union]] [[unsigned]]
+[[virtual]] [[void]] [[volatile]] [[wchar_t]] [[while]] [[xor]] [[xor_eq]]
+// [[using]]
+int main() {
+ std::cout << "Hello, World!" << std::endl;
+}
+
コンパイラのバージョン
$ 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
+ $ 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
+
コンパイルコマンド (C++17 指定)
$ clang –std=c++17 hoge.cpp
+ $ clang –std=c++17 hoge.cpp
+
この記事から得られるものはこれ以上ないので以下は蛇足になる。
@@ -135,8 +138,9 @@
上のコードでは [[using]] をコメントアウトしているが、これは using キーワードのみ属性構文の中で意味を持つからであり、このコメントアウトを外すとコンパイルに失敗する。
// using の例
-[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
+ // using の例
+[[using foo: attr1, attr2]] int x; // [[foo::attr1, foo::attr2]] の糖衣構文
+
C++17 の仕様も見てみる (正確には標準化前のドラフト)。 diff --git a/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html b/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html index 26fb852f..03e01be0 100644 --- a/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html +++ b/services/nuldoc/public/blog/posts/2021-10-02/python-unbound-local-error/index.html @@ -75,13 +75,14 @@ Python でクロージャを作ろうと、次のようなコードを書いた。
def f():
- x = 0
- def g():
- x += 1
- g()
-
-f()
+ def f():
+ x = 0
+ def g():
+ x += 1
+ g()
+
+f()
+
関数 g から 関数 f のスコープ内で定義された変数 x を参照し、それに 1 を足そうとしている。 これを実行すると x += 1 の箇所でエラーが発生する。
@@ -95,27 +96,29 @@
local変数 x が代入前に参照された、とある。これは、f の x を参照するのではなく、新しく別の変数を g 内に作ってしまっているため。前述のコードを宣言と代入を便宜上分けて書き直すと次のようになる。var を変数宣言のための構文として擬似的に利用している。
# 注: var は正しい Python の文法ではない。上記参照のこと
-def f():
- var x # f の local変数 'x' を宣言
- x = 0 # x に 0 を代入
- def g(): # f の内部関数 g を定義
- var x # g の local変数 'x' を宣言
- # たまたま f にも同じ名前の変数があるが、それとは別の変数
- x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文)
- # 加算する前の値を参照しようとするが、まだ代入されていないためエラー
- g()
+ # 注: var は正しい Python の文法ではない。上記参照のこと
+def f():
+ var x # f の local変数 'x' を宣言
+ x = 0 # x に 0 を代入
+ def g(): # f の内部関数 g を定義
+ var x # g の local変数 'x' を宣言
+ # たまたま f にも同じ名前の変数があるが、それとは別の変数
+ x += 1 # x に 1 を加算 (x = x + 1 の糖衣構文)
+ # 加算する前の値を参照しようとするが、まだ代入されていないためエラー
+ g()
+
当初の意図を表現するには、次のように書けばよい。
def f():
- x = 0
- def g():
- nonlocal x ## (*)
- x += 1
- g()
+ def f():
+ x = 0
+ def g():
+ nonlocal x ## (*)
+ x += 1
+ g()
+
(*) のように、nonlocal を追加する。これにより一つ外側のスコープ (g の一つ外側 = f) で定義されている x を探しに行くようになる。
diff --git a/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html b/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html
index b2e7a02a..db82851d 100644
--- a/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html
+++ b/services/nuldoc/public/blog/posts/2021-10-02/ruby-detect-running-implementation/index.html
@@ -81,12 +81,13 @@
上記ページの例から引用する:
$ ruby-1.9.1 -ve 'p RUBY_ENGINE'
-ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
-"ruby"
-$ jruby -ve 'p RUBY_ENGINE'
-jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
-"jruby"
+ $ ruby-1.9.1 -ve 'p RUBY_ENGINE'
+ruby 1.9.1p0 (2009-03-04 revision 22762) [x86_64-linux]
+"ruby"
+$ jruby -ve 'p RUBY_ENGINE'
+jruby 1.2.0 (ruby 1.8.6 patchlevel 287) (2009-03-16 rev 9419) [i386-java]
+"jruby"
+
それぞれの処理系がどのような値を返すかだが、stack overflow に良い質問と回答があった。 @@ -96,16 +97,17 @@
-+| RUBY_ENGINE | Implementation | -|:-----------:|:------------------| -| <undefined> | MRI < 1.9 | -| 'ruby' | MRI >= 1.9 or REE | -| 'jruby' | JRuby | -| 'macruby' | MacRuby | -| 'rbx' | Rubinius | -| 'maglev' | MagLev | -| 'ironruby' | IronRuby | -| 'cardinal' | Cardinal || RUBY_ENGINE | Implementation | +|:-----------:|:------------------| +| <undefined> | MRI < 1.9 | +| 'ruby' | MRI >= 1.9 or REE | +| 'jruby' | JRuby | +| 'macruby' | MacRuby | +| 'rbx' | Rubinius | +| 'maglev' | MagLev | +| 'ironruby' | IronRuby | +| 'cardinal' | Cardinal | +
@@ -121,10 +123,11 @@
/*
- * Ruby engine.
- */
-#define MRUBY_RUBY_ENGINE "mruby"
+ /*
+ * Ruby engine.
+ */
+#define MRUBY_RUBY_ENGINE "mruby"
+
diff --git a/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html b/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
index 9035fa18..0592f0a6 100644
--- a/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
+++ b/services/nuldoc/public/blog/posts/2021-10-02/ruby-then-keyword-and-case-in/index.html
@@ -103,36 +103,38 @@
使われることは稀だが、Ruby では then がキーワードになっている。次のように使う:
if cond then
- puts "Y"
-else
- puts "N"
-end
+ if cond then
+ puts "Y"
+else
+ puts "N"
+end
+
このキーワードが現れうる場所はいくつかあり、if、unless、rescue、case 構文がそれに当たる。 上記のように、何か条件を書いた後 then を置き、式がそこで終了していることを示すマーカーとして機能する。
# Example:
-
-if x then
- a
-end
-
-unless x then
- a
-end
-
-begin
- a
-rescue then
- b
-end
-
-case x
-when p then
- a
-end
+ # Example:
+
+if x then
+ a
+end
+
+unless x then
+ a
+end
+
+begin
+ a
+rescue then
+ b
+end
+
+case x
+when p then
+ a
+end
+
then を書くことはない。なぜか。次のコードを実行してみるとわかる。
if true puts 'Hello, World!' end
+ if true puts 'Hello, World!' end
+
次のような構文エラーが出力される。
20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
-if true puts 'Hello, World!' end
- ^~~~
-20:1: syntax error, unexpected `end', expecting end-of-input
-...f true puts 'Hello, World!' end
+ 20:1: syntax error, unexpected local variable or method, expecting `then' or ';' or '\n'
+if true puts 'Hello, World!' end
+ ^~~~
+20:1: syntax error, unexpected `end', expecting end-of-input
+...f true puts 'Hello, World!' end
+
二つ目のメッセージは無視して一つ目を読むと、then か ; か改行が来るはずのところ変数だかメソッドだかが現れたことによりエラーとなっているようだ。
@@ -160,8 +164,9 @@
ポイントは改行が then (や ;) の代わりとなることである。true の後に改行を入れてみる。
if true
-puts 'Hello, World!' end
+ if true
+puts 'Hello, World!' end
+
無事 Hello, World! と出力されるようになった。
@@ -173,22 +178,25 @@
なぜ then や ; や改行 (以下 「then 等」) が必要なのだろうか。次の例を見てほしい:
if a b end
+ if a b end
+
then も ; も改行もないのでエラーになるが、これは条件式がどこまで続いているのかわからないためだ。この例は二通りに解釈できる。
# a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
-if a then
-b
-end
+ # a という変数かメソッドの評価結果が truthy なら b という変数かメソッドを評価
+if a then
+b
+end
+
# a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
-# その結果が truthy なら何もしない
-if a(b) then
-end
+ # a というメソッドに b という変数かメソッドの評価結果を渡して呼び出し、
+# その結果が truthy なら何もしない
+if a(b) then
+end
+
then 等はこの曖昧性を排除するためにあり、条件式は if から then 等までの間にある、ということを明確にする。 C系の if 後に来る (/) や、Python の :、Rust/Go/Swift などの { も同じ役割を持つ。
@@ -209,39 +217,41 @@
p_case_body : keyword_in
-{
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p->command_start = FALSE;
- $<ctxt>1 = p->ctxt;
- p->ctxt.in_kwarg = 1;
- $<tbl>$ = push_pvtbl(p);
-}
-{
- $<tbl>$ = push_pktbl(p);
-}
-p_top_expr then
-{
- pop_pktbl(p, $<tbl>3);
- pop_pvtbl(p, $<tbl>2);
- p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
-}
-compstmt
-p_cases
-{
- /*%%%*/
- $$ = NEW_IN($4, $7, $8, &@$);
- /*% %*/
- /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
-}
-;
+ p_case_body : keyword_in
+{
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+}
+{
+ $<tbl>$ = push_pktbl(p);
+}
+p_top_expr then
+{
+ pop_pktbl(p, $<tbl>3);
+ pop_pvtbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+}
+compstmt
+p_cases
+{
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+}
+;
+
簡略版:
p_case_body : keyword_in p_top_expr then compstmt p_cases
-;
+ p_case_body : keyword_in p_top_expr then compstmt p_cases
+;
+
ここで、keyword_in は文字通り in、p_top_expr はいわゆるパターン、then は then キーワードのことではなく、この記事で then 等と呼んでいるもの、つまり then キーワード、;、改行のいずれかである。
@@ -250,36 +260,38 @@
これにより、case - when による従来の構文と同じように、then 等をパターンの後ろに挿入すればよいことがわかった。つまり次の3通りのいずれかになる:
case x
-in 1 then a
-in 2 then b
-in 3 then c
-end
-
-case x
-in 1
- a
-in 2
- b
-in 3
- c
-end
-
-case x
-in 1; a
-in 2; b
-in 3; c
-end
+ case x
+in 1 then a
+in 2 then b
+in 3 then c
+end
+
+case x
+in 1
+ a
+in 2
+ b
+in 3
+ c
+end
+
+case x
+in 1; a
+in 2; b
+in 3; c
+end
+
ところで、p_top_expr には if による guard clause が書けるので、その場合は if - then と似たような見た目になる。
case x
-in 0 then a
-in n if n < 0 then b
-in n then c
-end
+ case x
+in 0 then a
+in n if n < 0 then b
+in n then c
+end
+
#![allow(non_camel_case_types)]
-#![allow(dead_code)]
-
-struct bool;
-struct char;
-struct i8;
-struct i16;
-struct i32;
-struct i64;
-struct i128;
-struct isize;
-struct u8;
-struct u16;
-struct u32;
-struct u64;
-struct u128;
-struct usize;
-struct f32;
-struct f64;
-struct str;
+ #![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
+struct bool;
+struct char;
+struct i8;
+struct i16;
+struct i32;
+struct i64;
+struct i128;
+struct isize;
+struct u8;
+struct u16;
+struct u32;
+struct u64;
+struct u128;
+struct usize;
+struct f32;
+struct f64;
+struct str;
+
では、普段単に bool と書いたとき、この bool は一体どこから来ているのか。rustc のソースを追ってみた。
@@ -134,23 +135,25 @@
rustc はセルフホストされている (= rustc 自身が Rust で書かれている) ので、bool や char などで適当に検索をかけてもノイズが多すぎて話にならない。しかし、お誂え向きなことに i128/u128 というコンパイラ自身が使うことがなさそうな型が存在するのでこれを使って git grep してみる。
$ git grep "\bi128\b" | wc # i128
-165 1069 15790
-
-$ git grep "\bu128\b" | wc # u128
-293 2127 26667
-
-$ git grep "\bbool\b" | wc # cf. bool の結果
-3563 23577 294659
+ $ git grep "\bi128\b" | wc # i128
+165 1069 15790
+
+$ git grep "\bu128\b" | wc # u128
+293 2127 26667
+
+$ git grep "\bbool\b" | wc # cf. bool の結果
+3563 23577 294659
+
165 程度であれば探すことができそうだ。今回は、クレート名を見ておおよその当たりをつけた。
$ git grep "\bi128\b"
-...
-rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
-...
+ $ git grep "\bi128\b"
+...
+rustc_resolve/src/lib.rs: table.insert(sym::i128, Int(IntTy::I128));
+...
+
rustc_resolve というのはいかにも名前解決を担いそうなクレート名である。該当箇所を見てみる。
@@ -159,72 +162,75 @@
/// Interns the names of the primitive types.
-///
-/// All other types are defined somewhere and possibly imported, but the primitive ones need
-/// special handling, since they have no place of origin.
-struct PrimitiveTypeTable {
- primitive_types: FxHashMap<Symbol, PrimTy>,
-}
-
-impl PrimitiveTypeTable {
- fn new() -> PrimitiveTypeTable {
- let mut table = FxHashMap::default();
-
- table.insert(sym::bool, Bool);
- table.insert(sym::char, Char);
- table.insert(sym::f32, Float(FloatTy::F32));
- table.insert(sym::f64, Float(FloatTy::F64));
- table.insert(sym::isize, Int(IntTy::Isize));
- table.insert(sym::i8, Int(IntTy::I8));
- table.insert(sym::i16, Int(IntTy::I16));
- table.insert(sym::i32, Int(IntTy::I32));
- table.insert(sym::i64, Int(IntTy::I64));
- table.insert(sym::i128, Int(IntTy::I128));
- table.insert(sym::str, Str);
- table.insert(sym::usize, Uint(UintTy::Usize));
- table.insert(sym::u8, Uint(UintTy::U8));
- table.insert(sym::u16, Uint(UintTy::U16));
- table.insert(sym::u32, Uint(UintTy::U32));
- table.insert(sym::u64, Uint(UintTy::U64));
- table.insert(sym::u128, Uint(UintTy::U128));
- Self { primitive_types: table }
- }
-}
+ /// Interns the names of the primitive types.
+///
+/// All other types are defined somewhere and possibly imported, but the primitive ones need
+/// special handling, since they have no place of origin.
+struct PrimitiveTypeTable {
+ primitive_types: FxHashMap<Symbol, PrimTy>,
+}
+
+impl PrimitiveTypeTable {
+ fn new() -> PrimitiveTypeTable {
+ let mut table = FxHashMap::default();
+
+ table.insert(sym::bool, Bool);
+ table.insert(sym::char, Char);
+ table.insert(sym::f32, Float(FloatTy::F32));
+ table.insert(sym::f64, Float(FloatTy::F64));
+ table.insert(sym::isize, Int(IntTy::Isize));
+ table.insert(sym::i8, Int(IntTy::I8));
+ table.insert(sym::i16, Int(IntTy::I16));
+ table.insert(sym::i32, Int(IntTy::I32));
+ table.insert(sym::i64, Int(IntTy::I64));
+ table.insert(sym::i128, Int(IntTy::I128));
+ table.insert(sym::str, Str);
+ table.insert(sym::usize, Uint(UintTy::Usize));
+ table.insert(sym::u8, Uint(UintTy::U8));
+ table.insert(sym::u16, Uint(UintTy::U16));
+ table.insert(sym::u32, Uint(UintTy::U32));
+ table.insert(sym::u64, Uint(UintTy::U64));
+ table.insert(sym::u128, Uint(UintTy::U128));
+ Self { primitive_types: table }
+ }
+}
+
これは初めに列挙したプリミティブ型の一覧と一致している。doc comment にも、
All other types are defined somewhere and possibly imported, but the
-primitive ones need special handling, since they have no place of
-origin.
+ All other types are defined somewhere and possibly imported, but the
+primitive ones need special handling, since they have no place of
+origin.
+
とある。次はこの struct の使用箇所を追う。追うと言っても使われている箇所は次の一箇所しかない。なお説明に不要な箇所は大きく削っている。
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-/// (略)
-fn resolve_ident_in_lexical_scope(
- &mut self,
- mut ident: Ident,
- ns: Namespace,
- // (略)
-) -> Option<LexicalScopeBinding<'a>> {
- // (略)
-
- if ns == TypeNS {
- if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
- let binding =
- (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
- .to_name_binding(self.arenas);
- return Some(LexicalScopeBinding::Item(binding));
- }
- }
-
- None
-}
+ /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
+/// (略)
+fn resolve_ident_in_lexical_scope(
+ &mut self,
+ mut ident: Ident,
+ ns: Namespace,
+ // (略)
+) -> Option<LexicalScopeBinding<'a>> {
+ // (略)
+
+ if ns == TypeNS {
+ if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
+ let binding =
+ (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
+ .to_name_binding(self.arenas);
+ return Some(LexicalScopeBinding::Item(binding));
+ }
+ }
+
+ None
+}
+
関数名や doc comment が示している通り、この関数は識別子 (identifier, ident) を現在のレキシカルスコープ内で解決 (resolve) する。if ns == TypeNS のブロック内では、primitive_type_table (上記の PrimitiveTypeTable::new() で作られた変数) に含まれている識別子 (bool、i32 など) かどうか判定し、そうであればそれに紐づけられたプリミティブ型を返している。
@@ -239,13 +245,14 @@
動作がわかったところで、例として次のコードを考える。
#![allow(non_camel_case_types)]
-
-struct bool;
-
-fn main() {
- let _: bool = bool;
-}
+ #![allow(non_camel_case_types)]
+
+struct bool;
+
+fn main() {
+ let _: bool = bool;
+}
+
ここで main() の bool は struct bool として解決される。なぜなら、プリミティブ型の判定をする前に bool という名前の別の型が見つかるからだ。
diff --git a/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html b/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
index cafadae1..275086e6 100644
--- a/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
+++ b/services/nuldoc/public/blog/posts/2021-10-02/vim-difference-between-autocmd-bufwrite-and-bufwritepre/index.html
@@ -146,8 +146,9 @@
{"BufAdd", EVENT_BUFADD},
-{"BufCreate", EVENT_BUFADD},
+ {"BufAdd", EVENT_BUFADD},
+{"BufCreate", EVENT_BUFADD},
+
https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L95-L97 @@ -156,9 +157,10 @@
{"BufRead", EVENT_BUFREADPOST},
-{"BufReadCmd", EVENT_BUFREADCMD},
-{"BufReadPost", EVENT_BUFREADPOST},
+ {"BufRead", EVENT_BUFREADPOST},
+{"BufReadCmd", EVENT_BUFREADCMD},
+{"BufReadPost", EVENT_BUFREADPOST},
+
https://github.com/vim/vim/blob/8e6be34338f13a6a625f19bcef82019c9adc65f2/src/autocmd.c#L103-L105 @@ -167,9 +169,10 @@
{"BufWrite", EVENT_BUFWRITEPRE},
-{"BufWritePost", EVENT_BUFWRITEPOST},
-{"BufWritePre", EVENT_BUFWRITEPRE},
+ {"BufWrite", EVENT_BUFWRITEPRE},
+{"BufWritePost", EVENT_BUFWRITEPOST},
+{"BufWritePre", EVENT_BUFWRITEPRE},
+
aliases = {
- BufCreate = 'BufAdd',
- BufRead = 'BufReadPost',
- BufWrite = 'BufWritePre',
- FileEncoding = 'EncodingChanged',
-},
+ aliases = {
+ BufCreate = 'BufAdd',
+ BufRead = 'BufReadPost',
+ BufWrite = 'BufWritePre',
+ FileEncoding = 'EncodingChanged',
+},
+
ところで、上では取り上げなかった FileEncoding だが、これは :help FileEncoding にしっかりと書いてある。
@@ -198,9 +202,10 @@
*FileEncoding*
-FileEncoding Obsolete. It still works and is equivalent
- to |EncodingChanged|.
+ *FileEncoding*
+FileEncoding Obsolete. It still works and is equivalent
+ to |EncodingChanged|.
+
" License: Public Domain
-
-command! -bar -range=%
- \ Reverse
- \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+ " License: Public Domain
+
+command! -bar -range=%
+ \ Reverse
+ \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+
:g/^/m0 は全ての行を入れ替えるが、:N,Mg/^/mN-1 とすることで N行目から M行目を処理範囲とするよう拡張できる。手でこれを入力するわけにはいかないので、次のようなコマンドを用意する。
command! -bar -range=%
- \ Reverse
- \ <line1>,<line2>g/^/m<line1>-1
+ command! -bar -range=%
+ \ Reverse
+ \ <line1>,<line2>g/^/m<line1>-1
+
これは望みの動作をするが、実際に実行してみると全行がハイライトされてしまう。次節で詳細を述べる。
@@ -200,13 +202,14 @@
前述した :Reverse コマンドの定義を少し変えて、次のようにする:
function! s:reverse_lines(from, to) abort
- execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
-endfunction
-
-command! -bar -range=%
- \ Reverse
- \ call <SID>reverse_lines(<line1>, <line2>)
+ function! s:reverse_lines(from, to) abort
+ execute printf("%d,%dg/^/m%d", a:from, a:to, a:from - 1)
+endfunction
+
+command! -bar -range=%
+ \ Reverse
+ \ call <SID>reverse_lines(<line1>, <line2>)
+
実行しているコマンドが変わったわけではないが、関数呼び出しを経由するようにした。これだけで前述の問題が解決する。 @@ -253,9 +256,10 @@
command! -bar -range=%
- \ Reverse
- \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+ command! -bar -range=%
+ \ Reverse
+ \ keeppatterns <line1>,<line2>g/^/m<line1>-1
+
まさにこのための Exコマンド、:keeppatterns が存在する。:keeppatterns {command} のように使い、読んで字の如く、後ろに続く Exコマンドを「現在の検索パターンを保ったまま」実行する。はるかに分かりやすく意図を表現できる。
--
cgit v1.3-1-g0d28