Neovim 用於 PHP 和 Laravel

如果你曾經想用 Neovim 來進行 PHP 和 Laravel 的開發,這篇指南應該可以幫助你入門。如果你使用 VSCode,那麼可以看看這篇 文章

在這篇文章中,我將使用 Neovim 搭配 LazyVim。LazyVim 是一個很棒的 Neovim 設定,開箱即用,擁有許多功能和工具。我花了比我願意承認的更多時間來配置 Vim 和 Neovim,而 LazyVim 幾乎省去了所有這些時間。當你開始熟悉 LazyVim 的配置後,你可以考慮從頭開始創建自己的配置。

這篇文章假設你正在使用最新版本的 Neovim(發布時是 v0.10.0)。如果你需要安裝它,可以在這裡為你的操作系統下載 這裡

一旦你安裝好 Neovim,我們將使用 LazyVim。如果你不想使用 LazyVim 而想使用你自己的配置,也可以,但對於這篇文章來說,那樣的設置會更加複雜。

要安裝 LazyVim,你需要將倉庫克隆下來並移動到你的 Neovim 配置文件夾中(在 MacOS/Linux 系統上是 ~/.config/nvim)。

git clone https://github.com/LazyVim/starter ~/.config/nvim

克隆完成後,你可以刪除 .git 文件夾,因為你現在不需要它,並且你可能會想對你的配置更改進行版本控制。

rm -rf ~/.config/nvim/.git

如果你使用的是 Windows,可以按照安裝說明 這裡 進行操作。

完成後,你可以運行 Neovim,它會下載所有 LazyVim 的插件和依賴項。

LazyVim 開箱即用,提供了方便的菜單以便你需要時進行導航。

LazyVim 最近添加了一個更新,可以快速添加 PHP 支援。你只需從主畫面點擊 x 進入附加功能菜單或輸入 :LazyExtras

在菜單中,你可以先輸入斜線然後輸入 php 來搜尋 PHP,即 /php。斜線 / 開始在 Neovim 中搜尋。

將光標放在 lang.php 行,按 x 以切換附加功能。然後重新啟動 Neovim。現在,Neovim 將支援 PHP 語法並安裝 Phpactor LSP。

為了測試 LSP,我使用 Laravel Breeze 創建了一個新的 Laravel 項目。從項目目錄中,打開 Neovim,並使用 <leader>ff 打開 ProfileController。在 Neovim 中,許多鍵盤命令都以 <leader> 鍵為前綴,預設為 space。因此,要查找文件,輸入 space + f + f。接著,你可以使用模糊搜尋器進行搜尋。

當第一次加載控制器時,Phpactor 會開始索引你的代碼庫,通常從項目的 Git 根目錄開始。

你還會看到許多錯誤和其他診斷信息。這些都是由 LSP 提供的,還包括代碼補全、跳轉定義、重構和許多其他功能。

如果你想修改基本控制器,你可以導航到 Controller 並點擊 gd 進行跳轉定義。

在跳轉定義後,你可以回到類定義並點擊 gr 進行跳轉到 Controller 類的引用。接下來,你可以使用 ctrl+o 跳回到之前的位置。

如果 Phpactor 對你有效,請不要猶豫繼續使用它。雖然它在處理 Laravel 的一些魔法和缺失類型方面有困難,但它完全免費且開源。你可以使用像 Laravel IDE Helper 的工具來改善這一點,該工具為模型、外觀和其他框架功能生成存根,以提供更好的自動補全。

就我個人而言,我使用 Intelephense LSP 的體驗更好,如果你來自 VSCode,你可能會對此比較熟悉。不幸的是,如果沒有 Intelephense 的高級版本,你會錯過 Phpactor 的一些功能,所以我建議如果你使用 Intelephense 的話,還是購買高級版。一個許可證可以用於 VSCode、Neovim 和任何其他支持 LSP 的編輯器。

要設置 Intelephense,你需要修改 LazyVim 配置。在 ~/.config/nvim 文件夾中,打開 options.lua 並添加以下行:

vim.g.lazyvim_php_lsp = "intelephense"

