summaryrefslogtreecommitdiff
path: root/helm-shell.el
diff options
context:
space:
mode:
authorPierre Neidhardt <mail@ambrevar.xyz>2019-02-04 20:28:04 +0100
committerPierre Neidhardt <mail@ambrevar.xyz>2019-02-04 20:28:04 +0100
commit16c7f1c379d3cf0eae3335c9db677d3e9926f795 (patch)
tree2e14cdd39e0ef57cd4927d49d6fba70c7e461147 /helm-shell.el
parentaa4600e0db01b4812c8b89c1fa940a15caefddce (diff)
helm-shell: Init M-x shell prompt navigation
This is mostly a copy-paste from helm-eshell, with subtle differences.
Diffstat (limited to 'helm-shell.el')
-rw-r--r--helm-shell.el169
1 files changed, 169 insertions, 0 deletions
diff --git a/helm-shell.el b/helm-shell.el
new file mode 100644
index 00000000..1b6326ab
--- /dev/null
+++ b/helm-shell.el
@@ -0,0 +1,169 @@
+;;; helm-shell.el --- Shell prompt navigation for helm. -*- lexical-binding: t -*-
+
+;; Copyright (C) 2019 Pierre Neidhardt <mail@ambrevar.xyz>
+
+;; 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, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Enable like this in .emacs:
+;; (add-hook 'shell-mode-hook
+;; (lambda ()
+;; (define-key shell-mode-map (kbd "M-s f") 'helm-shell-prompts-all)))
+
+;;; Code:
+(require 'cl-lib)
+(require 'helm)
+(require 'helm-lib)
+(require 'helm-help)
+(require 'helm-elisp)
+
+;;; Shell prompts
+;;
+(defface helm-shell-prompts-promptidx
+ '((t (:foreground "cyan")))
+ "Face used to highlight Shell prompt index."
+ :group 'helm-shell-faces)
+
+(defface helm-shell-prompts-buffer-name
+ '((t (:foreground "green")))
+ "Face used to highlight Shell buffer name."
+ :group 'helm-shell-faces)
+
+(defcustom helm-shell-prompts-promptidx-p t
+ "Show prompt number."
+ :group 'helm-shell
+ :type 'boolean)
+
+(defvar helm-shell-prompts-keymap
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map helm-map)
+ (define-key map (kbd "C-c o") 'helm-shell-prompts-other-window)
+ (define-key map (kbd "C-c C-o") 'helm-shell-prompts-other-frame)
+ map)
+ "Keymap for `helm-shell-prompt-all'.")
+
+(defvar shell-prompt-pattern)
+
+(defun helm-shell-prompts-list (&optional buffer)
+ "List the prompts in Shell BUFFER.
+
+Return a list of (\"prompt\" (point) (buffer-name) prompt-index))
+e.g. (\"ls\" 162 \"*shell*\" 3).
+If BUFFER is nil, use current buffer."
+ (with-current-buffer (or buffer (current-buffer))
+ (when (eq major-mode 'shell-mode)
+ (save-excursion
+ (goto-char (point-min))
+ (let (result (count 1))
+ (save-mark-and-excursion
+ (helm-awhile (and (not (eobp)) (comint-next-prompt 1))
+ (push (list (buffer-substring-no-properties
+ it (point-at-eol))
+ it (buffer-name) count)
+ result)
+ (setq count (1+ count))))
+ (nreverse result))))))
+
+(defun helm-shell-prompts-list-all ()
+ "List the prompts of all Shell buffers.
+See `helm-shell-prompts-list'."
+ (cl-loop for b in (buffer-list)
+ append (helm-shell-prompts-list b)))
+
+(defun helm-shell-prompts-transformer (candidates &optional all)
+ ;; ("ls" 162 "*shell*" 3) => ("*shell*:3:ls" . ("ls" 162 "*shell*" 3))
+ (cl-loop for (prt pos buf id) in candidates
+ collect `(,(concat
+ (when all
+ (concat (propertize
+ buf
+ 'face 'helm-shell-prompts-buffer-name)
+ ":"))
+ (when helm-shell-prompts-promptidx-p
+ (concat (propertize
+ (number-to-string id)
+ 'face 'helm-shell-prompts-promptidx)
+ ":"))
+ prt)
+ . ,(list prt pos buf id))))
+
+(defun helm-shell-prompts-all-transformer (candidates)
+ (helm-shell-prompts-transformer candidates t))
+
+(cl-defun helm-shell-prompts-goto (candidate &optional (action 'switch-to-buffer))
+ ;; Candidate format: ("ls" 162 "*shell*" 3)
+ (let ((buf (nth 2 candidate)))
+ (unless (and (string= (buffer-name) buf)
+ (eq action 'switch-to-buffer))
+ (funcall action buf))
+ (goto-char (nth 1 candidate))
+ (recenter)))
+
+(defun helm-shell-prompts-goto-other-window (candidate)
+ (helm-shell-prompts-goto candidate 'switch-to-buffer-other-window))
+
+(defun helm-shell-prompts-goto-other-frame (candidate)
+ (helm-shell-prompts-goto candidate 'switch-to-buffer-other-frame))
+
+(defun helm-shell-prompts-other-window ()
+ (interactive)
+ (with-helm-alive-p
+ (helm-exit-and-execute-action 'helm-shell-prompts-goto-other-window)))
+(put 'helm-shell-prompts-other-window 'helm-only t)
+
+(defun helm-shell-prompts-other-frame ()
+ (interactive)
+ (with-helm-alive-p
+ (helm-exit-and-execute-action 'helm-shell-prompts-goto-other-frame)))
+(put 'helm-shell-prompts-other-frame 'helm-only t)
+
+;;;###autoload
+(defun helm-shell-prompts ()
+ "Pre-configured `helm' to browse the prompts of the current Shell."
+ (interactive)
+ (if (eq major-mode 'shell-mode)
+ (helm :sources
+ (helm-build-sync-source "Shell prompts"
+ :candidates (helm-shell-prompts-list)
+ :candidate-transformer 'helm-shell-prompts-transformer
+ :action '(("Go to prompt" . helm-shell-prompts-goto)))
+ :buffer "*helm Shell prompts*")
+ (message "Current buffer is not an Shell buffer")))
+
+;;;###autoload
+(defun helm-shell-prompts-all ()
+ "Pre-configured `helm' to browse the prompts of all Shell sessions."
+ (interactive)
+ (helm :sources
+ (helm-build-sync-source "All Shell prompts"
+ :candidates (helm-shell-prompts-list-all)
+ :candidate-transformer 'helm-shell-prompts-all-transformer
+ :action '(("Go to prompt" . helm-shell-prompts-goto)
+ ("Go to prompt in other window `C-c o`" .
+ helm-shell-prompts-goto-other-window)
+ ("Go to prompt in other frame `C-c C-o`" .
+ helm-shell-prompts-goto-other-frame))
+ :keymap helm-shell-prompts-keymap)
+ :buffer "*helm Shell all prompts*"))
+
+(provide 'helm-shell)
+
+;; Local Variables:
+;; byte-compile-warnings: (not obsolete)
+;; coding: utf-8
+;; indent-tabs-mode: nil
+;; End:
+
+;;; helm-shell ends here