Web Sailor
Sailor Family

Home
My Blog
Albums
Wedding
Friends
Hobbies

Sailor At Work

Firefox
Java
Rubik Cube
Toto/4D

Html
Perl
Chinese

Web Tools
Emacs/Cygwin









Drop me a note
Email Web Sailor
Welcome to Web Sailor's Home
Home > Emacs/Cygwin > Cygwin Customizations

Introduction

Since Emacs depends on a lot of Unix commands, I found a lot of Gnu Emacs functions are not working properly under Windows environment. Fortunately, I have discovered Cygwin recently. Cygwin contains a set of essential Unix utilities that make my Gnu Emacs works almost the same as the Emacs under Unix enviroment. After Cygwin is installed, I can use Unix commands like ls, pwd, cp, mv, rm, mkdir, rmdir, history, grep, find, awk, sed, gzip, tar and a lot more. In addition, Cygwin contains perl, gcc, gdb, make, tcl and others.

However, making Emacs to work with Cygwin requires some customizations. This information is scattered in a lot of different places. I am trying to share my customization experiences with all of you who are interested in using Gnu Emacs and Cygwin.

This web page assumes you have certain knowledge about Gnu Emacs. Please refer to the Gnu Manuals for details if you need it.



Installations

I have selected the following addtional packages:

  • Archive - unzip
  • Archive - zip
  • Devel - autoconf
  • Devel - binutils
  • Devel - cvs
  • Devel - gcc-core
  • Devel - gcc-g++
  • Devel - gdb
  • Devel - make
  • Devel - mingw-runtime
  • Devel - subversion
  • Doc - man
  • Doc - newlib-man
  • Editor - vim
  • Interpreters - perl
  • Libs - w32api
  • Net - inetutils
  • Net - openssh
  • Shells - pdksh
  • Shells - rxvt
  • Shells - tcsh
  • System - ping
  • System - procps
  • Text - groff
  • Text - less
  • Text - more
  • Text - texinfo
  • Utils - bzip2

I have installed Cygwin under c:\programs\cygwin.



cygwin-mount.el

You will need the package cygwin-mount.el in order for Gnu Emacs to recognize Cygwin's path names. If you do not have this package, Gnu Emacs will not understand /cygdrive/c. Put this package under directory site-lisp. In my PC, the full directory name is c:\programs\emacs\site-lisp. After you have done that, add the following lines in your .emacs file.

