Right now I use Windows box for development at work and I use Emacs, but I needed to run RStudio to run the shiny application that I was working on. I though it would be nice to run shiny app from Emacs. On windows I was not able to run ansi-term but eshell was working.
Here is a function that run shiny app if the buffer you’re in is directory that contain server.R:
(defun shiny () "run shiny R application in new shell buffer if there is displayed buffer that have shell it will use that window" (interactive) (let* ((R (concat "shiny::runApp('" default-directory "')")) (name "*shiny*") (new-buffer (get-buffer-create name)) (script-proc-buffer (apply 'make-comint-in-buffer "script" new-buffer "R" nil `("-e" ,R))) (window (get-window-with-mode '(comint-mode eshell-mode))) (script-proc (get-buffer-process script-proc-buffer))) (if window (set-window-buffer window new-buffer) (switch-to-buffer-other-window new-buffer)) (set-process-sentinel script-proc 'special-mode-sentinel))) (defun search-window-buffer (fn) "return first window for witch given function return non nil value" (let ((buffers (buffer-list)) (value)) (dolist (buffer buffers value) (let ((window (get-buffer-window buffer))) (if (and window (not value) (funcall fn buffer window)) (setq value window))))))) (defun get-window-with-mode (modes) "return window with given major modes" (search-window-buffer (lambda (buff window) ((let ((mode (with-current-buffer buffer major-mode))) (member mode modes)))))
I’ve needed to use sentinels because If I run simple eshell command it was freezing Emacs and I need to press C-g to cancel the command, it din’t kill R but it was not very good solution.
I’ve also need to update my switch to other major mode buffer, because I was using Eshell that had eshell-mode and my new shiny buffer had comint-mode, I wanted those buffers it to be treated as the same. Above I’ve defined two functions for searching windows because I was using eshell and I wanted to have R from shiny run in the same window. If you’re using ansi-term (on windows it don’t work) you can check it’s major mode and add it to the list of modes in call to get-window-with-mode.
Below is the code for switching to other buffer with same mode (it’s should be common maybe), using
(setq same-mode-alist '((eshell-mode comint-mode) (comint-mode eshell-mode))) ;; SAME BUFFER SWITCH (defun buffer-same-mode (change-buffer-fun) "execute function for next buffer with the same major mode or mode on the list in same-mode-alist variable" (let ((current-mode major-mode) (next-mode nil)) (while (not (or (eq next-mode current-mode) (member next-mode (cdr (assoc current-mode same-mode-alist))))) (funcall change-buffer-fun) (setq next-mode major-mode)))) (defun previous-buffer-same-mode () "switch to previous buffer with same mode" (interactive) (buffer-same-mode #'previous-buffer)) (defun next-buffer-same-mode () "switch to next buffer with same mode" (interactive) (buffer-same-mode #'next-buffer)) (global-set-key [C-M-tab] 'previous-buffer-same-mode) (global-set-key [C-tab] 'next-buffer-same-mode)