├── LICENSE ├── README.org └── ob-powershell.el /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rob Kiggen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | * ob-powershell 2 | 3 | Execute powershell commands from org mode source blocks. 4 | 5 | ** Setup 6 | 7 | *** Install from melpa 8 | With =use-package= just add the declaration 9 | 10 | #+begin_src emacs-lisp 11 | (use-package ob-powershell) 12 | #+end_src 13 | 14 | *** Install with straight.el 15 | #+begin_src emacs-lisp 16 | (use-package ob-powershell 17 | :straight t 18 | :commands 19 | (org-babel-execute:powershell 20 | org-babel-expand-body:powershell)) 21 | #+end_src 22 | 23 | *** Install from source 24 | - clone from github 25 | - add to load path 26 | #+begin_src emacs-lisp 27 | (add-to-list 'load-path "~/.emacs.d/lisp/ob-powershell") 28 | #+end_src 29 | 30 | - add to your =.emacs=: 31 | #+begin_src emacs-lisp 32 | (require 'ob-powershell) 33 | #+end_src 34 | 35 | *** Add powershell to babel languages 36 | 37 | #+begin_src emacs-lisp 38 | (org-babel-do-load-languages 39 | 'org-babel-load-languages 40 | (quote ( 41 | ;; ... 42 | (powershell . t)))) 43 | #+end_src 44 | 45 | *** Configure OS command 46 | On different OSs the command for Powershell differs. Configure the shell command according to the installation on you OS. 47 | 48 | #+begin_src emacs-lisp 49 | (customize-set-variable 'org-babel-powershell-os-command "pwsh") 50 | #+end_src 51 | 52 | ** Usage 53 | 54 | Add a source block with powershell language: 55 | 56 | : #+name: get-env-path 57 | : #+begin_src powershell 58 | : echo $env:path 59 | : #+end_src 60 | 61 | And execute it using =org-babel-execute-src-block=. 62 | 63 | Another example with a variable: 64 | 65 | : #+begin_src powershell :var tmp="Hello World!" 66 | : 67 | : Write-Host $tmp 68 | : 69 | : #+end_src 70 | : 71 | : #+RESULTS: 72 | : : Hello World! 73 | -------------------------------------------------------------------------------- /ob-powershell.el: -------------------------------------------------------------------------------- 1 | ;;; ob-powershell.el --- org-babel functions for powershell evaluation 2 | 3 | 4 | ;; Copyright (C) 2022 Rob Kiggen 5 | 6 | ;; Authors: Rob Kiggen 7 | ;; Chris Bilson 8 | ;; Pedro Morais 9 | ;; Maintainer: Mois Moshev 10 | ;; Version: 1.0 11 | ;; Package-Requires: ((emacs "26.1")) 12 | ;; Keywords: powershell, shell, execute, outlines, processes 13 | ;; URL: https://github.com/rkiggen/ob-powershell 14 | 15 | ;;; Commentary: 16 | 17 | ;; Org-Babel support for evaluating powershell source code. 18 | 19 | 20 | ;;; Code: 21 | (require 'ob) 22 | (require 'ob-core) 23 | (eval-when-compile (require 'cl-lib)) 24 | 25 | (declare-function org-babel--get-vars "ob" (params)) 26 | 27 | (defvar org-babel-tangle-lang-exts) 28 | (add-to-list 'org-babel-tangle-lang-exts '("powershell" . "ps1")) 29 | 30 | (defvar org-babel-default-header-args:powershell '()) 31 | 32 | (defcustom org-babel-powershell-os-command "powershell" 33 | "Shell command of the OS to use with `org-babel-execute:powershell'. 34 | Examples: 35 | - \"powershell\" 36 | - \"pwsh\" 37 | - \"pwsh-preview\"." 38 | :group 'org-babel 39 | :type 'string) 40 | 41 | (defcustom org-babel-powershell-hline-to "None" 42 | "Replace hlines in incoming tables with this when translating to powershell." 43 | :group 'org-babel 44 | :version "24.4" 45 | :package-version '(Org . "8.0") 46 | :type 'string) 47 | 48 | (defun org-babel-expand-body:powershell (body params) 49 | "Expand BODY according to PARAMS, return the expanded body." 50 | (let ((vars (org-babel--get-vars params)) 51 | (print-level nil) 52 | (print-length nil)) 53 | (if (null vars) (concat body "\n") 54 | (format "%s\n%s\n" 55 | (mapconcat 56 | (lambda (var) 57 | (format "$%s = %s" (car var) (org-babel-powershell-var-to-powershell (cdr var)))) 58 | vars "\n") 59 | body)))) 60 | 61 | (defun org-babel-powershell-var-to-powershell (var) 62 | "Convert an elisp value to a powershell variable. 63 | Convert an elisp value, VAR, into a string of powershell source code 64 | specifying a variable of the same value." 65 | (if (listp var) 66 | (concat "@(" (mapconcat #'org-babel-powershell-var-to-powershell var ", ") ")") 67 | (if (eq var 'hline) 68 | org-babel-powershell-hline-to 69 | (format 70 | (if (and (stringp var) (string-match "[\n\r]" var)) "\"\"%S\"\"" "%S") 71 | (if (stringp var) (substring-no-properties var) var))))) 72 | 73 | 74 | (defun org-babel-execute:powershell (body params) 75 | "Execute a block of Powershell code with Babel. 76 | This function is called by `org-babel-execute-src-block'." 77 | (let* ((in-file (org-babel-temp-file "powershell-" ".ps1")) 78 | (cmdline (or (cdr (assq :cmdline params)) 79 | "-NoProfile -NoLogo -NonInteractive")) 80 | (cmd (or (cdr (assq :cmd params)) 81 | org-babel-powershell-os-command))) 82 | (with-temp-file in-file 83 | (insert (org-babel-expand-body:powershell body params))) 84 | (message "cmd: %s" cmd) 85 | (message "cmdline: %s" cmdline) 86 | (message "in-file: %s" in-file) 87 | (message "body: %s" (org-babel-expand-body:powershell body params)) 88 | (org-babel-eval 89 | (concat cmd " " cmdline 90 | " -File " (org-babel-process-file-name in-file)) 91 | ""))) 92 | 93 | ;; TODO: I think I *can* support sessions in powershell and really want to... 94 | (defun org-babel-prep-session:powershell (session params) 95 | "Prepare SESSION according to the header arguments in PARAMS." 96 | (error "Sessions are not supported for Powershell")) 97 | 98 | (defun org-babel-variable-assignments:powershell (params) 99 | "Return list of powershell statements assigning the block's variables." 100 | (mapcar 101 | (lambda (pair) 102 | (org-babel-powershell--var-to-powershell (cdr pair) (car pair))) 103 | (mapcar #'cdr (org-babel--get-vars params)))) 104 | 105 | ;; helper functions 106 | 107 | (defvar org-babel-powershell--lvl 0) 108 | 109 | (defun org-babel-powershell--var-to-powershell (var &optional varn) 110 | "Convert an elisp value to a powershell variable. 111 | The elisp value, VAR, is converted to a string of powershell source code 112 | specifying a var of the same value." 113 | (if varn 114 | (let ((org-babel-powershell--lvl 0) (lvar (listp var)) prefix) 115 | (concat "$" (symbol-name varn) "=" (when lvar "\n") 116 | (org-babel-powershell--var-to-powershell var) 117 | ";\n")) 118 | (let ((prefix (make-string (* 2 org-babel-powershell--lvl) ?\ ))) 119 | (concat prefix 120 | (if (listp var) 121 | (let ((org-babel-powershell--lvl (1+ org-babel-powershell--lvl))) 122 | (concat "[\n" 123 | (mapconcat #'org-babel-powershell--var-to-powershell var "") 124 | prefix "]")) 125 | (format "${%s}" var)) 126 | (unless (zerop org-babel-powershell--lvl) ",\n"))))) 127 | 128 | (defvar org-babel-powershell-buffers '(:default . nil)) 129 | 130 | (defun org-babel-powershell-initiate-session (&optional session params) 131 | "Return nil because sessions are not supported by powershell." 132 | nil) 133 | 134 | (defvar org-babel-powershell-preface nil) 135 | 136 | (defun org-babel-powershell-evaluate (session ibody &optional result-type result-params) 137 | "Pass BODY to the Powershell process in SESSION. 138 | If RESULT-TYPE equals 'output then return a list of the outputs 139 | of the statements in BODY, if RESULT-TYPE equals 'value then 140 | return the value of the last statement in BODY, as elisp." 141 | (when session (error "Sessions are not supported for Powershell")) 142 | (let* ((body (concat org-babel-powershell-preface ibody)) 143 | (out-file (org-babel-temp-file "powershell-")) 144 | (tmp-babel-file (org-babel-process-file-name 145 | out-file 'noquote)) 146 | (in-file (org-babel-temp-file "powershell-")) 147 | (command (format "%s -File '%s'" org-babel-powershell-command in-file))) 148 | 149 | (with-temp-file in-file 150 | (insert body)) 151 | 152 | (message "body: %s" body) 153 | (message "in-file: %s" in-file) 154 | (message "out-file: %s" out-file) 155 | (message "command: %s" command) 156 | 157 | (let ((results 158 | (case result-type 159 | (output 160 | (with-temp-file out-file 161 | (insert 162 | (org-babel-eval org-babel-powershell-command body)) 163 | (buffer-string))) 164 | (value 165 | (message "evaliing now...") 166 | (org-babel-eval command body))))) 167 | (when results 168 | (org-babel-result-cond result-params 169 | (org-babel-eval-read-file out-file) 170 | (org-babel-import-elisp-from-file out-file '(16))))))) 171 | 172 | (provide 'ob-powershell) 173 | ;;; ob-powershell.el ends here 174 | --------------------------------------------------------------------------------