aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emacs/.config/emacs/.config/eshell/aliases2
-rw-r--r--Emacs/.config/emacs/config.org169
-rw-r--r--Emacs/.config/emacs/elisp/eshell-additions.el57
-rw-r--r--Emacs/.config/emacs/elisp/eshell-prompt.el112
4 files changed, 216 insertions, 124 deletions
diff --git a/Emacs/.config/emacs/.config/eshell/aliases b/Emacs/.config/emacs/.config/eshell/aliases
index 8686c44..c7effa4 100644
--- a/Emacs/.config/emacs/.config/eshell/aliases
+++ b/Emacs/.config/emacs/.config/eshell/aliases
@@ -5,4 +5,4 @@ alias gs magit-status
alias clear clear-scrollback
alias d dired-other-window $1
alias gt goto
-alias p~ project-root
+alias pr project-root
diff --git a/Emacs/.config/emacs/config.org b/Emacs/.config/emacs/config.org
index 84c25e1..3411eea 100644
--- a/Emacs/.config/emacs/config.org
+++ b/Emacs/.config/emacs/config.org
@@ -1686,16 +1686,27 @@ expression it tries to evaluate it by testing against these conditions:
- it's an external command (bash evaluator)
Essentially, you get the best of both Emacs and external shell
programs *ALL WITHIN* Emacs for free.
-*** Eshell functionality
-Bind some evil-like movements for easy shell usage, and a toggle
-function to pull up the eshell quickly.
+*** Eshell keymaps, display and variables
+Bind some evil-like movements for easy shell usage, a display record
+so when you call eshell it kinda looks like VSCode's terminal popup.
+
+NOTE: This mode doesn't allow you to set maps the normal way; you need
+to set keybindings on eshell-mode-hook, otherwise it'll just overwrite
+them.
#+begin_src emacs-lisp
(use-package eshell
:defer t
:general
(shell-leader
"t" #'eshell)
+ :display
+ ("\\*e?shell\\*"
+ (display-buffer-at-bottom)
+ (window-height . 0.33))
:init
+ (setq eshell-cmpl-ignore-case t
+ eshell-cd-on-directory t
+ eshell-highlight-prompt nil)
(add-hook
'eshell-mode-hook
(proc
@@ -1703,6 +1714,7 @@ function to pull up the eshell quickly.
(general-def
:states '(normal insert)
:keymaps 'eshell-mode-map
+ "0" #'eshell-bol
"M-j" #'eshell-next-matching-input-from-input
"M-k" #'eshell-previous-matching-input-from-input)
(local-leader
@@ -1711,134 +1723,45 @@ function to pull up the eshell quickly.
(recenter))
"k" #'eshell-kill-process))))
#+end_src
-*** Eshell pretty symbols and display
-Pretty symbols and a display record.
-#+begin_src emacs-lisp
-(use-package eshell
- :defer t
- :display
- ("\\*e?shell\\*" ; for general shells as well
- (display-buffer-at-bottom)
- (window-height . 0.33)))
-#+end_src
-*** Eshell variables and aliases
-Set some sane defaults, a banner and a prompt. The prompt checks for
-a git repo in the current directory and provides some extra
-information in that case (in particular, branch name and if there any
-changes that haven't been committed).
+*** Eshell prompt
+Here I use my external library
+[[file:elisp/eshell-prompt.el][eshell-prompt]], which provides a more
+dynamic prompt for Eshell. Current features include:
++ Git (with difference from remote and number of modified files)
++ Current date and time
++ A coloured prompt which changes colour based on the exit status of
+ the previous command
+NOTE: I don't defer this package because it doesn't use any eshell
+internals, just standard old Emacs packages.
#+begin_src emacs-lisp
-(use-package eshell
- :defer t
+(use-package eshell-prompt
+ :load-path "elisp/"
:config
- (defun +eshell/--git-get-remote-status ()
- (let* ((branch-status (split-string
- (shell-command-to-string "git status | grep 'Your branch is'")))
- (status (nth 3 branch-status))
- (diff (cl-position "by" branch-status :test #'string=)))
- (if (null diff)
- (propertize "=" 'font-lock-face '(:foreground "green"))
- (let ((n (nth (+ 1 diff) branch-status)))
- (concat
- (cond
- ((string= status "ahead")
- (propertize "→ " 'font-lock-face '(:foreground "dodger blue")))
- ((string= status "behind")
- (propertize "← " 'font-lock-face '(:foreground "orange red"))))
- n)))))
-
- (defun +eshell/--git-get-change-status ()
- (let ((changed-files (- (length (split-string (shell-command-to-string "git status -s" ) "\n")) 1)))
- (if (= changed-files 0)
- (propertize "✓" 'font-lock-face '(:foreground "green"))
- (propertize (number-to-string changed-files) 'font-lock-face '(:foreground "red")))))
-
- (defun +eshell/get-git-properties ()
- (let ((git-branch (shell-command-to-string "git branch")))
- (if (or (string= git-branch "")
- (not (string= "*" (substring git-branch 0 1))))
- ""
- (format
- "(%s<%s>[%s])"
- (nth 2 (split-string git-branch "\n\\|\\*\\| "))
- (+eshell/--git-get-change-status)
- (+eshell/--git-get-remote-status)))))
-
- (defun +eshell/prompt-function ()
- (let ((git (+eshell/get-git-properties)))
- (mapconcat
- (lambda (item)
- (if (listp item)
- (propertize (car item)
- 'read-only t
- 'font-lock-face (cdr item)
- 'front-sticky '(font-lock-face read-only)
- 'rear-nonsticky '(font-lock-face read-only))
- item))
- (list
- '("[")
- `(,(abbreviate-file-name (eshell/pwd)) :foreground "LimeGreen")
- '("]")
- (if (string= git "")
- ""
- (concat "-" git ""))
- "\n"
- `(,(format-time-string "[%H:%M:%S]") :foreground "purple")
- "\n"
- '("𝜆> " :foreground "DeepSkyBlue")))))
-
(defun +eshell/banner-message ()
(concat (shell-command-to-string "~/.local/scripts/cowfortune")
"\n"))
-
- (setq eshell-cmpl-ignore-case t
- eshell-cd-on-directory t
- eshell-banner-message '(+eshell/banner-message)
- eshell-highlight-prompt nil
- eshell-prompt-function #'+eshell/prompt-function
- eshell-prompt-regexp "^𝜆> "))
-#+end_src
-*** Eshell change directory quickly
-Add ~eshell/goto~, which is actually a command accessible from within
-eshell (this is because ~eshell/*~ creates an accessible function
-within eshell with name ~*~). ~eshell/goto~ makes it easier to change
-directories by using Emacs' find-file interface (which is much faster
-than ~cd ..; ls -l~).
-
-~eshell/goto~ is a better ~cd~ for eshell. However it is really just
-a plaster over a bigger issue for my workflow; many times I want
-eshell to be present in the current directory of the buffer I am
-using. So here's also a command for opening eshell with the current
-directory.
-#+begin_src emacs-lisp
-(use-package eshell
- :defer t
+ (setq eshell-prompt-regexp (format "^%s" +eshell-prompt/user-prompt)
+ eshell-prompt-function #'+eshell-prompt/make-prompt
+ eshell-banner-message '(+eshell/banner-message)))
+#+end_src
+*** Eshell additions
+Using my external library
+[[file:elisp/eshell-additions.el][eshell-additions]], I get a few new
+eshell internal commands and a surface command to open eshell at the
+current working directory.
+
+NOTE: I don't defer this package because it autoloads any eshell
+internals that it uses so I'm only loading what I need to. Any
+~eshell/*~ functions need to be known by eshell before launching, so
+if I loaded this ~:after~ eshell then the first instance has no
+knowledge of the new additions.
+#+begin_src emacs-lisp
+(use-package eshell-additions
+ :load-path "elisp/"
:general
(leader
- "T" #'+eshell/current-buffer)
- :config
- (defun eshell/goto (&rest args)
- "Use `read-directory-name' to change directories."
- (eshell/cd (list (read-directory-name "Directory?: "))))
-
- (defun eshell/project-root (&rest args)
- "Change to directory `project-root'"
- (if (project-current)
- (eshell/cd (list (project-root (project-current))))
- (eshell/echo (format "[%s]: No project in current directory"
- (propertize "Error" 'font-lock-face '(:foreground "red"))))))
-
- (defun +eshell/current-buffer ()
- (interactive)
- (let ((dir (if buffer-file-name
- (file-name-directory buffer-file-name)
- default-directory))
- (buf (eshell)))
- (if dir
- (with-current-buffer buf
- (eshell/cd dir)
- (eshell-send-input))
- (message "Could not switch eshell: buffer is not real file")))))
+ "T" #'+eshell/at-cwd))
#+end_src
** WAIT Elfeed
:PROPERTIES:
diff --git a/Emacs/.config/emacs/elisp/eshell-additions.el b/Emacs/.config/emacs/elisp/eshell-additions.el
new file mode 100644
index 0000000..94c948f
--- /dev/null
+++ b/Emacs/.config/emacs/elisp/eshell-additions.el
@@ -0,0 +1,57 @@
+;;; eshell-additions.el --- Some aliases for Eshell -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Aryadev Chavali
+
+;; Author: Aryadev Chavali <aryadev@aryadevchavali.com>
+;; Keywords:
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation version 2 of the License
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(autoload #'eshell/cd "eshell")
+(autoload #'eshell/echo "eshell")
+(autoload #'eshell/send-input "eshell")
+
+;; Aliases
+(defun eshell/goto (&rest args)
+ "Use `read-directory-name' to change directories"
+ (eshell/cd (list (read-directory-name "Directory?: "))))
+
+(defun eshell/project-root (&rest args)
+ "Change to directory `project-root'"
+ (if (project-current)
+ (eshell/cd (list (project-root (project-current))))
+ (let ((error-msg (propertize "Error" 'font-lock-face
+ '(:foreground "red"))))
+ (eshell/echo
+ (format "[%s]: No project in current directory" error-msg)))))
+
+;; Additional functions
+(defun +eshell/at-cwd ()
+ "Open an instance of eshell at the current working directory."
+ (interactive)
+ (let ((dir (if buffer-file-name
+ (file-name-directory buffer-file-name)
+ default-directory))
+ (buf (eshell)))
+ (with-current-buffer buf
+ (eshell/cd dir)
+ (eshell-send-input))))
+
+(provide 'eshell-additions)
+;;; eshell-additions.el ends here
diff --git a/Emacs/.config/emacs/elisp/eshell-prompt.el b/Emacs/.config/emacs/elisp/eshell-prompt.el
new file mode 100644
index 0000000..7e78c7c
--- /dev/null
+++ b/Emacs/.config/emacs/elisp/eshell-prompt.el
@@ -0,0 +1,112 @@
+;;; eshell-prompt.el --- Generating a good prompt for Eshell -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Aryadev Chavali
+
+;; Author: Aryadev Chavali <aryadev@aryadevchavali.com>
+;; Keywords:
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation version 2 of the License.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; We provide a function +eshell-prompt which generates a prompt on
+;; demand.
+
+;;; Code:
+
+(defvar +eshell-prompt/user-prompt "𝜆> "
+ "Prompt for user to input.")
+
+(defun +eshell-prompt/--colour-on-last-command ()
+ "Returns an Emacs colour based on ESHELL-LAST-COMMAND-STATUS."
+ (if (zerop eshell-last-command-status)
+ "forestgreen"
+ "darkred"))
+
+(defun +eshell-prompt/--git-remote-status ()
+ "Returns a propertized string for the status of a repository
+in comparison to its remote. 3 differing strings are returned
+dependent on:
+
+- Is it equivalent to the remote?
+- Is it ahead of the remote?
+- Is it behind the remote?
+
+The latter 2 also have a number for exactly how many commits
+behind or ahead the local repository is."
+ (let* ((git-cmd "git status | grep 'Your branch is'")
+ (branch-status (split-string (shell-command-to-string git-cmd)))
+ (status (nth 3 branch-status))
+ (diff (cl-position "by" branch-status :test #'string=)))
+ (if (null diff)
+ (propertize "=" 'font-lock-face '(:foreground "green"))
+ (let ((n (nth (+ 1 diff) branch-status)))
+ (concat
+ (cond
+ ((string= status "ahead")
+ (propertize "→ " 'font-lock-face '(:foreground "dodger blue")))
+ ((string= status "behind")
+ (propertize "← " 'font-lock-face '(:foreground "orange red"))))
+ n)))))
+
+(defun +eshell-prompt/--git-change-status ()
+ "Returns a propertized string for the condition of the worktree in
+a repository. If there are no changes i.e. the worktree is clean
+then a green tick is returned, but if there are changes then the
+number of files affected are returned in red."
+ (let* ((git-cmd "git status -s")
+ (command-output (split-string git-cmd))
+ (changed-files (- (length command-output) 1)))
+ (if (= changed-files 0)
+ (propertize "✓" 'font-lock-face '(:foreground "green"))
+ (propertize (number-to-string changed-files) 'font-lock-face '(:foreground "red")))))
+
+(defun +eshell-prompt/--git-status ()
+ "Returns a completely formatted string of
+form (BRANCH-NAME<CHANGES>[REMOTE-STATUS])."
+ (let ((git-branch (shell-command-to-string "git brnach")))
+ (if (or (string= git-branch "")
+ (not (string= "*" (substring git-branch 0 1))))
+ ""
+ (format
+ "(%s<%s>[%s])"
+ (nth 2 (split-string git-branch "\n\\|\\*\\| "))
+ (+eshell-prompt/--git-change-status)
+ (+eshell-prompt/--git-remote-status)))))
+
+(defun +eshell-prompt/make-prompt ()
+ (let ((git (+eshell-prompt/--git-status)))
+ (mapconcat
+ (lambda (item)
+ (if (listp item)
+ (propertize (car item)
+ 'read-only t
+ 'font-lock-face (cdr item)
+ 'front-sticky '(font-lock-face read-only)
+ 'rear-nonsticky '(font-lock-face read-only))
+ item))
+ (list
+ "["
+ `(,(abbreviate-file-name (eshell/pwd)) :foreground "LimeGreen")
+ "]"
+ (if (string= git "")
+ ""
+ (concat "-" git ""))
+ "\n"
+ `(,(format-time-string "[%H:%M:%S]") :foreground "purple")
+ "\n"
+ (list "𝜆> " ':foreground (+eshell-prompt/--colour-on-last-command))))))
+
+
+(provide 'eshell-prompt)
+;;; eshell-prompt.el ends here