Source

ecb / ecb-eshell.el

scop aea8b4f 

berndl 6115922 



scop aea8b4f 
berndl 6115922 






scop aea8b4f 


berndl 6115922 

scop aea8b4f 



berndl 6115922 
scop aea8b4f 
berndl 6115922 



scop aea8b4f 



berndl 6115922 
scop aea8b4f 











berndl 6115922 

scop aea8b4f 












berndl 6115922 

scop aea8b4f 


berndl 6115922 






scop aea8b4f 



berndl 94dceff 











scop aea8b4f 




berndl 6115922 










scop aea8b4f 



berndl 6115922 

berndl 94dceff 
scop aea8b4f 


berndl 94dceff 
berndl 6115922 


berndl 94dceff 






berndl 6115922 



berndl 94dceff 
scop aea8b4f 
berndl 6115922 





scop aea8b4f 
berndl 6115922 



















berndl 5315697 
berndl 6115922 












berndl 5315697 
berndl 6115922 

scop aea8b4f 
berndl 6115922 





scop aea8b4f 
berndl 6115922 



scop aea8b4f 
berndl 6115922 
scop aea8b4f 
berndl 6115922 


scop aea8b4f 
berndl 6115922 

scop aea8b4f 
berndl 94dceff 






berndl 6115922 

scop aea8b4f 
berndl 6115922 



scop aea8b4f 
berndl 6115922 

berndl 94dceff 

berndl 6115922 


berndl 94dceff 
berndl 6115922 




scop aea8b4f 

berndl 6115922 



scop aea8b4f 
berndl 6115922 




































scop aea8b4f 
berndl 6115922 





































































berndl 94dceff 
berndl 6115922 

berndl 94dceff 
scop aea8b4f 

berndl 94dceff 

berndl 6115922 
scop aea8b4f 
berndl 94dceff 




scop aea8b4f 


berndl 94dceff 
scop aea8b4f 
;;; ecb-eshell.el --- eshell integration for the ECB.

;; Copyright (C) 2000 - 2003 Jesper Nordenberg,
;;                           Klaus Berndl,
;;                           Kevin A. Burton,
;;                           Free Software Foundation, Inc.

;; Author: Jesper Nordenberg <mayhem@home.se>
;;         Klaus Berndl <klaus.berndl@sdm.de>
;;         Kevin A. Burton <burton@openprivacy.org>
;; Maintainer: Klaus Berndl <klaus.berndl@sdm.de>
;;             Kevin A. Burton <burton@openprivacy.org>
;; Keywords: browser, code, programming, tools
;; Created: 2001

;; 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
;; GNU Emacs; see the file COPYING.  If not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;; $Id$

;;; Commentary:

;; This package provides eshell integration for the ECB.  This basically allows
;; you to jump to the eshell in the compilation window, sync 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.
;;
;; - Synchronizes the current directory of the eshell with the current buffer
;;   of the either the edit-window or the ecb-windows.
;;
;; - 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:

;; For the ChangeLog of this file see the CVS-repository. For a complete
;; history of the ECB-package see the file NEWS.

;;; Design:
;;
;; Syncing the current buffer with the eshell is done two ways.  If the buffer
;; is visible in a window, we always resync.  If it is not visible then
;; ecb-eshell-goto-eshell will sync up when the user goes to the eshell
;; buffer.
;;
;; Integrating of eshell is mostly done by advicing the command `eshell' which
;; uses the mechanism of the display-buffer (adviced version).


;;; Code:

(eval-when-compile
  (require 'silentcomp))

(require 'ecb-util)
(require 'ecb-compilation)

(silentcomp-defvar eshell-buffer-name)
(silentcomp-defun eshell)
(silentcomp-defun eshell/cd)
(silentcomp-defun eshell-send-input)
(silentcomp-defun eshell-bol)

(defgroup ecb-eshell nil
  "Settings for eshell integration within the ECB."
  :group 'ecb
  :prefix "ecb-eshell-")

(defcustom ecb-eshell-enlarge-when-eshell t
  "*Enlarge the compile-window if it is selected by `eshell'.