這告訴 LazyVim 設置 Intelephense。不過,你可能需要移除 Phpactor。要做到這一點,你可以輸入 <leader>cm,這會打開 Mason。Mason 是一個用於安裝各種格式化工具、代碼檢查器和 LSP 的工具。在 Mason 菜單中,找到 Phpactor,然後使用 X 進行卸載。

由於我們安裝了 Lazy Extras for PHP,因此 Laravel Pint 和 PHP-CS-Fixer 已經安裝好了。然而,PHP-CS-Fixer 被設置為默認工具。要更改這一點,我們可以在 Neovim 配置中創建一個新文件:~/.config/nvim/lua/plugins/php.lua。你可以為這個文件命名任何你想要的名稱,但在這篇文章中,我們將使用它來進行所有與 PHP/Laravel 相關的配置。

在文件中,你可以包括以下內容:

return {
  {
    "stevearc/conform.nvim",
    optional = true,
    opts = {
      formatters_by_ft = {
        php = { { "pint", "php_cs_fixer" } },
      },
    },
  },
}

這樣會將 Pint 設置為默認格式化工具,如果未找到它,則會退回到 PHP-CS-Fixer。通過這個更改,我可以回到 ProfileController 並添加一個未使用的導入並搞亂縮進,保存時會觸發格式化。

你可以進行的另一個可選更改是移除 phpcs 如果你不使用它。在 php.lua 文件中,只需添加另一個區塊,如下所示:

return {
  {
    -- 將 Laravel Pint 設置為默認 PHP 格式化工具,並將 PHP CS Fixer 設置為備用工具。
    "stevearc/conform.nvim",
    optional = true,
    opts = {
      formatters_by_ft = {
        php = { { "pint", "php_cs_fixer" } },
      },
    },
  },
  {
    -- 移除 phpcs 代碼檢查器。
    "mfussenegger/nvim-lint",
    optional = true,
    opts = {
      linters_by_ft = {
        php = {},
      },
    },
  },
}

我從 LazyVim 文檔 獲取這些配置。

接下來,我們將設置 Neatest,以便可以直接在 Neovim 中運行測試。這是另一個可以通過輸入 :LazyExtras,然後搜索「test.core」並用 X 切換的 LazyVim 附加功能。

然後,我們需要安裝 Neotest Pest 插件。將以下區塊添加到 php.lua 配置中。

return {
  {
    ...
  },
  {
    -- 添加 neotest-pest 插件以運行 PHP 測試。
    -- 如果需要,還可以使用 PHPUnit 的包。
    "nvim-neotest/neotest",
    dependencies = { "V13Axel/neotest-pest" },
    opts = { adapters = { "neotest-pest" } },
  }
}

配置好測試後,打開一個測試文件,您可以使用 <leader>tr 運行單個測試,或使用 <leader>tt 運行整個文件。

使用 <leader>to 切換測試結果的摘要。

添加對 Laravel Blade 的支持稍微複雜一些。LazyVim 已經設置了 Treesitter 來支持大多數語言的語法高亮。然而,Blade 預設未安裝,因此我們需要手動添加。

return {
  {
    ...
  },  
  {
    -- 添加一個 Treesitter 解析器以提供 Blade 語法高亮。
    "nvim-treesitter/nvim-treesitter",
    opts = function(_, opts)
      vim.list_extend(opts.ensure_installed, {
        "blade",
        "php_only",
      })
    end,
    config = function(_, opts)
      vim.filetype.add({
        pattern = {
          [".*%.blade%.php"] = "blade",
        },
      })

      require("nvim-treesitter.configs").setup(opts)
      local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
      parser_config.blade = {
        install_info = {
          url = "https://github.com/EmranMR/tree-sitter-blade",
          files = { "src/parser.c" },
          branch = "main",
        },
        filetype = "blade",
      }
    end,
  },
}

我們擴展默認的 Treesitter 配置來設置一個新的文件類型並下載 Blade 解析器。

重啟 Neovim 後,您可以運行 :TSInstall blade 來下載解析器。

接下來,我們需要添加一些 Treesitter 查詢以獲得更好的代碼支持。為此,我們需要在 Neovim 中創建一些新文件。

輸入 :TSEditQuery injections blade 並添加以下內容:

((text) @injection.content
    (#not-has-ancestor? @injection.content "envoy")
    (#set! injection.combined)
    (#set! injection.language php))

; tree-sitter-comment injection
; if available
((comment) @injection.content
 (#set! injection.language "comment"))

; could be bash or zsh
; or whatever tree-sitter grammar you have.
((text) @injection.content
    (#has-ancestor? @injection.content "envoy")
    (#set! injection.combined)
    (#set! injection.language bash))

((php_only) @injection.content
    (#set! injection.language php_only))

((parameter) @injection.content                                                                                                 
    (#set! injection.include-children) ; You may need this, depending on your editor e.g Helix                                                                                          
    (#set! injection.language "php-only"))

輸入 :TSEditQuery highlights blade 並新增:

(directive) @tag
(directive_start) @tag
(directive_end) @tag
(comment) @comment

輸入 :TSEditQuery folds blade 並新增:

((directive_start) @start
    (directive_end) @end.after
    (#set! role block))


((bracket_start) @start
    (bracket_end) @end
    (#set! role block))

最後,我們將為 Alpine 支援添加一些注入查詢。輸入 :TSEditQuery 並新增:

;; extends

; AlpineJS attributes
(attribute
  (attribute_name) @_attr
    (#lua-match? @_attr "^x%-%l")
  (quoted_attribute_value
    (attribute_value) @injection.content)
  (#set! injection.language "javascript"))

; Blade escaped JS attributes
; <x-foo ::bar="baz" />
(element
  (_
    (tag_name) @_tag
      (#lua-match? @_tag "^x%-%l")
  (attribute
    (attribute_name) @_attr
      (#lua-match? @_attr "^::%l")
    (quoted_attribute_value
      (attribute_value) @injection.content)
    (#set! injection.language "javascript"))))

; Blade PHP attributes
; <x-foo :bar="$baz" />
(element
  (_
    (tag_name) @_tag
      (#lua-match? @_tag "^x%-%l")
    (attribute
      (attribute_name) @_attr
        (#lua-match? @_attr "^:%l")
      (quoted_attribute_value
        (attribute_value) @injection.content)
      (#set! injection.language "php_only"))))

現在,添加完所有內容後,保存並重新啟動,您應該能夠看到 Blade 文件的語法高亮顯示!

欲了解更多資訊和安裝說明,請訪問 repo 以獲取 Blade Treesitter 解析器。

LazyVim 內建一個插件,可以輕鬆創建片段。要創建 PHP 片段,您可以創建一個新文件: ~/.config/nvim/snippets/php.json,格式類似於以下範例:

{
  "strict types": {
    "prefix": "strict",
    "description": "Add strict types declaration",
    "body": [
      "declare(strict_types=1);"
    ]
  },
  "inv": {
    "prefix": "inv",
    "description": "Create PHP __invoke method",
    "body": [
      "public function __invoke(${1}): ${2:void}",
      "{",
      "    ${3}",
      "}",
      ""
    ]
  },
  "public method": {
    "prefix": "pubf",
    "description": "Create a public method",
    "body": [
      "public function ${1}(${2}): ${3:void}",
      "{",
      "    ${0}",
      "}",
      ""
    ]
  },
  "protected method": {
    "prefix": "prof",
    "description": "Create a protected method",
    "body": [
      "protected function ${1}(${2}): ${3:void}",
      "{",
      "    ${0}",
      "}",
      ""
    ]
  },
  "private method": {
    "prefix": "prif",
    "description": "Create a private method",
    "body": [
      "private function ${1}(${2}): ${3:void}",
      "{",
      "    ${0}",
      "}",
      ""
    ]
  },
  "public static method": {
    "prefix": "pubsf",
    "description": "Create a public static method",
    "body": [
      "public static function ${1}(${2}): ${3:void}",
      "{",
      "    ${0}",
      "}",
      ""
    ]
  },
  "pest test (it) method": {
    "prefix": "it",
    "description": "Create a pest test",
    "body": [
      "it('${1}', function () {",
      "    // Arrange",
      "    ${0}",
      "",
      "    // Act",
      "",
      "    // Assert",
      "",
      "});"
    ]
  }
}

您可以將任何其他片段添加到此文件中,或為其他語言創建文件以添加片段。

此插件可用於通過 <leader>la 以出色的搜索功能快速運行 Artisan 命令。或者,您可以使用 <leader>lr 列出應用程式中的所有路由。

return { 
  {
    ...
  },
  {
    -- 添加 Laravel.nvim 插件,提供從 Neovim 運行 Artisan 命令的功能
    --。
    "adalessa/laravel.nvim",
    dependencies = {
      "nvim-telescope/telescope.nvim",
      "tpope/vim-dotenv",
      "MunifTanjim/nui.nvim",
      "nvimtools/none-ls.nvim",
    },
    cmd = { "Sail", "Artisan", "Composer", "Npm", "Yarn", "Laravel" },
    keys = {
      { "la", ":Laravel artisan" },
      { "lr", ":Laravel routes" },
      { "lm", ":Laravel related" },
    },
    event = { "VeryLazy" },
    config = true,
    opts = {
      lsp_server = "intelephense",
      features = { null_ls = { enable = false } },
    },
  },
}

新增了在 Blade 視圖上使用 Goto File 的功能,通過 gf 可以跳轉到組件和其他視圖。

return { 
  {
    ...
  },
  {
    -- 添加了 blade-nav.nvim 插件,提供 Blade 文件的 Goto File 功能。
    -- 
    "ricardoramirezr/blade-nav.nvim",
    dependencies = {
      "hrsh7th/nvim-cmp",
    },
    ft = { "blade", "php" },
  },
}

LazyVim 的一個巨大優勢是文檔。如果你在 VSCode 中習慣做某些事情並希望在 Neovim 中實現,LazyVim 可能已經內置了這些功能。我建議你逐一查看 LazyVim 的每個部分來了解更多信息。

最重要的部分之一可能是鍵位映射。LazyVim 使用 which-key.nvim 幫助你記住配置的按鍵,但若要查看完整列表,請點擊 這裡

想要 Git 支援嗎?LazyVim 已經提供了 LazyGit,這是一個非常好用的 Git 終端 UI。使用 <leader>gg 打開它。你甚至可以 直接安裝 LazyGit,例如通過 Homebrew 在命令行上運行 lazygit

需要額外的工具,如 PHPStan 或 Psalm 嗎?使用 <leader>cm:Mason 打開 Mason 菜單並搜索你需要的工具。它有許多流行的 linter 和 formatter 可供安裝。

如我前面提到的,LazyVim 提供了極好的文檔,絕對值得一讀。

Jess Archer 在 Laracasts 上提供了一個出色的 課程,介紹如何設置 Neovim。如果你沒有訂閱 Laracasts,我非常推薦。自 2017 年以來,我一直是終身用戶。如果你對此感興趣,請使用我的 推薦連結

DHH(Ruby on Rails 的創建者)創建了 Omakub 套件,作為在 Ubuntu Linux 上快速設置開發環境的方法。即使你不使用 Ubuntu,Omakub 的倉庫仍然值得查看,因為它擁有許多優秀的配置和工具,其中之一是帶有 LazyVim 的 Neovim。

如果你想要比 LazyVim 更簡約的配置,Kickstart.nvim 是一個不錯的起點。你可以觀看這段由 TJ DeVries 製作的視頻,了解如何開始使用。即使你想繼續使用 LazyVim,這仍然是了解 Neovim 配置的寶貴資源。

希望這能幫助你開始使用 Neovim。它是一個功能強大的編輯器,具有無限的可配置性。雖然不像 PhpStorm 那麼強大,但它幾乎可以免費達到相似的效果,並且佔用的 CPU 資源更少。

即使你不打算將 Neovim 作為主要的編輯器,我認為學習其快捷鍵仍然是有益的。我通常會在 Neovim 和 PhpStorm 之間分配時間,並嘗試使我的快捷鍵儘可能保持一致。幸運的是,JetBrains 的 IdeaVim 插件使這變得簡單。

供你參考,我創建了一個 repo,其中包含了我們在這篇文章中創建的所有文件。

如果你對設置或我可能遺漏的其他功能有任何疑問,請告訴我。

感謝你的閱讀!

Source:
https://seankegel.com/neovim-for-php-and-laravel