summaryrefslogtreecommitdiff
path: root/modules/prog-go.el
blob: 465cbf1461d119a7151635503ee56ff118b60569 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
;;; prog-go --- Golang Specific Settings and Functionality -*- lexical-binding: t; coding: utf-8; -*-
;; author Craig Jennings <c@cjennings.net>

;;; Commentary:
;; Configuration for Go programming using go-ts-mode (tree-sitter based).
;; Requires go-mode package for gofmt and related commands.
;;
;; Installation:
;;   go install golang.org/x/tools/cmd/goimports@latest
;;   go install golang.org/x/tools/gopls@latest
;;   go install honnef.co/go/tools/cmd/staticcheck@latest
;;
;; LSP will provide:
;;   - Intelligent code completion
;;   - Jump to definition (M-.)
;;   - Find references
;;   - On-the-fly error checking
;;   - Code lenses (run tests, show package stats)

;;; Code:

(defvar go-bin-path (expand-file-name "~/go/bin")
  "Path to Go binaries directory.
This is where tools like goimports and staticcheck are installed.")

(defvar gopls-path "gopls"
  "Path to gopls (Go language server).
Install with: go install golang.org/x/tools/gopls@latest")

(defvar dlv-path "dlv"
  "Path to Delve debugger.
Install with: go install github.com/go-delve/delve/cmd/dlv@latest")

(defvar go-ts-mode-map)
(defvar go-mod-ts-mode-map)

;; Forward declarations for LSP
(declare-function lsp-deferred "lsp-mode")
(defvar lsp-go-gopls-server-path)
(defvar lsp-go-analyses)
(defvar lsp-go-codelenses)

;; Forward declarations for external packages
(declare-function company-mode "company")
(declare-function cj/disabled "system-defaults")
(defvar gofmt-command)

;; ---------------------------------- Go Setup ---------------------------------
;; golang preferences following Go community standards

(defun cj/go-setup ()
  "Default code preferences for Golang following Go conventions."
  (company-mode)
  (setq-local tab-width 4)              ;; Go standard tab width
  (setq-local standard-indent 4)        ;; indent 4 spaces per level
  (setq-local indent-tabs-mode t)       ;; use real tabs (Go convention)
  (electric-pair-mode t)                ;; match delimiters automatically

  ;; Enable LSP if available
  (when (and (fboundp 'lsp-deferred)
             (executable-find gopls-path))
    (lsp-deferred)))

(defun cj/go-staticcheck ()
  "Run staticcheck on the current Go package."
  (interactive)
  (let* ((staticcheck-bin (expand-file-name "staticcheck" go-bin-path))
         (default-directory (if buffer-file-name
                               (file-name-directory buffer-file-name)
                             default-directory)))
    (if (file-executable-p staticcheck-bin)
        (compile (format "%s ./..." staticcheck-bin))
      (message "staticcheck not found at %s. Install with: go install honnef.co/go/tools/cmd/staticcheck@latest"
               staticcheck-bin))))

(defun cj/go-debug ()
  "Start Delve debugger for the current Go package."
  (interactive)
  (let* ((dlv-bin (expand-file-name dlv-path go-bin-path))
         (default-directory (if buffer-file-name
                               (file-name-directory buffer-file-name)
                             default-directory)))
    (if (or (executable-find dlv-path)
            (file-executable-p dlv-bin))
        (gud-gdb (format "%s debug" (or (executable-find dlv-path) dlv-bin)))
      (message "Delve not found. Install with: go install github.com/go-delve/delve/cmd/dlv@latest"))))

(defun cj/go-mode-keybindings ()
  "Set up keybindings for Go programming.
Overrides default prog-mode keybindings with Go-specific commands."
  ;; S-f5: Run staticcheck (static analysis)
  (local-set-key (kbd "S-<f5>") #'cj/go-staticcheck)

  ;; S-f6: Debug with Delve
  (local-set-key (kbd "S-<f6>") #'cj/go-debug))

;; ---------------------------------- Go Mode ----------------------------------
;; go-ts-mode configuration (treesit-based Go editing)

(use-package go-mode
  :hook ((go-ts-mode . cj/go-setup)
         (go-ts-mode . cj/go-mode-keybindings))
  :bind (:map go-ts-mode-map
			  ("C-; f"  . gofmt))  ;; Override global formatter with gofmt/goimports
  :mode (("\\.go\\'" . go-ts-mode)      ;; .go files use go-ts-mode
         ("go\\.mod\\'" . go-mod-ts-mode)) ;; go.mod uses go-mod-ts-mode
  :config
  (add-to-list 'exec-path go-bin-path)
  ;; Use goimports for formatting (adds/removes imports automatically)
  (setq gofmt-command "goimports"))

;; -------------------------------- LSP for Go ---------------------------------
;; Go-specific LSP configuration using gopls
;; Core LSP setup is in prog-general.el

(use-package lsp-mode
  :hook ((go-ts-mode go-mod-ts-mode) . lsp-deferred)
  :config
  (setq lsp-go-gopls-server-path gopls-path)

  ;; Configure gopls
  (setq lsp-go-analyses '((shadow . t)
                         (simplifycompositelit . :json-false)))
  (setq lsp-go-codelenses '((gc_details . t)
                           (generate . t)
                           (regenerate_cgo . t)
                           (test . t)
                           (tidy . t)
                           (upgrade_dependency . t)
                           (vendor . t))))

(provide 'prog-go)
;;; prog-go.el ends here