From 1b4eda2cbb0f7cb512d378dfbace56ff070d61c6 Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Fri, 8 Apr 2022 20:52:08 +0200 Subject: [PATCH] Override doom's default vterm module --- modules/term/vterm/README.org | 60 ++++++++++++++++ modules/term/vterm/autoload.el | 121 +++++++++++++++++++++++++++++++++ modules/term/vterm/config.el | 25 +++++++ modules/term/vterm/doctor.el | 10 +++ modules/term/vterm/packages.el | 6 ++ 5 files changed, 222 insertions(+) create mode 100644 modules/term/vterm/README.org create mode 100644 modules/term/vterm/autoload.el create mode 100644 modules/term/vterm/config.el create mode 100644 modules/term/vterm/doctor.el create mode 100644 modules/term/vterm/packages.el diff --git a/modules/term/vterm/README.org b/modules/term/vterm/README.org new file mode 100644 index 0000000..71fcf38 --- /dev/null +++ b/modules/term/vterm/README.org @@ -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) diff --git a/modules/term/vterm/autoload.el b/modules/term/vterm/autoload.el new file mode 100644 index 0000000..eb4d190 --- /dev/null +++ b/modules/term/vterm/autoload.el @@ -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)) diff --git a/modules/term/vterm/config.el b/modules/term/vterm/config.el new file mode 100644 index 0000000..6408253 --- /dev/null +++ b/modules/term/vterm/config.el @@ -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)) diff --git a/modules/term/vterm/doctor.el b/modules/term/vterm/doctor.el new file mode 100644 index 0000000..a1df32f --- /dev/null +++ b/modules/term/vterm/doctor.el @@ -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")) diff --git a/modules/term/vterm/packages.el b/modules/term/vterm/packages.el new file mode 100644 index 0000000..340fc3d --- /dev/null +++ b/modules/term/vterm/packages.el @@ -0,0 +1,6 @@ +;; -*- no-byte-compile: t; -*- +;;; term/vterm/packages.el + +(package! vterm + :built-in 'prefer + :pin "a940dd2ee8a82684860e320c0f6d5e15d31d916f")