-
Notifications
You must be signed in to change notification settings - Fork 101
/
rustic-comint.el
179 lines (154 loc) · 6.91 KB
/
rustic-comint.el
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
;;; rustic-comint.el --- Cargo and comint facilities -*-lexical-binding: t-*-
;;; Commentary:
;; This implements various functionalities related to cargo run and
;; comint interaction.
;;; Code:
(require 'comint)
(require 'rustic-cargo)
(require 'rustic-compile)
;;; Customization
(defcustom rustic-cargo-run-use-comint nil
"If t then interact with programs in `rustic-cargo-run' using
comint-mode. This creates a dependency on the polymode package.
No special configuration of polymode is needed for this to work,
but you need to install polymode separately."
:type 'boolean
:group 'rustic-cargo)
;;; Run with comint
(defvar rustic-run-comint-process-name "rustic-cargo-run-comint-process"
"Process name for run-comint processes.")
(defvar rustic-run-comint-buffer-name "*cargo-run-comint*"
"Buffer name for run-comint buffers.")
(defvar rustic-run-comint-arguments ""
"Holds arguments for `cargo run-comint', similar to `compilation-arguments'.")
(defvar rustic-cargo-run-comint-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-g") 'rustic-cargo-comint-run-rerun)
map)
"Local keymap for `rustic-cargo-comint-mode' buffers.")
(define-derived-mode rustic-cargo-run-comint-mode comint-mode "Cargo comint"
"Mode for `cargo run' that derives from `comint-mode'.
To send input to the compiled program, just type in a string and
hit RET to send it to the program."
(buffer-disable-undo)
(setq buffer-read-only nil))
;;;###autoload
(defun rustic-cargo-comint-run (&optional arg)
"Run 'cargo run' but for interactive programs.
If ARG is not nil, use value as argument and store it in `rustic-run-arguments'.
When calling this function from `rustic-popup-mode', always use the value of
`rustic-run-arguments'."
(interactive "P")
(rustic--inheritenv
(let ((run-args (rustic--get-run-arguments)))
(pop-to-buffer-same-window
(get-buffer-create rustic-run-comint-buffer-name))
(unless (comint-check-proc (current-buffer))
(rustic--cargo-repl-in-buffer
(current-buffer)
(concat "run" (cond
(arg
(setq rustic-run-comint-arguments
(read-from-minibuffer "Cargo run arguments: " rustic-run-comint-arguments)))
(run-args)
(t ""))))
(rustic-cargo-run-comint-mode)))))
;;;###autoload
(defun rustic-cargo-comint-run-rerun ()
"Run `cargo run' with `rustic-run-comint-arguments'."
(interactive)
(rustic--inheritenv
(pop-to-buffer-same-window
(get-buffer-create rustic-run-comint-buffer-name))
(rustic--cargo-repl-in-buffer
(current-buffer)
(concat "run" rustic-run-comint-arguments))))
(defun rustic--cargo-repl-in-buffer (buffer run-args)
"Make Cargo comint Repl in BUFFER.
Optionally accepts RUN-ARGS which will be passed to the
executable."
(make-comint-in-buffer
rustic-run-comint-buffer-name
buffer
(rustic-cargo-bin)
'()
run-args))
;;; Cargo run with plain comint and optional polymode
(defun rustic-cargo-plainrun-mode ()
(interactive)
(if rustic-cargo-run-use-comint
;; rustic-cargo-comint-run-mode toggles the mode; we want to
;; always enable.
(unless (and (boundp 'polymode-mode)
polymode-mode
(memq major-mode '(rustic-cargo-plain-run-mode
comint-mode)))
(rustic-cargo-comint-run-mode))
(rustic-cargo-plain-run-mode)))
;;;###autoload
(defun rustic-cargo-plain-run (&optional arg)
"Run `cargo run' for the current project.
Read the full command from the minibuffer when ARG is non-nil or
when called with a prefix command \\[universal-argument]."
(interactive "P")
(let* ((command (if arg
(read-from-minibuffer "Cargo run command: " "cargo run -- ")
(concat (rustic-cargo-bin) " run "
(setq rustic-run-arguments
(read-from-minibuffer
"Run arguments: "
(if (rustic-cargo-run-get-relative-example-name)
(concat "--example "
(rustic-cargo-run-get-relative-example-name))
(car compile-history))
nil nil 'compile-history)) ))))
(rustic-run-cargo-command command (list :mode 'rustic-cargo-plainrun-mode))))
(define-derived-mode rustic-cargo-plain-run-mode rustic-compilation-mode "Cargo run"
"Mode for `cargo run' that derives from `rustic-compilation-mode'.
To send input to the compiled program, use
`rustic-compile-send-input'. If you set
`rustic-cargo-run-use-comint' to t, you can also just type in a
string and hit RET to send it to the program. The latter
approach requires installing polymode."
(buffer-disable-undo)
(setq buffer-read-only nil)
(use-local-map comint-mode-map))
(defun rustic-cargo-comint-run-mode ()
"Mode for `cargo run' that combines `rustic-compilation-mode' with `comint-mode'.
The former for highlighting and interacting with compiler errors,
and the latter for interacting with the compiled program."
;; First time around, define the mode and invoke it. Next time, the
;; symbol will have been overwritten so this runs only once.
(unless (require 'polymode nil 'noerr)
(error "polymode not found; polymode must be installed for `rustic-cargo-run-use-comint' to work"))
(let ((docstr (documentation 'rustic-cargo-comint-run-mode)))
(define-hostmode poly-rustic-cargo-compilation-hostmode
:mode 'rustic-cargo-plain-run-mode)
(define-innermode poly-rustic-cargo-comint-innermode
:mode 'comint-mode
:head-matcher "^ *Running `.+`$"
:head-mode 'host
:tail-matcher "\\'"
:tail-mode 'host)
(define-polymode rustic-cargo-comint-run-mode
:hostmode 'poly-rustic-cargo-compilation-hostmode
:innermodes '(poly-rustic-cargo-comint-innermode)
:switch-buffer-functions '(poly-rustic-cargo-comint-switch-buffer-hook)
;; See comments in poly-rustic-cargo-comint-switch-buffer-hook below.
(set (make-local-variable 'pm-hide-implementation-buffers) nil)
)
(put 'rustic-cargo-comint-run-mode 'function-documentation docstr)
(rustic-cargo-comint-run-mode)))
(defun poly-rustic-cargo-comint-switch-buffer-hook (old-buffer new-buffer)
"Housekeeping for `rustic-cargo-comint-run-mode'."
;; Keep inferior process attached to the visible buffer.
(let ((proc (get-buffer-process old-buffer)))
(when proc
(set-process-buffer proc new-buffer)))
;; Prevent polymode from constantly renaming the
;; "*rustic-compilation*" buffer. A note in case this undocumented
;; variable stops working: if that happens, you'll see
;; *rustic-compilatin*[comint]<2>, <3>, etc. keep popping up.
(set (make-local-variable 'pm-hide-implementation-buffers) nil))
(provide 'rustic-comint)
;;; rustic-comint.el ends here