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

掌握 Emacs 中的 Golang 调试

Dec 02, 2024 am 11:56 AM

介绍

自从我开始使用 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中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Debian OpenSSL有哪些漏洞 Debian OpenSSL有哪些漏洞 Apr 02, 2025 am 07:30 AM

OpenSSL,作为广泛应用于安全通信的开源库,提供了加密算法、密钥和证书管理等功能。然而,其历史版本中存在一些已知安全漏洞,其中一些危害极大。本文将重点介绍Debian系统中OpenSSL的常见漏洞及应对措施。DebianOpenSSL已知漏洞:OpenSSL曾出现过多个严重漏洞,例如:心脏出血漏洞(CVE-2014-0160):该漏洞影响OpenSSL1.0.1至1.0.1f以及1.0.2至1.0.2beta版本。攻击者可利用此漏洞未经授权读取服务器上的敏感信息,包括加密密钥等。

从前端转型后端开发,学习Java还是Golang更有前景? 从前端转型后端开发,学习Java还是Golang更有前景? Apr 02, 2025 am 09:12 AM

后端学习路径:从前端转型到后端的探索之旅作为一名从前端开发转型的后端初学者,你已经有了nodejs的基础,...

Go语言中用于浮点数运算的库有哪些? Go语言中用于浮点数运算的库有哪些? Apr 02, 2025 pm 02:06 PM

Go语言中用于浮点数运算的库介绍在Go语言(也称为Golang)中,进行浮点数的加减乘除运算时,如何确保精度是�...

Go的爬虫Colly中Queue线程的问题是什么? Go的爬虫Colly中Queue线程的问题是什么? Apr 02, 2025 pm 02:09 PM

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

Beego ORM中如何指定模型关联的数据库? Beego ORM中如何指定模型关联的数据库? Apr 02, 2025 pm 03:54 PM

在BeegoORM框架下,如何指定模型关联的数据库?许多Beego项目需要同时操作多个数据库。当使用Beego...

在 Go 语言中,为什么使用 Println 和 string() 函数打印字符串会出现不同的效果? 在 Go 语言中,为什么使用 Println 和 string() 函数打印字符串会出现不同的效果? Apr 02, 2025 pm 02:03 PM

Go语言中字符串打印的区别:使用Println与string()函数的效果差异在Go...

在Go语言中使用Redis Stream实现消息队列时,如何解决user_id类型转换问题? 在Go语言中使用Redis Stream实现消息队列时,如何解决user_id类型转换问题? Apr 02, 2025 pm 04:54 PM

Go语言中使用RedisStream实现消息队列时类型转换问题在使用Go语言与Redis...

GoLand中自定义结构体标签不显示怎么办? GoLand中自定义结构体标签不显示怎么办? Apr 02, 2025 pm 05:09 PM

GoLand中自定义结构体标签不显示怎么办?在使用GoLand进行Go语言开发时,很多开发者会遇到自定义结构体标签在�...

See all articles