branch: elpa/powershell
commit 1aa74a4a9b5351f3a35c8b879acc977359122dc8
Author: Joe Schafer <[email protected]>
Commit: Joe Schafer <[email protected]>
Merge powershell.el into powershell-mode.el.
---
powershell-mode.el | 750 +++++++++++++++++++++++++++++++++++++++++++++++++++--
powershell.el | 691 ------------------------------------------------
2 files changed, 728 insertions(+), 713 deletions(-)
diff --git a/powershell-mode.el b/powershell-mode.el
index e2ef7348bfb..de6849fcb0d 100644
--- a/powershell-mode.el
+++ b/powershell-mode.el
@@ -35,6 +35,12 @@
;; Functions to quote, unquote and escape a selection, and one to wrap
;; a selection in $(). Meanwhile I hope I didn't break anything.
;;
+;; Joe Schafer Comments 2013-06-06: I combined powershell.el and
+;; powershell-mode.el. Since powershell.el was licensed with the new
+;; BSD license I can combine the two files using the more restrictive
+;; license, the GPL. I also cleaned up the documentation and
+;; reorganized some of the code.
+;;
;;; Updates
;; 2012/10/01 Fixed several bugs in highlighting variables and types.
;; Renamed some variables to be more descriptive.
@@ -42,7 +48,7 @@
;; Fixed dangling parens and re-indented the elisp itself.
;; 2012/10/05 Added eldoc support. Fixed bug where indent could loop.
;; See comment below on how to generate powershell-eldoc.el
-
+;; 2013/06/06 Merged powershell.el and powershell-mode.el
;;; Code:
@@ -59,7 +65,7 @@
(defgroup powershell nil
"Customization of PowerShell mode."
:link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
- :group 'languages )
+ :group 'languages)
(defcustom powershell-indent 4
"Amount of horizontal space to indent.
@@ -281,7 +287,8 @@ The text is assumed to be `regexp-opt' output."
"if" "in" "param"
"process" "return" "switch"
"throw" "trap" "try"
- "until" "where" "while" ) t)
+ "until" "where" "while")
+ t)
"\\_>")
"Powershell keywords.")
@@ -290,13 +297,16 @@ The text is assumed to be `regexp-opt' output."
(concat "\\_<"
(regexp-opt
'("-eq" "-ne" "-gt" "-ge" "-lt" "-le"
- "-ceq" "-cne" "-cgt" "-cge" "-clt" "-cle" ;; case sensitive
versions
- "-ieq" "-ine" "-igt" "-ige" "-ilt" "-ile" ;; explicitly case
insensitive
+ ;; case sensitive versions
+ "-ceq" "-cne" "-cgt" "-cge" "-clt" "-cle"
+ ;; explicitly case insensitive
+ "-ieq" "-ine" "-igt" "-ige" "-ilt" "-ile"
"-band" "-bor" "-bxor"
"-and" "-or" "-xor"
"-like" "-notlike" "-clike" "-cnotlike" "-ilike" "-inotlike"
"-match" "-notmatch" "-cmatch" "-cnotmatch" "-imatch" "-inotmatch"
- "-contains" "-notcontains" "-ccontains" "-cnotcontains"
"-icontains" "-inotcontains"
+ "-contains" "-notcontains" "-ccontains" "-cnotcontains"
+ "-icontains" "-inotcontains"
"-replace" "-creplace" "-ireplace"
"-is" "-as" "-f"
;; Questionable --> specific to certain contexts
@@ -311,7 +321,7 @@ The text is assumed to be `regexp-opt' output."
"Names of scopes in Powershell mode.")
(defvar powershell-variable-drive-names
- (append '("env" "function" "variable" "alias" )
powershell-scope-names)
+ (append '("env" "function" "variable" "alias") powershell-scope-names)
"Names of scopes in Powershell mode.")
(defconst powershell-variables-regexp
@@ -320,8 +330,10 @@ The text is assumed to be `regexp-opt' output."
;; Match 1 is scope when the former syntax is found.
;; Match 2 is scope when the latter syntax is found.
(concat
- "\\_<$\\(?:{\\(?:" (regexp-opt powershell-variable-drive-names t)
":\\)?[^}]+}\\|"
- "\\(?:" (regexp-opt powershell-variable-drive-names t)
":\\)?[a-zA-Z0-9_]+\\_>\\)")
+ "\\_<$\\(?:{\\(?:" (regexp-opt powershell-variable-drive-names t)
+ ":\\)?[^}]+}\\|"
+ "\\(?:" (regexp-opt powershell-variable-drive-names t)
+ ":\\)?[a-zA-Z0-9_]+\\_>\\)")
"Identifies legal powershell variable names.")
(defconst powershell-function-names-regex
@@ -520,7 +532,8 @@ characters that can't be set by the `syntax-table' alone.")
nil
;; font-lock-syntactic-keywords
;; takes (matcher (match syntax override lexmatch) ...)...
- (font-lock-syntactic-keywords .
powershell-font-lock-syntactic-keywords))))
+ (font-lock-syntactic-keywords
+ . powershell-font-lock-syntactic-keywords))))
(defvar powershell-mode-syntax-table
(let ((powershell-mode-syntax-table (make-syntax-table)))
@@ -551,12 +564,14 @@ characters that can't be set by the `syntax-table'
alone.")
(let ((powershell-mode-map (make-keymap)))
;; (define-key powershell-mode-map "\r" 'powershell-indent-line)
(define-key powershell-mode-map "\t" 'powershell-indent-line)
- (define-key powershell-mode-map (kbd "M-\"")
'powershell-doublequote-selection)
+ (define-key powershell-mode-map (kbd "M-\"")
+ 'powershell-doublequote-selection)
(define-key powershell-mode-map (kbd "M-'") 'powershell-quote-selection)
(define-key powershell-mode-map (kbd "C-'") 'powershell-unquote-selection)
(define-key powershell-mode-map (kbd "C-\"") 'powershell-unquote-selection)
(define-key powershell-mode-map (kbd "M-`") 'powershell-escape-selection)
- (define-key powershell-mode-map (kbd "C-$")
'powershell-dollarparen-selection)
+ (define-key powershell-mode-map (kbd "C-$")
+ 'powershell-dollarparen-selection)
powershell-mode-map)
"Keymap for PS major mode.")
@@ -567,11 +582,13 @@ characters that can't be set by the `syntax-table'
alone.")
(define-key (current-local-map) [menu-bar powershell-menu doublequote]
'(menu-item "DoubleQuote Selection" powershell-doublequote-selection
:key-sequence(kbd "M-\"")
- :help "DoubleQuotes the selection escaping embedded double
quotes"))
+ :help
+ "DoubleQuotes the selection escaping embedded double quotes"))
(define-key (current-local-map) [menu-bar powershell-menu quote]
'(menu-item "SingleQuote Selection" powershell-quote-selection
:key-sequence (kbd "M-'")
- :help "SingleQuotes the selection escaping embedded single
quotes"))
+ :help
+ "SingleQuotes the selection escaping embedded single quotes"))
(define-key (current-local-map) [menu-bar powershell-menu unquote]
'(menu-item "UnQuote Selection" powershell-unquote-selection
:key-sequence (kbd "C-'")
@@ -579,7 +596,8 @@ characters that can't be set by the `syntax-table' alone.")
(define-key (current-local-map) [menu-bar powershell-menu escape]
'(menu-item "Escape Selection" powershell-escape-selection
:key-sequence (kbd "M-`")
- :help "Escapes variables in the selection and extends existing
escapes."))
+ :help (concat "Escapes variables in the selection"
+ " and extends existing escapes.")))
(define-key (current-local-map) [menu-bar powershell-menu dollarparen]
'(menu-item "DollarParen Selection" powershell-dollarparen-selection
:key-sequence (kbd "C-$")
@@ -590,8 +608,9 @@ characters that can't be set by the `syntax-table' alone.")
(defcustom powershell-eldoc-def-files nil
"List of files containing function help strings used by function
`eldoc-mode'.
-These are the strings function `eldoc-mode' displays as help for functions
near point.
-The format of the file must be exactly as follows or who knows what happens.
+These are the strings function `eldoc-mode' displays as help for
+functions near point. The format of the file must be exactly as
+follows or who knows what happens.
(set (intern \"<fcn-name1>\" powershell-eldoc-obarray) \"<helper string1>\")
(set (intern \"<fcn-name2>\" powershell-eldoc-obarray) \"<helper string2>\")
@@ -603,7 +622,8 @@ Where <fcn-name> is the name of the function to which
<helper string> applies.
:group 'powershell)
(defvar powershell-eldoc-obarray ()
- "Array into which powershell-eldoc-def-files entries are added for use by
eldoc.")
+ "Array for file entries by the function `eldoc'.
+`powershell-eldoc-def-files' entries are added into this array.")
(defun powershell-eldoc-function ()
"Return a documentation string appropriate for the current context or nil."
@@ -672,7 +692,7 @@ Where <fcn-name> is the name of the function to which
<helper string> applies.
"List of regexps matching important expressions, for speebar & imenu.")
(defun powershell-setup-imenu ()
- "Install powershell-imenu-expression."
+ "Install `powershell-imenu-expression'."
(when (require 'imenu nil t)
;; imenu doc says these are buffer-local by default
(setq imenu-generic-expression powershell-imenu-expression)
@@ -700,9 +720,7 @@ Where <fcn-name> is the name of the function to which
<helper string> applies.
compilation-error-regexp-alist))
-;; the hook is automatically run by derived-mode
-(defvar powershell-mode-hook '(imenu-add-menubar-index)
- "Hook run after the initialization of Powershell mode.")
+(add-hook 'powershell-mode-hook #'imenu-add-menubar-index)
;;;###autoload
(define-derived-mode powershell-mode prog-mode "PS"
@@ -721,6 +739,694 @@ that value is non-nil."
(powershell-setup-menu)
(powershell-setup-eldoc))
+
+;;; Powershell - run an inferior shell with powershell
+
+
+;;;; powershell.el --- run powershell as an inferior shell in emacs
+;;
+;; Author : Dino Chiesa <[email protected]>
+;; Created : 10 Apr 2008
+;; Modified : May 2010
+;; Version : 0.2.4
+;; Keywords : powershell shell ms-windows
+;; X-URL : http://www.emacswiki.org/emacs/PowerShell#toc3
+;; Last-saved : <2011-February-17 12:10:59>
+;;
+
+;;; Commentary:
+;;
+;; Run Windows PowerShell v1.0 or v2.0 as an inferior shell within
+;; Emacs. Tested with Emacs v22.2 and v23.2.
+;;
+;; To use it, M-x powershell.
+;;
+;; ==============
+;;
+;; TODO:
+;;
+;; - get TAB to do proper completion for powershell commands, filenames,
+;; etc.
+;;
+;;
+
+;;; Versions:
+;;
+;; 0.1.0 - Initial release.
+;; 0.2.4 - make powershell fn an autoload.
+;; - fixed problem where running a single shell, caused all
+;; future shells to be powershell. This meant reverting to
+;; the original value of explicit-shell-file-name after
+;; invoking `shell'.
+;; - make location of powershell specifiable, via defcustom
+;; `powershell-location-of-exe'. Also turn a few other defvar
+;; into defcustom.
+;; - fix "Marker does not point anywhere" problem in
+;; `ansi-color-apply-on-region'.
+;;
+
+;;; License:
+;;
+;; This code is distributed under the New BSD License.
+;;
+;; Copyright (c) 2008-2010, Dino Chiesa
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions
+;; are met:
+;;
+;; Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;;
+;; Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in the
+;; documentation and/or other materials provided with the distribution.
+;;
+;; Neither the name of the author or any contributors, nor the names of
+;; any organizations they belong to, may be used to endorse or promote
+;; products derived from this software without specific prior written
+;; permission.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+;; HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+;; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+;; OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+;; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+;; WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+;; POSSIBILITY OF SUCH DAMAGE.
+;;
+;;
+
+(require 'shell)
+
+;; TODO: set this programmatically, relying on %WINDIR%
+;;; Code:
+
+(defcustom powershell-location-of-exe
+ "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"
+ "A string, providing the location of the Powershell.exe."
+ :group 'powershell)
+
+(defcustom powershell-log-level 3
+ "The current log level for powershell internal operations.
+0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG."
+ :group 'powershell)
+
+(defcustom powershell-squish-results-of-silent-commands t
+"The function `powershell-invoke-command-silently' returns the results
+of a command in a string. PowerShell by default, inserts newlines when
+the output exceeds the configured width of the powershell virtual
+window. In some cases callers might want to get the results with the
+newlines and formatting removed. Set this to true, to do that."
+:group 'powershell)
+
+(defvar powershell-prompt-regex "PS [^#$%>]+> "
+ "Regexp to match the powershell prompt.
+Powershell.el uses this regex to determine when a command has
+completed. Therefore, you need to set this appropriately if you
+explicitly change the prompt function in powershell. Any value
+should include a trailing space, if the powershell prompt uses a
+trailing space, but should not include a trailing newline.
+
+The default value will match the default PowerShell prompt.")
+
+(defvar powershell-command-reply nil
+ "The reply of powershell commands.
+This is retained for housekeeping purposes.")
+
+(defvar powershell--max-window-width 0
+ "The maximum width of a powershell window.
+You shouldn't need to ever set this. It gets set automatically,
+once, when the powershell starts up.")
+
+(defvar powershell-command-timeout-seconds 12
+ "The timeout for a powershell command.
+Powershell.el will wait this long before giving up.")
+
+(defvar powershell--need-rawui-resize t
+ "No need to fuss with this. It's intended for internal use
+only. It gets set when powershell needs to be informed that
+emacs has resized its window.")
+
+(defconst powershell--find-max-window-width-command
+ (concat
+ "function _Emacs_GetMaxPhsWindowSize \n"
+ "{\n"
+ " $rawui = (Get-Host).UI.RawUI\n"
+ " $mpws_exists = ($rawui | Get-Member | ? "
+ "{$_.Name -eq \"MaxPhysicalWindowSize\"})\n"
+ " if ($mpws_exists -eq $null) {\n"
+ " \"210\" | Out-Host\n"
+ " } else {\n"
+ " $rawui.MaxPhysicalWindowSize.Width | Out-Host\n"
+ " }\n"
+ "}\n"
+ "_Emacs_GetMaxPhsWindowSize\n")
+ "The powershell logic to determine the max physical window width.")
+
+(defconst powershell--set-window-width-fn-name "_Emacs_SetWindowWidth"
+ "The name of the function this mode defines in PowerShell to
+set the window width. Intended for internal use only.")
+
+(defconst powershell--text-of-set-window-width-ps-function
+ ;; see
+ ;;
http://blogs.msdn.com/lior/archive/2009/05/27/ResizePowerShellConsoleWindow.aspx
+ ;;
+ ;; When making the console window narrower, you mus set the window
+ ;; size first. When making the console window wider, you must set the
+ ;; buffer size first.
+
+ (concat "function " powershell--set-window-width-fn-name
+ "([string] $pswidth)\n"
+ "{\n"
+ ;;" \"resetting window width to $pswidth\n\" | Out-Host\n"
+ " $rawui = (Get-Host).UI.RawUI\n"
+ " # retrieve the values\n"
+ " $bufsize = $rawui.BufferSize\n"
+ " $winsize = $rawui.WindowSize\n"
+ " $cwidth = $winsize.Width\n"
+ " $winsize.Width = $pswidth \n"
+ " $bufsize.Width = $pswidth\n"
+ " if ($cwidth -lt $pswidth) {\n"
+ " # increase the width\n"
+ " $rawui.BufferSize = $bufsize\n"
+ " $rawui.WindowSize = $winsize\n"
+ " }\n"
+ " elseif ($cwidth -gt $pswidth) {\n"
+ " # decrease the width\n"
+ " $rawui.WindowSize = $winsize\n"
+ " $rawui.BufferSize = $bufsize\n"
+ " }\n"
+ " # destroy variables\n"
+ " Set-Variable -name rawui -value $null\n"
+ " Set-Variable -name winsize -value $null\n"
+ " Set-Variable -name bufsize -value $null\n"
+ " Set-Variable -name cwidth -value $null\n"
+ "}\n\n")
+
+ "The text of the powershell function that will be used at runtime to
+set the width of the virtual Window in PowerShell, as the Emacs window
+gets resized.")
+
+(defun powershell-log (level text &rest args)
+ "Log a message at level LEVEL.
+If LEVEL is higher than `powershell-log-level', the message is
+ignored. Otherwise, it is printed using `message'.
+TEXT is a format control string, and the remaining arguments ARGS
+are the string substitutions (see `format')."
+ (if (<= level powershell-log-level)
+ (let* ((msg (apply 'format text args)))
+ (message "%s" msg))))
+
+;; (defun dino-powershell-complete (arg)
+;; "do powershell completion on the given STRING. Pop up a buffer
+;; with the completion list."
+;; (interactive
+;; (list (read-no-blanks-input "\
+;; Stub to complete: ")))
+
+;; (let ((proc
+;; (get-buffer-process (current-buffer))))
+;; (comint-proc-query proc (concat "Get-Command " arg "*\n"))
+;; )
+;; )
+
+;; (defun dino-powershell-cmd-complete ()
+;; "try to get powershell completion to work."
+;; (interactive)
+;; (let ((proc
+;; (get-buffer-process (current-buffer))))
+;; ;; (comint-proc-query proc "Get-a\t")
+;; ;; (comint-simple-send proc "Get-a\t")
+;; (comint-send-string proc "Get-a\t\n")
+;; ;; (process-send-eof)
+;; )
+;; )
+
+(defun powershell--define-set-window-width-function (proc)
+ "Sends a function definition to the PowerShell instance
+identified by PROC. The function sets the window width of the
+PowerShell virtual window. Later, the function will be called
+when the width of the emacs window changes."
+ (if proc
+ (progn
+ ;;process-send-string
+ (comint-simple-send
+ proc
+ powershell--text-of-set-window-width-ps-function))))
+
+(defun powershell--get-max-window-width (buffer-name)
+ "Gets the maximum width of the virtual window for PowerShell running
+in the buffer with name BUFFER-NAME.
+
+In PowerShell 1.0, the maximum WindowSize.Width for
+PowerShell is 210, hardcoded, I believe. In PowerShell 2.0, the max
+windowsize.Width is provided in the RawUI.MaxPhysicalWindowSize
+property.
+
+This function does the right thing, and sets the buffer-local
+`powershell--max-window-width' variable with the correct value."
+ (let ((proc (get-buffer-process buffer-name)))
+
+ (if proc
+ (with-current-buffer buffer-name
+ (powershell-invoke-command-silently
+ proc
+ powershell--find-max-window-width-command
+ 0.90)
+
+ ;; store the retrieved width
+ (setq powershell--max-window-width
+ (if (and (not (null powershell-command-reply))
+ (string-match
+ "\\([1-9][0-9]*\\)[ \t\f\v\n]+"
+ powershell-command-reply))
+ (string-to-number (match-string 1
powershell-command-reply))
+ 200)))))) ;; could go to 210, but let's use 200 to be safe
+
+(defun powershell--set-window-width (proc)
+ "Run the PowerShell function that sets the RawUI width
+appropriately for a PowerShell shell.
+
+This is necessary to get powershell to do the right thing, as far
+as text formatting, when the emacs window gets resized.
+
+The function gets defined in powershell upon powershell startup."
+ (let ((ps-width
+ (number-to-string (min powershell--max-window-width (window-width)))))
+ (progn
+ ;;(process-send-string
+ (comint-simple-send
+ proc
+ (concat powershell--set-window-width-fn-name
+ "('" ps-width "')")))))
+
+(defun powershell (&optional buffer prompt-string)
+ "Run an inferior PowerShell.
+If BUFFER is non-nil, use it to hold the powershell
+process. Defaults to *PowerShell*.
+
+Interactively, a prefix arg means to prompt for BUFFER.
+
+If BUFFER exists but the shell process is not running, it makes a
+new shell.
+
+If BUFFER exists and the shell process is running, just switch to
+BUFFER.
+
+If PROMPT-STRING is non-nil, sets the prompt to the given value.
+
+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*")))))
+
+ (setq buffer (get-buffer-create (or buffer "*PowerShell*")))
+ (powershell-log 1 "powershell starting up...in buffer %s" (buffer-name
buffer))
+ (let ((tmp-shellfile explicit-shell-file-name))
+ ;; set arguments for the powershell exe.
+ ;; Does this need to be tunable?
+
+ (setq explicit-shell-file-name powershell-location-of-exe)
+ (setq explicit-powershell.exe-args '("-Command" "-" ))
+ (shell buffer)
+ (setq explicit-shell-file-name tmp-shellfile))
+
+ ;; (powershell--get-max-window-width "*PowerShell*")
+ ;; (powershell-invoke-command-silently (get-buffer-process "*csdeshell*")
+ ;; "[Ionic.Csde.Utilities]::Version()" 2.9)
+
+ ;; (comint-simple-send (get-buffer-process "*csdeshell*") "prompt\n")
+
+ (let ((proc (get-buffer-process buffer)))
+
+ (make-local-variable 'powershell-prompt-regex)
+ (make-local-variable 'powershell-command-reply)
+ (make-local-variable 'powershell--max-window-width)
+ (make-local-variable 'powershell-command-timeout-seconds)
+ (make-local-variable 'powershell-squish-results-of-silent-commands)
+ (make-local-variable 'powershell--need-rawui-resize)
+ (make-local-variable 'comint-prompt-read-only)
+
+ ;; disallow backspace over the prompt:
+ (setq comint-prompt-read-only t)
+
+ ;; We need to tell powershell how wide the emacs window is, because
+ ;; powershell pads its output to the width it thinks its window is.
+ ;;
+ ;; The way it's done: every time the width of the emacs window changes, we
+ ;; set a flag. Then, before sending a powershell command that is
+ ;; typed into the buffer, to the actual powershell process, we check
+ ;; that flag. If it is set, we resize the powershell window
appropriately,
+ ;; before sending the command.
+
+ ;; If we didn't do this, powershell output would get wrapped at a
+ ;; column width that would be different than the emacs buffer width,
+ ;; and everything would look ugly.
+
+ ;; get the maximum width for powershell - can't go beyond this
+ (powershell--get-max-window-width buffer)
+
+ ;; define the function for use within powershell to resize the window
+ (powershell--define-set-window-width-function proc)
+
+ ;; add the hook that sets the flag
+ (add-hook 'window-size-change-functions
+ '(lambda (&optional x)
+ (setq powershell--need-rawui-resize t)))
+
+ ;; set the flag so we resize properly the first time.
+ (setq powershell--need-rawui-resize t)
+
+ (if prompt-string
+ (progn
+ ;; This sets up a prompt for the PowerShell. The prompt is
+ ;; important because later, after sending a command to the
+ ;; shell, the scanning logic that grabs the output looks for
+ ;; the prompt string to determine that the output is complete.
+ (comint-simple-send
+ proc
+ (concat "function prompt { '" prompt-string "' }"))
+
+ (setq powershell-prompt-regex prompt-string)))
+
+ ;; 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)
+
+ ;; send a carriage-return (get the prompt)
+ (comint-send-input)
+ (accept-process-output proc))
+
+ ;; The launch hooks for powershell has not (yet?) been implemented
+ ;;(run-hooks 'powershell-launch-hook)
+
+ ;; return the buffer created
+ buffer)
+
+;; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+;; Using powershell on emacs23, I get an error:
+;;
+;; ansi-color-process-output: Marker does not point anywhere
+;;
+;; Here's what's happening.
+;;
+;; In order to be able to read the output from powershell, this shell
+;; starts powershell.exe in "interactive mode", using the -i
+;; option. This which has the curious side-effect of turning off the
+;; prompt in powershell. Normally powershell will return its results,
+;; then emit a prompt to indicate that it is ready for more input. In
+;; interactive mode it doesn't emit the prompt. To work around this,
+;; this code (powershell.el) sends an explicit `prompt` command after
+;; sending any user-entered command to powershell. This tells powershell
+;; to explicitly return the prompt, after the results of the prior
+;; command. The prompt then shows up in the powershell buffer. Lovely.
+;;
+;; But, `ansi-color-apply-on-region` gets called after every command
+;; gets sent to powershell. It gets called with args `(begin end)`,
+;; which are both markers. Turns out the very first time this fn is
+;; called, the position for the begin marker is nil.
+;;
+;; `ansi-color-apply-on-region` calls `(goto-char begin)` (effectively),
+;; and when the position on the marker is nil, the call errors with
+;; "Marker does not point anywhere."
+;;
+;; The following advice suppresses the call to
+;; `ansi-color-apply-on-region` when the begin marker points
+;; nowhere.
+(defadvice ansi-color-apply-on-region (around
+ powershell-throttle-ansi-colorizing
+ (begin end)
+ activate compile)
+ (progn
+ (let ((start-pos (marker-position begin)))
+ (cond
+ (start-pos
+ (progn
+ ad-do-it))))))
+
+(defun powershell--silent-cmd-filter (process result)
+"A process filter that captures output from a shell and stores it
+to `powershell-command-reply', rather than allowing the output to
+be displayed in the shell buffer.
+
+This function is intended for internal use only."
+ (let ((end-of-result
+ (string-match (concat ".*\n\\(" powershell-prompt-regex "\\)[
\n]*\\'")
+ result)))
+ (if (and end-of-result (numberp end-of-result))
+
+ (progn
+ ;; Store everything except the follow-on prompt.
+ ;; The result probably includes a final newline!
+ (setq result (substring result 0 (match-beginning 1)))
+
+ (if powershell-squish-results-of-silent-commands
+ (setq result
+ (replace-regexp-in-string "\n" "" result)))
+
+ (setq powershell-command-reply
+ (concat powershell-command-reply result)))
+
+ (progn
+ (if powershell-squish-results-of-silent-commands
+ (setq result
+ (replace-regexp-in-string "\n" "" result)))
+
+ (setq powershell-command-reply
+ (concat powershell-command-reply result))
+
+ ;; recurse. For very very long output, the recursion can
+ ;; cause stack overflow. Careful!
+ (accept-process-output process powershell-command-timeout-seconds)))))
+
+(defun powershell-invoke-command-silently (proc command
+ &optional timeout-seconds)
+ "In the PowerShell instance PROC, invoke COMMAND silently.
+Neither the COMMAND is echoed nor the results to the associated
+buffer. Use TIMEOUT-SECONDS as the timeout, waiting for a
+response. The COMMAND should be a string, and need not be
+terminated with a newline.
+
+This is helpful when, for example, doing setup work. Or other sneaky
+stuff, such as resetting the size of the PowerShell virtual window.
+
+Returns the result of the command, a string, without the follow-on
+command prompt. The result will probably end in a newline. This result
+is also stored in the buffer-local variable `powershell-command-reply'.
+
+In some cases the result can be prepended with the command prompt, as
+when, for example, several commands have been send in succession and the
+results of the prior command were not fully processed by the application.
+
+If a PowerShell buffer is not the current buffer, this function
+should be invoked within a call to `with-current-buffer' or
+similar in order to insure that the buffer-local values of
+`powershell-command-reply', `powershell-prompt-regex', and
+`powershell-command-timeout-seconds' are used.
+
+Example:
+
+ (with-current-buffer powershell-buffer-name
+ (powershell-invoke-command-silently
+ proc
+ command-string
+ 1.90))"
+
+ (let ((old-timeout powershell-command-timeout-seconds)
+ (original-filter (process-filter proc)))
+
+ (setq powershell-command-reply nil)
+
+ (if timeout-seconds
+ (setq powershell-command-timeout-seconds timeout-seconds))
+
+ (set-process-filter proc 'powershell--silent-cmd-filter)
+
+ ;; Send the command plus the "prompt" command. The filter
+ ;; will know the command is finished when it sees the command
+ ;; prompt.
+ ;;
+ (process-send-string proc (concat command "\nprompt\n"))
+
+ (accept-process-output proc powershell-command-timeout-seconds)
+
+ ;; output of the command is now available in powershell-command-reply
+
+ ;; Trim prompt from the beginning of the output.
+ ;; this can happen for the first command through
+ ;; the shell. I think there's a race condition.
+ (if (and powershell-command-reply
+ (string-match (concat "^" powershell-prompt-regex "\\(.*\\)\\'")
+ powershell-command-reply))
+ (setq powershell-command-reply
+ (substring powershell-command-reply
+ (match-beginning 1)
+ (match-end 1))))
+
+ ;; restore the original filter
+ (set-process-filter proc original-filter)
+
+ ;; restore the original timeout
+ (if timeout-seconds
+ (setq powershell-command-timeout-seconds old-timeout))
+
+ ;; the result:
+ powershell-command-reply))
+
+(defun powershell-delete-process (&optional proc)
+ "Delete the current buffer process or PROC."
+ (or proc
+ (setq proc (get-buffer-process (current-buffer))))
+ (and (processp proc)
+ (delete-process proc)))
+
+(defun powershell-preoutput-filter-for-prompt (string)
+ "Trim the newline from STRING, the prompt that we get back from
+powershell. This fn is set into the preoutput filters, so the
+newline is trimmed before being put into the output buffer."
+ (if (string-match (concat powershell-prompt-regex "\n\\'") string)
+ (substring string 0 -1) ;; remove newline
+ string))
+
+(defun powershell-simple-send (proc string)
+ "Override of the comint-simple-send function, with logic
+specifically designed for powershell. This just sends STRING,
+plus the prompt command.
+
+When running as an inferior shell with stdin/stdout redirected,
+powershell is in noninteractive mode. This means no prompts get
+emitted when a PS command completes. This makes it difficult for
+a comint mode to determine when the command has completed.
+Therefore, we send an explicit request for the prompt, after
+sending the actual (primary) command. When the primary command
+completes, Powershell then responds to the \"prompt\" command,
+and emits the prompt.
+
+This insures we get and display the prompt."
+ ;; Tell PowerShell to resize its virtual window, if necessary. We do
+ ;; this by calling a resize function in the PowerShell, before sending
+ ;; the user-entered command to the shell.
+ ;;
+ ;; Powershell keeps track of its \"console\", and formats its output
+ ;; according to the width it thinks it is using. This is true even when
+ ;; powershell is invoked with the - argument, which tells it to use
+ ;; stdin as input.
+
+ ;; Therefore, if the user has resized the emacs window since the last
+ ;; PowerShell command, we need to tell PowerShell to change the size
+ ;; of its virtual window. Calling that function does not change the
+ ;; size of a window that is visible on screen - it only changes the
+ ;; size of the virtual window that PowerShell thinks it is using. We
+ ;; do that by invoking the PowerShell function that this module
+ ;; defined for that purpose.
+ ;;
+ (if powershell--need-rawui-resize
+ (progn
+ (powershell--set-window-width proc)
+ (setq powershell--need-rawui-resize nil)))
+ (comint-simple-send proc (concat string "\n"))
+ (comint-simple-send proc "prompt\n"))
+
+;; Notes on TAB for completion.
+;; -------------------------------------------------------
+;; Emacs calls comint-dynamic-complete when the TAB key is pressed in a shell.
+;; This is set up in shell-mode-map.
+;;
+;; comint-dynamic-complete calls the functions in
+;; comint-dynamic-complete-functions, until one of them returns
+;; non-nil.
+;;
+;; comint-dynamic-complete-functions is a good thing to set in the mode hook.
+;;
+;; The default value for that var in a powershell shell is:
+;; (comint-replace-by-expanded-history
+;; shell-dynamic-complete-environment-variable
+;; shell-dynamic-complete-command
+;; shell-replace-by-expanded-directory
+;; comint-dynamic-complete-filename)
+
+;; (defun powershell-dynamic-complete-command ()
+;; "Dynamically complete the command at point. This function is
+;; similar to `comint-dynamic-complete-filename', except that it
+;; searches the commands from powershell and then the `exec-path'
+;; (minus the trailing Emacs library path) for completion candidates.
+
+;; Completion is dependent on the value of
+;; `shell-completion-execonly', plus those that effect file
+;; completion. See `powershell-dynamic-complete-as-command'.
+
+;; Returns t if successful."
+;; (interactive)
+;; (let ((filename (comint-match-partial-filename)))
+;; (if (and filename
+;; (save-match-data (not (string-match "[~/]" filename)))
+;; (eq (match-beginning 0)
+;; (save-excursion (shell-backward-command 1) (point))))
+;; (prog2 (message "Completing command name...")
+;; (powershell-dynamic-complete-as-command)))))
+
+;; (defun powershell-dynamic-complete-as-command ()
+;; "Dynamically complete at point as a command.
+;; See `shell-dynamic-complete-filename'. Returns t if successful."
+;; (let* ((filename (or (comint-match-partial-filename) ""))
+;; (filenondir (file-name-nondirectory filename))
+;; (path-dirs (cdr (reverse exec-path)))
+;; (cwd (file-name-as-directory (expand-file-name default-directory)))
+;; (ignored-extensions
+;; (and comint-completion-fignore
+;; (mapconcat (function (lambda (x) (concat (regexp-quote x)
"$")))
+;; comint-completion-fignore "\\|")))
+;; (dir "") (comps-in-dir ())
+;; (file "") (abs-file-name "") (completions ()))
+
+;; ;; Go thru each cmd in powershell's lexicon, finding completions.
+
+;; ;; Go thru each dir in the search path, finding completions.
+;; (while path-dirs
+;; (setq dir (file-name-as-directory (comint-directory (or (car
path-dirs) ".")))
+;; comps-in-dir (and (file-accessible-directory-p dir)
+;; (file-name-all-completions filenondir dir)))
+;; ;; Go thru each completion found, to see whether it should be used.
+;; (while comps-in-dir
+;; (setq file (car comps-in-dir)
+;; abs-file-name (concat dir file))
+;; (if (and (not (member file completions))
+;; (not (and ignored-extensions
+;; (string-match ignored-extensions file)))
+;; (or (string-equal dir cwd)
+;; (not (file-directory-p abs-file-name)))
+;; (or (null shell-completion-execonly)
+;; (file-executable-p abs-file-name)))
+;; (setq completions (cons file completions)))
+;; (setq comps-in-dir (cdr comps-in-dir)))
+;; (setq path-dirs (cdr path-dirs)))
+;; ;; OK, we've got a list of completions.
+;; (let ((success (let ((comint-completion-addsuffix nil))
+;; (comint-dynamic-simple-complete filenondir
completions))))
+;; (if (and (memq success '(sole shortest)) comint-completion-addsuffix
+;; (not (file-directory-p (comint-match-partial-filename))))
+;; (insert " "))
+;; success)))
+
;; Local Variables:
;; lexical-binding: t
;; End:
diff --git a/powershell.el b/powershell.el
deleted file mode 100644
index ba99369bdc0..00000000000
--- a/powershell.el
+++ /dev/null
@@ -1,691 +0,0 @@
-;;;; powershell.el --- run powershell as an inferior shell in emacs
-;;
-;; Author : Dino Chiesa <[email protected]>
-;; Created : 10 Apr 2008
-;; Modified : May 2010
-;; Version : 0.2.4
-;; Keywords : powershell shell ms-windows
-;; X-URL : http://www.emacswiki.org/emacs/PowerShell#toc3
-;; Last-saved : <2011-February-17 12:10:59>
-;;
-
-;;; Commentary:
-;;
-;; Run Windows PowerShell v1.0 or v2.0 as an inferior shell within
-;; Emacs. Tested with Emacs v22.2 and v23.2.
-;;
-;; To use it, M-x powershell.
-;;
-;; ==============
-;;
-;; TODO:
-;;
-;; - get TAB to do proper completion for powershell commands, filenames,
-;; etc.
-;;
-;;
-
-;;; Versions:
-;;
-;; 0.1.0 - Initial release.
-;; 0.2.4 - make powershell fn an autoload.
-;; - fixed problem where running a single shell, caused all
-;; future shells to be powershell. This meant reverting to
-;; the original value of explicit-shell-file-name after
-;; invoking `shell'.
-;; - make location of powershell specifiable, via defcustom
-;; `powershell-location-of-exe'. Also turn a few other defvar
-;; into defcustom.
-;; - fix "Marker does not point anywhere" problem in
-;; `ansi-color-apply-on-region'.
-;;
-
-;;; License:
-;;
-;; This code is distributed under the New BSD License.
-;;
-;; Copyright (c) 2008-2010, Dino Chiesa
-;; All rights reserved.
-;;
-;; Redistribution and use in source and binary forms, with or without
-;; modification, are permitted provided that the following conditions
-;; are met:
-;;
-;; Redistributions of source code must retain the above copyright
-;; notice, this list of conditions and the following disclaimer.
-;;
-;; Redistributions in binary form must reproduce the above copyright
-;; notice, this list of conditions and the following disclaimer in the
-;; documentation and/or other materials provided with the distribution.
-;;
-;; Neither the name of the author or any contributors, nor the names of
-;; any organizations they belong to, may be used to endorse or promote
-;; products derived from this software without specific prior written
-;; permission.
-;;
-;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-;; HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-;; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-;; OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-;; AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
-;; WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-;; POSSIBILITY OF SUCH DAMAGE.
-;;
-;;
-
-(require 'shell)
-
-;; TODO: set this programmatically, relying on %WINDIR%
-;;; Code:
-
-(defcustom powershell-location-of-exe
- "c:\\windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"
- "A string, providing the location of the Powershell.exe."
- :group 'powershell)
-
-(defcustom powershell-log-level 3
- "The current log level for powershell internal operations.
-0 = NONE, 1 = Info, 2 = VERBOSE, 3 = DEBUG."
- :group 'powershell)
-
-(defcustom powershell-squish-results-of-silent-commands t
-"The function `powershell-invoke-command-silently' returns the results
-of a command in a string. PowerShell by default, inserts newlines when
-the output exceeds the configured width of the powershell virtual
-window. In some cases callers might want to get the results with the
-newlines and formatting removed. Set this to true, to do that."
-:group 'powershell)
-
-(defvar powershell-prompt-regex "PS [^#$%>]+> "
- "Regexp to match the powershell prompt.
-Powershell.el uses this regex to determine when a command has
-completed. Therefore, you need to set this appropriately if you
-explicitly change the prompt function in powershell. Any value
-should include a trailing space, if the powershell prompt uses a
-trailing space, but should not include a trailing newline.
-
-The default value will match the default PowerShell prompt.")
-
-(defvar powershell-command-reply nil
- "The reply of powershell commands.
-This is retained for housekeeping purposes.")
-
-(defvar powershell--max-window-width 0
- "The maximum width of a powershell window.
-You shouldn't need to ever set this. It gets set automatically,
-once, when the powershell starts up.")
-
-(defvar powershell-command-timeout-seconds 12
- "The timeout for a powershell command.
-Powershell.el will wait this long before giving up.")
-
-(defvar powershell--need-rawui-resize t
- "No need to fuss with this. It's intended for internal use
-only. It gets set when powershell needs to be informed that
-emacs has resized its window.")
-
-(defconst powershell--find-max-window-width-command
- (concat
- "function _Emacs_GetMaxPhsWindowSize \n"
- "{\n"
- " $rawui = (Get-Host).UI.RawUI\n"
- " $mpws_exists = ($rawui | Get-Member | ? "
- "{$_.Name -eq \"MaxPhysicalWindowSize\"})\n"
- " if ($mpws_exists -eq $null) {\n"
- " \"210\" | Out-Host\n"
- " } else {\n"
- " $rawui.MaxPhysicalWindowSize.Width | Out-Host\n"
- " }\n"
- "}\n"
- "_Emacs_GetMaxPhsWindowSize\n")
- "The powershell logic to determine the max physical window width.")
-
-(defconst powershell--set-window-width-fn-name "_Emacs_SetWindowWidth"
- "The name of the function this mode defines in PowerShell to
-set the window width. Intended for internal use only.")
-
-(defconst powershell--text-of-set-window-width-ps-function
- ;; see
- ;;
http://blogs.msdn.com/lior/archive/2009/05/27/ResizePowerShellConsoleWindow.aspx
- ;;
- ;; When making the console window narrower, you mus set the window
- ;; size first. When making the console window wider, you must set the
- ;; buffer size first.
-
- (concat "function " powershell--set-window-width-fn-name
- "([string] $pswidth)\n"
- "{\n"
- ;;" \"resetting window width to $pswidth\n\" | Out-Host\n"
- " $rawui = (Get-Host).UI.RawUI\n"
- " # retrieve the values\n"
- " $bufsize = $rawui.BufferSize\n"
- " $winsize = $rawui.WindowSize\n"
- " $cwidth = $winsize.Width\n"
- " $winsize.Width = $pswidth \n"
- " $bufsize.Width = $pswidth\n"
- " if ($cwidth -lt $pswidth) {\n"
- " # increase the width\n"
- " $rawui.BufferSize = $bufsize\n"
- " $rawui.WindowSize = $winsize\n"
- " }\n"
- " elseif ($cwidth -gt $pswidth) {\n"
- " # decrease the width\n"
- " $rawui.WindowSize = $winsize\n"
- " $rawui.BufferSize = $bufsize\n"
- " }\n"
- " # destroy variables\n"
- " Set-Variable -name rawui -value $null\n"
- " Set-Variable -name winsize -value $null\n"
- " Set-Variable -name bufsize -value $null\n"
- " Set-Variable -name cwidth -value $null\n"
- "}\n\n")
-
- "The text of the powershell function that will be used at runtime to
-set the width of the virtual Window in PowerShell, as the Emacs window
-gets resized.")
-
-(defun powershell-log (level text &rest args)
- "Log a message at level LEVEL.
-If LEVEL is higher than `powershell-log-level', the message is
-ignored. Otherwise, it is printed using `message'.
-TEXT is a format control string, and the remaining arguments ARGS
-are the string substitutions (see `format')."
- (if (<= level powershell-log-level)
- (let* ((msg (apply 'format text args)))
- (message "%s" msg))))
-
-;; (defun dino-powershell-complete (arg)
-;; "do powershell completion on the given STRING. Pop up a buffer
-;; with the completion list."
-;; (interactive
-;; (list (read-no-blanks-input "\
-;; Stub to complete: ")))
-
-;; (let ((proc
-;; (get-buffer-process (current-buffer))))
-;; (comint-proc-query proc (concat "Get-Command " arg "*\n"))
-;; )
-;; )
-
-;; (defun dino-powershell-cmd-complete ()
-;; "try to get powershell completion to work."
-;; (interactive)
-;; (let ((proc
-;; (get-buffer-process (current-buffer))))
-;; ;; (comint-proc-query proc "Get-a\t")
-;; ;; (comint-simple-send proc "Get-a\t")
-;; (comint-send-string proc "Get-a\t\n")
-;; ;; (process-send-eof)
-;; )
-;; )
-
-(defun powershell--define-set-window-width-function (proc)
- "Sends a function definition to the PowerShell instance
-identified by PROC. The function sets the window width of the
-PowerShell virtual window. Later, the function will be called
-when the width of the emacs window changes."
- (if proc
- (progn
- ;;process-send-string
- (comint-simple-send
- proc
- powershell--text-of-set-window-width-ps-function))))
-
-(defun powershell--get-max-window-width (buffer-name)
- "Gets the maximum width of the virtual window for PowerShell running
-in the buffer with name BUFFER-NAME.
-
-In PowerShell 1.0, the maximum WindowSize.Width for
-PowerShell is 210, hardcoded, I believe. In PowerShell 2.0, the max
-windowsize.Width is provided in the RawUI.MaxPhysicalWindowSize
-property.
-
-This function does the right thing, and sets the buffer-local
-`powershell--max-window-width' variable with the correct value."
- (let ((proc (get-buffer-process buffer-name)))
-
- (if proc
- (with-current-buffer buffer-name
- (powershell-invoke-command-silently
- proc
- powershell--find-max-window-width-command
- 0.90)
-
- ;; store the retrieved width
- (setq powershell--max-window-width
- (if (and (not (null powershell-command-reply))
- (string-match
- "\\([1-9][0-9]*\\)[ \t\f\v\n]+"
- powershell-command-reply))
- (string-to-number (match-string 1
powershell-command-reply))
- 200)))))) ;; could go to 210, but let's use 200 to be safe
-
-(defun powershell--set-window-width (proc)
- "Run the PowerShell function that sets the RawUI width
-appropriately for a PowerShell shell.
-
-This is necessary to get powershell to do the right thing, as far
-as text formatting, when the emacs window gets resized.
-
-The function gets defined in powershell upon powershell startup."
- (let ((ps-width
- (number-to-string (min powershell--max-window-width (window-width)))))
- (progn
- ;;(process-send-string
- (comint-simple-send
- proc
- (concat powershell--set-window-width-fn-name
- "('" ps-width "')")))))
-
-(defun powershell (&optional buffer prompt-string)
- "Run an inferior PowerShell.
-If BUFFER is non-nil, use it to hold the powershell
-process. Defaults to *PowerShell*.
-
-Interactively, a prefix arg means to prompt for BUFFER.
-
-If BUFFER exists but the shell process is not running, it makes a
-new shell.
-
-If BUFFER exists and the shell process is running, just switch to
-BUFFER.
-
-If PROMPT-STRING is non-nil, sets the prompt to the given value.
-
-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*")))))
-
- (setq buffer (get-buffer-create (or buffer "*PowerShell*")))
- (powershell-log 1 "powershell starting up...in buffer %s" (buffer-name
buffer))
- (let ((tmp-shellfile explicit-shell-file-name))
- ;; set arguments for the powershell exe.
- ;; Does this need to be tunable?
-
- (setq explicit-shell-file-name powershell-location-of-exe)
- (setq explicit-powershell.exe-args '("-Command" "-" ))
- (shell buffer)
- (setq explicit-shell-file-name tmp-shellfile))
-
- ;; (powershell--get-max-window-width "*PowerShell*")
- ;; (powershell-invoke-command-silently (get-buffer-process "*csdeshell*")
- ;; "[Ionic.Csde.Utilities]::Version()" 2.9)
-
- ;; (comint-simple-send (get-buffer-process "*csdeshell*") "prompt\n")
-
- (let ((proc (get-buffer-process buffer)))
-
- (make-local-variable 'powershell-prompt-regex)
- (make-local-variable 'powershell-command-reply)
- (make-local-variable 'powershell--max-window-width)
- (make-local-variable 'powershell-command-timeout-seconds)
- (make-local-variable 'powershell-squish-results-of-silent-commands)
- (make-local-variable 'powershell--need-rawui-resize)
- (make-local-variable 'comint-prompt-read-only)
-
- ;; disallow backspace over the prompt:
- (setq comint-prompt-read-only t)
-
- ;; We need to tell powershell how wide the emacs window is, because
- ;; powershell pads its output to the width it thinks its window is.
- ;;
- ;; The way it's done: every time the width of the emacs window changes, we
- ;; set a flag. Then, before sending a powershell command that is
- ;; typed into the buffer, to the actual powershell process, we check
- ;; that flag. If it is set, we resize the powershell window
appropriately,
- ;; before sending the command.
-
- ;; If we didn't do this, powershell output would get wrapped at a
- ;; column width that would be different than the emacs buffer width,
- ;; and everything would look ugly.
-
- ;; get the maximum width for powershell - can't go beyond this
- (powershell--get-max-window-width buffer)
-
- ;; define the function for use within powershell to resize the window
- (powershell--define-set-window-width-function proc)
-
- ;; add the hook that sets the flag
- (add-hook 'window-size-change-functions
- '(lambda (&optional x)
- (setq powershell--need-rawui-resize t)))
-
- ;; set the flag so we resize properly the first time.
- (setq powershell--need-rawui-resize t)
-
- (if prompt-string
- (progn
- ;; This sets up a prompt for the PowerShell. The prompt is
- ;; important because later, after sending a command to the
- ;; shell, the scanning logic that grabs the output looks for
- ;; the prompt string to determine that the output is complete.
- (comint-simple-send
- proc
- (concat "function prompt { '" prompt-string "' }"))
-
- (setq powershell-prompt-regex prompt-string)))
-
- ;; 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)
-
- ;; send a carriage-return (get the prompt)
- (comint-send-input)
- (accept-process-output proc))
-
- ;; The launch hooks for powershell has not (yet?) been implemented
- ;;(run-hooks 'powershell-launch-hook)
-
- ;; return the buffer created
- buffer)
-
-;; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
-;; Using powershell on emacs23, I get an error:
-;;
-;; ansi-color-process-output: Marker does not point anywhere
-;;
-;; Here's what's happening.
-;;
-;; In order to be able to read the output from powershell, this shell
-;; starts powershell.exe in "interactive mode", using the -i
-;; option. This which has the curious side-effect of turning off the
-;; prompt in powershell. Normally powershell will return its results,
-;; then emit a prompt to indicate that it is ready for more input. In
-;; interactive mode it doesn't emit the prompt. To work around this,
-;; this code (powershell.el) sends an explicit `prompt` command after
-;; sending any user-entered command to powershell. This tells powershell
-;; to explicitly return the prompt, after the results of the prior
-;; command. The prompt then shows up in the powershell buffer. Lovely.
-;;
-;; But, `ansi-color-apply-on-region` gets called after every command
-;; gets sent to powershell. It gets called with args `(begin end)`,
-;; which are both markers. Turns out the very first time this fn is
-;; called, the position for the begin marker is nil.
-;;
-;; `ansi-color-apply-on-region` calls `(goto-char begin)` (effectively),
-;; and when the position on the marker is nil, the call errors with
-;; "Marker does not point anywhere."
-;;
-;; The following advice suppresses the call to
-;; `ansi-color-apply-on-region` when the begin marker points
-;; nowhere.
-(defadvice ansi-color-apply-on-region (around
- powershell-throttle-ansi-colorizing
- (begin end)
- activate compile)
- (progn
- (let ((start-pos (marker-position begin)))
- (cond
- (start-pos
- (progn
- ad-do-it))))))
-
-(defun powershell--silent-cmd-filter (process result)
-"A process filter that captures output from a shell and stores it
-to `powershell-command-reply', rather than allowing the output to
-be displayed in the shell buffer.
-
-This function is intended for internal use only."
- (let ((end-of-result
- (string-match (concat ".*\n\\(" powershell-prompt-regex "\\)[
\n]*\\'")
- result)))
- (if (and end-of-result (numberp end-of-result))
-
- (progn
- ;; Store everything except the follow-on prompt.
- ;; The result probably includes a final newline!
- (setq result (substring result 0 (match-beginning 1)))
-
- (if powershell-squish-results-of-silent-commands
- (setq result
- (replace-regexp-in-string "\n" "" result)))
-
- (setq powershell-command-reply
- (concat powershell-command-reply result)))
-
- (progn
- (if powershell-squish-results-of-silent-commands
- (setq result
- (replace-regexp-in-string "\n" "" result)))
-
- (setq powershell-command-reply
- (concat powershell-command-reply result))
-
- ;; recurse. For very very long output, the recursion can
- ;; cause stack overflow. Careful!
- (accept-process-output process powershell-command-timeout-seconds)))))
-
-(defun powershell-invoke-command-silently (proc command
- &optional timeout-seconds)
- "In the PowerShell instance PROC, invoke COMMAND silently.
-Neither the COMMAND is echoed nor the results to the associated
-buffer. Use TIMEOUT-SECONDS as the timeout, waiting for a
-response. The COMMAND should be a string, and need not be
-terminated with a newline.
-
-This is helpful when, for example, doing setup work. Or other sneaky
-stuff, such as resetting the size of the PowerShell virtual window.
-
-Returns the result of the command, a string, without the follow-on
-command prompt. The result will probably end in a newline. This result
-is also stored in the buffer-local variable `powershell-command-reply'.
-
-In some cases the result can be prepended with the command prompt, as
-when, for example, several commands have been send in succession and the
-results of the prior command were not fully processed by the application.
-
-If a PowerShell buffer is not the current buffer, this function
-should be invoked within a call to `with-current-buffer' or
-similar in order to insure that the buffer-local values of
-`powershell-command-reply', `powershell-prompt-regex', and
-`powershell-command-timeout-seconds' are used.
-
-Example:
-
- (with-current-buffer powershell-buffer-name
- (powershell-invoke-command-silently
- proc
- command-string
- 1.90))"
-
- (let ((old-timeout powershell-command-timeout-seconds)
- (original-filter (process-filter proc)))
-
- (setq powershell-command-reply nil)
-
- (if timeout-seconds
- (setq powershell-command-timeout-seconds timeout-seconds))
-
- (set-process-filter proc 'powershell--silent-cmd-filter)
-
- ;; Send the command plus the "prompt" command. The filter
- ;; will know the command is finished when it sees the command
- ;; prompt.
- ;;
- (process-send-string proc (concat command "\nprompt\n"))
-
- (accept-process-output proc powershell-command-timeout-seconds)
-
- ;; output of the command is now available in powershell-command-reply
-
- ;; Trim prompt from the beginning of the output.
- ;; this can happen for the first command through
- ;; the shell. I think there's a race condition.
- (if (and powershell-command-reply
- (string-match (concat "^" powershell-prompt-regex "\\(.*\\)\\'")
- powershell-command-reply))
- (setq powershell-command-reply
- (substring powershell-command-reply
- (match-beginning 1)
- (match-end 1))))
-
- ;; restore the original filter
- (set-process-filter proc original-filter)
-
- ;; restore the original timeout
- (if timeout-seconds
- (setq powershell-command-timeout-seconds old-timeout))
-
- ;; the result:
- powershell-command-reply))
-
-(defun powershell-delete-process (&optional proc)
- "Delete the current buffer process or PROC."
- (or proc
- (setq proc (get-buffer-process (current-buffer))))
- (and (processp proc)
- (delete-process proc)))
-
-(defun powershell-preoutput-filter-for-prompt (string)
- "Trim the newline from STRING, the prompt that we get back from
-powershell. This fn is set into the preoutput filters, so the
-newline is trimmed before being put into the output buffer."
- (if (string-match (concat powershell-prompt-regex "\n\\'") string)
- (substring string 0 -1) ;; remove newline
- string))
-
-(defun powershell-simple-send (proc string)
- "Override of the comint-simple-send function, with logic
-specifically designed for powershell. This just sends STRING,
-plus the prompt command.
-
-When running as an inferior shell with stdin/stdout redirected,
-powershell is in noninteractive mode. This means no prompts get
-emitted when a PS command completes. This makes it difficult for
-a comint mode to determine when the command has completed.
-Therefore, we send an explicit request for the prompt, after
-sending the actual (primary) command. When the primary command
-completes, Powershell then responds to the \"prompt\" command,
-and emits the prompt.
-
-This insures we get and display the prompt."
- ;; Tell PowerShell to resize its virtual window, if necessary. We do
- ;; this by calling a resize function in the PowerShell, before sending
- ;; the user-entered command to the shell.
- ;;
- ;; Powershell keeps track of its \"console\", and formats its output
- ;; according to the width it thinks it is using. This is true even when
- ;; powershell is invoked with the - argument, which tells it to use
- ;; stdin as input.
-
- ;; Therefore, if the user has resized the emacs window since the last
- ;; PowerShell command, we need to tell PowerShell to change the size
- ;; of its virtual window. Calling that function does not change the
- ;; size of a window that is visible on screen - it only changes the
- ;; size of the virtual window that PowerShell thinks it is using. We
- ;; do that by invoking the PowerShell function that this module
- ;; defined for that purpose.
- ;;
- (if powershell--need-rawui-resize
- (progn
- (powershell--set-window-width proc)
- (setq powershell--need-rawui-resize nil)))
- (comint-simple-send proc (concat string "\n"))
- (comint-simple-send proc "prompt\n"))
-
-;; Notes on TAB for completion.
-;; -------------------------------------------------------
-;; Emacs calls comint-dynamic-complete when the TAB key is pressed in a shell.
-;; This is set up in shell-mode-map.
-;;
-;; comint-dynamic-complete calls the functions in
-;; comint-dynamic-complete-functions, until one of them returns
-;; non-nil.
-;;
-;; comint-dynamic-complete-functions is a good thing to set in the mode hook.
-;;
-;; The default value for that var in a powershell shell is:
-;; (comint-replace-by-expanded-history
-;; shell-dynamic-complete-environment-variable
-;; shell-dynamic-complete-command
-;; shell-replace-by-expanded-directory
-;; comint-dynamic-complete-filename)
-
-;; (defun powershell-dynamic-complete-command ()
-;; "Dynamically complete the command at point. This function is
-;; similar to `comint-dynamic-complete-filename', except that it
-;; searches the commands from powershell and then the `exec-path'
-;; (minus the trailing Emacs library path) for completion candidates.
-
-;; Completion is dependent on the value of
-;; `shell-completion-execonly', plus those that effect file
-;; completion. See `powershell-dynamic-complete-as-command'.
-
-;; Returns t if successful."
-;; (interactive)
-;; (let ((filename (comint-match-partial-filename)))
-;; (if (and filename
-;; (save-match-data (not (string-match "[~/]" filename)))
-;; (eq (match-beginning 0)
-;; (save-excursion (shell-backward-command 1) (point))))
-;; (prog2 (message "Completing command name...")
-;; (powershell-dynamic-complete-as-command)))))
-
-;; (defun powershell-dynamic-complete-as-command ()
-;; "Dynamically complete at point as a command.
-;; See `shell-dynamic-complete-filename'. Returns t if successful."
-;; (let* ((filename (or (comint-match-partial-filename) ""))
-;; (filenondir (file-name-nondirectory filename))
-;; (path-dirs (cdr (reverse exec-path)))
-;; (cwd (file-name-as-directory (expand-file-name default-directory)))
-;; (ignored-extensions
-;; (and comint-completion-fignore
-;; (mapconcat (function (lambda (x) (concat (regexp-quote x)
"$")))
-;; comint-completion-fignore "\\|")))
-;; (dir "") (comps-in-dir ())
-;; (file "") (abs-file-name "") (completions ()))
-
-;; ;; Go thru each cmd in powershell's lexicon, finding completions.
-
-;; ;; Go thru each dir in the search path, finding completions.
-;; (while path-dirs
-;; (setq dir (file-name-as-directory (comint-directory (or (car
path-dirs) ".")))
-;; comps-in-dir (and (file-accessible-directory-p dir)
-;; (file-name-all-completions filenondir dir)))
-;; ;; Go thru each completion found, to see whether it should be used.
-;; (while comps-in-dir
-;; (setq file (car comps-in-dir)
-;; abs-file-name (concat dir file))
-;; (if (and (not (member file completions))
-;; (not (and ignored-extensions
-;; (string-match ignored-extensions file)))
-;; (or (string-equal dir cwd)
-;; (not (file-directory-p abs-file-name)))
-;; (or (null shell-completion-execonly)
-;; (file-executable-p abs-file-name)))
-;; (setq completions (cons file completions)))
-;; (setq comps-in-dir (cdr comps-in-dir)))
-;; (setq path-dirs (cdr path-dirs)))
-;; ;; OK, we've got a list of completions.
-;; (let ((success (let ((comint-completion-addsuffix nil))
-;; (comint-dynamic-simple-complete filenondir
completions))))
-;; (if (and (memq success '(sole shortest)) comint-completion-addsuffix
-;; (not (file-directory-p (comint-match-partial-filename))))
-;; (insert " "))
-;; success)))
-
-;; Local Variables:
-;; lexical-binding: t
-;; End:
-
-(provide 'powershell)
-
-;;; powershell.el ends here