blob: 1f44a682a463de1f7197d538a08ff906321ac53e (
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
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
|
;;; vterm.el --- This package implements a terminal via libvterm
;;; Commentary:
;;
;; This Emacs module implements a bridge to libvterm to display a terminal in a
;; Emacs buffer.
;;; Code:
(require 'vterm-module)
(require 'subr-x)
(require 'cl-lib)
(require 'color)
(defcustom vterm-shell (getenv "SHELL")
"The shell that gets run in the vterm."
:group 'vterm)
(defcustom vterm-keymap-exceptions '("C-x" "C-u" "C-g" "C-h" "M-x" "M-o")
"Exceptions for vterm-keymap.
If you use a keybinding with a prefix-key that prefix-key cannot
be send to the terminal."
:group 'vterm)
(defface vterm
'((t :inherit default))
"Default face to use in Term mode."
:group 'vterm)
(defface vterm-color-black
'((t :foreground "black" :background "black"))
"Face used to render black color code."
:group 'vterm)
(defface vterm-color-red
'((t :foreground "red3" :background "red3"))
"Face used to render red color code."
:group 'vterm)
(defface vterm-color-green
'((t :foreground "green3" :background "green3"))
"Face used to render green color code."
:group 'vterm)
(defface vterm-color-yellow
'((t :foreground "yellow3" :background "yellow3"))
"Face used to render yellow color code."
:group 'vterm)
(defface vterm-color-blue
'((t :foreground "blue2" :background "blue2"))
"Face used to render blue color code."
:group 'vterm)
(defface vterm-color-magenta
'((t :foreground "magenta3" :background "magenta3"))
"Face used to render magenta color code."
:group 'vterm)
(defface vterm-color-cyan
'((t :foreground "cyan3" :background "cyan3"))
"Face used to render cyan color code."
:group 'vterm)
(defface vterm-color-white
'((t :foreground "white" :background "white"))
"Face used to render white color code."
:group 'vterm)
(defvar vterm--term nil
"Pointer to struct Term.")
(make-variable-buffer-local 'vterm--term)
(defvar vterm--buffers nil
"List of active vterm-buffers.")
(define-derived-mode vterm-mode fundamental-mode "VTerm"
"Mayor mode for vterm buffer."
(buffer-disable-undo)
(setq vterm--term (vterm-new vterm-shell (window-body-height) (window-body-width))
buffer-read-only t)
(setq-local scroll-conservatively 101)
(setq-local scroll-margin 0)
(add-hook 'kill-buffer-hook #'vterm--kill-buffer-hook t t)
(add-hook 'window-size-change-functions #'vterm--window-size-change t t))
;; Keybindings
(define-key vterm-mode-map [t] #'vterm--self-insert)
(define-key vterm-mode-map [mouse-1] nil)
(define-key vterm-mode-map [mouse-2] nil)
(define-key vterm-mode-map [mouse-3] nil)
(define-key vterm-mode-map [mouse-4] #'ignore)
(define-key vterm-mode-map [mouse-5] #'ignore)
(dolist (prefix '("M-" "C-"))
(dolist (char (cl-loop for char from ?a to ?z
collect char))
(let ((key (concat prefix (char-to-string char))))
(unless (cl-member key vterm-keymap-exceptions)
(define-key vterm-mode-map (kbd key) #'vterm--self-insert)))))
(dolist (exception vterm-keymap-exceptions)
(define-key vterm-mode-map (kbd exception) nil))
(defun vterm--self-insert ()
"Sends invoking key to libvterm."
(interactive)
(let* ((modifiers (event-modifiers last-input-event))
(shift (memq 'shift modifiers))
(meta (memq 'meta modifiers))
(ctrl (memq 'control modifiers))
(window (posn-window (event-end last-input-event))))
(when-let ((key (key-description (vector (event-basic-type last-input-event))))
(inhibit-redisplay t)
(inhibit-read-only t))
(when (equal modifiers '(shift))
(setq key (upcase key)))
(with-selected-window window
(vterm-update vterm--term key shift meta ctrl)))))
(defun vterm-create ()
"Create a new vterm."
(interactive)
(let ((buffer (generate-new-buffer "vterm")))
(add-to-list 'vterm--buffers buffer)
(pop-to-buffer buffer)
(vterm-mode)))
(defun vterm--event ()
"Update the vterm BUFFER."
(interactive)
(let ((inhibit-redisplay t)
(inhibit-read-only t))
(mapc (lambda (buffer)
(with-current-buffer buffer
(unless (vterm-update vterm--term)
(kill-buffer-and-window)
(message "Shell exited!"))))
vterm--buffers)))
(define-key special-event-map [sigusr1] #'vterm--event)
(defun vterm--kill-buffer-hook ()
"Kill the corresponding process of vterm."
(when (eq major-mode 'vterm-mode)
(setq vterm--buffers (remove (current-buffer) vterm--buffers))
(vterm-kill vterm--term)))
(defun vterm--window-size-change (frame)
"Notify the vterm over size-change in FRAME."
(dolist (window (window-list frame 1))
(let ((buffer (window-buffer window)))
(with-current-buffer buffer
(when (eq major-mode 'vterm-mode)
(vterm-set-size vterm--term (window-body-height) (window-body-width)))))))
(defun vterm--face-color-hex (face attr)
"Return the color of the FACE's ATTR as a hex string."
(apply #'color-rgb-to-hex (color-name-to-rgb (face-attribute face attr nil 'default))))
(provide 'vterm)
;;; vterm.el ends here
|