Skip to content

Latest commit

 

History

History
213 lines (191 loc) · 9.38 KB

emacs24.eshell.org

File metadata and controls

213 lines (191 loc) · 9.38 KB

Helper functions

(defun fish-path (path max-len)
  "Return a potentially trimmed-down version of the directory PATH, replacing
parent directories with their initial characters to try to get the character
length of PATH (sans directory slashes) down to MAX-LEN."
  (let* ((components (split-string (abbreviate-file-name path) "/"))
         (len (+ (1- (length components))
                 (cl-reduce '+ components :key 'length)))
         (str ""))
    (while (and (> len max-len)
                (cdr components))
      (setq str (concat str
                        (cond ((= 0 (length (car components))) "/")
                              ((= 1 (length (car components)))
                               (concat (car components) "/"))
                              (t
                               (if (string= "."
                                            (string (elt (car components) 0)))
                                   (concat (substring (car components) 0 2)
                                           "/")
                                 (string (elt (car components) 0) ?/)))))
            len (- len (1- (length (car components))))
            components (cdr components)))
    (concat str (cl-reduce (lambda (a b) (concat a "/" b)) components))))

;; (setq eshell-prompt-function
;;   (lambda ()
;;     (concat (fish-path (eshell/pwd) 3 ) (if (= (user-uid) 0) " # " " $ "))))

