From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Andy Stewart Newsgroups: gmane.emacs.devel Subject: Integrate shell.el with multi-shell.el Date: Sat, 20 Dec 2008 10:21:00 +0800 Message-ID: <87r64360z7.fsf@debian.domain> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: ger.gmane.org 1229739685 24376 80.91.229.12 (20 Dec 2008 02:21:25 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 20 Dec 2008 02:21:25 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Dec 20 03:22:30 2008 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1LDrU5-0004LL-CZ for ged-emacs-devel@m.gmane.org; Sat, 20 Dec 2008 03:22:30 +0100 Original-Received: from localhost ([127.0.0.1]:42713 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LDrSs-0002dK-K4 for ged-emacs-devel@m.gmane.org; Fri, 19 Dec 2008 21:21:14 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LDrSn-0002dF-W3 for emacs-devel@gnu.org; Fri, 19 Dec 2008 21:21:10 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LDrSm-0002cs-J7 for emacs-devel@gnu.org; Fri, 19 Dec 2008 21:21:09 -0500 Original-Received: from [199.232.76.173] (port=49497 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LDrSm-0002co-Bc for emacs-devel@gnu.org; Fri, 19 Dec 2008 21:21:08 -0500 Original-Received: from ti-out-0910.google.com ([209.85.142.188]:27671) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LDrSl-0008EO-2B for emacs-devel@gnu.org; Fri, 19 Dec 2008 21:21:08 -0500 Original-Received: by ti-out-0910.google.com with SMTP id u5so797491tia.10 for ; Fri, 19 Dec 2008 18:21:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:subject:date :message-id:user-agent:mime-version:content-type; bh=LBTbax8EVho/hs7oovF4tZwTTlbLieq1A9Aw4pKwD7o=; b=sUYdfQhJqqt0b8Sxjb6H+0ULyct1suZLeR3PgpB3tlUFTu6xWHcyWu897EHm347e7i i7wiyGqbszbPQufOum567rGT2GU3n4CDiVzVRAS6Kq3tJVWngVI+AcEnl8uYbrWG0W8z 2u5K2FkYZmbFUfk7cZ5tqeYfNjgA1eLtjHg58= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:subject:date:message-id:user-agent:mime-version :content-type; b=qAnFq0QMz0creaX/R2T28OSs93C3a7HHaDlCbA503iEZ6QmM3P948cigPwQ1JQGrtV 22R7MpWICfISTigIHevLsup3XBLzsAABBkXuw+wlG72a/q/d2tqlSVOWC5kK5zowGLTy ne6LIh+agN5DP4eBMoyQE7dBHkR4io0v9CGGU= Original-Received: by 10.110.33.15 with SMTP id g15mr599127tig.42.1229739665509; Fri, 19 Dec 2008 18:21:05 -0800 (PST) Original-Received: from smtp.gmail.com ([222.212.143.192]) by mx.google.com with ESMTPS id i9sm10570112tid.39.2008.12.19.18.21.02 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 19 Dec 2008 18:21:04 -0800 (PST) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux) X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:107088 Archived-At: --=-=-= Hi all, shell.el is a great shell in Emacs. But it have some point not very convenient: ,---- | 1-> Have a good method to manage multiple shell-buffer create and | switch. | | 2-> Don't handle close buffer when type "exit" in shell-buffer. | | 3-> Don't interrupt the sub-process before kill shell-buffer forcible. | | 4-> Don't revert window configuration after completion window popup, | i mean shell.el just can rever window configuration after first | completion, it can't revert window configuration if you completion many times. `---- And multi-shell.el have those extension feature with shell.el I have attached newest version of shell.el I want integrate shell.el with multi-shell.el I have sign copyright of FSF. Any suggestions? Thanks -- Andy --=-=-= Content-Type: application/emacs-lisp Content-Disposition: attachment; filename=multi-shell.el Content-Transfer-Encoding: quoted-printable Content-Description: multi-shell.el ;;; multi-shell.el --- Multi-Shell Manager ;; Filename: multi-shell.el ;; Description: Multi-Shell Manager ;; Author: Andy Stewart lazycat.manatee@gmail.com ;; Maintainer: Andy Stewart lazycat.manatee@gmail.com ;; Copyright (C) 2008, Andy Stewart, all rights reserved. ;; Created: 2008-12-10 12:03:20 ;; Version: 0.2.1 ;; Last-Updated: 2008-12-17 17:48:34 ;; By: Andy Stewart ;; URL: ;; Keywords: multi-shell, shell ;; Compatibility: GNU Emacs 23.0.60.1 ;; ;; Features that might be requried by this library: ;; ;; `shell' `ansi-color' ;; ;;; This file is NOT part of GNU Emacs ;;; License ;; ;; 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 2, 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; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;;; Commentary: ;; ;; Multi-Shell Manager ;; ;; Here, have below command you can use: ;; ;; `multi-shell-new' create a new shell buffer. ;; `multi-shell-next' switch to next shell buffer. ;; `multi-shell-prev' switch to previous shell buffer. ;; `multi-shell-current-directory' create a new shell with current-di= rectory. ;; ;; choose your like key bind above command. ;) ;; ;; This package extension `shell-mode' with below features: ;; ;; 1 -> ;; Can create or navigation shell buffers quickly. ;; ;; 2 -> ;; Close buffer when type command `exit' in shell buffer. ;; ;; 3 -> ;; Interrupt sub-process before kill shell buffer forcible. ;; ;; 4 -> ;; Revert window configuration before completion window popup. ;; ;;; Installation: ;; ;; Put multi-shell.el to your load-path. ;; The load-path is usually ~/elisp/. ;; It's set in your ~/.emacs like this: ;; (setq load-path (append (list (expand-file "~/elisp")) load-path)) ;; ;; And the following to your ~/.emacs startup file. ;; ;; (require 'multi-shell) ;; ;; And setup program that `multi-term' will need: ;; ;; (setq multi-shell-command "/bin/bash") ;; ;; or setup like me "/bin/zsh" ;) ;; ;;; Customize: ;; ;; `multi-shell-command' default is nil, so when create new shell buffer, ;; send environment variable of `SHELL' (`ESHELL', `/bin/sh'). ;; ;; And you can set it to your like, like me: ;-) ;; ;; (setq multi-shell-command "/bin/zsh") ;; ;; `multi-shell-use-ansi-color' whether translate ANSI escape sequences int= o faces. ;; ;; `multi-shell-try-create' will create a new shell buffer when ;; haven't any shell buffers exist. ;; ;; `multi-shell-default-dir' default is `~/', only use when current buffer ;; is in non-exist directory. ;; ;; `multi-shell-bottom-window-height' is window height when use function ;; `multi-shell-current-directory'. ;; ;; `multi-shell-buffer-name' is a name of shell buffer. ;; ;; `multi-shell-revert-window-after-complete' is revert window layout after ;; `comint-dynamic-complete'. ;; ;; `multi-shell-revert-window-keystroke' is the keystroke to rever window l= ayout. ;; bind it with your like keystroke, default is `SPACE'. ;; ;; All above setup can customize by: ;; M-x customize-group RET multi-shell RET ;; ;;; Change log: ;; ;; 2008/12/17 ;; Fix the device bug of `multi-shell-revert-window-after-complete'. ;; ;; 2008/12/10 ;; Advice `comint-dynamic-complete' to rever window configuration. ;; ;; First realead. ;; ;;; Acknowledgements: ;; ;; ;; ;;; TODO ;; ;; ;; ;;; Require (require 'shell) (require 'ansi-color) ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Variable ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defvar multi-shell-window-configuration-before-complete nil "The window configuration will record before complete window popup first = time, and window configuration will revert when you type `multi-shell-revkert-win= dow-keystroke' next time.") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Advice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defadvice comint-dynamic-complete (around record-window-configuration-befo= re-popup-window) "This advice record window configuration before popup complete window. And just record when variable `multi-shell-window-configuration-before-comp= lete' is nil." (if (and (boundp 'multi-shell-window-configuration-before-complete) multi-shell-window-configuration-before-complete) ad-do-it (let (window-configuration-before-do window-configuration-after-do) (setq window-configuration-before-do (current-window-configuration)) ad-do-it (setq window-configuration-after-do (current-window-configuration)) (unless (equal window-configuration-before-do window-configuration-af= ter-do) (setq multi-shell-window-configuration-before-complete window-confi= guration-before-do))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Customize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defgroup multi-shell nil "Multi-Shell Manager" :group 'shell) (defcustom multi-shell-command nil "The command that multi-shell will use. If nil, will try to get value of environment varialbe `SHELL' or `ESHELL'." :type 'string :group 'multi-shell) (defcustom multi-shell-use-ansi-color t "Whether translate ANSI escape sequences into faces. And default is t." :type 'boolean :group 'multi-shell) (defcustom multi-shell-try-create t "Try to create a new shell buffer when switch. When use `multi-shell-next' or `multi-shell-prev' to switch shell buffer, try to create a new shell buffer if haven't any shell buffers exist." :type 'boolean :group 'multi-shell) (defcustom multi-shell-default-dir "~/" "The default directory for create shell buffer, when current local directory is no exist." :type 'string :group 'multi-shell) (defcustom multi-shell-buffer-name "multi-shell" "The name of shell buffer." :type 'string :group 'multi-shell) (defcustom multi-shell-bottom-window-height -13 "The height of bottom window create." :type 'integer :group 'multi-shell) (defcustom multi-shell-revert-window-keystroke "SPC" "The keystroke that revert window after `comint-dynamic-complete'. Default is `SPACE." :type 'string :group 'multi-shell) (defcustom multi-shell-revert-window-after-complete t "Revert window laytou after `comint-dynamic-complete'. Default, type `TAB' (comint-dynamic-complete) in `shell-mode', will popup a window complete, but when you type TAB many times, `shell-mode' can't revert window layout before you type TAB. So it's too bad use `comint-dynamic-complete' in complex window layout, it can break your window layout and can't revert. If you type `TAB' in `multi-shell' buffer, and window layout will revert when you type keystroke `multi-shell-revert-window-keystroke' n= ext time." :type 'boolean :set (lambda (symbol value) (set symbol value) (if value (progn (define-key shell-mode-map (read-kbd-macro multi-shell-revert-window-keystroke) 'multi-shell-insert-or-revert-window-layout) (ad-enable-advice 'comint-dynamic-complete 'around 'record-w= indow-configuration-before-popup-window)) (define-key shell-mode-map (read-kbd-macro multi-shell-revert-window-keystroke) 'self-insert-command) (ad-disable-advice 'comint-dynamic-complete 'around 'record-wind= ow-configuration-before-popup-windowo)) (ad-activate 'comint-dynamic-complete)) :group 'multi-shell) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Code ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun multi-shell-new () "Create a new multi-shell buffer." (interactive) (let* ((shell-buffer (multi-shell-get-buffer))) (set-buffer shell-buffer) ;; Add `ansi-color' to shell-mode (if multi-shell-use-ansi-color (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on) (remove-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)) ;; Load mode (save-window-excursion (shell (buffer-name shell-buffer))) ;; Handle shell buffer close (multi-shell-handle-close) ;; Handle revert window layout after complete (multi-shell-handle-revert-window-after-complete) ;; Switch shell buffer (switch-to-buffer shell-buffer) ;; Add hook to be sure `shell' interrupt subjob before buffer killed (add-hook 'kill-buffer-hook 'multi-shell-handle-kill-buffer) )) (defun multi-shell-get-buffer () "Get shell buffer." (let* ((shell-list-length (length (multi-shell-list))) ;get leng= th of shell list (index (if shell-list-length (1+ shell-list-length) 1))) ;setup ne= w shell index (with-temp-buffer ;; switch to current local directory, ;; if in-existence, switch to `multi-shell-default-dir'. (cd (or default-directory (expand-file-name multi-shell-default-dir))) ;; adjust value N when max index of shell buffer is less than length = of shell list (while (buffer-live-p (get-buffer (format "*%s<%s>*" multi-shell-buff= er-name index))) (incf index)) ;; Set explicit shell program (setq explicit-shell-file-name (or multi-shell-command (getenv "SHELL") (getenv "ESHELL") "/bin/sh")) ;; Return buffer (get-buffer-create (format "*%s<%s>*" multi-shell-buffer-name index)) ))) (defun multi-shell-handle-close () "This function for close current shell buffer. When `exit' from shell buffer." (when (ignore-errors (get-buffer-process (current-buffer))) (set-process-sentinel (get-buffer-process (current-buffer)) (lambda (proc change) (when (string-match "\\(finished\\|exited\\)" c= hange) (kill-buffer (process-buffer proc))))))) (defun multi-shell-handle-kill-buffer () "Function that hook `kill-buffer-hook'." ;; Interrupt the current subjob ;; when have alive process with current shell buffer (when (and (eq major-mode 'shell-mode) (comint-check-proc (current-buffer))) (comint-interrupt-subjob))) (defun multi-shell-handle-revert-window-after-complete () "Handle window configuration after complete." (if multi-shell-revert-window-after-complete (progn (define-key shell-mode-map (read-kbd-macro multi-shell-revert-window-keystroke) 'multi-shell-insert-or-revert-window-layout) (ad-enable-advice 'comint-dynamic-complete 'around 'record-window-c= onfiguration-before-popup-window)) (define-key shell-mode-map (read-kbd-macro multi-shell-revert-window-keystroke) 'self-insert-command) (ad-disable-advice 'comint-dynamic-complete 'around 'record-window-conf= iguration-before-popup-windowo)) (ad-activate 'comint-dynamic-complete)) (defun multi-shell-insert-or-revert-window-layout (&optional arg) "Handle insert self or window configuration revert." (interactive "P") (if multi-shell-window-configuration-before-complete (progn (set-window-configuration multi-shell-window-configuration-before-c= omplete) (setq multi-shell-window-configuration-before-complete nil) (message "Have revert window layout.")) (self-insert-command (or arg 1)))) (defun multi-shell-list () "The shell buffers presently active." ;; Autload command `remove-if-not'. (autoload 'remove-if-not "cl-seq") (sort (remove-if-not (lambda (b) (string-match (concat "^\*" multi-shell-buffer-name) (buffer-name b))) (buffer-list)) (lambda (a b) (< (string-to-number (cadr (split-string (buffer-name a) "[<>]"))) (string-to-number (cadr (split-string (buffer-name b) "[<>]"))))))) (defun multi-shell-switch (direction offset) "Switch to shell buffer. If DIRECTION is `NEXT', switch to next shell buffer. if DIRECTION is `PREVIOUS', switch to previous shell buffer. Default OFFSET is 1. If option `multi-shell-try-create' is non-nil, will create a new shell buff= er if have any shell buffer exist." (let (shells this-buffer) (setq shells (multi-shell-list)) (if (consp shells) (progn (setf (cdr (last shells)) shells) (setq this-buffer (position (current-buffer) (multi-shell-list))) (if this-buffer (if (eql direction 'NEXT) (switch-to-buffer (nth (+ this-buffer offset) shells)) (switch-to-buffer (nth (+ (- (length (multi-shell-list)) of= fset) this-buffer) shells))) (switch-to-buffer (car shells)))) (if multi-shell-try-create (progn (multi-shell-new) (message "Create a new `multi-shell' buffer.")) (message "Haven't any `multi-shell' buffer exist."))))) (defun multi-shell-next (&optional offset) "Switch to next shell buffer." (interactive "P") (multi-shell-switch 'NEXT (or offset 1))) (defun multi-shell-prev (&optional offset) "Switch to previous shell buffer." (interactive "P") (multi-shell-switch 'PREVIOUS (or offset 1))) (defun multi-shell-current-directory () "Open shell that start at current directory." (interactive) (split-window-vertically multi-shell-bottom-window-height) (other-window 1) (multi-shell-new)) (provide 'multi-shell) ;;; multi-shell.el ends here --=-=-=--