├── README.md
└── gorepl-mode.el
/README.md:
--------------------------------------------------------------------------------
1 | [](https://melpa.org/#/gorepl-mode)
2 |
3 | # gorepl-mode
4 | A minor emacs mode for Go REPL.
5 |
6 |
7 | ## Synopsis
8 | **gorepl-mode** is a Go REPL interaction library for Emacs. It's built on top of
9 | [gore](https://github.com/motemen/gore).
10 |
11 |
12 | Gorepl packs some features (in no particular order):
13 |
14 | * Powerful REPL - thanks to gore
15 | * Interactive code evaluation
16 | * Evaluate expressions selected
17 | * Launch a repl with loaded file in a context
18 |
19 | ## Installation
20 |
21 | `gorepl-mode` is available on [MELPA](http://melpa.org)
22 |
23 | You can install `gorepl-mode` with the following command:
24 |
25 | M-x package-install [RET] gorepl-mode [RET]
26 |
27 |
28 | ### Prerequisite
29 |
30 | Install [gore](https://github.com/motemen/gore).
31 |
32 | ### Basic configuration
33 |
34 | * Enable `gorepl-mode` in `go-mode` buffers:
35 |
36 | ```el
37 | (add-hook 'go-mode-hook #'gorepl-mode)
38 | ```
39 |
40 | ## Keyboard shortcuts
41 |
42 | * M-x gorepl-run: Launch an instance of gore REPL client.
43 |
44 | * M-x gorepl-run-load-current-file: Launch an instance of gore REPL client with the current file loaded.
45 |
46 | ### gorepl-mode
47 |
48 | Keyboard shortcut | Description
49 | -------------------------------------|-------------------------------
50 | C-C C-g | Launch an instance of gore REPL client
51 | C-C C-l | Launch an instance of gore REPL client - with the current file loaded
52 | C-c C-e | Evaluate the region selected
53 | C-c C-r | Evaluate the current line
54 |
55 | ### Issues
56 |
57 | The performance for gore is not very fast, in fact when a gorepl is running using `gorepl-run-load-current-file` it can be slow at first, especially with large files, because it's doing `go run `to all file.
58 |
59 |
60 | ### TODO
61 |
62 | * Autocompletion
63 | * go-mode in gorepl-mode
64 |
--------------------------------------------------------------------------------
/gorepl-mode.el:
--------------------------------------------------------------------------------
1 | ;;; gorepl-mode.el --- Go REPL Interactive Development in top of Gore -*- lexical-binding: t -*-
2 |
3 | ;; Copyright © 2015-2016 Manuel Alonso
4 |
5 | ;; Author: Manuel Alonso
6 | ;; Maintainer: Manuel Alonso
7 | ;; URL: http://www.github.com/manute/gorepl-mode
8 | ;; Version: 1.0.0
9 | ;; Package-Requires: ((emacs "24") (s "1.11.0") (f "0.19.0") (hydra "0.13.0"))
10 | ;; Keywords: languages, go, golang, gorepl
11 |
12 | ;; This file is NOT part of GNU Emacs.
13 |
14 | ;; This program is free software: you can redistribute it and/or modify
15 | ;; it under the terms of the GNU General Public License as published by
16 | ;; the Free Software Foundation, either version 3 of the License, or
17 | ;; (at your option) any later version.
18 |
19 | ;; This program is distributed in the hope that it will be useful,
20 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | ;; GNU General Public License for more details.
23 |
24 | ;; You should have received a copy of the GNU General Public License
25 | ;; along with this program. If not, see .
26 |
27 | ;;; Commentary:
28 | ;;
29 | ;; This library provides a Go repl interactive development environment for Emacs, built on
30 | ;; top of Gore (https://github.com/motemen/gore).
31 | ;;
32 | ;;; Code:
33 |
34 | (require 's)
35 | (require 'f)
36 | (require 'hydra)
37 |
38 | (defgroup gorepl nil
39 | "GO repl interactive"
40 | :prefix "gorepl-"
41 | :group 'applications
42 | :link '(url-link :tag "Github" "https://github.com/manute/gorepl-mode")
43 | :link '(emacs-commentary-link :tag "Commentary" "gorepl"))
44 |
45 | (defcustom gorepl-command
46 | "gore"
47 | "The command used to execute gore."
48 | :type 'string
49 | :group 'gorepl)
50 |
51 |
52 | (defcustom gorepl-mode-hook nil
53 | "Hook called by `gorepl-mode'."
54 | :type 'hook
55 | :group 'gorepl)
56 |
57 |
58 | (defconst gorepl-version "1.0.0")
59 | (defconst gorepl-buffer "*Go REPL*")
60 | (defconst gorepl-buffer-name "Go REPL")
61 |
62 |
63 | ;; MANY THANKS to masteringenmacs for this:
64 | ;; https://www.masteringemacs.org/article/comint-writing-command-interpreter
65 | (defun gorepl--run-gore (args)
66 | "Run an inferior instance of `gore' inside Emacs."
67 | (let* ((buffer (comint-check-proc gorepl-buffer-name)))
68 | ;; pop to the "*GO REPL Buffer*" buffer if the process is dead, the
69 | ;; buffer is missing or it's got the wrong mode.
70 | (display-buffer
71 | (if (or buffer (not (derived-mode-p 'gorepl-mode))
72 | (comint-check-proc (current-buffer)))
73 | (get-buffer-create (or buffer gorepl-buffer))
74 | (current-buffer)))
75 | ;; create the comint process if there is no buffer.
76 | (unless buffer
77 | (apply 'make-comint-in-buffer gorepl-buffer-name buffer
78 | gorepl-command nil args)
79 | (gorepl-mode))))
80 |
81 |
82 | ;;;;;;;;;;;;;;;;;;;;;;;
83 | ;; API
84 | ;;;;;;;;;;;;;;;;;;;;;;
85 |
86 | (defun gorepl-version ()
87 | "Display GoREPL's version."
88 | (interactive)
89 | (message "GOREPL %s" gorepl-version))
90 |
91 | (defun gorepl-run ()
92 | "Start or switch to the GoREPL buffer"
93 | (interactive)
94 | (message "Entering gore session...")
95 | (gorepl--run-gore '()))
96 |
97 | (defun gorepl-eval (stmt)
98 | "Send `stmt' to gore, maybe starting it"
99 | (interactive)
100 | (gorepl-run)
101 | (with-current-buffer gorepl-buffer
102 | (insert stmt)
103 | (comint-send-input)
104 | (message (format "Just sent to gore: %s" stmt))))
105 |
106 | (defun gorepl-eval-region (begin end)
107 | "Evaluate region selected."
108 | (interactive "r")
109 | (gorepl-mode t)
110 | (let ((cmd (buffer-substring begin end)))
111 | (gorepl-eval cmd)))
112 |
113 | (defun gorepl-eval-line (&optional arg)
114 | "Evaluate current line."
115 | (interactive "P")
116 | (unless arg
117 | (setq arg 1))
118 | (when (> arg 0)
119 | (gorepl-eval-region
120 | (line-beginning-position)
121 | (line-end-position arg))))
122 |
123 | (defun gorepl-run-load-current-file ()
124 | "Run a GoREPL with a context file in it"
125 | (interactive)
126 | (gorepl--run-gore (list "-context" (buffer-file-name))))
127 |
128 | (defun gorepl-import ()
129 | "Import "
130 | (interactive)
131 | (catch 'err
132 | (let ((name (read-string "Package path? ")))
133 | (unless name
134 | (message "No package specified")
135 | (throw 'err nil))
136 | (let ((name (s-trim (s-chomp name))))
137 | (unless (s-present? name)
138 | (message "No package specified")
139 | (throw 'err nil))
140 | (when (s-contains? " " name)
141 | (message "Package names can't contain a space")
142 | (throw 'err nil))
143 | (message (format "Package specified: %s" name))
144 | (let ((stmt (format ":import %s" name)))
145 | (gorepl-eval stmt))))))
146 |
147 | (defun gorepl-print ()
148 | "Print the source code from this session"
149 | (interactive)
150 | (gorepl-eval ":print"))
151 |
152 | (defun gorepl-write ()
153 | "Write the source code from this session out to a file"
154 | (interactive)
155 | (let ((name (read-file-name "Output file name? ")))
156 | (message (format "Output file name: %s" name))
157 | (let ((name (f-expand name)))
158 | (catch 'err
159 | (when (s-blank? name)
160 | (message "Aborted write: no file name given")
161 | (throw 'err nil))
162 | (if (f-exists? name) (progn (message "Stomping: %s" name) (f-touch name))
163 | (progn
164 | (f-write-text (format "// gore dump on `%s' by `%s'\n\n"
165 | (format-time-string
166 | "%a %b %d %H:%M:%S %Z %Y"
167 | (current-time))
168 | (user-original-login-name))
169 | 'utf-8
170 | name)))
171 | (let ((stmt (format ":write %s" name)))
172 | (gorepl-eval stmt))))))
173 |
174 | (defun gorepl-doc ()
175 | "Show documentation on
215 | _f_: Run this file | _k_: Line+Step | _y_: Print this source
216 | _q_: Quit Hydra | _K_: Line | _u_: Write this sourceto
217 | ^^| ^^| _o_: List `these' actual commands
218 | ^^| ^^| _r_: Restart this REPL
219 | ^^| ^^| _p_: Quit this REPL (or C-d)
220 | "
221 | ("d" gorepl-run)
222 | ("f" gorepl-run-load-current-file)
223 | ("j" gorepl-eval-region)
224 | ("r" gorepl-restart)
225 | ("k" gorepl-eval-line-goto-next-line :exit nil)
226 | ("K" gorepl-eval-line)
227 | ("t" gorepl-import)
228 | ("y" gorepl-print)
229 | ("u" gorepl-write)
230 | ("i" gorepl-doc)
231 | ("o" gorepl-help)
232 | ("p" gorepl-quit)
233 | ("q" nil))
234 |
235 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
236 | ;; DEFINE MINOR MODE
237 | ;;
238 | ;; Many thanks -> https://github.com/ruediger/rusti.el
239 | ;;
240 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
241 |
242 | (defvar gorepl-mode-map
243 | (let ((map (make-sparse-keymap)))
244 | (define-key map (kbd "C-c C-g") #'gorepl-run)
245 | (define-key map (kbd "C-c C-l") #'gorepl-run-load-current-file)
246 | (define-key map (kbd "C-c C-e") #'gorepl-eval-region)
247 | (define-key map (kbd "C-c C-r") #'gorepl-eval-line)
248 | map)
249 | "Mode map for `gorepl-mode'.")
250 |
251 | (defcustom gorepl-mode-lighter " Gorepl"
252 | "Text displayed in the mode line (Lighter) if `gorepl-mode' is active."
253 | :group 'gorepl
254 | :type 'string)
255 |
256 | ;;;###autoload
257 | (define-minor-mode gorepl-mode
258 | "A minor mode for run a go repl on top of gore"
259 | :group 'gorepl
260 | :lighter gorepl-mode-lighter
261 | :keymap gorepl-mode-map)
262 |
263 |
264 | (provide 'gorepl-mode)
265 | ;;; gorepl-mode.el ends here
266 |
--------------------------------------------------------------------------------