Emacs: how to break out of ido minibuffer? - emacs

I'm generally using ido-switch-buffer, but sometimes when there are too many candidates,
helm-buffers-list is preferable. But it's a hassle to break out of ido,
call helm and re-enter the lost information.
So I wrote this code, that re-uses information entered in ido directly in helm:
(require 'helm-buffers)
(defun switch-to-helm-buffers-list ()
"Emulate `helm-buffers-list' call with ido contents as initial input."
(interactive)
(let ((str (minibuffer-contents-no-properties)))
(helm :sources '(helm-source-buffers-list
helm-source-ido-virtual-buffers
helm-source-buffer-not-found)
:buffer "*helm buffers*"
:keymap helm-buffer-map
:truncate-lines t
:input str)
;; (ido-exit-minibuffer)
))
(add-hook
'ido-setup-hook
(lambda()
(define-key ido-buffer-completion-map "\C-i"
'switch-to-helm-buffers-list)))
One problem is that ido is left to linger in the minibuffer.
When I add a call ido-exit-minibuffer before helm, it's not called.
And when I add it after, it resets the window configuration.
How can I solve this problem?

See answer https://stackoverflow.com/a/21165658/1937596
First, I patch your function a little.
(require 'helm-buffers)
(defun switch-to-helm-buffers-list ()
"Emulate `helm-buffers-list' call with ido contents as initial input."
(interactive)
(let ((str ido-text))
(helm :sources '(helm-source-buffers-list
helm-source-ido-virtual-buffers
helm-source-buffer-not-found)
:buffer "*helm buffers*"
:keymap helm-buffer-map
:truncate-lines t
:input str)
))
My recipe patches the body of function ido-buffer-internal (internal for ido-switch-buffer) too.
You have to execute this code once.
(eval
(read
(replace-regexp-in-string
"cond"
"cond ((eq ido-exit 'eab-ido-helm) (call-interactively 'switch-to-helm-buffers-list)) "
(save-window-excursion
(find-function-do-it 'ido-buffer-internal nil 'switch-to-buffer)
(let ((bgn (point)))
(forward-sexp)
(let ((end (point)))
(buffer-substring-no-properties bgn end)))))))
And I add one auxiliary function.
(defun eab/ido-helm ()
(interactive)
(setq ido-exit 'eab-ido-helm)
(exit-minibuffer))
Note, I use eab/ido-helm instead of switch-to-helm-buffers-list in define-key.
(add-hook
'ido-setup-hook
(lambda()
(define-key ido-buffer-completion-map "\C-i"
'eab/ido-helm)))

Here's what I've come up with. No patching required.
(define-key ido-buffer-completion-map "\C-i" 'ido-buffer-helm)
(defvar ibh-initial nil)
(defun ibh-hook ()
(when ibh-initial
(let ((str ibh-initial))
(setq ibh-initial)
(helm :sources '(helm-source-buffers-list
helm-source-ido-virtual-buffers
helm-source-buffer-not-found)
:buffer "*helm buffers*"
:keymap helm-buffer-map
:truncate-lines t
:input str)))
(remove-hook 'post-command-hook 'ibh-hook))
(require 'delsel)
(defun ido-buffer-helm ()
(interactive)
(setq ibh-initial ido-text)
(add-hook 'post-command-hook 'ibh-hook)
(minibuffer-keyboard-quit))

Related

Generate quoted symbol in Emacs Lisp macro

I am creating a simple macro to disable show trailing whitespace in certain major modes (I will loop this macro in a dolist loop later):
(defmacro non-trailing-whitespaces-modes (mode)
(let ((hook (intern (concat mode "-mode-hook"))))
`(add-hook ,hook (lambda () (setq show-trailing-whitespace nil)))))
After this macroexpand: (macroexpand '(non-trailing-whitespaces-modes "eshell")), the result is
(add-hook eshell-mode-hook
(lambda nil
(setq show-trailing-whitespace nil)))
I want eshell-mode-hook to be 'eshell-mode-hook, otherwise it will cause error.
Simply change the body of the macro to begin (add-hook ',hook ...)
No need for a macro, here:
(defun non-trailing-whitespaces-modes (mode)
(let ((hook (intern (concat mode "-mode-hook"))))
(add-hook hook (lambda () (setq show-trailing-whitespace nil)))))

emacs 24.x Recursive 'require' for feature 'magit-simple-keys'

I've just upgraded my whole distro and I'm trying to setup my emacs with my previous settings and when using my 'magit' plugin and typing 'M-x magit-status' I get the following error:
Recursive `require' for feature `magit-simple-keys'
Here is my config (.emacs.d/init.el)
(require 'package)
(add-to-list 'package-archives '("elpa" . "http://tromey.com/elpa/"))
(add-to-list 'package-archives
'("marmalade" . "http://marmalade-repo.org/packages/") t)
(package-initialize)
(setq required-packages
(list 'mwe-log-commands 'drag-stuff 'flymake-ruby 'flymake-haml 'regex-tool 'mic-paren 'highline 'android-mode 'css-mode 'csv-mode 'apache-mode 'crontab-mode 'emms 'switch-window 'multi-term 'undo-tree 'rvm 'auto-complete 'yasnippet-bundle 'ruby-electric 'rinari 'inf-ruby 'coffee-mode 'yaml-mode 'feature-mode 'scss-mode 'haml-mode 'magit-simple-keys))
(dolist (package required-packages)
(when (not (package-installed-p package))
(package-refresh-contents)
(package-install package)))
;; Setup external directory variable
(setq elisp-dir
(expand-file-name "elisp" user-emacs-directory))
(setq elisp-external-dir
(expand-file-name "external" elisp-dir))
;; Add external projects to load path
(add-to-list 'load-path elisp-external-dir)
(dolist (project (directory-files elisp-external-dir t "\\w+"))
(when (file-directory-p project)
(add-to-list 'load-path project)))
; Keybinding
(global-set-key [f1] 'twit)
(global-set-key [f2] 'gist-region-or-buffer)
(global-set-key [f3] 'switch-window)
(global-set-key [f4] 'magit-display-log)
(global-set-key [f5] 'magit-status)
(global-set-key [f6] 'multi-term)
(global-set-key [f7] 'split-window-vertically)
(global-set-key [f8] 'next-multiframe-window)
;; f9 is taken by git-status somewhere.
(global-set-key [f10] 'undo-tree-visualize)
(global-set-key [f12] 'switch-full-screen)
(global-set-key (kbd "C-x f") 'rinari-find-file-in-project)
(global-set-key (kbd "C-x g") 'rinari-rgrep)
(global-set-key (kbd "C-c I") 'irc)
;fullscreen mode
(defun switch-full-screen ()
(interactive)
(shell-command "wmctrl -r :ACTIVE: -btoggle,fullscreen"))
;; Allow using mouse thumb button to browse URLs
(global-set-key [mouse-10] 'browse-url-at-mouse)
; stop emacs from contaminating each directory with semantic.cache
(setq semanticdb-default-save-directory "/tmp")
; General settings
(setq-default tab-width 4)
(menu-bar-mode 1) ;; enable the menu bar
(tool-bar-mode -1) ; Disable tool-bar
(display-battery-mode)
(setq column-number-mode t)
(display-time)
(setq backup-inhibited t) ;; disable backup
;; Org-mode options
(add-hook 'org-mode-hook 'turn-on-visual-line-mode)
;; (add-hook 'org-mode-hook 'my-org-mode-autosave-settings)
;; (defun my-org-mode-autosave-settings ()
;; (set (make-local-variable 'auto-save-visited-file-name) t)
;; (setq auto-save-interval 20))
(add-to-list 'auto-mode-alist '("\\.org$" . org-mode))
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(setq org-agenda-files '("~/Dropbox/org/"))
(setq org-directory "~/Dropbox/org")
(setq org-mobile-inbox-for-pull "~/Dropbox/org/inbox.org");; new notes will be stored here
(setq org-support-shift-select t)
(setq org-mobile-directory "~/Dropbox/MobileOrg") ;; Set to <your Dropbox root directory>/MobileOrg.
;; Set color
(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(default ((t (:inherit nil :stipple nil :background "black" :foreground "white" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 98 :width normal :foundry "unknown" :family "DejaVu Sans Mono")))))
; Auto complete settings
(setq hippie-expand-try-functions-list
'(try-complete-abbrev
try-complete-file-name
try-expand-dabbrev))
; -------------------- Custom Settings --------------------
(custom-set-variables
;; custom-set-variables was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(column-number-mode t)
'(display-battery-mode t)
'(display-time-mode t)
'(ecb-options-version "2.32")
'(inhibit-startup-screen t)
'(org-agenda-files (quote ("~/Dropbox/org")) t)
'(rails-ws:default-server-type "mongrel")
'(send-mail-function (quote smtpmail-send-it))
'(smtpmail-smtp-server "smtp.googlemail.com")
'(smtpmail-smtp-service "smtp")
'(tool-bar-mode nil)
'(tooltip-mode nil))
; -------------------- File plugins --------------------
; Interactively Do Things
(ido-mode t)
; tramp - remote ssh editing
(require 'tramp)
(setq tramp-default-method "ssh")
; -------------------- Rails setting files --------------------
(require 'yaml-mode)
(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
; -------------------- Rails minor plugin --------------------
(setq x-select-enable-clipboard t)
(setq interprogram-paste-function 'x-cut-buffer-or-selection-value)
;; https://github.com/remvee/emacs-rails
;; Currently this interfers with auto complete, using rinari instead
;; automatically adds end to blocks.
(require 'rails)
;; Rinari - Rails plugin
(add-to-list 'load-path "~/.emacs.d/rinari/")
(require 'rinari)
(add-hook 'ruby-mode-hook
(lambda ()
(defadvice ruby-mode-set-encoding
(around ruby-mode-set-encoding-disable activate) nil)))
; -------------------- Rails Views --------------------
; haml-sass
(require 'haml-mode nil 't)
(add-hook 'haml-mode-hook
'(lambda () (setq tab-width 2)))
(setq scss-compile-at-save nil)
; stylesheets
(autoload 'css-mode "css-mode")
(setq auto-mode-alist (cons '("\\.css\\'" . css-mode) auto-mode-alist))
; html2haml function to convert current buffer to haml
(defun haml-ify ()
"run html2haml on current buffer"
(interactive)
(setf filename buffer-file-name)
(setf newfilename (concat filename ".haml"))
(save-buffer)
(shell-command (concat
"html2haml " filename " > " newfilename))
(kill-buffer (current-buffer))
(delete-file filename)
(find-file newfilename))
;; -------------------- Rails Testing --------------------
;; Cucumber
(require 'feature-mode)
;; -------------------- Rails Tools --------------------
;; Check out abbrev-mode instead as it seems lighter.
(require 'snippet)
;; -------------------- Ruby plugins --------------------
(add-to-list 'auto-mode-alist '("Capfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Gemfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("Rakefile" . ruby-mode))
(add-to-list 'auto-mode-alist '("god" . ruby-mode))
(add-to-list 'auto-mode-alist '("Guardfile" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.rake\\'" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.rb\\'" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.ru\\'" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.html.erb\\'" . html-mode))
(add-to-list 'auto-mode-alist '("\\.ejs\\'" . html-mode))
(add-to-list 'auto-mode-alist '("\\.eco\\'" . html-mode))
(add-to-list 'auto-mode-alist '("\\.hamlc\\'" . haml-mode))
;; Ruby-electric
(require 'ruby-electric)
(add-hook 'ruby-mode-hook 'ruby-electric-mode)
;; Issues under some compiles of emacs
;; (require 'ruby-electric)
;; (add-hook 'ruby-mode-hook
;; (lambda()
;; (add-hook 'local-write-file-hooks
;; '(lambda()
;; (save-excursion
;; (untabify (point-min) (point-max))
;; ;(delete-trailing-whitespace)
;; )))
;; (set (make-local-variable 'indent-tabs-mode) 'nil)
;; (set (make-local-variable 'tab-width) 2)
;; (imenu-add-to-menubar "IMENU")
;; (require 'ruby-electric)
;; (ruby-electric-mode t)))
;; Inferior Ruby Mode
(autoload 'inf-ruby "inf-ruby" "Run an inferior Ruby process" t)
(autoload 'inf-ruby-keys "inf-ruby" "" t)
(eval-after-load 'ruby-mode '(add-hook 'ruby-mode-hook 'inf-ruby-keys))
;; -------------------- SQL --------------------
(defun my-sql-interactive-mode-hook ()
(setq tab-width 8))
(add-hook 'sql-interactive-mode-hook 'my-sql-interactive-mode-hook)
(require 'sql)
(put 'upcase-region 'disabled nil)
;; -------------------- Autocomplete --------------------
;; Use with Rsense for Ruby autocomplete:
;; http://cx4a.org/software/rsense/
;; Follow instructions on: http://itstickers.blogspot.com/2010/11/all-about-emacs.html
(require 'auto-complete-config)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/ac-dict")
(ac-config-default)
;; Rsense
(setq rsense-home "/opt/rsense-0.3")
(add-to-list 'load-path (concat rsense-home "/etc"))
(require 'rsense)
;; Rsense + Autocomplete
(add-hook 'ruby-mode-hook
(lambda ()
(add-to-list 'ac-sources 'ac-source-rsense-method)
(add-to-list 'ac-sources 'ac-source-rsense-constant)))
;; Complete by C-c .
(add-hook 'ruby-mode-hook
(lambda ()
(local-set-key (kbd "C-c .") 'rsense-complete)))
;; RVM in emacs
;; (require 'rvm)
;; (rvm-use-default) ;; use rvm’s default ruby for the current Emacs session
;; Switch windows easier when you have 3 or more.
(require 'switch-window)
;; gist
(require 'gist)
(setq gist-authentication-function 'gist-basic-authentication)
(setq the-secrets-file
(expand-file-name "secrets.el" user-emacs-directory))
(when (file-exists-p the-secrets-file)
(load the-secrets-file))
;; highline-mode
(require 'highline)
(defun highline-mode-on ()
(highline-mode 1))
;; Turn on local highlighting for Dired (C-x d)
(add-hook 'dired-after-readin-hook #'highline-mode-on)
;; Turn on local highlighting for list-buffers (C-x C-b)
(defadvice list-buffers (after highlight-line activate) (save-excursion (set-buffer "*Buffer List*") (highline-mode-on)))
;; mic-paren - advanced highlighting of matching parentheses
(paren-activate)
;; flyspell
(add-hook 'org-mode-hook
(lambda ()
(flyspell-mode)
(setq flyspell-issue-message-flag 'nil)))
(add-hook 'ruby-mode-hook
(lambda ()
(flyspell-prog-mode)
(setq flyspell-issue-message-flag 'nil)))
;; flymake haml
(add-hook 'haml-mode-hook 'flymake-haml-load)
;; undo
(add-hook 'ruby-mode-hook 'undo-tree-mode)
;; multi-term
;; (setq term-default-fg-color "#aaa")
;; Upgrade all packages
(defun package-update-all ()
"Update all packages"
(interactive)
(dolist (elt package-alist)
(let* ((name (car elt))
(file-name (symbol-name name))
(available-pkg (assq name package-archive-contents))
(available-version (and available-pkg
(package-desc-vers (cdr available-pkg))))
(current-version (package-desc-vers (cdr elt)))
)
(when (and available-version
(version-list-< current-version available-version))
(message "Updating to: %s - %s" file-name
(package-version-join available-version))
(package-install name)
(package-delete file-name (package-version-join current-version))))))
;; Music player
(add-to-list 'load-path "~/.emacs.d/elisp/external/bongo")
(setq bongo-global-lastfm-mode t)
(autoload 'bongo "bongo"
"Start Bongo by switching to a Bongo buffer." t)
;; Volume manager (Use 'v' in bongo music player)
(add-to-list 'load-path "~/.emacs.d/elisp/external/volume-el")
(autoload 'volume "volume"
"Tweak your sound card volume." t)
;; Twitter mode
(add-to-list 'load-path "~/.emacs.d/elisp/external/twitter-mode")
(require 'twittering-mode)
(setq twittering-icon-mode t)
(setq twittering-timer-interval 40)
(setq twittering-url-show-status nil)
(add-hook 'twittering-edit-mode-hook (lambda () (ispell-minor-mode) (flyspell-mode)))
(setq twittering-use-master-password t) ;; Don't prompt for authorisation.
;; drag-stuff
(require 'drag-stuff)
;; coffee-mode
(defun coffee-custom ()
"coffee-mode-hook"
(set (make-local-variable 'tab-width) 2))
;; (define-key coffee-mode-map [(meta r)] 'coffee-compile-buffer)
;; (define-key coffee-mode-map [(meta R)] 'coffee-compile-region)
(add-hook 'coffee-mode-hook
'(lambda() (coffee-custom)))
;; Don't ask to save abbrevs
(setq save-abbrevs 'silently)
;; log commands.
;; M-x mwe:open-command-log-buffer
(add-hook 'LaTeX-mode-hook (function mwe:log-keyboard-commands))
;; screensaver
(setq zone-when-idle t)
;; IRC reconnect
(eval-after-load 'rcirc
'(defun-rcirc-command reconnect (arg)
"Reconnect the server process."
(interactive "i")
(unless process
(error "There's no process for this target"))
(let* ((server (car (process-contact process)))
(port (process-contact process :service))
(nick (rcirc-nick process))
channels query-buffers)
(dolist (buf (buffer-list))
(with-current-buffer buf
(when (eq process (rcirc-buffer-process))
(remove-hook 'change-major-mode-hook
'rcirc-change-major-mode-hook)
(if (rcirc-channel-p rcirc-target)
(setq channels (cons rcirc-target channels))
(setq query-buffers (cons buf query-buffers))))))
(delete-process process)
(rcirc-connect server port nick
rcirc-default-user-name
rcirc-default-full-name
channels))))
;; Video editor
;; (load "~/.emacs.d/elisp/external/gneve.el")
The problem was I only need to install 'magit not 'magit-simple-keys.
I am going to guess that you need to update one or other of magit and magit-simple-keys (and you might as well do both).
I can see that you are installing magit-simple-keys via package.el, but not magit itself, so you might want to source magit from there too in order to try to keep the versions synchronised.

How can I execute a lisp function while pressing prefix key C-h and then let Emacs continue the normal processing of C-h?

I want to execute a lisp function while pressing prefix key C-h and then let Emacs continue the normal processing of C-h.
How can I do it?
Thank you!
Evaluating
(key-binding [(control h)])
I found out the command bound is help-command. You can use an "around" defadvice to run your code. See manual.
(defvar smart-ime--state 'normal)
(defvar smart-ime--debug nil)
(defvar smart-ime--ena-prefix-override-keymap nil)
(defvar smart-ime--prefix-override-keymap (make-sparse-keymap))
(defvar smart-ime--keymaps-initialized nil)
(defvar smart-ime--keymap-alist
`(
(smart-ime--ena-prefix-override-keymap . ,smart-ime--prefix-override-keymap)
)
)
(defun smart-ime--init-keymaps ()
(define-key smart-ime--prefix-override-keymap [(control x)] 'smart-ime--prefix-override-handler)
(define-key smart-ime--prefix-override-keymap [(control c)] 'smart-ime--prefix-override-handler)
(define-key smart-ime--prefix-override-keymap [(control h)] 'smart-ime--prefix-override-handler)
)
(defun smart-ime--prefix-override-handler (arg)
(interactive "P")
(smart-ime--prefix-override-replay arg))
;; the most important part
(defun smart-ime--prefix-override-replay (arg)
(let* ((keys (this-command-keys))
(i (length keys))
(key (aref keys (1- i))))
(ime-save-and-set-status 0)
(add-hook 'post-command-hook 'smart-ime--post-command-handler)
(setq smart-ime--state 'prefix)
(setq smart-ime--ena-prefix-override-keymap nil)
;; Don't record this command
(setq this-command last-command)
;; Restore the prefix arg
(setq prefix-arg arg)
(reset-this-command-lengths)
;; Push the key back on the event queue
(setq unread-command-events (cons key unread-command-events))))
(defun smart-ime--post-command-handler-1 ()
(cond ((eq smart-ime--state 'prefix)
(setq smart-ime--state 'sequence))
((eq smart-ime--state 'sequence)
(ime-restore-status)
(setq smart-ime--ena-prefix-override-keymap t)
(setq smart-ime--state 'normal)
(remove-hook 'post-command-hook 'smart-ime--post-command-handler)))
(t
(error "error state")))
(defun smart-ime--post-command-handler ()
(when smart-ime-mode
(condition-case nil
(smart-ime--post-command-handler-1)
(error nil))))
(define-minor-mode smart-ime-mode
"Toggle Smart IME mode."
:init-value nil
:lighter " SmartIME"
:global t
(unless smart-ime--keymaps-initialized
(smart-ime--init-keymaps)
(setq smart-ime--keymaps-initialized t))
(unless smart-ime-mode
(remove-hook 'post-command-hook 'smart-ime--post-command-handler))
(if (not smart-ime-mode)
(setq emulation-mode-map-alists (delq 'smart-ime--keymap-alist emulation-mode-map-alists))
(add-to-ordered-list 'emulation-mode-map-alists 'smart-ime--keymap-alist 400)
(setq smart-ime--ena-prefix-override-keymap t))
)
;;; Announce
(provide 'smart-ime)

Word wrap for Emacs print buffer to PDF

I use this function for printing a buffer's content to PDF
(from my .emacs file:)
(defun print-to-pdf ()
(interactive)
(ps-spool-buffer-with-faces)
(switch-to-buffer "*PostScript*")
(write-file "/tmp/tmp.ps")
(kill-buffer "tmp.ps")
(setq cmd (concat "ps2pdf14 /tmp/tmp.ps /home/user/" (buffer-name) ".pdf"))
(shell-command cmd)
(shell-command "rm /tmp/tmp.ps")
(message (concat "Saved to: /home/user/" (buffer-name) ".pdf"))
)
I cannot, however, find a way to enable or apply the visual-line minor mode to the PostScript buffer before it gets written to disk so to enable word wrap in the output.
The problem with getting visual line mode to be respected is that it inserts "soft newlines" (which get ignored by the PS renderer). A solution is to replace these with hard newlines. The code below does what you want, I think. Note that we call harden-newlines in a temporary buffer so as not to mess up the current document. Also, I've changed the output destination to always land in /tmp/print.pdf. It seems... unwise to overwrite documents in your /home without any sort of warning! You can always move the PDF afterwards.
Anyway, here you go. Is this what you wanted?
(defun harden-newlines ()
(interactive)
"Make all the newlines in the buffer hard."
(save-excursion
(goto-char (point-min))
(while (search-forward "\n" nil t)
(backward-char)
(put-text-property (point) (1+ (point)) 'hard t)
(forward-char))))
(defun spool-buffer-given-name (name)
(load "ps-print")
(let ((tmp ps-left-header))
(unwind-protect
(progn
(setq ps-left-header
(list (lambda () name) 'ps-header-dirpart))
(ps-spool-buffer-with-faces))
(setf ps-left-header tmp))))
(defun print-to-pdf ()
"Print the current file to /tmp/print.pdf"
(interactive)
(let ((wbuf (generate-new-buffer "*Wrapped*"))
(sbuf (current-buffer)))
(jit-lock-fontify-now)
(save-current-buffer
(set-buffer wbuf)
(insert-buffer sbuf)
(longlines-mode t)
(harden-newlines)
(spool-buffer-given-name (buffer-name sbuf))
(kill-buffer wbuf)
(switch-to-buffer "*PostScript*")
(write-file "/tmp/print.ps")
(kill-buffer (current-buffer)))
(call-process "ps2pdf14" nil nil nil
"/tmp/print.ps" "/tmp/print.pdf")
(delete-file "/tmp/print.ps")
(message "PDF saved to /tmp/print.pdf")))

How to have colors in the output of (emacs) shell-command?

When executing the command shell-command, the output shown in the associated buffer is not colorized.
This is particularly annoying when calling a testing framework (outputting yellow/green/red...) from within emacs.
How can I configure, or extend, emacs in order to have shell-command allowing colorized output in the shell and preserving the colors while representing that output?
Thanks!
ps. I'm using the Bash shell, on a UN*X system.
This is probably what you want :
(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
You can implement your own shell-execute, something like
(defun my-shell-execute(cmd)
(interactive "sShell command: ")
(shell (get-buffer-create "my-shell-buf"))
(process-send-string (get-buffer-process "my-shell-buf") (concat cmd "\n")))
This adds an advice to run ansi-color-apply-on-region on the minibuffer after shell-command finishes:
(require 'ansi-color)
(defun ansi-color-apply-on-buffer ()
(ansi-color-apply-on-region (point-min) (point-max)))
(defun ansi-color-apply-on-minibuffer ()
(let ((bufs (remove-if-not
(lambda (x) (string-starts-with (buffer-name x) " *Echo Area"))
(buffer-list))))
(dolist (buf bufs)
(with-current-buffer buf
(ansi-color-apply-on-buffer)))))
(defun ansi-color-apply-on-minibuffer-advice (proc &rest rest)
(ansi-color-apply-on-minibuffer))
(advice-add 'shell-command :after #'ansi-color-apply-on-minibuffer-advice)
;; (advice-remove 'shell-command #'ansi-color-apply-on-minibuffer-advice)
It does not rely on shell-mode or comint. I accompany it with something like the following to get nice test output (a green smiley with the count of successful doctests.
(defun add-test-function (cmd)
(interactive "sCommand to run: ")
(setq my-testall-test-function cmd)
(defun my-testall ()
(interactive)
(shell-command my-testall-test-function))
(local-set-key [f9] 'my-testall))
This solution is inspired by #ArneBabenhauserheide's but uses xterm-color instead of ansi-color. It also colorizes the *Shell Command Output* buffer as well as the mini
(defun xterm-color-colorize-shell-command-output ()
"Colorize `shell-command' output."
(let ((bufs
(seq-remove
(lambda (x)
(not (or (string-prefix-p " *Echo Area" (buffer-name x))
(string-prefix-p "*Shell Command" (buffer-name x)))))
(buffer-list))))
(dolist (buf bufs)
(with-current-buffer buf
(xterm-color-colorize-buffer)))))
(defun xterm-color-colorize-shell-command-output-advice (proc &rest rest)
(xterm-color-colorize-shell-command-output))
(advice-add 'shell-command :after #'xterm-color-colorize-shell-command-output-advice)
;; (advice-remove 'shell-command #'xterm-color-colorize-shell-command-output-advice)