I'm looking for some assistance, please, further modifying the following already modified excerpt from the highlight-parentheses library: https://github.com/nschum/highlight-parentheses.el [Fn 1.]
GOAL: The goal is to use something like mapcar or dolist to automatically replace INSERT-FACE-HERE with a different face from the variable my-parens-faces each time while does a loop. The visual effect will be a rainbow coloring of parentheses based on the level of nesting.
I am removing the overlays with a post-command-hook and a function similar to remove-overlays, and then subsequently adding new overlays with the parens function below. I will not be moving any overlays -- just creating and deleting. The final version will use variables for the faces and target specific overlays for removal, but here is a sample of what it will look like: (add-hook 'post-command-hook (lambda () (remove-overlays) (parens)))
Each time while does a loop, I want to insert a different face from the variable my-parens-faces -- going in order, like dolist. For example:
while doing loop # 1: (:foreground "black" :background "cyan")
while doing loop # 2: (:foreground "blue" :background "purple")
while doing loop # 3: (:foreground "green" :background "blue")
while doing loop # 4: (:foreground "yellow" :background "purple")
while doing loop # 5: (:foreground "orange" :background "yellow")
while doing loop # 6: (:foreground "red" :background "green")
while doing loop # 7: (:foreground "pink" :background "brown")
while doing loop # 8: (:foreground "blue" :background "beige")
(defun parens ()
(let* (pos1 pos2)
(save-excursion
(condition-case err
(while (setq pos1 (cadr (syntax-ppss pos1)))
(overlay-put (make-overlay pos1 (1+ pos1)) 'face 'INSERT-FACE-HERE)
(when (setq pos2 (scan-sexps pos1 1))
(overlay-put (make-overlay (1- pos2) pos2) 'face 'INSERT-FACE-HERE)))
(error nil)) )))
(defvar my-parens-faces '(
(:foreground "black" :background "cyan")
(:foreground "blue" :background "purple")
(:foreground "green" :background "blue")
(:foreground "yellow" :background "purple")
(:foreground "orange" :background "yellow")
(:foreground "red" :background "green")
(:foreground "pink" :background "brown")
(:foreground "blue" :background "beige")))
[Footnote number 1: Reference to the highlight-parentheses library is not needed to answer this question, but the reference is being included so that proper attribute is made to the author (i.e., Nikolaj Schumacher) who inspired the parens function in this question.]
(defvar parens-mode-command-exclusions '(mwheel-scroll scroll-up scroll-down)
"List of functions that are excluded from triggering the function `parens'.")
(defvar parens-mode-syntax-table
(let ((st (make-syntax-table)))
st)
"Syntax table used while executing the function `parens'.")
(defgroup parens nil
"Faces for highlighting parentheses in `parens-mode'."
:group 'parens)
(defface parens-one-face
'((t (:foreground "magenta")))
"Face for `parens-one-face'."
:group 'parens)
(defface parens-two-face
'((t (:foreground "red")))
"Face for `parens-two-face'."
:group 'parens)
(defface parens-three-face
'((t (:foreground "yellow")))
"Face for `parens-three-face'."
:group 'parens)
(defface parens-four-face
'((t (:foreground "green")))
"Face for `parens-four-face'."
:group 'parens)
(defface parens-five-face
'((t (:foreground "cyan")))
"Face for `parens-five-face'."
:group 'parens)
(defface parens-six-face
'((t (:foreground "orange")))
"Face for `parens-six-face'."
:group 'parens)
(defface parens-seven-face
'((t (:foreground "purple")))
"Face for `parens-seven-face'."
:group 'parens)
(defface parens-eight-face
'((t (:foreground "blue")))
"Face for `parens-eight-face'."
:group 'parens)
(defface parens-nine-face
'((t (:foreground "brown")))
"Face for `parens-nine-face'."
:group 'parens)
(defface parens-ten-face
'((t (:foreground "white")))
"Face for `parens-ten-face'."
:group 'parens)
(defvar parens-overlays-exist-p nil
"Simple test to see whether the parens overlays have been placed.")
(make-variable-buffer-local 'parens-overlays-exist-p)
(defun parens ()
"Portions of this function were borrowed from the library
`highlight-parentheses` written by Nikolaj Schumacher.
https://github.com/nschum/highlight-parentheses.el"
(unless (memq this-command parens-mode-command-exclusions)
(with-syntax-table parens-mode-syntax-table
(let* (
(pt (point))
(pos1 (if
(or
(= pt (point-min))
(eq (preceding-char) 40) ;; open-parentheses
(eq (preceding-char) 91) ;; open-squre-bracket
(eq (preceding-char) 123)) ;; open-wavy-bracket
pt
(1- pt)))
pos2
selected-face
(i 0) )
(remove-parens-overlays)
(save-excursion
(condition-case nil
(while (setq pos1 (cadr (syntax-ppss pos1)))
(if (= i 10)
(setq i 1)
(setq i (1+ i)))
(cond
((= i 1)
(setq selected-face 'parens-one-face))
((= i 2)
(setq selected-face 'parens-two-face))
((= i 3)
(setq selected-face 'parens-three-face))
((= i 4)
(setq selected-face 'parens-four-face))
((= i 5)
(setq selected-face 'parens-five-face))
((= i 6)
(setq selected-face 'parens-six-face))
((= i 7)
(setq selected-face 'parens-seven-face))
((= i 8)
(setq selected-face 'parens-eight-face))
((= i 9)
(setq selected-face 'parens-nine-face))
((= i 10)
(setq selected-face 'parens-ten-face)) )
(overlay-put (make-overlay pos1 (1+ pos1)) 'face selected-face)
(when (setq pos2 (scan-sexps pos1 1))
(overlay-put (make-overlay (1- pos2) pos2) 'face selected-face)))
(error nil) ))
(setq parens-overlays-exist-p t)))))
(defun remove-parens-overlays ()
(when parens-overlays-exist-p
(dolist (face '(
parens-one-face
parens-two-face
parens-three-face
parens-four-face
parens-five-face
parens-six-face
parens-seven-face
parens-eight-face
parens-nine-face
parens-ten-face))
(remove-overlays nil nil 'face face))
(setq parens-overlays-exist-p nil)))
(defun turn-off-parens-mode ()
(parens-mode -1))
(define-minor-mode parens-mode
"A minor-mode for highlighting parentheses."
:init-value nil
:lighter " ‹›"
:keymap nil
:global nil
:group 'parens
(cond
(parens-mode
(add-hook 'post-command-hook 'parens t t)
(add-hook 'change-major-mode-hook 'turn-off-parens-mode nil t)
(when (called-interactively-p 'any)
(message "Turned ON `parens-mode`.")))
(t
(remove-hook 'post-command-hook 'parens t)
(remove-hook 'change-major-mode-hook 'turn-off-parens-mode t)
(remove-parens-overlays)
(when (called-interactively-p 'any)
(message "Turned OFF `parens-mode`.")))))
Related
How can I color entries in ibuffer accoding to the buffer type ?
Based on which mode the buffer is - for example python mode is blue, lisp mode is yellow etc ...
Is this possible ?
Building on the comment from #lawlist, here's some sample code you could use and tweak to your liking:
(setq ibuffer-fontification-alist
'((1 (eq major-mode 'c++-mode) yellow-face)
(1 (eq major-mode 'fundamental-mode) green-face)
(1 (member major-mode '(shell-mode sh-mode)) purple-face)
(1 (eq major-mode 'tcl-mode) brown-face)))
(defface yellow-face '((t :foreground "yellow")) "")
(defface green-face '((t :foreground "green")) "")
(defface purple-face '((t :foreground "black")) "")
(defface brown-face '((t :foreground "brown")) "")
Obviously you can use existing faces, or create new ones (like in this example). See the manual for faces for more information.
I am trying to make my powerline have a custom color for the second section.
The code I am using is this:
(require 'powerline)
(defface my-pl-segment1-active
'((t (:foreground "#3C3F41" :background "#3C3F41")))
"Powerline first segment active face.")
(defface my-pl-segment1-inactive
'((t (:foreground "#3C3F41" :background "#3C3F41")))
"Powerline first segment inactive face.")
(defface my-pl-segment2-active
'((t (:foreground "#4fddb0" :background "#4fddb0")))
"Powerline third segment active face.")
(defface my-pl-segment2-inactive
'((t (:foreground "#4fddb0" :background "#4fddb0")))
"Powerline third segment inactive face.")
(defface my-pl-segment3-active
'((t (:foreground "#3C3F41" :background "#3C3F41")))
"Powerline second segment active face.")
(defface my-pl-segment3-inactive
'((t (:foreground "#3C3F41" :background "#3C3F41")))
"Powerline second segment inactive face.")
;; My custom powerline theme: see <https://github.com/milkypostman/powerline/blob/master/powerline-themes.el> to get your own.
(defun my-powerline-theme ()
"Setup the default mode-line."
(interactive)
(setq-default mode-line-format
'("%e"
(:eval
(let* ((active (powerline-selected-window-active))
(mode-line (if active 'my-pl-segment1-active 'my-pl-segment1-inactive))
(face1 (if active 'my-pl-segment2-active 'my-pl-segment2-inactive))
(face2 (if active 'my-pl-segment3-active 'my-pl-segment3-inactive))
(separator-left (intern (format "powerline-%s-%s"
(powerline-current-separator)
(car powerline-default-separator-dir))))
(separator-right (intern (format "powerline-%s-%s"
(powerline-current-separator)
(cdr powerline-default-separator-dir))))
(lhs (list (powerline-raw "%*" nil 'l)
(when powerline-display-buffer-size
(powerline-buffer-size nil 'l))
(when powerline-display-mule-info
(powerline-raw mode-line-mule-info nil 'l))
(powerline-buffer-id nil 'l)
(when (and (boundp 'which-func-mode) which-func-mode)
(powerline-raw which-func-format nil 'l))
(powerline-raw " ")
(funcall separator-left mode-line face1)
(when (boundp 'erc-modified-channels-object)
(powerline-raw erc-modified-channels-object face1 'l))
(powerline-major-mode face1 'l)
(powerline-process face1)
(powerline-minor-modes face1 'l)
(powerline-narrow face1 'l)
(powerline-raw " " face1)
(funcall separator-left face1 face2)
(powerline-vc face2 'r)
(when (bound-and-true-p nyan-mode)
(powerline-raw (list (nyan-create)) face2 'l))))
(rhs (list (powerline-raw global-mode-string face2 'r)
(funcall separator-right face2 face1)
(unless window-system
(powerline-raw (char-to-string #xe0a1) face1 'l))
(powerline-raw "%4l" face1 'l)
(powerline-raw ":" face1 'l)
(powerline-raw "%3c" face1 'r)
(funcall separator-right face1 mode-line)
(powerline-raw " ")
(powerline-raw "%6p" nil 'r)
(when powerline-display-hud
(powerline-hud face2 face1)))))
(concat (powerline-render lhs)
(powerline-fill face2 (powerline-width rhs))
(powerline-render rhs)))))))
(my-powerline-theme)
The basic problem I'm having is that the 'my-pl-segment2-active :background is affecting the text color and the color of the seperator. Is there a way to separate them?
Picture where 'my-pl-segment2-active :background is black:
Picture where 'my-pl-segment2-active :backgroune is the same as the foreground (#4fddb0):
You need to add an additional face, where the background represents the background color and the foreground does absolutely nothing.
Declare it next to (face2 (if active 'my-pl-segment2-active my-pl-segment2-inactive)). (Ex: (newface (if active 'my-pl-fixed-face-active my-pl-fixed-face-inactive)))
Then replace face1 in the lines that contain "separator" with the name of the new face (as you wrote in step 2.) (Ex: (funcall separator-right face2 face1) => (funcall separator-right face2 newface))
I'm trying to define some emacs font faces to do some custom highlighting. This seems to work when I define them individually:
(defface my-r-face `((t (:foreground "red"))) "Red highlight")
(defvar m-r-face 'my-r-face "Red.")
(defface my-g-face `((t (:foreground "green"))) "Green highlight")
(defvar m-g-face 'my-g-face "Green.")
(defface my-b-face `((t (:foreground "#0088ff"))) "Blue highlight")
(defvar m-b-face 'my-b-face "Blue.")
....etc
However I have a few dozen of these and I want to define them all in one go from some kind of colour table:
(setq ctable '(("red" "r")
("orange" "o")
("yellow" "y")
("#88ff00" "gy")
("green" "g")
("#00ff88" "gc")
("cyan" "c")
("#0088ff" "bc")
("blue" "b")
("purple" "bm")
("magenta" "m")
("#ff0088" "rm")
("grey" "lg")
("white" "w") ))
My difficulty is with assembling the symbol names for each face, ie concatenating "my-" and "-face" onto either side of an entry from the table. I have discovered (intern) that can make a new symbol from a string, however this symbol is then not acceptable to (defface), as it seems what I am doing is equivalent to (defface 'my-r-face ..., and defface doesn't like the quoted symbol, and expects (defface my-r-face .. instead. My attempt is as follows:
(dolist (tpl ctable)
(defvar (intern (concat "my-" (nth 1 tpl) "-face"))
(quote (intern (concat "my-" (nth 1 tpl) "-face"))) "colour")
(defface (intern (concat "my-" (nth 1 tpl) "-face"))
`((t (:foreground ,(car tpl)))) "Highlight" :group 'fortran)
)
Running this results in
Lisp error: (wrong-type-argument symbolp (intern (concat "fegs-" (nth 1 tpl) "-face")))
(defvar (intern (concat "fegs-" ... "-face")) (quote (intern ...)) "colour")
Can anyone shed some light on what I'm doing wrong, or if I'm barking up the wrong tree entirely and there is a better way of doing this?
Thanks.
You can avoid eval:
(defconst my-ctable '(...))
(defmacro my-init-cfaces ()
`(progn
,#(mapcar (lambda (tpl)
`(defface ,(intern (format "my-%s-face" (nth 1 tpl)))
'((t :foreground ,(car tpl)))
,(format "Face for color %s." (car tpl))
:group 'fortran))
my-ctable)))
(my-init-cfaces)
defvar is an special form, defface is a macro (so arguments are passed unevaluated). Have you tried to use something in the line of
(eval `(defface ,(intern "foo") '((t (:foreground "red"))) "Highlight" :group 'fortran))
(eval `(defvar ,(intern "bar")))
The complete code that worked in the end is as follows:
(setq ctable '(("red" "r")
("orange" "o")
("yellow" "y")
("#88ff00" "gy")
("green" "g")
("#00ff88" "gc")
("cyan" "c")
("#0088ff" "bc")
("blue" "b")
("purple" "bm")
("magenta" "m")
("#ff0088" "rm")
("grey" "lg")
("white" "w") ))
(dolist (tpl ctable)
(let ((fname (concat "fegs-" (nth 1 tpl) "-face")))
(eval `(defface ,(intern fname) '((t (:foreground ,(car tpl)))) "Highlight" :group 'fortran))
(eval `(defvar ,(intern fname) ',(intern fname)))
)
)
My defvar line is slightly different as this allows the face to be picked up by the highlighting code elsewhere as a global variable.
Is there a way to dynamically change the color of the mode-line depending on specific conditions e.g. change color if I'm in narrowed view and to a different color if the buffer is read-only
Thank you very much!
You can use a post-command-hook and then just evaluate whatever you need and set the mode-line face color. I do this to change between 3 colors depending on which evil-mode state I'm in and if the buffer has any unsaved changes.
(lexical-let ((default-color (cons (face-background 'mode-line)
(face-foreground 'mode-line))))
(add-hook 'post-command-hook
(lambda ()
(let ((color (cond ((minibufferp) default-color)
((evil-insert-state-p) '("#e80000" . "#ffffff"))
((evil-emacs-state-p) '("#af00d7" . "#ffffff"))
((buffer-modified-p) '("#006fa0" . "#ffffff"))
(t default-color))))
(set-face-background 'mode-line (car color))
(set-face-foreground 'mode-line (cdr color))))))
I use this code. It colors the buffer-modified indicator on the left orange if it's read-only and red if it's modified. When you narrow a buffer it colors the line number indicator yellow. Obviously you might want to change the format yourself.
(defface my-narrow-face
'((t (:foreground "black" :background "yellow3")))
"todo/fixme highlighting."
:group 'faces)
(defface my-read-only-face
'((t (:foreground "black" :background "orange3")))
"Read-only buffer highlighting."
:group 'faces)
(defface my-modified-face
'((t (:foreground "gray80" :background "red4")))
"Modified buffer highlighting."
:group 'faces)
(setq-default
mode-line-format
'(" "
(:eval (let ((str (if buffer-read-only
(if (buffer-modified-p) "%%*" "%%%%")
(if (buffer-modified-p) "**" "--"))))
(if buffer-read-only
(propertize str 'face 'my-read-only-face)
(if (buffer-modified-p)
(propertize str 'face 'my-modified-face)
str))))
(list 'line-number-mode " ")
(:eval (when line-number-mode
(let ((str "L%l"))
(if (/= (buffer-size) (- (point-max) (point-min)))
(propertize str 'face 'my-narrow-face)
str))))
" %p"
(list 'column-number-mode " C%c")
" " mode-line-buffer-identification
" " mode-line-modes))
How can I configure a different background color for the active window in Emacs?
Try Yoshida's hiwin-mode (visible active window mode): https://github.com/yoshida-mediba/hiwin-mode
If by "window" you mean Emacs' definition of windows, i.e., panes, not really.
If by "window" you mean everyone else's conception of windows, which Emacs calls frames, then yes. Here's an example:
(defadvice handle-switch-frame (around switch-frame-set-background)
(set-background-color "white")
ad-do-it
(set-background-color "yellow"))
(ad-activate 'handle-switch-frame)
(defadvice delete-frame (after delete-frame-set-background)
(set-background-color "yellow"))
(ad-activate 'delete-frame)
Here is an alternative using the modeline inactive color matching the background so the only modeline with color is the active window. I have a hooks for the minibuffer enter and exit, and also when switching windows. I use bold for certain modeline things like read only and the file name, so that the a different color doesn't stand out when switching windows. When I enter the minibuffer, the active window modeline turns to inactive until I exit the minibuffer, or when I switch from an active minibuffer (leaving it open) to another window. I had to set the modeline background box to match also.
(set-face-attribute 'default nil :background "black" :foreground "white"
:font "Courier" :height 180)
(set-face-attribute 'mode-line nil
:height 160 ;; affects everything
:foreground "black" :background "gray70")
(set-face-attribute 'mode-line-inactive nil
:foreground "gray70" :background "black" :box '(:line-width 1 :color "black"))
(defun enter-minibuffer-setup ()
(whitespace-mode t)
(set-face-attribute 'mode-line nil
:height 160 :foreground "gray70" :background "black" :box '(:line-width 1 :color "black"))
(set-face-attribute 'minibuffer-prompt nil :background "black" :foreground "cyan")
(set (make-local-variable 'face-remapping-alist)
'((default :background "black" :foreground "yellow"))) )
(defun exit-minibuffer-setup ()
(cond
((or save-as-variable multi-extract-variable multi-attach-variable)
(set-face-attribute 'mode-line nil :height 160 :foreground "black" :background "#eab700"))
(t (set-face-attribute 'mode-line nil :height 160 :foreground "black" :background "gray70" :box nil)))
(set-face-attribute 'minibuffer-prompt nil :background "black" :foreground "cyan"))
(add-hook 'minibuffer-setup-hook 'enter-minibuffer-setup)
(add-hook 'minibuffer-exit-hook 'exit-minibuffer-setup)
(defun lawlist-minibuffer-conditions ()
(cond
((minibufferp)
(set-face-attribute 'mode-line nil
:height 160 :foreground "gray70" :background "black" :box '(:line-width 1 :color "black"))
(set-face-attribute 'minibuffer-prompt nil :background "black" :foreground "cyan"))
(t
(set-face-attribute 'mode-line nil
:height 160 :foreground "black" :background "gray70")
(set-face-attribute 'minibuffer-prompt nil :background "black" :foreground "gray70")) ))
(defun lawlist-forward-window ()
(interactive)
(other-window 1)
(lawlist-minibuffer-conditions))
(defun lawlist-backward-window ()
(interactive)
(other-window -1)
(lawlist-minibuffer-conditions))
ALTERNATIVE ANSWER (similar concept): set-face-attribute is too slow for changing faces during redisplay. The preferred method for adjusting faces in that context is with the function face-remap-add-relative; however, that function is a little complicated to use because faces stack up one behind the other and get shadowed. So, I'll need to revise the following draft alternative answer (in the future) to incorporate face-remap-add-relative -- in the meantime, I'm setting the face-remapping-alist manually (which admittedly is not the preferred method according to the manual / doc-string).
(defvar modeline-selected-window nil)
(let ((default-background (face-background 'default nil 'default)))
(set-face-attribute 'mode-line-inactive nil :background default-background :box nil))
(defun modeline-record-selected-window ()
(setq modeline-selected-window (selected-window)))
(defun modeline-update-function ()
(cond
((minibufferp)
(let ((default-background (face-background 'default nil 'default)))
(with-selected-window (minibuffer-window)
(setq-local face-remapping-alist '(
(default :foreground "blue")
(minibuffer-prompt :foreground "red"))))
(setq-default face-remapping-alist `((mode-line ,'mode-line-inactive)))))
(t
(with-selected-window (minibuffer-window)
(when (local-variable-p 'face-remapping-alist)
(kill-local-variable 'face-remapping-alist)))
(setq-default face-remapping-alist nil))))
(defun modeline-set-format ()
(setq mode-line-format '(
(:eval
(if (eq modeline-selected-window (selected-window))
(propertize "SELECTED WINDOW" 'face 'font-lock-warning-face)
(propertize "NOT-SELECTED WINDOW" 'face 'font-lock-keyword-face)))))
;; next two lines make the affect immediately apparent
(setq modeline-selected-window (selected-window))
(force-mode-line-update))
(define-minor-mode modeline-mode
"This is a minor-mode for `modeline-mode`."
:init-value nil
:lighter " ML"
:keymap nil
:global t
:group nil
(cond
(modeline-mode
(add-hook 'post-command-hook 'modeline-record-selected-window)
(add-hook 'buffer-list-update-hook 'modeline-update-function)
(add-hook 'text-mode-hook 'modeline-set-format)
(when (called-interactively-p 'any)
(message "Globally turned ON `modeline-mode`.")))
(t
(remove-hook 'post-command-hook 'modeline-record-selected-window)
(remove-hook 'buffer-list-update-hook 'modeline-update-function)
(remove-hook 'text-mode-hook 'modeline-set-format)
(when (called-interactively-p 'any)
(message "Globally turned OFF `modeline-mode`.") ))))
(modeline-mode 1) ;; globally turn on minor-mode
If what you are trying to achieve is to highlight the current buffer/frame, the way I do that is through Highlight-Current-Line. It shows you the line where the cursor is, but a side effect of that is that it also shows you which buffer/frame you are in. You could configure it to highlight the entire buffer, or look into the code to see how they do it.
Crosshairs mode is your best bet, I think. It not only draws attention to the active window, but it also shows you immediately where the cursor is in an obvious way. You can easily toggle it on/off (I bind it to C-+.)
You can also use crosshairs-toggle-when-idle as an alternative. It does not show the crosshairs until a delay has past. It too is a toggle.
You can of course use crosshairs together with an in-your-face mode-line face.
I was using hiwin-mode as suggested in this topic but there is an open issue with shell buffers (when inactive, the text becomes invisible).
Therefore, another option which I'm enjoying so far is auto-dim-other-buffers mode.