This emacs module implements a bridge to libvterm to display a terminal in an Emacs buffer.
This is an alpha release, so it will crash your Emacs. If it does, please report a bug!
Clone the repository:
git clone https://github.com/akermu/emacs-libvterm.git
Before installing emacs-libvterm, you need to make sure you have installed
- Emacs with module
support.
You can check that, by verifying that
module-file-suffix
is notnil
. - cmake (>=3.11)
- libtool-bin (related issues: #66 #85)
- If you compile vterm with
-DUSE_SYSTEM_LIBVTERM
make sure you have the library from https://github.com/neovim/libvterm
Run the build:
mkdir -p build
cd build
cmake ..
make
And add this to your init.el
:
(add-to-list 'load-path "path/to/emacs-libvterm")
(require 'vterm)
Or, with use-package
:
(use-package vterm
:load-path "path/to/emacs-libvterm/"
)
vterm
is available on MELPA, and it can be installed as
a normal package. If the requirements are satisfied (mainly, Emacs was built
with support for modules), vterm
will take care of the compilation of all its
components.
vterm
can be install with MELPA with use-package
by adding the following
lines to your init.el
:
(use-package vterm
:ensure t
)
If you have successfully built the module, you can test it by executing the
following command in the build
directory:
make run
Open a terminal in the current window.
Open a terminal in another window.
When you enable vterm-copy-mode
, the terminal buffer behaves like a normal
read-only
text buffer: you can search, copy text, etc. The default keybinding
to toggle vterm-copy-mode
is C-c C-t
. When a region is selected, it is
possible to copy the text and leave vterm-copy-mode
with the enter key.
vterm-clear-scrollback
does exactly what the name suggests: it clears the
current buffer from the data that it is not currently visible.
vterm-clear-scrollback
is bound to C-c C-l
. This function is typically used
with the clear
function provided by the shell to clear both screen and
scrollback. In order to achieve this behavior, you need to add a new shell alias.
For bash
or zsh
, put this in your .zshrc
or .bashrc
function vterm_printf(){
if [ -n "$TMUX" ]; then
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\ePtmux;\e\e]%s\007\e\\" "$1"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]%s\007\e\\" "$1"
else
printf "\e]%s\e\\" "$1"
fi
}
For fish
put this in your ~/.config/fish/config.fish
:
function vterm_printf;
if [ -n "$TMUX" ]
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\ePtmux;\e\e]%s\007\e\\" "$argv"
else if string match -q -- "screen*" "$TERM"
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]%s\007\e\\" "$argv"
else
printf "\e]%s\e\\" "$argv"
end
end
For zsh
, put this in your .zshrc
:
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then
alias clear='vterm_printf "51;Evterm-clear-scrollback";tput clear'
fi
For bash
, put this in your .bashrc
:
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then
function clear(){
vterm_printf "51;Evterm-clear-scrollback";
tput clear;
}
fi
These aliases take advantage of the fact that vterm
can execute elisp
commands, as explained below.
Shell to run in a new vterm. It defaults to $SHELL
.
Value for the TERM
environment variable. It defaults to xterm-256color
. If
eterm-256color is installed,
setting vterm-term-environment-variable
to eterm-color
improves the
rendering of colors in some systems.
If you want a key to be sent to the terminal, bind it to vterm--self-insert
,
or remove it from vterm-mode-map
. By default, vterm.el
binds most of the
C-<char>
and M-<char>
keys, <f1>
through <f12>
and some special keys
like <backspace>
and <return>
. Sending a keyboard interrupt is bound to C-c C-c
.
Set the :foreground
and :background
attributes of the following faces to a
color you like. The :foreground
is ansi color 0-7, the :background
attribute
is ansi color 8-15.
- vterm-color-default
- vterm-color-black
- vterm-color-red
- vterm-color-green
- vterm-color-yellow
- vterm-color-blue
- vterm-color-magenta
- vterm-color-cyan
- vterm-color-white
vterm
supports directory tracking. If this feature is enabled, the default
directory in Emacs and the current working directory in vterm
are synced. As a
result, interactive functions that ask for a path or a file (e.g., dired
or
find-file
) will do so starting from the current location.
Directory tracking requires some configuration, as the shell has to be instructed to share the relevant information with Emacs.
For zsh
, put this at the end of your .zshrc
:
vterm_prompt_end() {
vterm_printf "51;A$(whoami)@$(hostname):$(pwd)";
}
PROMPT=$PROMPT'%{$(vterm_prompt_end)%}'
For bash
, put this at the end of your .bashrc
:
vterm_prompt_end(){
vterm_printf "51;A$(whoami)@$(hostname):$(pwd)"
}
PS1=$PS1'\[$(vterm_prompt_end)\]'
For fish
, put this in your ~/.config/fish/config.fish
:
function fish_vterm_prompt_end;
vterm_printf '51;A'(whoami)'@'(hostname)':'(pwd)
end
function track_directories --on-event fish_prompt; fish_vterm_prompt_end; end
Directory tracking works on remote servers too. In case the hostname of your
remote machine does not match the actual hostname needed to connect to that
server, change $(hostname)
with the correct one.
vterm
can read and execute commands. At the moment, a command is
passed by providing a specific escape sequence. For example, to evaluate
(message "Hello!")
use
printf "\e]51;Emessage \"Hello\!\"\e\\"
# or
vterm_printf "51;Emessage \"Hello\!\""
The commands that are understood are defined in the setting vterm-eval-cmds
.
As split-string-and-unquote
is used the parse the passed string, double quotes
and backslashes need to be escaped via backslash. For instance, bash can replace
strings internally.
vterm_cmd() {
if [ -n "$TMUX" ]; then
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\ePtmux;\e\e]51;E"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]51;E"
else
printf "\e]51;E"
fi
printf "\e]51;E"
local r
while [[ $# -gt 0 ]]; do
r="${1//\\/\\\\}"
r="${r//\"/\\\"}"
printf '"%s" ' "$r"
shift
done
if [ -n "$TMUX" ]; then
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\007\e\\"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\007\e\\"
else
printf "\e\\"
fi
}
However if you are using dash and need a pure POSIX implementation:
vterm_cmd() {
if [ -n "$TMUX" ]; then
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\ePtmux;\e\e]51;E"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\eP\e]51;E"
else
printf "\e]51;E"
fi
while [ $# -gt 0 ]; do
printf '"%s" ' "$(printf "%s" "$1" | sed -e 's|\\|\\\\|g' -e 's|"|\\"|g')"
shift
done
if [ -n "$TMUX" ]; then
# tell tmux to pass the escape sequences through
# (Source: http://permalink.gmane.org/gmane.comp.terminal-emulators.tmux.user/1324)
printf "\007\e\\"
elif [ "${TERM%%-*}" = "screen" ]; then
# GNU screen (screen, screen-256color, screen-256color-bce)
printf "\007\e\\"
else
printf "\e\\"
fi
}
Now we can write shell functions to call the ones defined in vterm-eval-cmds
.
find_file() {
vterm_cmd find-file "$(realpath "$@")"
}
say() {
vterm_cmd message "%s" "$*"
}
This can be used inside vterm
as
find_file name_of_file_in_local_directory
As an example, say you like having files opened below the current window. You could add the command to do it on the lisp side like so:
(push (list "find-file-below"
(lambda (path)
(if-let* ((buf (find-file-noselect path))
(window (display-buffer-below-selected buf nil)))
(select-window window)
(message "Failed to open file: %s" path))))
vterm-eval-cmds)
Then add the command in your .bashrc
file.
open_file_below() {
vterm_cmd find-file-below "$(realpath "$@")"
}
Then you can open any file from inside your shell.
open_file_below ~/Documents
- vterm-toggle: Toggles between a vterm and the current buffer
- multi-libvterm: Multiterm for emacs-libvterm