(defmacro with-face (str &rest properties)
  `(propertize ,str 'face (list ,@properties)))

(defun curr-dir-git-branch-string (pwd)
  "Returns current git branch as a string, or the empty string if
PWD is not in a git repo (or the git command is not found)."
  (interactive)
  (when (and (eshell-search-path "git")
             (locate-dominating-file pwd ".git"))
    (let ((git-output (shell-command-to-string (concat "git branch | grep '\\*' | sed -e 's/^\\* //'"))))
      (concat "["
              (if (> (length git-output) 0)
                  (substring git-output 0 -1)
                "(no branch)")
              "]"))))

(defun curr-dir-git-unstaged-changes-string (pwd)
  "Returns current unstaged changes to the git repo as a string, or the empty string if
PWD is not in a git repo (or the git command is not found)."
  (interactive)
  (when (and (eshell-search-path "git")
             (locate-dominating-file pwd ".git"))
    (let ((git-output (string-trim (shell-command-to-string
                                    (concat "git --no-pager diff --numstat | grep ^[0-9] | wc -l")))))
      (cond ((eq (string-to-number git-output) 1)
             "1 unstaged change")
            ((> (string-to-number git-output) 1)
             (format "%s unstaged changes" git-output))
            (t "")))))


(defun curr-dir-git-uncommitted-changes-string (pwd)
  "Returns current uncommitted changes in the index of the git repo as a string, or the empty string if
PWD is not in a git repo (or the git command is not found)."
  (interactive)
  (when (and (eshell-search-path "git")
             (locate-dominating-file pwd ".git"))
    (let ((git-output (string-trim (shell-command-to-string
                                    (concat "git --no-pager diff --cached --numstat | grep ^[0-9] | wc -l")))))
      (cond ((eq (string-to-number git-output) 1)
             "1 uncommitted change")
            ((> (string-to-number git-output) 1)
             (format "%s uncommitted changes" git-output))
            (t "")))))

(defun shk-eshell-prompt ()
  (let ((header-bg "#222")
        (shk-git-branch (curr-dir-git-branch-string (eshell/pwd)))
        (shk-git-unstaged-changes (curr-dir-git-unstaged-changes-string (eshell/pwd)))
        (shk-git-uncommitted-changes (curr-dir-git-uncommitted-changes-string (eshell/pwd))))
    (concat
     (if (boundp 'venv-current-name)
         (with-face (if (> (length venv-current-name) 0)
                        (concat "(" venv-current-name ") ") "") :foreground "#8592F2")
       "")
     (with-face (concat (eshell/pwd) " ") )
     (with-face (format-time-string "(%Y-%m-%d %H:%M) " (current-time)) :foreground "#AAA")
     (with-face
      (format "%s%s%s"
              (or shk-git-branch "")
              (if (> (length shk-git-unstaged-changes) 0)
                  (concat " - " shk-git-unstaged-changes) "")
              (if (> (length shk-git-uncommitted-changes) 0)
                  (concat " - " shk-git-uncommitted-changes) ""))

      :foreground "yellow")
     (with-face "\n" )
     (with-face user-login-name :foreground "blue")
     "@"
     (with-face (first (split-string (system-name) "\\.")) :foreground "green")
     (if (= (user-uid) 0)
         (with-face " #" :foreground "red")
       " $")
     " ")))


(defun eshell/emacs (&rest args)
  "Open a file in emacs. Some habits die hard."
  (if (null args)
      ;; If I just ran "emacs", I probably expect to be launching
      ;; Emacs, which is rather silly since I'm already in Emacs.
      ;; So just pretend to do what I ask.
      (bury-buffer)
    ;; We have to expand the file names or else naming a directory in an
    ;; argument causes later arguments to be looked for in that directory,
    ;; not the starting directory
    (mapc #'find-file
          (mapcar #'expand-file-name
                  (flatten-tree (reverse args))))))


;;(add-to-list 'ac-modes 'eshell-mode)

(defun ac-pcomplete ()
  ;; eshell uses `insert-and-inherit' to insert a \t if no completion
  ;; can be found, but this must not happen as auto-complete source
  (cl-flet ((insert-and-inherit (&rest args)))
    ;; this code is stolen from `pcomplete' in pcomplete.el
    (let* (tramp-mode ;; do not automatically complete remote stuff
           (pcomplete-stub)
           (pcomplete-show-list t) ;; inhibit patterns like * being deleted
           pcomplete-seen pcomplete-norm-func
           pcomplete-args pcomplete-last pcomplete-index
           (pcomplete-autolist pcomplete-autolist)
           (candidates (pcomplete-completions))
           (beg (pcomplete-begin))
           ;; note, buffer text and completion argument may be
           ;; different because the buffer text may bet transformed
           ;; before being completed (e.g. variables like $HOME may be
           ;; expanded)
           (buftext (buffer-substring beg (point)))
           (arg (nth pcomplete-index pcomplete-args)))
      ;; we auto-complete only if the stub is non-empty and matches
      ;; the end of the buffer text
      (when (and (not (zerop (length pcomplete-stub)))
                 (or (string= pcomplete-stub ; Emacs 23
                              (substring buftext
                                         (max 0
                                              (- (length buftext)
                                                 (length pcomplete-stub)))))
                     (string= pcomplete-stub ; Emacs 24
                              (substring arg
                                         (max 0
                                              (- (length arg)
                                                 (length pcomplete-stub)))))))
        ;; Collect all possible completions for the stub. Note that
        ;; `candidates` may be a function, that's why we use
        ;; `all-completions`.
        (let* ((cnds (all-completions pcomplete-stub candidates))
               (bnds (completion-boundaries pcomplete-stub
                                            candidates
                                            nil
                                            ""))
               (skip (- (length pcomplete-stub) (car bnds))))
          ;; We replace the stub at the beginning of each candidate by
          ;; the real buffer content.
          (mapcar #'(lambda (cand) (concat buftext (substring cand skip)))
                  cnds))))))

Eshell

;; Add keybindings
(use-package eshell
  :commands (eshell helm-info-eshell helm-eshell-history
                    eshell-insert-buffer-name)
  :config
  (setq eshell-cmpl-cycle-completions nil
        ;; eshell-banner-message "..."
        eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'"
        eshell-highlight-prompt nil
        eshell-history-file-name "~/.bash_history"
        eshell-history-size nil
        eshell-prompt-function 'shk-eshell-prompt
        eshell-review-quick-commands nil
        eshell-save-history-on-exit t
        eshell-smart-space-goes-to-end t
        eshell-visual-commands '("vi" "screen" "top" "less" "more"
        "lynx" "ncftp" "ssh" "pine" "tin" "trn" "elm" "htop")
        eshell-where-to-jump 'begin
        pcomplete-cycle-completions nil))

(defvar ac-source-pcomplete
  '((candidates . ac-pcomplete)))

(add-hook 'eshell-mode-hook
          #'(lambda ()
              (smartparens-strict-mode 1)
              (rainbow-delimiters-mode 1)
              (setenv "PAGER" "cat")
              (smartscan-mode -1)
              (setq ac-sources '(ac-source-pcomplete))
              (define-key eshell-mode-map [remap eshell-pcomplete] 'helm-esh-pcomplete)))

(add-hook 'eshell-after-prompt-hook
          #'(lambda ()
              (rename-buffer (concat "eshell: " default-directory) t)))