diff --git a/oni-eshell.el b/oni-eshell.el index 1dfb744..7a0e0c2 100644 --- a/oni-eshell.el +++ b/oni-eshell.el @@ -4,7 +4,7 @@ ;; Author: Tom Willemse ;; Keywords: local -;; Version: 2022.1127.221317 +;; Version: 2023.0414.233822 ;; Package-Requires: (eshell-fringe-status esh-autosuggest xterm-color eshell-syntax-highlighting) ;; This program is free software; you can redistribute it and/or modify @@ -81,34 +81,26 @@ (eshell/cd (file-name-directory (buffer-file-name (get-buffer buffer-name)))) (eshell-reset)) -(defun oni-eshell-shorten-directories (path) - "Shorten PATH to a list of unique shortened directory names." - (let* ((directories (split-string path "/" t)) - (new-path - (string-join - (mapcar (lambda (d) - (let ((name (substring d 0 1)) - (length 1)) - (while (cl-find-if (lambda (s) (and (not (string= s d)) - (string-prefix-p name s))) - directories) - (setq name (substring d 0 (cl-incf length)))) - name)) - directories) "/"))) - (if (string-prefix-p "~" new-path) - new-path - (concat "/" new-path)))) - (defun oni-eshell-disable-beacon-on-scroll () "Disable ‘beacon-blink-when-window-scrolls’ in the current buffer." (setq-local beacon-blink-when-window-scrolls nil)) +(defun oni-eshell-change-font () + "Remap the default font to the one I use for terminals." + (face-remap-add-relative 'default :family "Classic Console Neue")) + +(defun oni-eshell-set-page-delimiter () + "Change the page delimiter so that it matches the prompt for easy navigation." + (setq-local page-delimiter eshell-prompt-regexp)) + (add-hook 'eshell-before-prompt-hook #'oni-eshell--set-xterm-variables) (add-hook 'eshell-first-time-mode-hook #'oni-eshell--expand-keymap) (add-hook 'eshell-load-hook #'oni-eshell--disable-ansi-color-handling) (add-hook 'eshell-load-hook #'oni-eshell--enable-truncating-buffers) (add-hook 'eshell-load-hook #'oni-eshell--enable-xterm-filter) +(add-hook 'eshell-mode-hook #'oni-eshell-change-font) (add-hook 'eshell-mode-hook #'oni-eshell-disable-beacon-on-scroll) +(add-hook 'eshell-mode-hook #'oni-eshell-set-page-delimiter) (add-hook 'eshell-mode-hook 'esh-autosuggest-mode) (add-hook 'eshell-mode-hook 'eshell-syntax-highlighting-mode) (add-hook 'eshell-mode-hook 'goto-address-mode) @@ -126,5 +118,81 @@ (slot . 0) (window-height . 0.33))) +;;; Eshell prompt + +(defun oni-eshell-shortest-unique-directory (current-path directory) + "Find the shortest unique substring of DIRECTORY. +DIRECTORY should be a directory that exists within CURRENT-PATH." + (catch 'result + (dotimes (i (length directory)) + (let* ((current-directory (substring directory 0 (1+ i))) + (dir-rx (rx string-start + (literal current-directory) + (zero-or-more any))) + (matches (directory-files current-path nil dir-rx))) + (when (= (length matches) 1) + (throw 'result current-directory)))))) + +(defun oni-eshell-shorten-directory (directory) + "Shorten DIRECTORY to the shortest unique names of each directory." + (let ((current-path "/") + (current-short-path "/") + (home (concat (getenv "HOME") "/")) + (components (string-split (expand-file-name directory) "/" t))) + (dolist (dir components current-short-path) + (let* ((shortened (propertize (oni-eshell-shortest-unique-directory current-path dir) + 'help-echo dir)) + (new-path (format "%s%s/" current-path dir)) + (new-short-path (if (string= new-path home) + "~/" + (format "%s%s/" current-short-path shortened)))) + (setq current-path new-path + current-short-path new-short-path))))) + +(defun oni-eshell-show-perforce-info-p () + "Predicate to indicate whether or not powershell info should be shown." + (locate-dominating-file "." ".p4config")) + +(defun oni-eshell-perforce-workspace () + "Function returning the current Perforce workspace." + (car (map-elt (mapcar (lambda (str) (split-string str ": ")) + (split-string (shell-command-to-string "p4 info -s") "\n")) + "Client name"))) + +(defun oni-eshell-perforce-root () + "Function returning the root directory of the current Perforce workspace." + (string-replace + "\\" + "/" + (car (map-elt (mapcar (lambda (str) (split-string str ": ")) + (split-string (shell-command-to-string "p4 info") "\n")) + "Client root")))) + +(defun oni-eshell-perforce-stream () + "Function returning the current Perforce stream." + (string-trim-right (shell-command-to-string "p4 switch"))) + +(defun oni-eshell-prompt-function () + "Construct a prompt string for Eshell." + (let* ((perforcep (oni-eshell-show-perforce-info-p)) + (pwd (eshell/pwd)) + (dir (if perforcep + (concat (propertize (oni-eshell-perforce-workspace) + 'face '((foreground-color . "#ca3cad90828e"))) + ":" + (let ((relative-path (string-remove-prefix (oni-eshell-perforce-root) pwd))) + (if (string= relative-path "") "/" relative-path))) + (oni-eshell-shorten-directory pwd))) + (stream (if perforcep (concat " (" + (propertize (oni-eshell-perforce-stream) + 'face '((foreground-color . "#90e4ca3c828e"))) + ")") + ""))) + (concat dir + stream + (if (= (user-uid) 0) " # " " $ ")))) + +(setq eshell-prompt-function #'oni-eshell-prompt-function) + (provide 'oni-eshell) ;;; oni-eshell.el ends here