This takes only effect if the command `eshell' is called!"
  :group 'ecb-eshell
  :type 'boolean)

(defcustom ecb-eshell-fit-window-to-command-output t
  "*Fit the compile-window after an eshell-command to the output.
This is done by the function `ecb-eshell-fit-window-to-output' which is added
to `eshell-post-command-hook' ie. which is running autom. after each
eshell-command."
  :group 'ecb-eshell
  :type 'boolean)

(defcustom ecb-eshell-auto-activate nil
  "*Startup the eshell and display it in the compile-window.
If current layout does not display a compile-window \(see
`ecb-compile-window-height') then nothing is done."
  :group 'ecb-eshell
  :type 'boolean)

(defcustom ecb-eshell-synchronize t
  "*Synchronize eshell with the default-directory of current source-buffer.
The synchronization is done by `ecb-eshell-current-buffer-sync' which can be
called interactively but normally it is called autom. by the
`ecb-current-buffer-sync-hook'."
  :group 'ecb-eshell
  :type 'boolean)

(defvar ecb-eshell-pre-command-point nil
  "Point in the buffer we are at before we executed a command.")

(defvar ecb-eshell-buffer-list nil
  "List of eshell-buffers created until now.
Background: `eshell' creates new eshell-buffers with `generate-new-buffer' if
called with an prefix arg!")


(defconst ecb-eshell-adviced-functions '((eshell . around))
  "These functions of eshell are adviced if ehsell is active during ECB is
active. Each element of the list is a cons-cell where the car is the
function-symbol and the cdr the advice-class \(before, around or after). If a
function should be adviced with more than one class \(e.g. with a before and
an after-advice) then for every class a cons must be added to this list.")

(defadvice eshell (around ecb)
  "Ensure that ehsell is running in the ECB-compile-window if any."
  ;; we tell ECB to handle the eshell-buffers as compilation-buffers so they
  ;; will be displayed in the compile-window (if any). We must add this as
  ;; regexp because ehsell can open new eshell-buffers with a name created by
  ;; generate-new-buffer-name! This approach is not completely save because if
  ;; a users changes `eshell-buffer-name' during acivated ECB we get not
  ;; informed about this and maybe we can handle the new buffer-name of eshell
  ;; not as compilation-buffer. But we have no other chance: Adding the return
  ;; value of `eshell' in the advice to `ecb-compilation-buffer-names-internal'
  ;; does not help because `eshell' uses the new buffer-name already for
  ;; `pop-to-buffer'. So an after advice would add the new buffer-name to late
  ;; and a before-advice does not know the new-buffer name. The only way would
  ;; be to reimplement the whole `eshell'-code in an around advice but this is
  ;; not related to the benefit. IMO is it very improbably that a user changes
  ;; `eshell-buffer-name' at all...
  (let ((new-elem (cons (concat ".*"
                                (regexp-quote eshell-buffer-name)
                                ".*")
                        t)))
    (if ecb-compile-window-height
        (progn
          (add-to-list 'ecb-compilation-buffer-names-internal new-elem)
          (add-to-list 'ecb-compilation-major-modes-internal 'eshell-mode))
      ;; if we have no durable compile-window we do not handle eshell autom.
      ;; as compilation-buffer. If the user wants this then he has to modify
      ;; `ecb-compilation-buffer-names' and/or `ecb-compilation-major-modes'.
      ;; Therefore we remove the new-elem here from the internal lists.
      (setq ecb-compilation-buffer-names-internal
            (delete new-elem ecb-compilation-buffer-names-internal))
      (setq ecb-compilation-major-modes-internal
            (delete 'eshell-mode ecb-compilation-major-modes-internal))))
  
  ;; maybe we have to auto toggle our compile-window if temporally hidden
  (when (equal 'hidden (ecb-compile-window-state))
    (ecb-layout-debug-error "eshell around-advice: comp-win will be toggled.")
    (ecb-toggle-compile-window 1))

  ;; some hooks
  (add-hook 'ecb-current-buffer-sync-hook 'ecb-eshell-current-buffer-sync)  
  (add-hook 'eshell-post-command-hook 'ecb-eshell-recenter)
  (add-hook 'eshell-post-command-hook 'ecb-eshell-fit-window-to-output)
  (add-hook 'eshell-pre-command-hook 'ecb-eshell-precommand-hook)
  (add-hook 'window-size-change-functions 'ecb-eshell-window-size-change)

  ;; run `eshell' --------------------------------------------
  (ecb-eshell-save-buffer-history
   ad-do-it)
  ;; ---------------------------------------------------------

  ;; some post processing

  ;; add the buffer of the buffer used/created by `eshell' to
  ;; `ecb-eshell-buffer-list'
  (add-to-list 'ecb-eshell-buffer-list ad-return-value)

  (when ecb-eshell-enlarge-when-eshell
    (ecb-toggle-compile-window-height 1))

  ;;always recenter because if the point is at the top of the eshell buffer
  ;;and we switch to it the user is not going to be able to type a command
  ;;right away.
  (ecb-eshell-recenter)  
  
  ;;sync to the current buffer
  (ecb-eshell-current-buffer-sync))
  
  

(defun ecb-eshell-activate-integration ()
  "Does all necessary to activate the eshell-integration. But this doesn not
load or activate eshell - it just prepares ECB to work perfectly with eshell."
  (ecb-enable-advices ecb-eshell-adviced-functions))

(defun ecb-eshell-deactivate-integration ()
  (ecb-disable-advices ecb-eshell-adviced-functions)
  (remove-hook 'ecb-current-buffer-sync-hook 'ecb-eshell-current-buffer-sync)
  (remove-hook 'eshell-post-command-hook 'ecb-eshell-recenter)
  (remove-hook 'eshell-post-command-hook 'ecb-eshell-fit-window-to-output)
  (remove-hook 'eshell-pre-command-hook 'ecb-eshell-precommand-hook)
  (remove-hook 'window-size-change-functions 'ecb-eshell-window-size-change))

(defun ecb-eshell-current-buffer-sync()
  "Synchronize the eshell with the directory of current source-buffer.
This is only done if the eshell is currently visible in the compile-window of
ECB and if either this function is called interactively or
`ecb-eshell-synchronize' is not nil."
  (interactive)

  (when (and (equal (selected-frame) ecb-frame)
             (or ecb-eshell-synchronize (interactive-p))
             (ecb-compile-window-live-p)
             (not (ecb-point-in-compile-window)))

    (let* ((my-eshell-buffer
            ;; nil or a living eshell-buffer in the ecb-compile-window
            (car (member (window-buffer ecb-compile-window)
                         ecb-eshell-buffer-list)))
           (my-reference-directory default-directory)
           (my-eshell-directory (and (bufferp my-eshell-buffer)
                                     (save-excursion
                                       (set-buffer my-eshell-buffer)
                                       default-directory))))
      (when (and (bufferp my-eshell-buffer)
                 (stringp my-reference-directory)
                 (stringp my-eshell-directory)
                 (not (string-equal (ecb-fix-filename my-reference-directory)
                                    (ecb-fix-filename my-eshell-directory))))
        (ecb-eshell-save-buffer-history
         (save-excursion
           (set-buffer my-eshell-buffer)
           ;; make sure we have a clean eshell-command-line
           (goto-char (point-max))
           (eshell-bol)
           (delete-region (point) (point-at-eol))
           ;;change the directory without showing the cd command
           (eshell/cd my-reference-directory))
           
         ;;execute the command
         (save-selected-window
           (select-window ecb-compile-window)
           (eshell-send-input)))
        
        (ecb-eshell-recenter)
        
        ;; we need to make sure that that the eshell buffer isn't at the
        ;; top of the buffer history list just because we implicitly
        ;; changed its directory and switched to it. It might not be a
        ;; good idea in the long term to put it all the way at the end of
        ;; the history list but it is better than leaving it at the top.
        (bury-buffer eshell-buffer-name)))))

(defmacro ecb-eshell-save-buffer-history (&rest body)
  "Protect the buffer-list so that the eshell buffer name is not placed early
in the buffer list or at all if it currently doesn't exist."
  (let ((eshell-buffer-list (make-symbol "my-buffer-list")))
    `(let ((,eshell-buffer-list (ecb-frame-parameter (selected-frame)
                                                     'buffer-list)))
       (unwind-protect
           (progn
             ,@body)
         (modify-frame-parameters nil (list (cons 'buffer-list
                                                  ,eshell-buffer-list)))))))

(defun ecb-eshell-recenter(&optional display-errors)
  "Recenter the eshell window so that the prompt is at the buffer-end."
  (interactive (list t))

  (if (and (equal (selected-frame) ecb-frame)
           (ecb-compile-window-live-p)
           ;; the buffer in the ecb-compile-window is a living eshell-buffer
           (member (window-buffer ecb-compile-window)
                   ecb-eshell-buffer-list))
      (save-selected-window
        (select-window ecb-compile-window)
        (goto-char (point-max))
        (recenter -2))
    (when display-errors
      (ecb-error "Eshell not running or compile-window not visible!"))))

(defun ecb-eshell-precommand-hook ()
  ;;use the eshell-pre-command-hook to set the point.
  (setq ecb-eshell-pre-command-point (point)))


(defun ecb-eshell-fit-window-to-output()
  "Fit window of eshell to the output of last command. This function is added
to `eshell-post-command-hook' and only called there. This function tries to
fit the height of the compile-window best to the last command-output. The
algorithm fit the window to the height of the last command-output but do not
enlarge the compile-window over half of the frame-height and also not below
`ecb-compile-window-height' (in lines)."
  (when (and (equal (selected-frame) ecb-frame)
             (ecb-compile-window-live-p)
             ;; the buffer in the ecb-compile-window is a living eshell-buffer
             (member (window-buffer ecb-compile-window)
                     ecb-eshell-buffer-list))

    ;; fit the window to the height of the last command-output but do not
    ;; enlarge the compile-window over half of the frame-height and also not
    ;; below `ecb-compile-window-height' (in lines).
    (when (and ecb-eshell-fit-window-to-command-output
               (integer-or-marker-p ecb-eshell-pre-command-point))
      (let* ((compile-window-height-lines
              (ecb-normalize-number ecb-compile-window-height
                                    (1- (frame-height))))
             (ecb-enlarged-compilation-window-max-height
              (max (min (save-excursion
                          (set-buffer (window-buffer ecb-compile-window))
                          ;; we want to see the old command line too and 2
                          ;; must be added because we have a modeline and one
                          ;; empty line cause of the (recenter -2) in
                          ;; `ecb-eshell-recenter'. For XEmacs it would be
                          ;; better to check if a horiz. scrollbar is used.
                          ;; This causes the one line more we need for XEmacs
                          (+ (if ecb-running-xemacs 4 3)
                             (count-lines ecb-eshell-pre-command-point
                                          (point))))
                        (/ (1- (frame-height)) 2))
                   compile-window-height-lines)))
                 (ecb-toggle-compile-window-height 1)
        (ecb-eshell-recenter))
        
      ;;reset
      (setq ecb-eshell-pre-command-point nil))))


(defun ecb-eshell-auto-activate-hook()
  "Activate the eshell when ECB is activated. See `ecb-eshell-auto-activate'."
  (when ecb-eshell-auto-activate
    (ignore-errors (eshell))))

(defun ecb-eshell-window-size-change(frame)
  "Called when we change window sizes so that the eshell can resize."
  (when (and ecb-minor-mode
             (equal frame ecb-frame))
    (ignore-errors (ecb-eshell-recenter))))

(add-hook 'ecb-activate-hook 'ecb-eshell-auto-activate-hook)

(silentcomp-provide 'ecb-eshell)

;;; ecb-eshell.el ends here