summaryrefslogtreecommitdiffhomepage
path: root/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-03-29 00:47:55 +0900
committernsfisis <nsfisis@gmail.com>2025-03-29 00:55:14 +0900
commitd30dfc89bf1b673b2fdc0638766b930adaec228c (patch)
tree739d8826451947adfeb526ef1adeb1db397a9af4 /vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file
parentf65ec15aaf8fc46685c39d721cab82f64baead8c (diff)
downloadnsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.tar.gz
nsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.tar.zst
nsfisis.dev-d30dfc89bf1b673b2fdc0638766b930adaec228c.zip
feat(blog/nuldoc): migrate syntax highlighter from highlight.js to shiki.js
Diffstat (limited to 'vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file')
-rw-r--r--vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html265
1 files changed, 136 insertions, 129 deletions
diff --git a/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html b/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html
index 1e7cd5ee..07043627 100644
--- a/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html
+++ b/vhosts/blog/public/posts/2024-01-10/neovim-insert-namespace-declaration-to-empty-php-file/index.html
@@ -14,8 +14,7 @@
<meta property="og:locale" content="ja_JP">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<title>【Neovim】 空の PHP ファイルに namespace 宣言を挿入する|REPL: Rest-Eat-Program Loop</title>
- <link rel="stylesheet" href="/style.css?h=79020a898c7052f79b32e90376a4497d">
- <link rel="stylesheet" href="/hl.css?h=340e65ffd5c17713efc9107c06304f7b">
+ <link rel="stylesheet" href="/style.css?h=60eb349e583f5bd51518a7eb98598043">
</head>
<body class="single">
<header class="header">
@@ -76,17 +75,21 @@
Neovim で空の PHP ファイルを開いたとき、そのファイルが置かれているディレクトリの構造に基づいて、自動的に <code>namespace</code> 宣言を挿入したい。具体的には、トップレベルの名前空間が <code>MyNamespace</code> であり、ファイル <code>src/Foo/Bar/Baz.php</code> を開いたときに、そのファイルが空であるなら、次のようなテンプレートが自動的に挿入されてほしい。
</p>
- <pre class="highlight" language="php"><code class="highlight"><span class="hljs-meta">&lt;?php</span>
-
-<span class="hljs-keyword">namespace</span> <span class="hljs-title class_">MyNamespace</span>\<span class="hljs-title class_">Foo</span>\<span class="hljs-title class_">Bar</span>;</code></pre>
+ <div class="codeblock" language="php">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">&#x3C;?</span><span style="color:#005CC5">php</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">namespace</span><span style="color:#6F42C1"> MyNamespace\Foo\Bar</span><span style="color:#24292E">;</span></span></code></pre>
+ </div>
</section>
<section id="section--version">
<h2><a href="#section--version">バージョン情報</a></h2>
- <pre class="highlight"><code>$ nvim --version
-NVIM v0.9.2
-Build type: Release
-LuaJIT 2.1.1693350652</code></pre>
+ <div class="codeblock">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span>$ nvim --version</span></span>
+<span class="line"><span>NVIM v0.9.2</span></span>
+<span class="line"><span>Build type: Release</span></span>
+<span class="line"><span>LuaJIT 2.1.1693350652</span></span></code></pre>
+ </div>
<p>
今回は Lua で処理を記述したため、Vim では動作しない。以下の説明でも Neovim に絞って述べる。また、パス区切りがスラッシュである前提で記述したため、Windows には対応していない。
@@ -114,13 +117,15 @@ LuaJIT 2.1.1693350652</code></pre>
ファイルタイプは読み込んだあとに変更されることもあるので、ftplugin は複数回実行されうる。二重読み込みを防ぐために、<code>did_ftplugin_&lt;FILE_TYPE&gt;_after</code> というバッファローカル変数を定義しておくのが慣習となっている。
</p>
- <pre class="highlight" language="lua"><code class="highlight"><span class="hljs-keyword">if</span> vim.b.did_ftplugin_php_after <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span>
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-comment">-- ここに実際の処理を書く</span>
-
-vim.b.did_ftplugin_php_after = <span class="hljs-literal">true</span></code></pre>
+ <div class="codeblock" language="lua">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6A737D">-- ここに実際の処理を書く</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E">vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> true</span></span></code></pre>
+ </div>
</section>
<section id="section--implement">
@@ -159,119 +164,121 @@ vim.b.did_ftplugin_php_after = <span class="hljs-literal">true</span></code></pr
実装を簡単にするため、Composer を用いない場合や PSR 4 以外のオートロード規則を使う場合には対応しない。少々長くなるが、以下にスクリプト全文を載せる。
</p>
- <pre class="highlight" language="lua"><code class="highlight"><span class="hljs-keyword">if</span> vim.b.did_ftplugin_php_after <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span>
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-comment">-- base_dir を起点としてディレクトリを上向きに辿っていき、composer.json を探す</span>
-<span class="hljs-comment">-- :help vim.fs.find()</span>
-<span class="hljs-keyword">local</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find_composer_json</span><span class="hljs-params">(base_dir)</span></span>
- <span class="hljs-keyword">return</span> vim.fs.<span class="hljs-built_in">find</span>(<span class="hljs-string">&#x27;composer.json&#x27;</span>, {
- <span class="hljs-built_in">path</span> = base_dir,
- upward = <span class="hljs-literal">true</span>,
- <span class="hljs-comment">-- ホームディレクトリまで到達したら探索を打ち切る</span>
- stop = vim.loop.os_homedir(),
- <span class="hljs-built_in">type</span> = <span class="hljs-string">&#x27;file&#x27;</span>,
- })[<span class="hljs-number">1</span>]
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-comment">-- JSON ファイルを読み込み、デコードして返す</span>
-<span class="hljs-comment">-- :help readblob()</span>
-<span class="hljs-comment">-- :help vim.json.decode</span>
-<span class="hljs-comment">-- :help luaref-pcall()</span>
-<span class="hljs-keyword">local</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load_json</span><span class="hljs-params">(file_path)</span></span>
- <span class="hljs-comment">-- readblob() は Vim script では Blob オブジェクトを返すが、Lua から呼ぶと string に変換される</span>
- <span class="hljs-keyword">local</span> ok_read, content = <span class="hljs-built_in">pcall</span>(vim.fn.readblob, file_path)
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ok_read <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">local</span> ok_decode, obj = <span class="hljs-built_in">pcall</span>(vim.json.decode, content)
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ok_decode <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">return</span> obj
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-comment">-- 対象ファイルの置かれたディレクトリを基に namespace 宣言を生成する</span>
-<span class="hljs-comment">-- :help nvim_buf_get_name()</span>
-<span class="hljs-comment">-- :help vim.fs.dirname()</span>
-<span class="hljs-keyword">local</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generate_namespace_declaration</span><span class="hljs-params">()</span></span>
- <span class="hljs-comment">-- composer.json を探し、トップレベルの名前空間とディレクトリを特定する</span>
- <span class="hljs-keyword">local</span> current_dir = vim.fs.dirname(vim.api.nvim_buf_get_name(<span class="hljs-number">0</span>))
- <span class="hljs-keyword">local</span> path_to_composer_json = find_composer_json(current_dir)
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> path_to_composer_json <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- failed to locate composer.json</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">local</span> composer_json = load_json(path_to_composer_json)
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> composer_json <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- failed to load composer.json</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-comment">-- autoload.psr-4 を探し、型が期待される型と一致するかどうか調べる</span>
- <span class="hljs-keyword">local</span> psr4 = vim.tbl_get(composer_json, <span class="hljs-string">&#x27;autoload&#x27;</span>, <span class="hljs-string">&#x27;psr-4&#x27;</span>)
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> psr4 <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- autoload.psr-4 section is absent</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">if</span> vim.tbl_count(psr4) ~= <span class="hljs-number">1</span> <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- psr-4 section is ambiguous</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">local</span> psr4_namespace, psr4_dir
- <span class="hljs-keyword">for</span> k, v <span class="hljs-keyword">in</span> <span class="hljs-built_in">pairs</span>(psr4) <span class="hljs-keyword">do</span>
- psr4_namespace = k
- psr4_dir = v
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">if</span> <span class="hljs-built_in">type</span>(psr4_dir) == <span class="hljs-string">&#x27;table&#x27;</span> <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">if</span> #psr4_dir == <span class="hljs-number">1</span> <span class="hljs-keyword">then</span>
- psr4_dir = psr4_dir[<span class="hljs-number">1</span>]
- <span class="hljs-keyword">else</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- psr-4 section is ambiguous</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">if</span> <span class="hljs-built_in">type</span>(psr4_namespace) ~= <span class="hljs-string">&#x27;string&#x27;</span> <span class="hljs-keyword">or</span> <span class="hljs-built_in">type</span>(psr4_dir) ~= <span class="hljs-string">&#x27;string&#x27;</span> <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> <span class="hljs-comment">-- psr-4 section is invalid</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-comment">-- 末尾のスラッシュとバックスラッシュを取り除いておく</span>
- <span class="hljs-keyword">if</span> psr4_namespace:<span class="hljs-built_in">sub</span>(<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>) == <span class="hljs-string">&#x27;\\&#x27;</span> <span class="hljs-keyword">then</span>
- psr4_namespace = psr4_namespace:<span class="hljs-built_in">sub</span>(<span class="hljs-number">0</span>, <span class="hljs-number">-2</span>)
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">if</span> psr4_dir:<span class="hljs-built_in">sub</span>(<span class="hljs-number">-1</span>, <span class="hljs-number">-1</span>) == <span class="hljs-string">&#x27;/&#x27;</span> <span class="hljs-keyword">then</span>
- psr4_dir = psr4_dir:<span class="hljs-built_in">sub</span>(<span class="hljs-number">0</span>, <span class="hljs-number">-2</span>)
- <span class="hljs-keyword">end</span>
-
- <span class="hljs-comment">-- 対象ファイルが置かれたディレクトリとトップレベルのディレクトリを比較し、その差分を名前空間とする</span>
- <span class="hljs-keyword">local</span> namespace_root_dir = vim.fs.dirname(path_to_composer_json) .. <span class="hljs-string">&#x27;/&#x27;</span> .. psr4_dir
- <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> vim.startswith(current_dir, namespace_root_dir) <span class="hljs-keyword">then</span>
- <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-keyword">local</span> current_path_suffix = current_dir:<span class="hljs-built_in">sub</span>(#namespace_root_dir + <span class="hljs-number">1</span>)
- <span class="hljs-keyword">local</span> namespace = psr4_namespace .. current_path_suffix:<span class="hljs-built_in">gsub</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-string">&#x27;\\&#x27;</span>)
- <span class="hljs-keyword">return</span> (<span class="hljs-string">&quot;namespace %s;&quot;</span>):<span class="hljs-built_in">format</span>(namespace)
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-keyword">local</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generate_template</span><span class="hljs-params">()</span></span>
- <span class="hljs-keyword">local</span> <span class="hljs-built_in">lines</span> = {
- <span class="hljs-string">&#x27;&lt;?php&#x27;</span>,
- <span class="hljs-string">&#x27;&#x27;</span>,
- <span class="hljs-string">&#x27;declare(strict_types=1);&#x27;</span>,
- <span class="hljs-string">&#x27;&#x27;</span>,
- }
- <span class="hljs-keyword">local</span> namespace_decl = generate_namespace_declaration()
- <span class="hljs-keyword">if</span> namespace_decl <span class="hljs-keyword">then</span>
- <span class="hljs-built_in">lines</span>[#<span class="hljs-built_in">lines</span> + <span class="hljs-number">1</span>] = namespace_decl
- <span class="hljs-built_in">lines</span>[#<span class="hljs-built_in">lines</span> + <span class="hljs-number">1</span>] = <span class="hljs-string">&#x27;&#x27;</span>
- <span class="hljs-keyword">end</span>
- <span class="hljs-built_in">lines</span>[#<span class="hljs-built_in">lines</span> + <span class="hljs-number">1</span>] = <span class="hljs-string">&#x27;&#x27;</span>
- <span class="hljs-keyword">return</span> <span class="hljs-built_in">lines</span>
-<span class="hljs-keyword">end</span>
-
-<span class="hljs-keyword">if</span> vim.fn.line(<span class="hljs-string">&#x27;$&#x27;</span>) == <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> vim.fn.getline(<span class="hljs-number">1</span>) == <span class="hljs-string">&#x27;&#x27;</span> <span class="hljs-keyword">then</span>
- <span class="hljs-comment">-- 対象ファイルが空なら、テンプレートを挿入してカーソルを末尾に移動させる</span>
- <span class="hljs-comment">-- :help setline()</span>
- <span class="hljs-comment">-- :help cursor()</span>
- vim.fn.setline(<span class="hljs-number">1</span>, generate_template())
- vim.fn.cursor(<span class="hljs-string">&#x27;$&#x27;</span>, <span class="hljs-number">0</span>)
-<span class="hljs-keyword">end</span>
-
-vim.b.did_ftplugin_php_after = <span class="hljs-literal">true</span></code></pre>
+ <div class="codeblock" language="lua">
+ <pre class="shiki github-light" style="background-color:#f5f5f5;color:#24292e" tabindex="0"><code><span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6A737D">-- base_dir を起点としてディレクトリを上向きに辿っていき、composer.json を探す</span></span>
+<span class="line"><span style="color:#6A737D">-- :help vim.fs.find()</span></span>
+<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> find_composer_json</span><span style="color:#24292E">(base_dir)</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">find</span><span style="color:#24292E">(</span><span style="color:#032F62">'composer.json'</span><span style="color:#24292E">, {</span></span>
+<span class="line"><span style="color:#24292E"> path </span><span style="color:#D73A49">=</span><span style="color:#24292E"> base_dir,</span></span>
+<span class="line"><span style="color:#24292E"> upward </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> true</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#6A737D"> -- ホームディレクトリまで到達したら探索を打ち切る</span></span>
+<span class="line"><span style="color:#24292E"> stop </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">loop</span><span style="color:#24292E">.</span><span style="color:#005CC5">os_homedir</span><span style="color:#24292E">(),</span></span>
+<span class="line"><span style="color:#24292E"> type </span><span style="color:#D73A49">=</span><span style="color:#032F62"> 'file'</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> })[</span><span style="color:#005CC5">1</span><span style="color:#24292E">]</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6A737D">-- JSON ファイルを読み込み、デコードして返す</span></span>
+<span class="line"><span style="color:#6A737D">-- :help readblob()</span></span>
+<span class="line"><span style="color:#6A737D">-- :help vim.json.decode</span></span>
+<span class="line"><span style="color:#6A737D">-- :help luaref-pcall()</span></span>
+<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> load_json</span><span style="color:#24292E">(file_path)</span></span>
+<span class="line"><span style="color:#6A737D"> -- readblob() は Vim script では Blob オブジェクトを返すが、Lua から呼ぶと string に変換される</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> ok_read, content </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> pcall</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#6F42C1">readblob</span><span style="color:#24292E">, file_path)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> ok_read </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> ok_decode, obj </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> pcall</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">json</span><span style="color:#24292E">.</span><span style="color:#6F42C1">decode</span><span style="color:#24292E">, content)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> ok_decode </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> obj</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6A737D">-- 対象ファイルの置かれたディレクトリを基に namespace 宣言を生成する</span></span>
+<span class="line"><span style="color:#6A737D">-- :help nvim_buf_get_name()</span></span>
+<span class="line"><span style="color:#6A737D">-- :help vim.fs.dirname()</span></span>
+<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> generate_namespace_declaration</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#6A737D"> -- composer.json を探し、トップレベルの名前空間とディレクトリを特定する</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> current_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">dirname</span><span style="color:#24292E">(vim.</span><span style="color:#6F42C1">api</span><span style="color:#24292E">.</span><span style="color:#005CC5">nvim_buf_get_name</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">))</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> path_to_composer_json </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> find_composer_json</span><span style="color:#24292E">(current_dir)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> path_to_composer_json </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- failed to locate composer.json</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> composer_json </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> load_json</span><span style="color:#24292E">(path_to_composer_json)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> composer_json </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- failed to load composer.json</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#6A737D"> -- autoload.psr-4 を探し、型が期待される型と一致するかどうか調べる</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> psr4 </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">tbl_get</span><span style="color:#24292E">(composer_json, </span><span style="color:#032F62">'autoload'</span><span style="color:#24292E">, </span><span style="color:#032F62">'psr-4'</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> psr4 </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- autoload.psr-4 section is absent</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">tbl_count</span><span style="color:#24292E">(psr4) </span><span style="color:#D73A49">~=</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is ambiguous</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> psr4_namespace, psr4_dir</span></span>
+<span class="line"><span style="color:#D73A49"> for</span><span style="color:#24292E"> k, v </span><span style="color:#D73A49">in</span><span style="color:#005CC5"> pairs</span><span style="color:#24292E">(psr4) </span><span style="color:#D73A49">do</span></span>
+<span class="line"><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">=</span><span style="color:#24292E"> k</span></span>
+<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> v</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_dir) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> 'table' </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> #</span><span style="color:#24292E">psr4_dir </span><span style="color:#D73A49">==</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> then</span></span>
+<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> psr4_dir[</span><span style="color:#005CC5">1</span><span style="color:#24292E">]</span></span>
+<span class="line"><span style="color:#D73A49"> else</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is ambiguous</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_namespace) </span><span style="color:#D73A49">~=</span><span style="color:#032F62"> 'string' </span><span style="color:#D73A49">or</span><span style="color:#005CC5"> type</span><span style="color:#24292E">(psr4_dir) </span><span style="color:#D73A49">~=</span><span style="color:#032F62"> 'string' </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span><span style="color:#6A737D"> -- psr-4 section is invalid</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#6A737D"> -- 末尾のスラッシュとバックスラッシュを取り除いておく</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> psr4_namespace</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '</span><span style="color:#005CC5">\\</span><span style="color:#032F62">' </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> psr4_namespace</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#6F42C1"> psr4_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '/' </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#24292E"> psr4_dir </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> psr4_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#005CC5">0</span><span style="color:#24292E">, </span><span style="color:#D73A49">-</span><span style="color:#005CC5">2</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#6A737D"> -- 対象ファイルが置かれたディレクトリとトップレベルのディレクトリを比較し、その差分を名前空間とする</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace_root_dir </span><span style="color:#D73A49">=</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fs</span><span style="color:#24292E">.</span><span style="color:#005CC5">dirname</span><span style="color:#24292E">(path_to_composer_json) </span><span style="color:#D73A49">..</span><span style="color:#032F62"> '/' </span><span style="color:#D73A49">..</span><span style="color:#24292E"> psr4_dir</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#D73A49"> not</span><span style="color:#24292E"> vim.</span><span style="color:#005CC5">startswith</span><span style="color:#24292E">(current_dir, namespace_root_dir) </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#005CC5"> nil</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> current_path_suffix </span><span style="color:#D73A49">=</span><span style="color:#6F42C1"> current_dir</span><span style="color:#24292E">:</span><span style="color:#005CC5">sub</span><span style="color:#24292E">(</span><span style="color:#D73A49">#</span><span style="color:#24292E">namespace_root_dir </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace </span><span style="color:#D73A49">=</span><span style="color:#24292E"> psr4_namespace </span><span style="color:#D73A49">..</span><span style="color:#6F42C1"> current_path_suffix</span><span style="color:#24292E">:</span><span style="color:#005CC5">gsub</span><span style="color:#24292E">(</span><span style="color:#032F62">'/'</span><span style="color:#24292E">, </span><span style="color:#032F62">'</span><span style="color:#005CC5">\\</span><span style="color:#032F62">'</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> (</span><span style="color:#032F62">"namespace %s;"</span><span style="color:#24292E">):</span><span style="color:#005CC5">format</span><span style="color:#24292E">(namespace)</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">local</span><span style="color:#D73A49"> function</span><span style="color:#6F42C1"> generate_template</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> lines </span><span style="color:#D73A49">=</span><span style="color:#24292E"> {</span></span>
+<span class="line"><span style="color:#032F62"> '&#x3C;?php'</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#032F62"> ''</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#032F62"> 'declare(strict_types=1);'</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#032F62"> ''</span><span style="color:#24292E">,</span></span>
+<span class="line"><span style="color:#24292E"> }</span></span>
+<span class="line"><span style="color:#D73A49"> local</span><span style="color:#24292E"> namespace_decl </span><span style="color:#D73A49">=</span><span style="color:#005CC5"> generate_namespace_declaration</span><span style="color:#24292E">()</span></span>
+<span class="line"><span style="color:#D73A49"> if</span><span style="color:#24292E"> namespace_decl </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#24292E"> namespace_decl</span></span>
+<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span></span>
+<span class="line"><span style="color:#D73A49"> end</span></span>
+<span class="line"><span style="color:#24292E"> lines[</span><span style="color:#D73A49">#</span><span style="color:#24292E">lines </span><span style="color:#D73A49">+</span><span style="color:#005CC5"> 1</span><span style="color:#24292E">] </span><span style="color:#D73A49">=</span><span style="color:#032F62"> ''</span></span>
+<span class="line"><span style="color:#D73A49"> return</span><span style="color:#24292E"> lines</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#D73A49">if</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">line</span><span style="color:#24292E">(</span><span style="color:#032F62">'$'</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#005CC5"> 1</span><span style="color:#D73A49"> and</span><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">getline</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">) </span><span style="color:#D73A49">==</span><span style="color:#032F62"> '' </span><span style="color:#D73A49">then</span></span>
+<span class="line"><span style="color:#6A737D"> -- 対象ファイルが空なら、テンプレートを挿入してカーソルを末尾に移動させる</span></span>
+<span class="line"><span style="color:#6A737D"> -- :help setline()</span></span>
+<span class="line"><span style="color:#6A737D"> -- :help cursor()</span></span>
+<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">setline</span><span style="color:#24292E">(</span><span style="color:#005CC5">1</span><span style="color:#24292E">, </span><span style="color:#005CC5">generate_template</span><span style="color:#24292E">())</span></span>
+<span class="line"><span style="color:#24292E"> vim.</span><span style="color:#6F42C1">fn</span><span style="color:#24292E">.</span><span style="color:#005CC5">cursor</span><span style="color:#24292E">(</span><span style="color:#032F62">'$'</span><span style="color:#24292E">, </span><span style="color:#005CC5">0</span><span style="color:#24292E">)</span></span>
+<span class="line"><span style="color:#D73A49">end</span></span>
+<span class="line"></span>
+<span class="line"><span style="color:#24292E">vim.</span><span style="color:#6F42C1">b</span><span style="color:#24292E">.</span><span style="color:#6F42C1">did_ftplugin_php_after</span><span style="color:#D73A49"> =</span><span style="color:#005CC5"> true</span></span></code></pre>
+ </div>
</section>
<section id="section--outro">