首页 > 后端开发 > Golang > 掌握 Emacs 中的 Golang 调试

掌握 Emacs 中的 Golang 调试

Linda Hamilton
发布: 2024-12-02 11:56:09
原创
213 人浏览过

介绍

自从我开始使用 Golang 开发以来,我并没有真正使用过调试器。相反,我天真地在各处添加 fmt.Print 语句来验证我的代码?虽然打印语句和日志可能也是您的第一个调试本能,但在处理大型且复杂的代码库、复杂的运行时行为以及(当然!)似乎无法重现的复杂并发问题时,它们通常会出现不足。

开始处理更复杂的项目(比如这个:https://github.com/cloudoperators/heureka)后,我不得不强迫自己更深入地了解 delve(Golang 调试器)并了解 Emacs 提供的功能与它互动。虽然 Go 生态系统提供了出色的调试工具,但将它们集成到舒适的开发工作流程中可能具有挑战性。

在这篇文章中,我将详细阐述 Emacs、Delve 和 dape 的强大组合。这些工具共同创造了模仿(并且常常超越)传统 IDE 的调试体验,同时保留了 Emacs 闻名的灵活性和可扩展性。

这是你所期望的:

  • 使用 dape 设置和配置 Delve
  • 调试标准应用程序和 Ginkgo 测试(这就是我目前正在使用的?)
  • 使用 Emacs 特定的自定义功能优化您的调试工作流程

设置开发环境

在这篇文章中,我假设您已经有一些 Emacs 经验,现在了解如何配置包和编写小的 Elisp 片段。我个人使用 Straight.el 作为包管理器,minimal-emacs.d 作为最小的普通 Emacs 配置(以及我自己的自定义),dape 作为调试适配器客户端,eglot 作为我的 LSP 客户端

所需的 Emacs 软件包

对于 Emacs 29 用户,eglot 是内置的。查看为 gopls 配置 eglot 和一些更高级的 gopls 设置。我们首先添加 dape:

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

和运行​​模式:

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))
登录后复制
登录后复制
登录后复制
登录后复制

安装所需的 Go 工具

安装 Delve 和 gopls(LSP 服务器):

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest
登录后复制
登录后复制
登录后复制
登录后复制

此外,我还有一些我不时使用的其他工具:

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest
登录后复制
登录后复制
登录后复制
登录后复制

然后需要配置相应的Emacs包:

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)
登录后复制
登录后复制
登录后复制
登录后复制

戴普配置

我使用 dape 而不是 dap 没有什么特别的原因。当我还在使用 MinEmacs 时,它就是其中的一部分,我只是习惯了它。正如文档所述:

  • Dape 不支持 launch.json 文件,如果需要每个项目配置,请使用 dir-locals 和 dape-command。
  • Dape 允许用户使用选项修改或添加 PLIST 条目到现有配置,从而增强了迷你缓冲区内的人体工程学。
  • 没有魔法,没有像 ${workspaceFolder} 这样的特殊变量。相反,函数和变量会在开始新会话之前解析。
  • 尝试设想如果 vscode 不存在,如何在 Emacs 中实现调试适配器配置。

如果您曾经使用过 VSCode,您已经知道它使用 launch.json 来存储不同的调试配置文件:

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

您有不同的字段/属性,根据此页面,您可以在调试配置中进行调整:

Property Description
name Name for your configuration that appears in the drop down in the Debug viewlet
type Always set to "go". This is used by VS Code to figure out which extension should be used for debugging your code
request Either of launch or attach. Use attach when you want to attach to an already running process
mode For launch requests, either of auto, debug, remote, test, exec. For attach requests, use either local or remote
program Absolute path to the package or file to debug when in debug & test mode, or to the pre-built binary file to debug in exec mode
env Environment variables to use when debugging. Example: { "ENVNAME": "ENVVALUE" }
envFile Absolute path to a file containing environment variable definitions
args Array of command line arguments that will be passed to the program being debugged
showLog Boolean indicating if logs from delve should be printed in the debug console
logOutput Comma separated list of delve components for debug output
buildFlags Build flags to be passed to the Go compiler
remotePath Absolute path to the file being debugged on the remote machine
processId ID of the process that needs debugging (for attach request with local mode)

申请样本

现在让我们通过调试实现 REST API 的真实应用程序来将我们的知识付诸实践。

项目结构

我们的示例是用于任务管理的 REST API,其结构如下:

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

核心组件

让我们看看核心组件

任务代表我们的核心领域模型:

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))
登录后复制
登录后复制
登录后复制
登录后复制

TaskStore 处理我们的内存数据操作:

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest
登录后复制
登录后复制
登录后复制
登录后复制

休息API

