;;; ecb-eshell.el --- eshell integration for the ECB. ;; $Id: ecb-eshell.el,v 1.37 2002/03/19 00:44:24 burtonator Exp $ ;; Copyright (C) 2000-2003 Free Software Foundation, Inc. ;; Copyright (C) 2000-2003 Kevin A. Burton (burton@openprivacy.org) ;; Author: Kevin A. Burton (burton@openprivacy.org) ;; Maintainer: Kevin A. Burton (burton@openprivacy.org) ;; Location: http://relativity.yi.org ;; Keywords: ;; Version: 1.0.0 ;; This file is [not yet] part of GNU Emacs. ;; 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 of the License, or 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, write to the Free Software Foundation, Inc., 59 Temple ;; Place - Suite 330, Boston, MA 02111-1307, USA. ;;; Commentary: ;; This package provides eshell integration for the ECB. This basically allows ;; you to jump to the eshell in the compilation window, synch up the current ;; eshell with the current ECB buffer and run commands without getting in the ;; way. ;; ;; It provides the following features: ;; ;; - ability to jump to the eshell buffer within the compilation window ( C-.e ) ;; If the eshell isn't running it will be started ;; ;; - expands the compilation window when you run commands. So for example it ;; allows you to view the eshell in minimized mode and then when you run 'ls' ;; the window automatically expands. ;; ;; - Sychronizes the current directory of the eshell with the current buffer ;; with each every ECB buffer. ;; ;; - Provides smart window layout of the eshell buffer. This makes sure that ;; the eshell is taking up the exact amount of space and that nothing is ;; hidden. ;; ;; The goal is to make it easy to jump to a command prompt to run OS level ;; commands. ;; ;; If you enjoy this software, please consider a donation to the EFF ;; (http://www.eff.org) ;;; History: ;; - Mon Feb 04 2002 10:44 PM (burton@openprivacy.org): BUG: I think at certain ;; conditions, we might be able to get the eshell window to expand after we ;; automatically change directories. I think this has to be: ;; ;; - Mon Feb 04 2002 10:43 PM (burton@openprivacy.org): BUGFIX: make sure the ;; eshell is not buffer-read-only. This is manifested by desktop.el for some ;; reason. ;; ;; - Tue Jan 29 2002 03:33 AM (burton@openprivacy.org): Include the ability to ;; startup the eshell when the ECB is started. ;; ;; ;; - Tue Jan 29 2002 03:31 AM (burton@openprivacy.org): RFE: make the ;; auto-enlargement on command execution optional, true by default. ;; ;; - Tue Jan 22 2002 11:38 PM (burton@openprivacy.org): enable customization ;; ;; - Tue Dec 25 2001 07:54 PM (burton@openprivacy.org): We now enlarge the ecb ;; window when you go to it. ;; ;; - Sat Dec 15 2001 01:50 AM (burton@openprivacy.org): We are not being much ;; smarter about saving selected windows. ;; ;; - Fri Dec 14 2001 05:57 PM (burton@openprivacy.org): fixed a bug which caused ;; ;; - Fri Dec 14 2001 04:48 PM (burton@openprivacy.org): only run eshell/cd if ;; the current directory is different than the eshell/pwd (this is a performance ;; issue and needs to be added in ecb-eshell-current-buffer-sync ;; ;; - we can't do this. eshell/pwd does't return a string. Instead we should ;; change to the eshell-buffer and see what the directory default-directory ;; is there. ;; ;; - Fri Dec 14 2001 03:24 PM (burton@openprivacy.org): use ;; eshell-pre-command-hook to increase the size of the window if we are in an ;; ECB layout (and the ecb is activated)... ;; ;; - Sun Nov 18 2001 07:20 PM (burton@openprivacy.org): putting the cursor one ;; line from the bottom of the window. ;;; Design: ;; ;; Synching the current buffer with the eshell is done two ways. If the buffer ;; is visible in a window, we always resynch. If it is not visible then ;; ecb-eshell-goto-eshell will synch up when the user goes to the eshell buffer. ;;; TODO: ;; ;; - Right now ecb-eshell doesn't work with dired. Why? Try to setup a hook ;; and an ecb-eshell-dired-buffer-sync function that will take care of this. ;; ;; - BUG: when we exit the eshell, we enlarge the compilation buffer.... there ;; is not needed since the buffer is about to exit. ;; ;; - this might be fixed by using an eshell post command hook. ;; ;; - RFE: could we possibly find a way to avoid window enlargement if we launch ;; a background process like 'xterm &'. This would require determining what the ;; command is and then making sure it is acceptable. ;; ;; - BUG: when ecb-eshell-enlarge-when-selecting is nil we need to recenter. If ;; we don't we just end up with the point in the middle of the eshell. ;; ;; - BUG: enable just-in-time current-buffer-sync... only execute if the current ;; buffer's directlry is not equal to the ecb directory. ;;; Code: (defgroup ecb-eshell nil "Settings for eshell integration within the ECB." :group 'ecb :prefix "ecb-eshell-") (defcustom ecb-eshell-enlarge-when-selecting t "*Enlarge the `ecb-eshell-buffer-name' buffer if it has been selected." :group 'ecb-eshell :type 'boolean) (defcustom ecb-eshell-enlarge-when-starting t "*When starting the eshell, enlarge the buffer if non-nil." :group 'ecb-eshell :type 'boolean) (defcustom ecb-eshell-auto-activate nil "*Startup the eshell when the ECB is activated." :group 'ecb-eshell :type 'boolean) (defvar ecb-eshell-buffer-name "*eshell*" "Buffer name for the eshell. We define it here so that we don't need to have the eshell loaded for ecb-eshell to function properly.") (defun ecb-eshell-current-buffer-sync() "Synchronize the eshell with the current buffer. This is only done if the eshell is currently visible." (interactive) ;;only do this if the user is looking at the eshell buffer (if (ecb-eshell-running-p) (let((source-buffer-directory nil) (ecb-buffer-directory nil) (window nil)) ;;make sure we are clean. (ecb-eshell-cleanse) ;;get copies of the current source directory. (setq source-buffer-directory default-directory) (setq window (get-buffer-window ecb-eshell-buffer-name)) (save-excursion (set-buffer (get-buffer-create ecb-eshell-buffer-name)) (setq buffer-read-only nil) (setq ecb-buffer-directory default-directory)) ;;at this point source-buffer-directory is a snapshot of the source ;;buffer window and default directory is the directory in the eshell ;;window (when (and window (window-live-p window) (not (string-equal source-buffer-directory ecb-buffer-directory))) (save-excursion (set-buffer ecb-eshell-buffer-name) ;;change the directory without showing the cd command (eshell/cd source-buffer-directory) ;;execute the command (save-selected-window (select-window window) (eshell-send-input))) (ecb-eshell-recenter))))) (defun ecb-eshell-recenter() "Recenter the eshell window so that the prompt is at the end of the buffer." (interactive) (save-selected-window (let(window) (setq window (get-buffer-window ecb-eshell-buffer-name)) (when (and (ecb-eshell-running-p) window (window-live-p window) (equal window ecb-compile-window)) (select-window window) ;;this needs to be present under GNU Emacs or recenter will fail. (end-of-buffer) (recenter -2))))) (defun ecb-eshell-running-p() "Return true if eshell is currently running." (and (boundp 'ecb-eshell-buffer-name) ecb-eshell-buffer-name (get-buffer ecb-eshell-buffer-name))) (defun ecb-eshell-goto-eshell() "Go ot the eshell buffer" (interactive) ;;first... make sure that we change the compilation window to the eshell ;;buffer. (if (ecb-eshell-running-p) (when (ecb-compile-window-live-p 'display-msg) (set-window-buffer ecb-compile-window ecb-eshell-buffer-name) (select-window ecb-compile-window) (if ecb-eshell-enlarge-when-selecting (ecb-eshell-enlarge) ;;else just recenter (ecb-eshell-recenter))) ;;we auto start the eshell here? I think so.. (ecb-eshell-activate) (when ecb-eshell-enlarge-when-starting (ecb-eshell-enlarge)))) (defun ecb-eshell-activate() "Startup the eshell in the compile window." (when (ecb-compile-window-live-p 'display-msg) (select-window ecb-compile-window) (eshell))) (defun ecb-eshell-enlarge() "Enlarge the eshell so more information is visible. This is usually done so that the eshell has more screen space after we execute a command. " (interactive) (let(window) (setq window (get-buffer-window ecb-eshell-buffer-name)) (when (and (ecb-eshell-running-p) (window-live-p window) (equal (selected-window) ecb-compile-window) ecb-minor-mode) ;;is there a better way to do this? It seems that there should be a way ;;to have emacs split or expand a window by 50% like it is done in a lot ;;of other places (display-buffer, etc) (ecb-enlarge-window window))) (ecb-eshell-recenter)) (defun ecb-eshell-cleanse() "If the user has entered text in the eshell, we need to clean it. If we don't do this we could end up executing a strange command resulting in a 'command not found'." (save-excursion (set-buffer ecb-eshell-buffer-name) (end-of-buffer) (eshell-bol) (delete-region (point) (point-at-eol)))) (defun ecb-eshell-auto-activate-hook() "Activate the eshell when ECB is activated. See `ecb-eshell-auto-activate'." (when ecb-eshell-auto-activate (ecb-eshell-activate))) (add-hook 'ecb-activate-hook 'ecb-eshell-auto-activate-hook) (add-hook 'ecb-current-buffer-sync-hook 'ecb-eshell-current-buffer-sync) (add-hook 'ecb-redraw-layout-hook 'ecb-eshell-recenter) (add-hook 'eshell-pre-command-hook 'ecb-eshell-enlarge) (provide 'ecb-eshell) ;;; ecb-eshell.el ends here