GitHub - riscy/shx-for-emacs: An Emacs shell-mode (and comint-mode) extension th...
source link: https://github.com/riscy/shx-for-emacs
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
README.org
shx for Emacs
Table of Contents
Description
shx or “shell-extras” extends comint-mode in Emacs (e.g. M-x shell
).
It’s compatible with any underlying REPL (zsh, bash, psql, ipython, etc.).
It parses the output stream in a few useful ways:
- Display graphics and plots in the shell with a simple markup
language (e.g.
<view image.png>
) - Add event-driven and timed behaviors to any shell session
- Open any filename or URL by arrowing up to it and pressing
<enter>
- Yank any line to the prompt by arrowing up to it and pressing
C-<enter>
- Check the time a command was run by mousing over its prompt
shx makes it easy to add new shell commands written in elisp. Some are already built in:
:clear
clears the buffer (likeclear
orCmd-K
on macOS):e filename.txt
opens a file for editing:ssh user@host:port
starts a remote shell session using tramp:view image_file.png
embeds an image in the shell:plotline data_file.txt
embeds a line plot- etc.
It also extends shell-mode
’s syntax highlighting, recenters and highlights
content for better viewing when you run commands like comint-previous-prompt
and comint-kill-input
, and improves compatibility with evil-mode
by
anticipating when to switch to insert
mode.
Use M-x shx <return>
to quickly start a new shell
session with shx
enabled.
This version is tested with Emacs 26.1 Check out the release log.
Install
From MELPA
M-x package-install RET shx RET
to install shx from MELPA.
Manually
Add the following to your .emacs
:
(add-to-list 'load-path "~/path/to/shx/") ; add shx.el's directory to the load-path (require 'shx) ; load shell-extras
Setup
Quick-start
Type M-x shx <return>
. Try out the following commands:
:e ~/.bashrc
to edit your .bashrc file (for example):man ls
to display the man page forls
:help
to a start a completing read for other shx commands
Enable automatically
If you like shx-mode, you can enable it everywhere:
(shx-global-mode 1) ; toggle shx-mode on globally
Now shx will run automatically in any comint-mode
buffer. If you don’t want
shx to run in every comint-mode buffer, you can use M-x shx-mode
on a
case-by-case basis, or just add hooks to the mode in question, for example:
(add-hook 'inferior-python-mode-hook #'shx-mode)
Customize
Use M-x customize-group RET shx RET
to see shx’s many customization options.
Here’s an example customization using setq
:
(setq ;; vastly improve display performance by breaking up long output lines shx-max-output 1024 ;; prevent input longer than macOS's typeahead buffer from going through shx-max-input 1024 ;; prefer inlined images to have a height of 250 pixels shx-img-height 250 ;; don't show any incidental hint messages about how to use shx shx-show-hints nil ;; flash the previous comint prompt for a full second when using C-c C-p shx-flash-prompt-time 1.0 ;; use `#' to prefix shx commands instead of the default `:' shx-leader "#")
Key bindings
Key bindingDescriptionC-RET
If the cursor is not on the prompt, paste the current line to the inputRET
If the cursor is on a filename or a URL, try to open itSPC
If the prompt is :
, send SPC
straight through to the processq
If the prompt is :
, send q
straight through to the processNote the prompt will be :
when reading through the output of less
or a man
page
if you run the following:
(setenv "LESS" "--dumb --prompt=s")
Markup in the shell
shx’s markup can enhance basic command-line applications and drive other events.
If the output ever contains <view mountains.png>
on a line by itself, then a
scaled rendering of mountains.png
will be inlined within the text in the
shell. This works because view
is a shx command. shx will execute any
(safe) shx command that appears with the following syntax:
<command arg1 arg2 ...>
where command
is a shx command and arg1 ... argn
is a space-separated
list of arguments. Arguments don’t need to be surrounded by quotes – the
command will figure out how to parse them.
You can use this markup to create a barplot (:plotbar
) after collecting some
stats, or generate an :alert
when a task is finished, and so forth.
Extra shell commands
shx’s ‘extra’ commands are invoked by typing a :
followed by the command’s
name. (You can change the :
prefix by customizing the shx-leader
variable.) These commands are written in elisp and so can access all of
Emacs’ facilities. Type :help
to see a complete listing of shx commands.
One command I use frequently is the :edit
(shorthand :e
) command:
# edit the .emacs file: :edit ~/.emacs # use tramp to edit the .emacs file on a remote host: :e /remote-host.com:~/.emacs # edit a local file as root :sedit /etc/passwd
Thanks to CeleritasCelery it’s also possible to use environment variables in the argument list:
:e $HOME/.emacs.d
(To see an environment variable’s value, use (getenv "<var>")
.)
I also use the :kept
and :keep
commands frequently:
# write a complicated command: wget https://bootstrap.pypa.io/get-pip.py && python get-pip.py # save the last command: :keep # search for commands having to do with pip: :kept pip
Because these commands are written in elisp, shx gives M-x shell
a lot of
the same advantages as eshell
. You can even evaluate elisp code directly in
the buffer (see :help eval
).
General commands
CommandDescription:alert
Reveal the buffer with an alert. Useful for markup:clear
Clear the buffer:date
Show the date (even when the process is blocked):diff file1 file2
Launch an Emacs diff between two files:edit file
Edit a file. Shortcut: :e <file>
:eval (elisp-sexp)
Evaluate some elisp code. Example: :eval (pwd)
:find <filename>
Run a fuzzy-find for <filename>:goto-url <url>
Completing-read for a URL:header New header
Change the current header-line-format
:kept regexp
Show a list of your ‘kept’ commands matching regexp:keep
Add the previous command to the list of kept commands:man topic
Invoke the Emacs man page browser on a topic:ssh host
Open another shell on the specified hostThere are more than this – type :help
for a listing of all user commands.
Graphical commands
CommandDescription:view image_file.jpg
Display an image:plotbar data_file.txt
Display a bar plot:plotline data_file.txt
Display a line plot:plotmatrix data_file.txt
Display a heatmap:plotscatter data_file.txt
Display a scatter plot:plot3d data_file.txt
Display a 3D plotThese are for displaying inline graphics and plots in the shell buffer. You
can control how much vertical space an inline image occupies by customizing
the shx-imgsize
variable. Note convert
(i.e., ImageMagick) and
gnuplot
need to be installed. If the binaries are installed but these
commands aren’t working, customize the shx-path-to-convert
and
shx-path-to-gnuplot
variables to point to the binaries.
Asynchronous commands
CommandDescription:delay <sec> <command>
Run a shell command after a specific delay:pulse <sec> <command>
Repeat a shell command forever with a given delay:repeat <count> <sec> <command>
Repeat a shell command <count>
times:stop <num>
Cancel a repeating or delayed commandUse these to delay, pulse, or repeat a command a specific number of times. Unfortunately these only support your typical shell commands, and not shx’s extra (colon-prefixed) commands. So this possible:
# Run the 'pwd' command 10 seconds from now: :delay 10 pwd
But this is not possible:
# Run the 'pwd' shx command 10 seconds from now (DOES NOT WORK)
:delay 10 :pwd
Adding new commands
New shx commands are written by defining single-argument elisp functions
named shx-cmd-COMMAND-NAME
, where COMMAND-NAME
is what the user would
type to invoke it.
Example: a command to rename the buffer
If you evaluate the following (or add it to your .emacs
),
(defun shx-cmd-rename (name) "(SAFE) Rename the current buffer to NAME." (if (not (ignore-errors (rename-buffer name))) (shx-insert 'error "Can't rename buffer.") (shx-insert "Renaming buffer to " name "\n") (shx--hint "Emacs won't save buffers starting with *")))
then each shx buffer will immediately have access to the :rename
command.
When it’s invoked, shx will also display a hint about buffer names.
Note the importance of defining a docstring. This documents the
command so that typing :help name
will give the user information on what
the command does. Further, since the docstring begins with (SAFE)
,
it becomes part of shx’s markup language. So in this case if:
<name A new name for the buffer>
appears on a line by itself in the output, the buffer will try to automatically rename itself.
Example: invoking ediff from the shell
A command similar to this one is built into shx:
(defun shx-cmd-diff (files) "(SAFE) Launch an Emacs `ediff' between FILES." (setq files (shx-tokenize files)) (if (not (eq (length files) 2)) (shx-insert 'error "diff <file1> <file2>\n") (shx-insert "invoking ediff...\n") (shx--asynch-funcall #'ediff (mapcar 'expand-file-name files))))
Note that files
is supplied as a string, but it’s immediately parsed
into a list of strings using shx-tokenize
. Helpfully, this function is
able to parse various styles of quoting and escaping, for example the string
"'file one' file\\ two"
turns into the list
("file one" "file two")
Example: a command to browse URLs
If you execute the following,
(defun shx-cmd-browse (url) "Browse the supplied URL." (shx-insert "Browsing " 'font-lock-keyword-face url) (browse-url url))
then each shx buffer will have access to the :browse
command.
Note the docstring does not specify that this command is SAFE
.
This means <browse url>
will not become part of shx’s markup. That
makes sense in this case, since you wouldn’t want to give a process the
power to open arbitrary URLs without prompting.
Related
If you’re here, these might be interesting:
- Shell & Comint Secrets: History commands
- Creating dynamic bash prompts
- The Keep Utility inspired the
kept
andkeep
commands
And if running a dumb
terminal in Emacs isn’t for you, here are some
alternatives:
- The Tao of tmux, re: working in the terminal with tmux
- oh my zsh, a community-driven zsh configuration
- bash-it, a community driven bash configuration
- zsh-syntax-highlighting
- Shell configuration tips from Vitaly Belman
- Shell integration for iTerm2 on macOS
- BitBar adds program output to menus on macOS
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK