Extending MisTTY
Hooks
mistty-mode-hook
The hook mistty-mode-hook is called on every MisTTY buffer
just after creating the buffer and selecting a window for it but
before executing the shell, with the buffer selected.
If you have enabled autocomplete or autosuggestion globally, you might
want to disable it for MisTTY buffers from a function called by
mistty-mode-hook.
This hook also provides a good time to rename the buffer, change its directory or change environment variables, to be inherited by the process.
For example, if you wanted a more generic name for the MisTTY buffers, you could do:
(defun my-lets-call-it-shell ()
(rename-buffer (generate-new-buffer-name "*shell*")))
(add-hook 'mistty-mode-hook #'my-lets-call-it-shell)
mistty-interactive-insert-hook
mistty-interactive-insert-hook is a hook that is called when
text is typed in the terminal region. It’s not called, for example,
for text that is inserted or displayed by the shell.
This hook provides an appropriate time to trigger auto-completion UI, which, by default, doesn’t work in the terminal region, as discussed in Auto-complete.
Auto-completion doesn’t work in the terminal region because it often
requires calling a post-command function. To work around that, in most
case, it’s enough to just turn on the option M-x
customize-option mistty-simulate-self-insert-command, which enables
the function mistty-self-insert-command, called by this hook
by default.
This might not always work and have unintended effects, so you might prefer to trigger the auto-completion UI yourself by adding your own function to this hook and turning the above option off.
mistty-after-process-start-hook
mistty-after-process-start-hook is a normal hook called from
within a new MisTTY work buffer just after starting the process,
usually a shell. The process itself is available as
mistty-proc. At the time this hook is called, the buffer is
typically empty, as no output from the process has been processed.
mistty-after-process-end-hook
mistty-after-process-end-hook is called from within a MisTTY
work buffer just after the process ended. The process is passed as an
argument to the hook and its status can be accessed using
process-status.
This can be used to, for example, kill the MisTTY work buffer after
the shell exits successfully, with mistty-kill-buffer or
mistty-kill-buffer-and-window.
(add-hook 'mistty-after-process-end-hook
'mistty-kill-buffer-and-window)
mistty-entered-fullscreen-hook
mistty-entered-fullscreen-hook is a normal hook called from
within a MisTTY work buffer just after switching to fullscreen mode.
In this mode, mistty-fullscreen is non-nil and user commands
run within the terminal buffer, available as
mistty-term-buffer. The work buffer is kept, but usually
buried until mistty-toggle-buffers is called.
mistty-left-fullscreen-hook
mistty-left-fullscreen-hook is a normal hook called from
within a MisTTY work buffer just after switching back to normal mode.
In this mode, mistty-fullscreen is nil and user commands run
in the work buffer.
OSC Sequences
OSC are “operating system command” control sequences. MisTTY supports some of these sequences and ignores the others.
By default, the supported sequences are OSC 2 (set window title), 7
(directory tracking, already mentioned in Directory Tracking) and 8
(hyperlinks), thanks to ansi-osc.el.
To add more, register handlers to mistty-osc-handlers. The
format is the same as the handlers supported for
ansi-osc-handlers and can usually be used interchangeably.
When working on OSC handlers for MisTTY, it’s important to keep the
following in mind: MisTTY separate buffers for the terminal (a
term-mode buffer) and for MisTTY itself. The OSC handlers run
in the term-mode buffer.
One consequence of this is that if you set a buffer-local variable in a handler, it won’t be available in the MisTTY buffer unless you register it to M-x configure-option mistty-variables-to-copy
MisTTY provides helpers for writing OSC handlers that set text properties:
The function
mistty-register-text-propertiesregisters a set of text properties to set on any text written to the terminal untilmistty-unregister-text-propertiesis called with the same argument.
Writing Your Own Commands
You might find the following functions useful if you’d like to write commands that extend MisTTY’s behavior:
- (mistty-mode): function
This function sets the major mode of the current buffer to mistty-mode. This only useful when followed by a call to
mistty-exec, described below.
- (mistty-exec PROGRAM &optional :width WIDTH :height HEIGHT)
This functions starts PROGRAM in the current buffer, which must be a
mistty-modebuffer.PROGRAM is normally a list of executable and its argument. It can also be a string containing only the executable, if no arguments to be set.
It is a good idea to display the buffer before calling this function, because the size of the terminal when PROGRAM is started is taken from the windows displaying the buffer.
Example:
(with-current-buffer (generate-new-buffer "*terminal*") (mistty-mode) (pop-to-buffer (current-buffer)) (mistty-exec '("bash" "-i")))
If the buffer isn’t displayed, the terminal size is taken from the currently selected window, which might not be what you want. You can also set an arbitrary terminal size by passing the :width and :height optional keyword arguments and calling
mistty-terminal-size-tracks-windowsonce the buffer has been tied to a window of a reasonable size, but that might cause a visible terminal refresh.
- (mistty-send-string STR): function
This function sends a string to the terminal, unmodified. The string that is sent appear only after the function return - and it might not ever appear at all depending on the application attached to the terminal. This is used to implement
mistty-sudofor example.
- (mistty-on-prompt-p POS)function
This function returns non-nil if the POS is inside of a prompt MisTTY is aware of. This is useful for writing commands that behave differently on a prompt than on program output, even while inside of the terminal zone. It is used to implement
mistty-beginning-of-linefor example.
- (mistty-maybe-realize-possible-prompt &optional POS)function
This function might be useful to call in your commands to tell MisTTY that there’s likely a prompt at the current pointer position or at POS.
- (mistty-before-positional)function
This function not only checks whether there’s a prompt at the position, but also attempt to move the terminal cursor to that position.
Terminal Keymap
To forward a key binding to the application attached to the terminal
mistty-send-key first needs to convert that key binding to something
applications will understand. The translation is done by
mistty-translate-key.
- mistty-translate-keyfunction
This function takes an Emacs key binding, as returned by kbd and returns a string containing the sequence of characters that correspond to that key to send to the application tied to the terminal.
The default terminal keymap used by MisTTY mimics xterm key
bindings. You might extend it or change it by changing the map
mistty-term-key-map.
For example, you can change the string that correspond to the first function keys from their default (”\eOP” - “\eOS”) as follows:
(define-key mistty-term-key-map (kbd "<f1>") "\e[11~")
(define-key mistty-term-key-map (kbd "<f2>") "\e[12~")
(define-key mistty-term-key-map (kbd "<f3>") "\e[13~")
(define-key mistty-term-key-map (kbd "<f4>") "\e[14~")
- mistty-reverse-input-decode-map: function
This function generates alternative values for
mistty-term-key-mapfor you if you’d like mimic another set of key bindings than xterm, for example, to generate a keymap that simulates rxvt, you might do:(load-library "term/rxvt.el") (mistty-reverse-input-decode-map rxvt-function-map)
mistty-reverse-input-decode-map.el is not included into the
distribution; it’s only available on github.
Auto-complete
Auto-complete is a completion UI that shows up automatically after
some delay, without having to call completion-at-point. This used
not to work in MisTTY terminal region. The hook
mistty-simulates-self-insert-command was introduced to fix
that. See mistty-interactive-insert-hook in Hooks.
By default this hook calls the buffer pre-command-hook and
post-command-hook with this-command set to
self-insert-command, as this is the way auto-complete is
normally triggered. This can be turned off if necessary using the
option on M-x customize-option
mistty-simulate-self-insert-command.
If the behavior described above doesn’t work for some packages, it should be possible to build a custom bridge between this hook and the auto-completion package.
Long-running commands
In Emacs, most editing tools are run as a single Emacs command, but some tools span multiple Emacs command, for example, when you expand a snippet with yasnippet, the snippet template is inserted into the buffer, together with placeholders for you to fill some missing information.
Filling in a template is a series of Emacs commands, that, together, have a single effect: to insert a snippet of text. MisTTY calls this a long-running command.
When run in the terminal region, such long-running commands fail as MisTTY sends the initial text to the shell, which echoes it back to be redisplayed, possibly jumbling things and definitely destroying any overlays.
To avoid such situations, MisTTY holds back sending text to the shell until long-running commands are done. For that to work, MisTTY needs to know when such command start and end.
You can tell whether MisTTY thinks a long-running command is active, as it displays CMD in the modeline. You can also do it programmatically:
- mistty-long-running-running-command-pfunction
This function returns non-nil if MisTTY thinks a long-running command is active.
MisTTY detects some long-running commands by looking for overlays they typically add to the buffer. This can be extended with M-x customize-option mistty-foreign-overlay-properties or turned off with M-x customize-option mistty-detect-foreign-overlays.
To add a new property to mistty-foreign-overlay-properties, start the interactive command, look for overlays with overlays-in then get their properties with overlay-properties. You can then choose, on that list, a property or face that identifies the feature or package.
If you find yourself extending mistty-foreign-overlay-properties, please add an issue to https://github.com/szermatt/mistty/issues/new so it can be integrated into the next version.
Alternatively, as not all long-running commands that can be confused
by MisTTY use overlays, you might need to tell MisTTY about them.
MisTTY does it already for completion-in-region.
- mistty-report-long-running-commandfunction
This function can be called to tell MisTTY when a long-running command start and end. It’s typically called from hooks provided by the package of the long-running command.
Here’s an example of code that would detect
completion-in-region-mode if MisTTY didn’t already do it:
(defun my-completion-in-region ()
(mistty-report-long-running-command
'my-completion-in-region completion-in-region-mode))
(defun my-detect-completion-in-region ()
(add-hook 'completion-in-region-mode-hook
#'my-completion-in-region nil t))
(add-hook 'mistty-mode-hook #'my-detect-completion-in-region)