Skip to content

Commit

Permalink
add libvterm
Browse files Browse the repository at this point in the history
  • Loading branch information
brotzeit committed Dec 9, 2018
1 parent 47682d4 commit 518684b
Show file tree
Hide file tree
Showing 9 changed files with 1,247 additions and 9 deletions.
11 changes: 11 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3743,6 +3743,17 @@ fi
AC_SUBST(LIBXML2_LIBS)
AC_SUBST(LIBXML2_CFLAGS)

HAVE_LIBVTERM=no
AC_DEFINE(HAVE_LIBVTERM, 1, [do I need this])
LIBVTERM_LIBS="-lvterm"

AC_SUBST(LIBVTERM_LIBS)
AC_SUBST(LIBVTERM_CFLAGS)





BLESSMAIL_TARGET=
LIBS_MAIL=
if test ! "$with_mailutils"; then
Expand Down
254 changes: 254 additions & 0 deletions lisp/vterm.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
(require 'subr-x)
(require 'cl-lib)
(require 'color)


(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-install-buffer-name " *Install vterm"
"Name of the buffer used for compiling vterm-module.")

(defcustom vterm-shell (getenv "SHELL")
"The shell that gets run in the vterm."
:type 'string
:group 'vterm)

(defcustom vterm-max-scrollback 1000
"Maximum 'scrollback' value."
:type 'number
:group 'vterm)

(defcustom vterm-keymap-exceptions '("C-c" "C-x" "C-u" "C-g" "C-h" "M-x" "M-o" "C-v" "M-v" "C-y")
"Exceptions for vterm-keymap.
If you use a keybinding with a prefix-key, add that prefix-key to
this list. Note that after doing so that prefix-key cannot be sent
to the terminal anymore."
:type '(repeat string)
:group 'vterm)

(defcustom vterm-exit-hook nil
"Shell exit hook.
This hook applies only to new vterms, created after setting this
value with `add-hook'.
Note that this hook will not work if another package like
`shell-pop' sets its own sentinel to the `vterm' process."
:type 'hook
:group 'vterm)

(defcustom vterm-set-title-hook nil
"Shell set title hook.
those functions are called one by one, with 1 arguments.
`vterm-set-title-hook' should be a symbol, a hook variable.
The value of HOOK may be nil, a function, or a list of functions.
for example
(defun vterm--rename-buffer-as-title (title)
(rename-buffer (format \"vterm %s\" title)))
(add-hook 'vterm-set-title-hook 'vterm--rename-buffer-as-title)
see http://tldp.org/HOWTO/Xterm-Title-4.html about how to set terminal title
for different shell. "
:type 'hook
:group 'vterm)

(defvar vterm--term nil
"Pointer to Term.")
(make-variable-buffer-local 'vterm--term)

(defvar vterm--process nil
"Shell process of current term.")
(make-variable-buffer-local 'vterm--process)

(define-derived-mode vterm-mode fundamental-mode "VTerm"
"Major mode for vterm buffer."
(buffer-disable-undo)
(setq vterm--term (vterm-new (window-body-height)
(window-body-width)
;; vterm-max-scrollback
))

(setq buffer-read-only t)
(setq-local scroll-conservatively 101)
(setq-local scroll-margin 0)
(vterm-make-process)
;; (add-hook 'window-size-change-functions #'vterm--window-size-change t t)
)

(defun vterm-make-process ()
(let ((process-environment (append '("TERM=xterm") process-environment)))
(setq vterm--process
(make-process
:name "vterm"
:buffer (current-buffer)
:command `("/bin/sh" "-c"
,(format "stty -nl sane iutf8 rows %d columns %d >/dev/null && exec %s"
(window-body-height)
(window-body-width)
vterm-shell))
:coding 'no-conversion
:connection-type 'pty
:filter #'vterm--filter
:sentinel (when vterm-exit-hook #'vterm--sentinel)))))

(defun vterm--filter (process input)
"I/O Event. Feeds PROCESS's INPUT to the virtual terminal.
Then triggers a redraw from the module."
(let ((inhibit-redisplay t)
(inhibit-read-only t))
(with-current-buffer (process-buffer process)
(vterm-write-input input)
(vterm-update))))

(defun vterm--sentinel (process event)
"Sentinel of vterm PROCESS."
(when (not (process-live-p process))
(with-current-buffer (process-buffer process)
(run-hooks 'vterm-exit-hook))))


;; ;; Keybindings
(define-key vterm-mode-map [tab] #'vterm--self-insert)
(define-key vterm-mode-map [backspace] #'vterm--self-insert)
(define-key vterm-mode-map [M-backspace] #'vterm--self-insert)
(define-key vterm-mode-map [return] #'vterm--self-insert)
(define-key vterm-mode-map [left] #'vterm--self-insert)
(define-key vterm-mode-map [right] #'vterm--self-insert)
(define-key vterm-mode-map [up] #'vterm--self-insert)
(define-key vterm-mode-map [down] #'vterm--self-insert)
(define-key vterm-mode-map [home] #'vterm--self-insert)
(define-key vterm-mode-map [end] #'vterm--self-insert)
(define-key vterm-mode-map [escape] #'vterm--self-insert)
(define-key vterm-mode-map [remap self-insert-command] #'vterm--self-insert)
(define-key vterm-mode-map [remap yank] #'vterm-yank)
(define-key vterm-mode-map (kbd "C-c C-y") #'vterm--self-insert)
(define-key vterm-mode-map (kbd "C-c C-c") #'vterm-send-ctrl-c)

;; ;; Function keys and most of C- and M- bindings
(mapcar (lambda (key)
(define-key vterm-mode-map (kbd key) #'vterm--self-insert))
(append (cl-loop for number from 1 to 12
collect (format "<f%i>" number))
(cl-loop for prefix in '("C-" "M-")
append (cl-loop for char from ?a to ?z
for key = (format "%s%c" prefix char)
unless (member key vterm-keymap-exceptions)
collect key))))

(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)))
(when-let ((key (key-description (vector (event-basic-type last-input-event)))))
(vterm-send-key key shift meta ctrl))))

(defun vterm-send-key (key &optional shift meta ctrl)
"Sends KEY to libvterm with optional modifiers SHIFT, META and CTRL."
(let ((inhibit-redisplay t)
(inhibit-read-only t))
(when (and shift (not meta) (not ctrl))
(setq key (upcase key)))
(vterm-update key shift meta ctrl)))

(defun vterm--face-color-hex (face attr)
"Return the color of the FACE's ATTR as a hex string."
(if (< emacs-major-version 26)
(apply #'color-rgb-to-hex (color-name-to-rgb (face-attribute face attr nil 'default)))
(apply #'color-rgb-to-hex (append (color-name-to-rgb (face-attribute face attr nil 'default)) '(2)))))

(defun vterm-yank ()
"Implementation of `yank' (paste) in vterm."
(interactive)
(vterm-send-string (current-kill 0)))

(defun vterm-send-string (string)
"Send the string STRING to vterm."
(when vterm--term
(dolist (char (string-to-list string))
(vterm-update (char-to-string char) nil nil nil))))

(defun vterm-flush-output (output)
"Sends the virtual terminal's OUTPUT to the shell."
(process-send-string vterm--process output))

;;;###autoload
(defun vterm ()
"Create a new vterm."
(interactive)
(let ((buffer (generate-new-buffer "vterm")))
(with-current-buffer buffer
(vterm-mode))
(switch-to-buffer buffer)))

;;;###autoload
(defun vterm-other-window ()
"Create a new vterm."
(interactive)
(let ((buffer (generate-new-buffer "vterm")))
(with-current-buffer buffer
(vterm-mode))
(pop-to-buffer buffer)))

(defun vterm--goto-line(n)
"Go to line N and return true on success."
(goto-char (point-min))
(let ((succ (eq 0 (forward-line (1- n)))))
succ))

(defun vterm--delete-lines (line-num count &optional delete-whole-line)
"Delete COUNT lines from LINE-NUM.
If option DELETE-WHOLE-LINE is non-nil, then this command kills
the whole line including its terminating newline"
(save-excursion
(when (vterm--goto-line line-num)
(delete-region (point) (point-at-eol count))
(when (and delete-whole-line
(looking-at "\n"))
(delete-char 1)))))

(provide 'vterm)
1 change: 1 addition & 0 deletions rust_src/src/lib.rs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ mod marker;
mod math;
mod minibuf;
mod multibyte;
mod vterm;
mod numbers;
mod obarray;
mod objects;
Expand Down
2 changes: 1 addition & 1 deletion rust_src/src/remacs_sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ extern "C" {
) -> Lisp_Object;
pub static minibuf_prompt: LispObject;
pub fn add_process_read_fd(fd: libc::c_int);
pub fn allocate_misc(t: Lisp_Misc_Type) -> LispObject;
// pub fn allocate_misc(t: Lisp_Misc_Type) -> LispObject;
#[cfg(windows)]
pub fn file_attributes_c(filename: LispObject, id_format: LispObject) -> LispObject;
#[cfg(unix)]
Expand Down

0 comments on commit 518684b

Please sign in to comment.