天天看點

從零開始配置vim(28)——代碼的編譯、運作與調試

在前面幾個章節,我們逐漸為 ​

​Vim​

​​ 配置了文法高亮、代碼的跳轉和自動補全功能。現在的 ​

​Vim​

​​ 已經可以作為代碼編輯器來使用了。但是想将它作為日常發開的主力編輯器來用還需要很長一段路要走,其中一個就是要為它配置代碼的一鍵編譯與運作功能。這裡我們仍然以 ​

​C​

​​ 和 ​

​Python​

​ 為例。一個是需要編譯運作的一個是直接就可以運作的,這兩個語言應該能代表大多數語言的情況。

自動運作

C 語言的配置

在之前 ​

​vim​

​​ 入門的一系列教程中我們介紹過 ​

​vim​

​​ 自帶 ​

​make​

​​ 指令的運作機制以及如何進行自定義。對于其他語言要實作這個自動編譯運作的效果我們核心的操作就是在修改 ​

​make​

​​ 指令。而 ​

​C/C++​

​​ 本身采用 ​

​make​

​​ 指令來進行編譯和運作,是以這裡 ​

​C/C++​

​​ 我們直接采用 vim 自帶的 ​

​:make​

​ 指令

我們先建立一個 ​

​C​

​​ 的工程。讓後使用上一節的生成 hello world 的代碼片段生成一個基本的程式。然後提供一個供 ​

​:make​

​​ 指令使用的 ​

​Makefile​

​ 檔案

main.out: main.o
    gcc main.o -o main.out
main.o: main.c
    gcc -c main.c
clean:
    rm -rf *.o *.out
run:
    ./main.out      

然後我們執行 ​

​make​

​​ 用來編譯。如果出錯了,可以使用 ​

​quickfix​

​ 相關指令跳轉到對應位置。

我們一般的流程是 ​

​:make​

​​ 進行編譯,然後使用 ​

​:make run​

​​ 來進行運作。把指令搞清楚了,下面就考慮如何加快這個流程,做到一鍵編譯運作。我們的思路還是綁定快捷鍵。每種語言雖然定義相同的快捷鍵但是運作的指令不同,我們需要根據不同的語言類型綁定對應的指令。這個時候最好的辦法就是在 ​

​filetype​

​ 的機制上完成綁定的操作。

我們在 ​

​lua/lsp/cpp.lua​

​ 中綁定快捷鍵。

local on_attach = function(client, bufnr)
    lsp_set_keymap.set_keymap(bufnr)
    -- 編譯
    vim.api.nvim_buf_set_keymap(bufnr, "n", "<F7>", "<cmd>make<CR>", {silent = true, noremap = true})
    -- 編譯運作
    vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>make run<CR>", {silent = true, noremap = true})
end      

到此我們關于 ​

​C/C++​

​​ 的配置就完成了。可能顯的有些簡單但是已經初步可用了,小夥伴可以根據自己的需求來進一步修改這個配置。使用這個配置的前提是 ​

​C/C++​

​​ 的工程中有已經定義好的 ​

​Makefile​

​ 檔案

從零開始配置vim(28)——代碼的編譯、運作與調試

Python的配置

之前我們在講解指令的模式的提到過可以使用 ​

​%​

​​ 來代表目前 ​

​buffer​

​​ 所對應的檔案。是以 ​

​python​

​​ 的配置就比較簡單了。因為 ​

​Python​

​​ 不需要編譯,是以這裡直接綁定 ​

​<F5>​

​ 來運作

vim.api.nvim_buf_set_keymap(bufnr, "n", "<F5>", "<cmd>!python %<CR>", {silent = true, noremap = true})      
從零開始配置vim(28)——代碼的編譯、運作與調試

dap 配置

我們經常看到有人配置 ​

​neovim​

​​ 或者 ​

​vim​

​​ 的時候會介紹到 ​

​dap​

​​ ,那麼什麼是 ​

​dap​

​​ 呢? ​

​dap​

​​ 的全稱是 ​

​Debug Adapter Protocol​

​​ 從名稱上看它又是一個協定。它為多種調試器提供了一層統一的适配抽象層。有點類似于前面的介紹的 ​

​lsp​

​。隻要在适配層提供接口的實作,那麼在用戶端,也就是代碼編輯器這端可以不做任何修改的內建不同調試

聯想到 ​

​lsp​

​​ 的配置,我們配置​

​dap​

​​ 首先需要的是有一個 ​

​dap​

​​ 的用戶端,用來向調試器發送各種指令,例如下斷點、顯示變量名等等。另外想要能夠調試也需要有具體的調試器,用來接收處理這些指令。現在思路有了,我們 這裡先以 ​

​Python​

​​ 為例來介紹 ​

​dap​

​ 的基本配置。

首先是需要一個用戶端,用于通過 ​

​neovim​

​下發各種調試指令并實時顯示調試資訊。

截止到 ​

​0.7​

​​ 版本 ​

​NeoVim​

​​ 并沒有在内部內建 ​

​dap​

​​ 用戶端的功能,需要我們單獨安裝相關插件來實作這部分的功能。這裡我們使用的用戶端是 ​

​nvim-dap​

​ 插件。

我們先使用 ​

​use {'mfussenegger/nvim-dap'}​

​ 來安裝它。

接着我們來定義一下相關的快捷鍵,這裡我喜歡使用 ​

​Visual Studio​

​​ 的快捷鍵。各位小夥伴可以自行選擇自己喜歡的快捷鍵。這裡我希望在插入模式和選擇中也可以使用這些快捷鍵,由于 ​

​vim.api.nvim_set_keymap​

​​ 函數第一個參數隻能有一個模式字元串,如果采用這個函數來定義快捷鍵,這裡同樣的代碼我要寫三次,為了簡化代碼,這裡介紹一個新的函數 ​

​vim.keymap.set​

​​。它與 ​

​vim.api.nvim_set_keymap​

​ 函數支援的參數相同,隻是它第一個表示模式的參數可以支援用字典來一次綁定到多個模式中。這樣就簡化了綁定快捷鍵的代碼量。

vim.keymap.set({"i", "n", "v"}, "<F5>", "<cmd>lua require'dap'.continue()<CR>", {silent = true, noremap = true, buffer = bufnr})
vim.keymap.set({"i", "n", "v"}, "<F10>", "<cmd>lua require'dap'.step_over()<CR>", {silent = true, noremap = true, buffer = bufnr})
vim.keymap.set({"i", "n", "v"}, "<F11>", "<cmd>lua require'dap'.step_into()<CR>", {silent = true, noremap = true, buffer = bufnr})
vim.keymap.set({"i", "n", "v"}, "<F12>", "<cmd>lua require'dap'.step_over()<CR>", {silent = true, noremap = true, buffer = bufnr})
vim.keymap.set({"i", "n", "v"}, "<F9>", "<cmd>lua require'dap'.toggle_breakpoint()<CR>", {silent = true, noremap = true, buffer = bufnr})      

這個函數是 0.7 以後的版本引進的,如果你的是0.7之前的版本,還是老老實實的多寫幾遍。另外我們這裡綁定了 ​

​<F5>​

​​ 快捷鍵,是以之前我們在 ​

​Python​

​​ 中,綁定的直接運作的 ​

​<F5>​

​ 鍵的代碼需要注釋一下。

我們想要真正實作調試,還需要配合調試器使用。前面說 ​

​dap​

​​ 隻是一層協定,需要用戶端伺服器按照這一層協定來實作相關功能,某些調試器可能自身支援這個協定,而某些可能不支援,這樣就需要額外的配置來使調試器也能支援該協定。下面我們以 ​

​Python​

​ 為例先把整個調試環境搭建起來,先跑起來再說

​Lsp​

​​ 在安裝 ​

​Server​

​​ 的時候有 ​

​nvim-lsp-installer​

​​ 這樣的插件來專門安裝 ​

​LSP server​

​​ 的,那麼 ​

​dap​

​​ 有沒有類似的插件來安裝 ​

​dap​

​​ 調試器相關的服務呢?有!我們使用 ​

​mason​

​​ 來管理 ​

​dap​

​ 的調試器。

use { "williamboman/mason.nvim" }      

當初我推薦過 ​

​nvim-lsp-installer​

​​ 插件作為下載下傳、管理 ​

​lsp server​

​​ 的工具。後來隻是知道作者釋出了新的管理工具,因為比較新怕出問題就沒怎麼關注,後來有好多小夥伴在評論區推薦,我仔細看了一下發現它已經支援 ​

​dap​

​​ 服務的管理了。那還是使用它吧 ​

​^_^​

​。

我們可以使用 ​

​Mason​

​​ 打開一個帶界面的 ​

​Lsp​

​​ 和 ​

​DAP​

