emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Run powershell as a shell within Emacs on Windows


From: D Chiesa
Subject: Run powershell as a shell within Emacs on Windows
Date: Tue, 27 May 2008 15:05:05 -0700

Another thing I put together - the ability to run Windows Powershell as a shell within emacs. For those who don't follow the whims of Redmond, Powershell is a shell for Windows, featuring a new script language . It is the replacement for cmd.exe and batch files.

If Powershell were a normal shell, running it within emacs would be really simple: just set explicit-shell-file-name and then explicit-powershell.exe-args , and then M-x shell. But Powershell does not emit a prompt when its input is redirected (aka when it is in non-interactive mode), and that makes for bad quality of life. There is also a weird issue with powershell and buffer sizes - it clips its output to the buffer size, and so if you resize emacs you need to tell the inferior powershell you've done so, to avoid clipping or line-wrapping in the shell buffer.

That felt like enough baling-wire and duct tape to justify an elisp file to me. So here is powershell.el. This is not an editing mode for powershell script; it is not "powershell mode". (That has been solved by someone else). It is a shell mode for running powershell within emacs.

I run it on GNU Emacs (for Windows) 22.2.1 (i386-mingw-nt6.0.6001).

This thing is mostly interesting to users on Windows, who run powershell. This could be administrative users, developers, hybrids, and that sort of thing. I am happy to have powershell.el included in future emacs shipments if that is appropriate. (I don't know if that is overly presumptuous or not. )

Is this useful if I post this kinda stuff here?

----
;; powershell.el, version 0.1
;;
;; Author: Dino Chiesa
;; Thu, 10 Apr 2008  11:10
;;
;; Run Windows PowerShell v1.0 as an inferior shell within emacs. Tested with emacs v22.2.
;;
;; TODO:
;; test what happens when you expand the window size beyond the maxWindowWidth for the RawUI ;; make everything configurable (Powershell exe, initial args, powershell prompt regexp)
;;  implement powershell launch hooks
;; prevent backspace from deleting the powershell prompt? (do other shells do this?)
;;

(require 'shell)


(defun powershell-gen-window-width-string ()
 (concat  "$a = (Get-Host).UI.RawUI\n"
           "$b = $a.WindowSize\n"
           "$c = $a.WindowSize\n"
           "$b.Width = 19999\n"
            "$c.width = " (number-to-string  (window-width)) "\n"
           "$a.BufferSize = $b\n"
           "$a.WindowSize = $c")
 )


(defvar powershell-prompt-pattern  "PS [^#$%>]+>"
"Regexp for powershell prompt. This isn't really used, because I couldn't figure out how to get it to work."
 )

(defgroup powershell nil
 "Running shell from within Emacs buffers."
 :group 'processes
 )


(defcustom powershell-need-rawui-resize t
 "set when powershell needs to be resized"
 :group 'powershell
)

;;;###autoload
(defun powershell (&optional buffer)
"Run Powershell, by invoking the shell function. See the help for shell for more details.
\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
 (interactive
  (list
   (and current-prefix-arg
        (read-buffer "Shell buffer: "
                     (generate-new-buffer-name "*PowerShell*")))))
 ; get a name for the buffer
 (setq buffer (get-buffer-create (or buffer "*PowerShell*")))

 (let (
       (tmp-shellfile explicit-shell-file-name)
       )
; set arguments for the powershell exe.
                                       ; This needs to be tunable.
(setq explicit-shell-file-name "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe") (setq explicit-powershell.exe-args '("-Command" "-" )) ; interactive, but no command prompt

                                       ; launch the shell
   (shell buffer)

   ; restore the original shell
   (if explicit-shell-file-name
       (setq explicit-shell-file-name tmp-shellfile)
     )
   )

 (let (
       (proc (get-buffer-process buffer))
       )

   ; This sets up the powershell RawUI screen width. By default,
   ; the powershell v1.0 assumes terminal width of 80 chars.
   ;This means input gets wrapped at the 80th column.  We reset the
   ; width of the PS terminal to the window width.
   (add-hook 'window-size-change-functions 'powershell-window-size-changed)

   (powershell-window-size-changed)

   ; ask for initial prompt
   (comint-simple-send proc "prompt")
   )

 ; hook the kill-buffer action so we can kill the inferior process?
 (add-hook 'kill-buffer-hook 'powershell-delete-process)

 ; wrap the comint-input-sender with a PS version
 ; must do this after launching the shell!
 (make-local-variable 'comint-input-sender)
 (setq comint-input-sender 'powershell-simple-send)

; set a preoutput filter for powershell. This will trim newlines after the prompt. (add-hook 'comint-preoutput-filter-functions 'powershell-preoutput-filter-for-prompt)

 ;(run-hooks 'powershell-launch-hook)

 ; return the buffer created
 buffer
)


(defun powershell-window-size-changed (&optional frame)
 ; do not actually resize here. instead just set a flag.
 (setq powershell-need-rawui-resize t)
)



(defun powershell-delete-process (&optional proc)
 (or proc
     (setq proc (get-buffer-process (current-buffer))))
 (and (processp proc)
      (delete-process proc))
 )



;; This function trims the newline from the prompt that we
;; get back from powershell.  It is set into the preoutput
;; filters, so the newline is trimmed before being put into
;; the output buffer.
(defun powershell-preoutput-filter-for-prompt (string)
  (if
      ; not sure why, but I have not succeeded in using a variable here???
      ;(string-match  powershell-prompt-pattern  string)

      (string-match  "PS [^#$%>]+>" string)
      (substring string 0 -1)

    string

    )
  )



(defun powershell-simple-send (proc string)
 "Override of the comint-simple-send function, specific for powershell.
This just sends STRING, plus the prompt command. Normally powershell is in
noninteractive model when run as an inferior shell with stdin/stdout
redirected, which is the case when running as a shell within emacs.
This function insures we get and display the prompt. "
 ; resize if necessary. We do this by sending a resize string to the shell,
 ; before sending the actual command to the shell.
 (if powershell-need-rawui-resize
     (and
      (comint-simple-send proc (powershell-gen-window-width-string))
      (setq powershell-need-rawui-resize nil)
      )
   )
 (comint-simple-send proc string)
 (comint-simple-send proc "prompt")
)

(provide 'powershell)

;; End of powershell.el







reply via email to

[Prev in Thread] Current Thread [Next in Thread]