Skip to content

hummuscience/emacs-libvterm

 
 

Repository files navigation

MELPA

Introduction

This emacs module implements a bridge to libvterm to display a terminal in an Emacs buffer.

Warning

This is an alpha release, so it will crash your Emacs. If it does, please report a bug!

Installation

Manual

Clone the repository:

git clone https://github.com/akermu/emacs-libvterm.git

Before installing emacs-libvterm, you need to make sure you have installed

  1. Emacs with module support. You can check that, by verifying that module-file-suffix is not nil.
  2. cmake (>=3.11)
  3. libtool-bin (related issues: #66 #85)
  4. 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/"
)

From MELPA

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
)

Debugging and testing

If you have successfully built the module, you can test it by executing the following command in the build directory:

make run

Usage

vterm

Open a terminal in the current window.

vterm-other-window

Open a terminal in another window.

vterm-copy-mode

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

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.

Customization

vterm-shell

Shell to run in a new vterm. It defaults to $SHELL.

vterm-term-environment-variable

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.

Keybindings

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.

Colors

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

Directory tracking

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.

Message passing

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

Related packages

About

Emacs libvterm integration

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • C 65.3%
  • Emacs Lisp 29.7%
  • C++ 2.9%
  • CMake 2.1%