Complete Computing Environment: Shell Configuration

Table of Contents

(provide 'cce-shells)


There's not much here right now, since I'm not a huge user of the shell. Instead, I opt to wrap most repetitive things in Emacs commands. As such, I opt for a very light configuration over the top of bash to provide enough affordances to make it useful.

Bash Configuration Loader

It's possible for multiple CCE modules to push out Bash configurations, so each one tangles to its own file which is then executed as so:

- name: ~/.bash_profile assembled
  become: yes
  become_user: "{{local_account}}"
    src: out/bash_profile.d
    dest: ~/.bash_profile
    mode: 0755
    remote_src: False

- name: ~/.bashrc assembled
  become: yes
  become_user: "{{local_account}}"
    src: out/bashrc.d
    dest: ~/.bashrc
    mode: 0755
    remote_src: False
export PATH=~/bin/:$PATH
export PATH=~/.local/bin/:$PATH
test -f /etc/bash_profile && . /etc/bash_profile

I am in San Francisco. This used to be a UTC setup, but it's really hard to make that work sanely, so I don't.

export TZ=America/Los_Angeles
export UBER_LDAP_UID=rrix
export EDITOR=emacsclient
export PS1="\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \[\033[00m\]\`if [ \$? == 0 ]; then echo \:\); else echo \:\(; fi\` "
test -f /etc/bashrc && . /etc/bashrc
function please () {
    until $@; do sleep 0.5; done


Emacs has Shell Mode, a simple comint-mode backed shell that lets me do simple crap that don't need ncurses or anything like that. It uses bash and works sanely with pipelines, unlock eshell and doesn't eat my keybindings like ansi-term and term.

As of my latest Emacs update, shell-mode displays buffers in a new window when I do M-x shell which is almost always not what I want, instead opting for them to always appear in the same window as my cursor.

(add-to-list 'display-buffer-alist
             `(,(rx bos "*shell")

When in shell-mode, things like ls on remote systems expect tabs to be 8 characters. This is easier than trying to clean that shit up.

(add-hook 'shell-mode-hook (lambda ()
                             (setq-local tab-width 8)))

Use Emacs as pager

uhoreg has a cool script on Reddit which lets you use Emacs buffers as your pager.

t=$(mktemp --suffix .emacs-pager) || exit 1
cat - >> $t
echo 'reading into emacs...'
emacsclient "$t"
rm -f -- $t
export PAGER=emacs-pager
- name: emacs pager installed
    src: out/emacs-pager
    dest: ~/bin/emacs-pager
    mode: 0755
  become_user: "{{local_account}}"
  become: yes

Of course, if you feed random terminal shit in to your Emacs, you're gonna end up with ANSI escape codes. Luckily, xterm-color.el exists, and we can use that to automatically color our buffers as necessary.

We start with xterm-colorize-maybe, a function which searches the buffer for an ANSI control-code, and colorizes the buffer if it finds one.

(defun cce/xterm-colorize-maybe ()
  (goto-char (point-min))
  (when (search-forward (string #x1b) nil t)

(add-hook 'find-file-hook #'cce/xterm-colorize-maybe)

I set TERM to xterm-256color everywhere that I can so that commands try to output the text and don't assume that Emacs (identifying as TERM=dumb) can't handle it. comint and compilation are handled a little bit differently due to one having a process filter and the other not.

(setenv "TERM" "xterm-256color")
(setq compilation-environment '("TERM=xterm-256color"))

(setq comint-output-filter-functions
      (remove 'ansi-color-process-output comint-output-filter-functions))
(add-hook 'shell-mode-hook
          (lambda () (add-hook 'comint-preoutput-filter-functions 'xterm-color-filter nil t)))

(defun cce/compilation-start-hook (proc)
  (when (eq (process-filter proc) 'compilation-filter)
    (set-process-filter proc
                        (lambda (proc string)
                          (funcall 'compilation-filter proc
                                   (xterm-color-filter string))))))
(add-hook 'compilation-start-hook #'cce/compilation-start-hook)

Author: Ryan Rix

Created: 2019-05-07 Tue 11:12

Validate XHTML 1.0