API 公开以下端点:

  • POST /task/create - 创建一个新任务
  • GET /task/get?id=; - 通过ID检索任务
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest
登录后复制
登录后复制
登录后复制
登录后复制

服务器

这是服务器实现:

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)
登录后复制
登录后复制
登录后复制
登录后复制

让我们看看我们的主要功能:

{
    "name": "Launch file",
    "type": "go",
    "request": "launch",
    "mode": "auto",
    "program": "${file}"
}
登录后复制
登录后复制

构建应用程序

让我们启动服务器:

taskapi/
├── go.mod
├── go.sum
├── main.go
├── task_store.go
└── task_test.go
登录后复制
登录后复制

现在从不同的终端创建一个新任务:

import (
    "fmt"
)

type Task struct {
    ID          int    `json:"id"`
    Title       string `json:"title"`
    Description string `json:"description"`
    Done        bool   `json:"done"`
}
登录后复制
登录后复制

回应:

type TaskStore struct {
    tasks  map[int]Task
    nextID int
}

func NewTaskStore() *TaskStore {
    return &TaskStore{
        tasks:  make(map[int]Task),
        nextID: 1,
    }
}
登录后复制
登录后复制

让我们看看是否可以获取它:

// CreateTask stores a given Task internally
func (ts *TaskStore) CreateTask(task Task) Task {
    task.ID = ts.nextID
    ts.tasks[task.ID] = task
    ts.nextID++
    return task
}

// GetTask retrieves a Task by ID
func (ts *TaskStore) GetTask(id int) (Task, error) {
    task, exists := ts.tasks[id]
    if !exists {
        return Task{}, fmt.Errorf("task with id %d not found", id)
    }
    return task, nil
}

// UpdateTask updates task ID with a new Task object
func (ts *TaskStore) UpdateTask(id int, task Task) error {
    if _, exists := ts.tasks[id]; !exists {
        return fmt.Errorf("task with id %d not found", id)
    }
    task.ID = id
    ts.tasks[id] = task
    return nil
}
登录后复制
登录后复制

回应:

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
)

// Server implements a web application for managing tasks
type Server struct {
    store *TaskStore
}

func (s *Server) handleCreateTask(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    createdTask := s.store.CreateTask(task)
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(createdTask)
}

