Override doom's default vterm module

This commit is contained in:
Wojciech Kozlowski 2022-04-08 20:52:08 +02:00
parent 6f9fadaea8
commit 1b4eda2cbb
5 changed files with 222 additions and 0 deletions

View File

@ -0,0 +1,60 @@
#+TITLE: term/vterm
#+DATE: April 4, 2022
#+SINCE: 3.0
#+STARTUP: inlineimages
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#dynamic-module-support][Dynamic Module support]]
- [[#libvterm][libvterm]]
- [[#compilation-tools-for-vterm-moduleso][Compilation tools for vterm-module.so]]
* Description
This module provides a terminal emulator powered by libvterm.
The following commands are available to open it:
+ ~+vterm/other-window~ (=C-c o t=): Opens vterm in other window
+ ~+vterm/project/other-window~ (=C-c o p=): Opens vterm in the current project in other window
+ ~+vterm/here~ (=C-c o T=): Opens vterm in the current window
+ ~+vterm/project/here~ (=C-c o P=): Opens vterm in the current project in the current window
These commands will first try to find an existing suitable vterm buffer and open
it. If one does not exist, they will create a new one. If the current buffer is
such a vterm buffer, a new vterm session will be created.
** Module Flags
This module provides no flags.
** Plugins
+ [[https://github.com/akermu/emacs-libvterm][vterm]]
* Prerequisites
+ Emacs must be built with dynamic module support, i.e. compiled with the
=--with-modules= option.
+ You need =libvterm= installed on your system.
+ You need =make=, =cmake= and a C compiler such as =gcc= so that vterm can
build =vterm-module.so=.
** Dynamic Module support
To check if your build of Emacs was built with dynamic module support, check
~bin/doom info~ for ~MODULES~ next to "System features". If it's there, you're
good to go.
You can also check for =--with-modules= in the ~system-configuration-options~
variable (=C-c h v system-configuration-options=).
** libvterm
+ Ubuntu or Debian users: ~apt-get install libvterm-dev~
** Compilation tools for vterm-module.so
When you first load vterm, it will compile =vterm-module.so= for you. For this
to succeed, you need the following:
+ =make=
+ =cmake=
+ A C compiler like =gcc=
+ An internet connection (=cmake= will download needed libraries)

View File

@ -0,0 +1,121 @@
;;; term/vterm/autoload.el -*- lexical-binding: t; -*-
(defun +vterm--buffer-name ()
"Get the base name for vterm buffers."
(format "*vterm%s*"
(if (bound-and-true-p persp-mode)
(format ":%s" (safe-persp-name (get-current-persp)))
"")))
(defun +vterm--get-existing-buffer ()
"Find an existing buffer in vterm-mode.
Assumes vterm buffers are killed on exit."
(seq-find (lambda (buffer)
(string-prefix-p (+vterm--buffer-name) (buffer-name buffer)))
(buffer-list)))
(defun +vterm--vterm (vterm-buffer-name)
"Create a vterm session with some tty hack."
;; HACK forces vterm to redraw, fixing strange artefacting in the tty.
(save-window-excursion
(pop-to-buffer "*scratch*"))
(vterm vterm-buffer-name))
(defun +vterm--spawn-or-switch (spawn-fn switch-fn)
"Open using `spawn-fn' or switch to active vterm using `switch-fn'.
If current buffer is in vterm-mode:
Open a new vterm using `spawn-fn';
If current buffer is not in vterm-mode:
If a buffer in vterm-mode exists:
Switch to that buffer using `switch-fn';
If it does not exist:
Open a new vterm using `spawn-fn'.
Returns the vterm buffer"
(unless (fboundp 'module-load)
(user-error "Your build of Emacs lacks dynamic modules support and cannot load vterm"))
(let ((vterm-buffer-name (+vterm--buffer-name)))
(if (string= major-mode "vterm-mode")
(funcall spawn-fn vterm-buffer-name)
(let ((existing-vterm (+vterm--get-existing-buffer)))
(if existing-vterm
(funcall switch-fn existing-vterm)
(funcall spawn-fn vterm-buffer-name))))))
(defun +vterm--spawn-or-switch-with-project (spawn-fn switch-fn)
"Open using `spawn-fn' or switch to active vterm using `switch-fn' in a project.
Returns the vterm buffer"
(let ((project-root (doom-project-root)))
(unless project-root
(user-error "vterm/project/* cannot find a project, because you are not in a project"))
(let ((default-directory project-root))
(+vterm--spawn-or-switch spawn-fn switch-fn))))
(defun +vterm--other-window (other-window-fn current-window-fn)
"Open or switch using `other-window-fn' unless current buffer is doom-dashboard.
Returns the vterm buffer."
(if (equal major-mode #'+doom-dashboard-mode)
(funcall current-window-fn)
(funcall other-window-fn)))
;;;###autoload
(defun +vterm/other-window ()
"Open or switch to active vterm in other window.
If invoked from a vterm window a new vterm session is created.
An exception is made for the doom-dashboard. If the current
buffer is the doom-dashboard, vterm opens in the current window.
Returns the vterm buffer."
(interactive)
(+vterm--other-window (lambda ()
(+vterm--spawn-or-switch #'vterm-other-window
#'switch-to-buffer-other-window))
(lambda ()
(+vterm--spawn-or-switch #'+vterm--vterm
#'switch-to-buffer))))
;;;###autoload
(defun +vterm/project/other-window ()
"Open or switch to active vterm in other window in current project.
If invoked from a vterm window a new vterm session is created.
An exception is made for the doom-dashboard. If the current
buffer is the doom-dashboard, vterm opens in the current window.
Returns the vterm buffer."
(interactive)
(+vterm--other-window (lambda ()
(+vterm--spawn-or-switch-with-project #'vterm-other-window
#'switch-to-buffer-other-window))
(lambda ()
(+vterm--spawn-or-switch-with-project #'+vterm--window
#'switch-to-buffer))))
;;;###autoload
(defun +vterm/here ()
"Open or switch to active vterm in the current window.
If invoked from a vterm window a new vterm session is created.
Returns the vterm buffer."
(interactive)
(+vterm--spawn-or-switch #'+vterm--vterm
#'switch-to-buffer))
;;;###autoload
(defun +vterm/project/here ()
"Open or switch to active vterm in the current window.
If invoked from a vterm window a new vterm session is created.
Returns the vterm buffer."
(interactive)
(+vterm--spawn-or-switch-with-project #'+vterm--vterm
#'switch-to-buffer))

View File

@ -0,0 +1,25 @@
;;; term/vterm/config.el -*- lexical-binding: t; -*-
(use-package! vterm
:when (bound-and-true-p module-file-suffix)
:commands (vterm vterm-other-window)
:hook (vterm-mode . doom-mark-buffer-as-real-h)
:init
;; HACK Because vterm clusmily forces vterm-module.so's compilation on us when
;; the package is loaded, this is necessary to prevent it when
;; byte-compiling this file (`use-package' blocks eagerly loads packages
;; when compiled).
(when noninteractive
(advice-add #'vterm-module-compile :override #'ignore)
(provide 'vterm-module))
:config
(set-popup-rule! "^\\*vterm" :ignore t)
;; Once vterm is dead, the vterm buffer is useless. Why keep it around? We can
;; spawn another if we want one.
(setq vterm-kill-buffer-on-exit t)
(setq-hook! 'vterm-mode-hook
;; Prevent premature horizontal scrolling
hscroll-margin 0))

View File

@ -0,0 +1,10 @@
;;; term/vterm/doctor.el -*- lexical-binding: t; -*-
(unless (executable-find "make")
(warn! "Couldn't find make command. Vterm module won't compile"))
(unless (executable-find "cmake")
(warn! "Couldn't find cmake command. Vterm module won't compile"))
(unless (fboundp 'module-load)
(warn! "Your emacs wasn't built with dynamic modules support. The vterm module won't build"))

View File

@ -0,0 +1,6 @@
;; -*- no-byte-compile: t; -*-
;;; term/vterm/packages.el
(package! vterm
:built-in 'prefer
:pin "a940dd2ee8a82684860e320c0f6d5e15d31d916f")