​​ 的服務管理視窗,可以使用 數字鍵在上面進行跳轉,找到想要的服務之後直接使用 ​

​i​

​ 來安裝

從零開始配置vim(28)——代碼的編譯、運作與調試

也可以使用 ​

​MasonInstall​

​ 來安裝想要的服務。

我們先在插件配置中删除與 ​

​nvim-lsp-installer​

​​ 相關的配置,包括 ​

​packer​

​​ 中對它的引用和 ​

​plugins-config​

​ 目錄中的配置。

下一步就是配置 ​

​dap​

​​ 的用戶端與 服務端的關聯,這需要配置 ​

​nvim-dap​

​ 插件,根據官方的描述我們主要配置兩個部分,第一個部分叫做擴充卡,主要配置我們加載哪個調試器,以及如何加載調試器。這一步需要提供如下的配置架構

local dap = require('dap')
dap.adapters.language = {
}      

​language​

​​ 是具體的調試器例如 ​

​debugpy​

​​ 這裡的 ​

​language​

​​ 就是 ​

​python​

​​了。既然與語言相關,我們自然的想到要用 ​

​ftplugin​

​​目錄。為了友善管理,這裡與 ​

​lsp​

​​ 配置的組織形式類似,我們将所有關于 ​

​dap​

​​ 的配置都放到 ​

​lua/dap​

​​目錄中。并且按語言名稱來命名,例如關于 ​

​python​

​​ 的 ​

​dap​

​​ 配置我們放到 ​

​lua/dap/python.lua​

​​ 中。然後在 ​

​ftplugin/python.lua​

​ 中加載這個配置檔案即。

require("dap/python")      

然後在 ​

​python.lua​

​ 檔案中寫入以下配置

local dap = require('dap')
dap.adapters.python = {
  type = 'executable';
  command = '/usr/bin/python3.8';
  args = { '-m', 'debugpy.adapter' };
}      

其中各個參數的含義如下:

  • ​type​

    ​​ : 表示啟動調試器的方式, ​

    ​executable​

    ​​ 表示由用戶端自行啟動調試器; ​

    ​server​

    ​ 表示 調試器已經單獨啟動了,後續用戶端隻需要将調試請求發送到伺服器即可。
  • ​command​

    ​: 表示啟動調試器的指令
  • ​args​

    ​: 表示啟動調試器的指令行參數

由于 ​

​python​

​​ 調試工具 ​

​debugpy​

​​ 是一個 ​

​Python​

​​ 的第三方子產品,是以這裡我們使用 ​

​python -m debugpy.adapter​

​ 來啟動這個調試器。

接着我們需要針對語言來配置如何進行調試。它的配置都放在一個名為 ​

​dap.configurations.language​

​​ 的 字典中。​

​language​

​​ 代表的是目前檔案的檔案類型名, 是以針對 ​

​Python​

​​ 來說這裡需要填寫的是 ​

​dap.configurations.python​

​。它的配置如下所示:

dap.configurations.python = {
    {
        type = "python";
        request = "launch";
        name = "launch file";
        program = "${file}";
        pythonPath = function ()
            return "/usr/bin/python3.8"
        end
    },
 }      

各參數的含義如下:

  • ​name​

    ​ : 是一個字元串它表示目前配置的名稱,你可以了解為一個id
  • ​type​

    ​​: 使用哪個調試器,跟我們之前配置的 ​

    ​dap.adapters​

    ​相關
  • ​request​

    ​​:調試的方式,支援 ​

    ​attach​

    ​​ 附加到一個已有的程序或者 ​

    ​launch​

    ​​ 啟動一個新程序。由于在上一步我們指定由用戶端來啟動調試器,是以這裡應該選擇 ​

    ​launch​

    ​ 來啟動一個新調試程序
  • ​program​

    ​​: 需要調試的代碼, ​

    ​${file}​

    ​​ 表示目前 ​

    ​buffer​

    ​ 所對應檔案
  • ​pythonPath​

    ​​: 執行該檔案需要使用的 ​

    ​python​

    ​ 解析器路徑

這樣我們在某一個打開的檔案上按下 ​

​<F5>​

​​ 的時候,它會通過 ​

​pythonPath​

​​ 指定的解析器來執行腳本,并且會按照配置中 ​

​request​

​ 指定的方式來打開一個新的調試器程序。并且将對應的調試指令發送到調試器完成調試工作。

從零開始配置vim(28)——代碼的編譯、運作與調試