func (s *Server) handleGetTask(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodGet {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    id := 0
    fmt.Sscanf(r.URL.Query().Get("id"), "%d", &id)

    task, err := s.store.GetTask(id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(task)
}
登录后复制

单元测试

下面是 TaskStore 的一些单元测试(用 Ginkgo 编写):

package main

import (
    "log"
    "net/http"
)

func main() {
    store := NewTaskStore()
    server := &Server{store: store}
    http.HandleFunc("/task/create", server.handleCreateTask)
    http.HandleFunc("/task/get", server.handleGetTask)

    log.Printf("Starting server on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
登录后复制
go build -o taskapi *.go
./taskapi
2024/11/14 07:03:48 Starting server on :8080
登录后复制

在 Emacs 中,我将调用 ginkgo-run-this-container,如以下屏幕截图所示:

Mastering Golang Debugging in Emacs

使用 Delve 和 Dape 进行基本调试

为了调试我们的任务 API,我们有以下方法:

  • 我们可以直接启动应用程序并调试它
  • 我们可以附加到正在运行的进程
  • 我们可以附加到正在运行的调试会话

以下是不同请求类型的选项:

请求 模式 必填 可选 标题>
request mode required optional
launch debug program dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug
test program dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug
exec program dlvCwd, env, backend, args, cwd, noDebug
core program, corefilePath dlvCwd, env
replay traceDirPath dlvCwd, env
attach local processId backend
remote
启动 调试 程序 dlvCwd、env、后端、args、cwd、buildFlags、输出、noDebug 测试 程序 dlvCwd、env、后端、args、cwd、buildFlags、输出、noDebug 执行 程序 dlvCwd、env、后端、args、cwd、noDebug 核心 程序,核心文件路径 dlvCwd,环境 重播 traceDirPath dlvCwd,环境 附加 本地 进程ID 后端 远程 表>

配置文件 1:启动应用程序

这是我们的第一个 .dir-locals.el 调试配置文件:

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

?您可能希望对 command-cwd 使用不同的值。就我而言,我想在当前不是项目的目录中启动调试器。 default-directory 是一个变量,它保存当前所在缓冲区的工作目录。

开始调试:

  • 运行 dape-in​​fo 显示调试信息

Mastering Golang Debugging in Emacs

  • 使用 dape-breakpoint-toggle 创建断点:

Mastering Golang Debugging in Emacs

使用此配置文件启动调试器后,您应该在 dape-repl 缓冲区中看到:

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))
登录后复制
登录后复制
登录后复制
登录后复制

请注意,我们没有指定任何要调试的二进制文件/文件(我们在 .dir-locals.el 中有 :program ".")。 delve 将在启动应用程序之前自动构建二进制文件:

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest
登录后复制
登录后复制
登录后复制
登录后复制

配置文件 2:连接到外部调试器

让我们添加一个配置文件以连接到现有的调试会话:

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest
登录后复制
登录后复制
登录后复制
登录后复制

现在让我们在 CLI 上启动 调试器

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)
登录后复制
登录后复制
登录后复制
登录后复制

现在在 Emacs 中,您可以启动 dape 并选择 go-attach-taskapi 配置文件:

Mastering Golang Debugging in Emacs

配置文件 3:附加到正在运行的进程

在这种情况下,应用程序已经正在运行,但您想要附加调试器到它。首先启动应用程序:

{
    "name": "Launch file",
    "type": "go",
    "request": "launch",
    "mode": "auto",
    "program": "${file}"
}
登录后复制
登录后复制

找出其进程ID (PID):

taskapi/
├── go.mod
├── go.sum
├── main.go
├── task_store.go
└── task_test.go
登录后复制
登录后复制

让我们添加另一个调试配置文件:

import (
    "fmt"
)

type Task struct {
    ID          int    `json:"id"`
    Title       string `json:"title"`
    Description string `json:"description"`
    Done        bool   `json:"done"`
}
登录后复制
登录后复制

我们需要一个辅助函数:

type TaskStore struct {
    tasks  map[int]Task
    nextID int
}

func NewTaskStore() *TaskStore {
    return &TaskStore{
        tasks:  make(map[int]Task),
        nextID: 1,
    }
}
登录后复制
登录后复制

Mastering Golang Debugging in Emacs

现在我启动调试器:

Mastering Golang Debugging in Emacs

如果我现在发送像这样的 POST 请求:

// CreateTask stores a given Task internally
func (ts *TaskStore) CreateTask(task Task) Task {
    task.ID = ts.nextID
    ts.tasks[task.ID] = task
    ts.nextID++
    return task
}

// GetTask retrieves a Task by ID
func (ts *TaskStore) GetTask(id int) (Task, error) {
    task, exists := ts.tasks[id]
    if !exists {
        return Task{}, fmt.Errorf("task with id %d not found", id)
    }
    return task, nil
}

// UpdateTask updates task ID with a new Task object
func (ts *TaskStore) UpdateTask(id int, task Task) error {
    if _, exists := ts.tasks[id]; !exists {
        return fmt.Errorf("task with id %d not found", id)
    }
    task.ID = id
    ts.tasks[id] = task
    return nil
}
登录后复制
登录后复制

调试器应在设置的断点处自动停止:

Mastering Golang Debugging in Emacs

调试 Ginkgo 测试

能够在 Golang 中调试测试至关重要。为了运行 ginkgo 测试,我使用 ginkgo-mode,它具有以下几个功能:

Mastering Golang Debugging in Emacs

Mastering Golang Debugging in Emacs

作为输出,我得到:

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

银杏的 Dape 配置

这是调试 Ginkgo 测试的基本配置:

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))
登录后复制
登录后复制
登录后复制
登录后复制

如果我选择 go-test-ginkgo 调试配置文件,我应该能够调试测试:

Mastering Golang Debugging in Emacs

现在配置非常静态,因此您无法预先选择单元测试/容器。我们需要以某种方式使参数 -ginkgo.focus 动态化:

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest
登录后复制
登录后复制
登录后复制
登录后复制

Mastering Golang Debugging in Emacs

之后,如果我查看 dape-configs 变量,我应该会看到这个值:

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest
登录后复制
登录后复制
登录后复制
登录后复制

在 dape-repl 缓冲区中启动调试器(使用以调试为中心的测试配置文件)后,我得到:

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)
登录后复制
登录后复制
登录后复制
登录后复制

?请注意,仅运行了“5 个规格中的 1 个”(❶),这意味着 ginkgo 只关注我们指定的容器 (❷)。

最佳实践和技巧

通过我的调试经验,我开始欣赏一些最佳实践:

  • 使用版本控制进行调试配置
  • 在 .dir-locals.el 中维护调试配置
  • 使用有意义的名称进行配置
  • 创建特定于项目的调试辅助函数
  • 在本地进行自定义(特定于缓冲区)

资源和参考

  • vscode-go/docs/debugging.md at master · golang/vscode-go
  • 直接支持 delve/dlv dap-mode · Issue #318 · emacs-lsp/dap-mode
  • Dape GitHub 存储库
  • 深入调试器
  • Eglot 文档
  • Ginkgo 测试框架

以上是掌握 Emacs 中的 Golang 调试的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板