(setenv "PATH" (concat "c:/programs/cygwin/bin;" (getenv "PATH")))
(setq exec-path (cons "c:/programs/cygwin/bin/" exec-path))
(require 'cygwin-mount)
(cygwin-mount-activate)


Replace DOS shell with Cygwin Bash Shell

If You wish to replace the problematic DOS shell that Gnu Emacs invokes when you press "alt-x shell" with Cygwin's Bash shell, add the following lines into your .emacs file.

(add-hook 'comint-output-filter-functions
    'shell-strip-ctrl-m nil t)
(add-hook 'comint-output-filter-functions
    'comint-watch-for-password-prompt nil t)
(setq explicit-shell-file-name "bash.exe")
;; For subprocesses invoked via the shell
;; (e.g., "shell -c command")
(setq shell-file-name explicit-shell-file-name)

If you restart Gnu Emacs after adding the above Lisp statements, you will be able to experience the power of Bash shell by pressing "alt-x shell". You will discover that you can use commands like ls, pwd, grep, cat, find in the shell.

Do not forget that Bash Shell requires the path name to be set correctly in the file %HOME%/.bashrc.

The content of my %HOME%/.bashrc is as follow:

# ------------------------
# prompt
# ------------------------
# export PS1="[\w] "
export PS1="sailor% "

if [ "$PS" == "" ] ; then
    export PS1="sailor\$ "
    if [ "$TERM" == "xterm" ] ; then
        export PS1="\[\e[34m\]sailor\$ \[\e[0m\]"
    elif [ "$TERM" == "cygwin" ] ; then
        export PS1="\[\e[32;1m\]sailor\$ \[\e[0m\]"
    fi
fi

if [ "$TERM" == "xterm" ] ; then
    PROMPT_COMMAND='echo -ne "\e]0;${HOSTNAME} - ${PWD}\007"'
fi

# ------------------------
# path
# ------------------------
PATH=.
PATH=$PATH:/cygdrive/c/programs/bin
PATH=$PATH:/usr/x11R6/bin
PATH=$PATH:/usr/bin
PATH=$PATH:`cygpath -S`
PATH=$PATH:`cygpath -W`

# ------------------------
# alias
# ------------------------
alias h=history
alias rm="rm -i"
alias ls="ls -C"


Using Cygwin Telnet

If you have used Emacs on Unix, you probably know that pressing "alt-x telnet" can start a telnet session. Unfortunately, the telnet program that come with Windows does not work for Gnu Emacs. You will need to use Cygwin's telnet (available in net.inetutils package). Again, Cygwin's telnet has its own problem with Gnu Emacs. To make them work together, you will need to add the following Lisp statements into your .emacs file.

(require 'telnet)

(defun telnet (host)
  "Open a network login connection to host named HOST (a string).
Communication with HOST is recorded in a buffer `*PROGRAM-HOST*'
where PROGRAM is the telnet program being used.  This program
is controlled by the contents of the global variable
`telnet-host-properties', falling back on the value of the
global variable `telnet-program'. Normally input is edited
in Emacs and sent a line at a time."
  (interactive "sOpen connection to host: ")
  (let* ((comint-delimiter-argument-list '(?\  ?\t))
         (properties (cdr (assoc host telnet-host-properties)))
         (telnet-program (if properties (car properties) telnet-program))
         (name (concat telnet-program "-" (comint-arguments host 0 nil) ))
         (buffer (get-buffer (concat "*" name "*")))
         (telnet-options (if (cdr properties)
                 (cons "-l" (cdr properties))))
         process)
    (if (and buffer (get-buffer-process buffer))
        (pop-to-buffer (concat "*" name "*"))
      (pop-to-buffer
       (apply 'make-comint name telnet-program nil telnet-options))
      (setq process (get-buffer-process (current-buffer)))
      ;;(set-process-filter process 'telnet-initial-filter)
      ;; Don't send the `open' cmd till telnet is ready for it.
      ;;(accept-process-output process)
      (erase-buffer)
      (send-string process (concat "open " host "\n"))
      (telnet-mode)
      (setq telnet-remote-echoes nil)
      (setq telnet-new-line "\n") ;; needed for cygwin 1.3.11
      (setq comint-input-sender 'telnet-simple-send)
      (setq telnet-count telnet-initial-count)
      (setq comint-process-echoes t)
      )))


Using Cygwin Ftp

Ftp (available in net.inetutils package) should work the same way as telnet by pressing "alt-x ftp". Again you need additional Lisp statements in your .emacs file.

(defun ftp (host)
  "03Mar01, sailor"
  "Run the ftp program using cygwin ftp."
  "Fixed the problem that the login prompt cannot be seen."
  (interactive "sFtp to Host : ")
  (let ((bufname)
        (bufobject))
    (setq bufname (concat "*ftp-" host "*"))
    (setq bufobject (get-buffer bufname))

    (cond
     ((and bufobject (get-buffer-process bufobject))
      (pop-to-buffer bufname)
      )
     (t
      (let ((login)
            (process)
            (ftp-program "ftp.exe"))
        (setq bufobject (get-buffer-create bufname))
        (pop-to-buffer bufobject)
        (comint-mode)
        (setq login (read-from-minibuffer (format "%s - Login : " host)))
        (comint-exec bufobject bufname ftp-program nil
            (list "--prompt=ftp> " "-v" host))
        (message "Login in progress. Please wait ...")
        (send-invisible (format "%s" login))
        (setq process (get-buffer-process (current-buffer)))
        (accept-process-output process)
        )
      )
     )
    )
  )


Invoke Bash Shell with Alternate Resource File

Sometimes, it is desired to start a bash shell with start-up file other than the default .bashrc. You may place the following simple lisp statements into your .emacs file. After that just invoke the shell with Alt-x shell-symbian.

(require 'shell)

(defun shell-symbian ()
  "10Jan02, sailor. Invoke a bash shell for Symbian"
  (interactive)
  (let ((bufname "*shell-symbian*")
        (bufobject))

    (setq bufobject (get-buffer bufname))

    (cond
     ((and bufobject (get-buffer-process bufobject))
      (pop-to-buffer bufname)
      )
     (t
      (progn
        (set-buffer
           (apply 'make-comint-in-buffer
                  "shell"
                  bufname
                  explicit-shell-file-name
                  nil
                  '("--rcfile" "c:/documents/config/.symbianrc" "-i")
                  ))
        (shell-mode)
        (pop-to-buffer (current-buffer))
        )
      )
     )
    )
  )


Key Binding for Previous Commands

Some people like to use the up and down arrow keys to traverse through the previous commands. Here is the way to bind the keys.

(add-hook 'shell-mode-hook 'n-shell-mode-hook)
(defun n-shell-mode-hook ()
  "12Jan2002 - sailor, shell mode customizations."
  (local-set-key '[up] 'comint-previous-input)
  (local-set-key '[down] 'comint-next-input)
  (local-set-key '[(shift tab)] 'comint-next-matching-input-from-input)
  )


Clear Command

When the "clear" command is entered into the bash shell, it is expected to clear the entire shell buffer. However, this does not work for bash shell under Gnu Emacs. The following lisp statements solve the problem.

Notice that the following statements also intercepts the "man" command entered by the user and execute it outside the shell.
(add-hook 'shell-mode-hook 'n-shell-mode-hook)
(defun n-shell-mode-hook ()
  "12Jan2002 - sailor, shell mode customizations."
  (local-set-key '[up] 'comint-previous-input)
  (local-set-key '[down] 'comint-next-input)
  (local-set-key '[(shift tab)] 'comint-next-matching-input-from-input)
  (setq comint-input-sender 'n-shell-simple-send)
  )

(defun n-shell-simple-send (proc command)
  "17Jan02 - sailor. Various commands pre-processing before sending to shell."
  (cond
   ;; Checking for clear command and execute it.
   ((string-match "^[ \t]*clear[ \t]*$" command)
    (comint-send-string proc "\n")
    (erase-buffer)
    )
   ;; Checking for man command and execute it.
   ((string-match "^[ \t]*man[ \t]*" command)
    (comint-send-string proc "\n")
    (setq command (replace-regexp-in-string "^[ \t]*man[ \t]*" "" command))
    (setq command (replace-regexp-in-string "[ \t]+$" "" command))
    ;;(message (format "command %s command" command))
    (funcall 'man command)
    )
   ;; Send other commands to the default handler.
   (t (comint-simple-send proc command))
   )
  )


Gzip and Gunzip

When viewing files using the Emacs dired utility, press Z should compress or uncompress a file. Since Cygwin is equiped with the gzip utility, you should be able to get this function working on your Windows Gnu Emacs. The lisp statement you need in your .emacs file is

(setq archive-zip-use-pkzip nil)

Unfortunately, if you are trying to use gunzip to uncompress a file under dired, you will probably encounter a problem saying "Failed to uncompress ..." or "spawning child process: exec format error". The problem is due to that gunzip provided by Cygwin is not an executable file. It is a symbolic link to gzip. (You can verify this by "ls -l /usr/bin/gunzip". Since Gnu Emacs does not understand Cygwin's symbolic link, it cannot execute gunzip. Here is the solution.

(require 'dired-aux)

(defun dired-call-process (program discard &rest arguments)
  ;; 09Feb02, sailor overwrite this function because Gnu Emacs cannot
  ;; recognize gunzip is a symbolic link to gzip. Thus, if the program
  ;; is "gunzip", replace it with "gzip" and add an option "-d".

  ;; "Run PROGRAM with output to current buffer unless DISCARD is t.
  ;; Remaining arguments are strings passed as command arguments to PROGRAM."
  ;; Look for a handler for default-directory in case it is a remote file name.
  (let ((handler
         (find-file-name-handler (directory-file-name default-directory)
                                 'dired-call-process)))
    (if handler (apply handler 'dired-call-process
                       program discard arguments)
      (progn
        (if (string-equal program "gunzip")
            (progn
              (setq program "gzip")
              (add-to-list 'arguments "-d")
              )
            )
        (apply 'call-process program nil (not discard) nil arguments)
        )
      )))


Various Cygwin Tools

After the above customizations, you should get all of the followings working on your PC.

Features Comments
Bash Shell "alt-x shell"
Standard Unix commands such as "ls", "pwd", "cp", "mv", "rm" are able to work under this shell.
Shell Commands "alt-!"
This command lets you run a shell command.
"alt-|"

This command lets you run a shell command using a selected region of text as inputs to the command.

This information is contributed by Travis Winfrey.

Telnet "alt-x telnet" "188.8.88.888"
(you need to install inetutils from Cygwin).
FTP "alt-x ftp" "188.8.88.888"
Ange FTP "alt-x find-file" "/user@188.8.88.888:/"
This is command that let you open a remote file for editing. Once the file is opened, the file can be viewed and editing as if it is a local file. I considered this as the most useful feature of Emacs.
Man "alt-x man" "ls" for example will display the manual for Unix command ls.
This is the man command under Unix.
VI Editor "alt-x term" "vi"
you do not really need this if you have learned all the Emacs functionalities.
Diff "alt-x ediff-buffers" "file1.txt" "file2.txt"
This function compares the differences between two files.
Command "diff file1.txt file2.txt" can also be run under a Bash shell.
IP Config "alt-x ipconfig"
This helps you to find out your PC's IP address.
Ping "alt-x ping" "188.8.88.888"
This helps you to check whether a remote machine is alive or not.
GCC Compiler In a Bash shell, just key in "gcc test.c" for example.
(you need to install gcc from Cygwin).
Grep "alt-x grep" "grep -n -e text *.c"
This command can also be run in a Bash shell.
Find In a Bash shell, just key in "find . -name test.c -print" for example.
Tar In a Bash shell, just key in "tar -cvf tmp.tar *.c" for example.
Gzip In a Bash shell, just key in "gzip tmp.txt" for example.
Bzip2 In a Bash shell, just key in "bzip2 tmp.txt" for example.
Rxvt In a Bash shell, just key in "rxvt -e bash &" for example.
rxvt is similar to xterm. This is useful for some programs that must be run under xterm. Read here for more details.
Lynx "alt-x term" "lynx"
This is text based web browser if you find it useful.
Perl You can execute a perl script in a Bash shell by typing its file name.
Ctags This feature helps you to browse source codes efficiently.

There are a lot of other features that I have never used in Cygwin. Those are left for you to explore. You may drop me a note if you think it should be here.




Langkawi Sunset