summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore12
l---------README.org1
-rw-r--r--config.org287
-rw-r--r--dracula-custom-theme.el53
-rw-r--r--init.el44
-rw-r--r--lisp/rainbow-delimiters.el310
6 files changed, 707 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c1d2d1e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+config.el
+custom-vars.el
+ido.last
+smex-items
+.last-package-update-day
+
+auto-save-list
+elpa
+transient
+lisp/**
+
+!lisp/rainbow-delimiters.el
diff --git a/README.org b/README.org
new file mode 120000
index 0000000..f13833e
--- /dev/null
+++ b/README.org
@@ -0,0 +1 @@
+config.org \ No newline at end of file
diff --git a/config.org b/config.org
new file mode 100644
index 0000000..0ab91ee
--- /dev/null
+++ b/config.org
@@ -0,0 +1,287 @@
+* Terminal
+
+** Setting default shell to zsh
+#+begin_src emacs-lisp
+ (defvar my-term-shell "/usr/bin/zsh")
+ (defadvice ansi-term (before force-bash)
+ (interactive (list my-term-shell)))
+ (ad-activate 'ansi-term)
+ (global-set-key (kbd "<s-C-return>") 'ansi-term)
+#+end_src
+
+* QoL section
+Some quality-of-life improvements
+
+** Enable line number
+Certain modes will break with line-numbers-mode (e.g. ansi-term) so I'm only enabling it
+on some major modes rather than globally
+#+begin_src emacs-lisp
+ (add-hook 'prog-mode-hook 'display-line-numbers-mode)
+ (add-hook 'text-mode-hook 'display-line-numbers-mode)
+#+end_src
+
+** Show parent parentheses
+#+begin_src emacs-lisp
+ (show-paren-mode 1)
+#+end_src
+
+** Enable rainbow-delimiters in all programming modes
+#+begin_src emacs-lisp
+ (add-hook 'prog-mode-hook 'rainbow-delimiters-mode)
+#+end_src
+
+** Disable default startup screen
+#+begin_src emacs-lisp
+ (setq inhibit-startup-message t)
+#+end_src
+
+** Disable most GUI elements
+#+begin_src emacs-lisp
+ (tool-bar-mode -1)
+ (menu-bar-mode -1)
+ (scroll-bar-mode -1)
+#+end_src
+
+** Enable copy-pasting outside of emacs
+#+begin_src emacs-lisp
+ (setq x-select-enable-clipboard t)
+#+end_src
+
+** Disable automatic creation of backup files
+#+begin_src emacs-lisp
+ (setq make-backup-files nil)
+ (setq auto-save-default nil)
+#+end_src
+
+** Enable conservative scrolling
+#+begin_src emacs-lisp
+ (setq scroll-conservatively 100)
+#+end_src
+
+** Disable ring-bell
+#+begin_src emacs-lisp
+ (setq ring-bell-function 'ignore)
+#+end_src
+
+** Indentation
+#+begin_src emacs-lisp
+ (setq-default tab-width 4)
+ (setq-default standard-indent 4)
+ (setq c-basic-offset tab-width)
+ (setq-default electric-indent-inhibit t)
+ (setq-default indent-tabs-mode t)
+ (setq backward-delete-char-untabify-method 'nil)
+#+end_src
+
+** Enable prettify symbols
+#+begin_src emacs-lisp
+ (global-prettify-symbols-mode t)
+#+end_src
+
+** Enable pair-matching
+#+begin_src emacs-lisp
+ (electric-pair-mode t)
+#+end_src
+
+** Creating new window automatically focuses it
+#+begin_src emacs-lisp
+ (defun split-and-follow-horizontally ()
+ (interactive)
+ (split-window-below)
+ (balance-windows)
+ (other-window 1))
+ (global-set-key (kbd "C-x 2") 'split-and-follow-horizontally)
+
+ (defun split-and-follow-vertically ()
+ (interactive)
+ (split-window-right)
+ (balance-windows)
+ (other-window 1))
+ (global-set-key (kbd "C-x 3") 'split-and-follow-vertically)
+#+end_src
+
+** Change yes/no prompt to just y/n
+#+begin_src emacs-lisp
+ (defalias 'yes-or-no-p 'y-or-n-p)
+#+end_src
+
+** More comfortable resize bindings
+#+begin_src emacs-lisp
+ (global-set-key (kbd "s-C-<left>") 'shrink-window-horizontally)
+ (global-set-key (kbd "s-C-<right>") 'enlarge-window-horizontally)
+ (global-set-key (kbd "s-C-<down>") 'shrink-window)
+ (global-set-key (kbd "s-C-<up>") 'enlarge-window)
+#+end_src
+
+** Highlight current line
+#+begin_src emacs-lisp
+ (global-hl-line-mode t)
+#+end_src
+
+** Enable ido mode
+#+begin_src emacs-lisp
+ (setq ido-enable-flex-matching nil)
+ (setq ido-create-new-buffer 'always)
+ (setq ido-everywhere t)
+ (setq ido-vertical-define-keys 'C-n-and-C-p-only)
+ (ido-mode 1)
+#+end_src
+
+** Change default buffer-list
+I hate the default buffer list. I'm using ido-switch-buffer on "C-x C-b" and
+ibuffer on "C-x b"
+
+#+begin_src emacs-lisp
+ (global-set-key (kbd "C-x C-b") 'ido-switch-buffer)
+ (global-set-key (kbd "C-x b") 'ibuffer)
+#+end_src
+
+* Org mode
+Defining sensible org-mode defaults
+
+#+begin_src emacs-lisp
+ (use-package org
+ :config
+ (add-hook 'org-mode-hook 'org-indent-mode)
+ (add-hook 'org-mode-hook
+ #'(lambda ()
+ (visual-line-mode 1))))
+
+ (use-package org-indent
+ :diminish org-indent-mode)
+
+ (use-package htmlize
+ :ensure t)
+#+end_src
+
+* Custom functions
+
+** Toggle transparency
+#+begin_src emacs-lisp
+ (defun toggle-transparency()
+ (interactive)
+ (let ((alpha (frame-parameter nil 'alpha)))
+ (set-frame-parameter
+ nil 'alpha
+ (if (eql (cond ((numberp alpha) alpha)
+ ((numberp (cdr alpha)) (cdr alpha))
+ ;; Also handle undocumented (<active> <inactive>) form.
+ ((numberp (cadr alpha)) (cadr alpha)))
+ 100)
+ '(80 . 80) '(100 . 100)))))
+ (global-set-key (kbd "C-c t") 'toggle-transparency)
+#+end_src
+
+** Config edit/reload
+
+*** edit
+#+begin_src emacs-lisp
+ (defun config-visit ()
+ (interactive)
+ (find-file "~/.emacs.d/config.org"))
+ (global-set-key (kbd "C-c e") 'config-visit)
+#+end_src
+
+*** reload
+#+begin_src emacs-lisp
+ (defun config-reload ()
+ (interactive)
+ (org-babel-load-file (expand-file-name "~/.emacs.d/config.org")))
+ (global-set-key (kbd "C-c r") 'config-reload)
+#+end_src
+
+* Use-Package section
+
+** Initialize =auto-package-update=
+
+*** Description
+Auto-package-update automatically updates and removes old packages
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package auto-package-update
+ :defer nil
+ :ensure t
+ :config
+ (setq auto-package-update-delete-old-versions t)
+ (setq auto-package-update-hide-results t)
+ (auto-package-update-maybe))
+#+end_src
+
+** Initialize =diminish=
+
+*** Description
+Hides minor modes to prevent cluttering mode line
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package diminish
+ :ensure t)
+#+end_src
+
+** Initialize =which-key=
+
+*** Description
+Completion menu for keybinds
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package which-key
+ :ensure t
+ :diminish which-key-mode
+ :init
+ (which-key-mode))
+#+end_src
+
+** Initialize =ido-vertical-mode=
+
+*** Description
+Uses a vertical mini-buffer for ido, instead of a horizontal one
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package ido-vertical-mode
+ :ensure t
+ :init
+ (ido-vertical-mode 1))
+#+end_src
+
+** Initialize =smex=
+
+*** Description
+Vertical buffer for interactive commands, similar to ido-vertical
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package smex
+ :ensure t
+ :init (smex-initialize)
+ :bind
+ ("M-x" . smex))
+#+end_src
+
+** Initialize =avy=
+
+*** Description
+Go to char
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package avy
+ :ensure t
+ :bind
+ ("M-s" . avy-goto-char))
+#+end_src
+
+** Initialize =rainbow-mode=
+
+*** Description
+Displays colour of a hex-code as background-colour behind said hex-code
+
+*** Code
+#+begin_src emacs-lisp
+ (use-package rainbow-mode
+ :ensure t
+ :init
+ (add-hook 'css-mode-hook #'rainbow-mode 1))
+#+end_src
diff --git a/dracula-custom-theme.el b/dracula-custom-theme.el
new file mode 100644
index 0000000..d9b3949
--- /dev/null
+++ b/dracula-custom-theme.el
@@ -0,0 +1,53 @@
+(deftheme dracula-custom
+ "Created 2022-11-27.")
+
+(custom-theme-set-faces
+ 'dracula-custom
+ '(cursor ((t (:background "#ccccc7"))))
+ '(fixed-pitch ((t (:family "Monospace"))))
+ '(variable-pitch ((((type w32)) (:foundry "outline" :family "Arial")) (t (:family "Sans Serif"))))
+ '(escape-glyph ((((background dark)) (:foreground "cyan")) (((type pc)) (:foreground "magenta")) (t (:foreground "brown"))))
+ '(homoglyph ((((background dark)) (:foreground "cyan")) (((type pc)) (:foreground "magenta")) (t (:foreground "brown"))))
+ '(minibuffer-prompt ((t (:weight bold :foreground "#ff79c6"))))
+ '(highlight ((t (:foreground "#ccccc7" :background "#464752"))))
+ '(region ((t (:extend t :inherit (match)))))
+ '(shadow ((t (:foreground "#6272a4"))))
+ '(secondary-selection ((((class color) (min-colors 88) (background light)) (:extend t :background "yellow1")) (((class color) (min-colors 88) (background dark)) (:extend t :background "SkyBlue4")) (((class color) (min-colors 16) (background light)) (:extend t :background "yellow")) (((class color) (min-colors 16) (background dark)) (:extend t :background "SkyBlue4")) (((class color) (min-colors 8)) (:extend t :foreground "black" :background "cyan")) (t (:inverse-video t))))
+ '(trailing-whitespace ((t (:background "#ffb86c"))))
+ '(font-lock-builtin-face ((t (:slant italic :foreground "#8be9fd"))))
+ '(font-lock-comment-delimiter-face ((t (:inherit (shadow)))))
+ '(font-lock-comment-face ((t (:inherit (shadow)))))
+ '(font-lock-constant-face ((t (:foreground "#bd93f9"))))
+ '(font-lock-doc-face ((t (:foreground "#6272a4"))))
+ '(font-lock-doc-markup-face ((t (:inherit (font-lock-constant-face)))))
+ '(font-lock-function-name-face ((t (:weight bold :foreground "#50fa7b"))))
+ '(font-lock-keyword-face ((t (:foreground "#ff79c6" :weight bold))))
+ '(font-lock-negation-char-face ((t (:foreground "#8be9fd"))))
+ '(font-lock-preprocessor-face ((t (:foreground "#ffb86c"))))
+ '(font-lock-regexp-grouping-backslash ((t (:foreground "#8be9fd"))))
+ '(font-lock-regexp-grouping-construct ((t (:foreground "#bd93f9"))))
+ '(font-lock-string-face ((t (:foreground "#f1fa8c"))))
+ '(font-lock-type-face ((t (:inherit (font-lock-builtin-face)))))
+ '(font-lock-variable-name-face ((t (:foreground "#d8a5f8" :weight bold))))
+ '(font-lock-warning-face ((t (:background "#373844" :inherit (warning)))))
+ '(button ((t (:inherit (link)))))
+ '(link ((t (:underline (:color foreground-color :style line) :foreground "#8be9fd"))))
+ '(link-visited ((default (:inherit (link))) (((class color) (background light)) (:foreground "magenta4")) (((class color) (background dark)) (:foreground "violet"))))
+ '(fringe ((t (:foreground "#b6b6b2" :background "#282a36"))))
+ '(header-line ((t (:inherit 'mode-line))))
+ '(tooltip ((t (:foreground "#f8f8f2" :background "#44475a"))))
+ '(mode-line ((t (:box (:line-width (1 . 1) :color "#44475a" :style nil) :inverse-video nil :foreground "#f8f8f2" :background "#44475a"))))
+ '(mode-line-buffer-id ((t (:weight bold))))
+ '(mode-line-emphasis ((t (:weight bold))))
+ '(mode-line-highlight ((((supports :box t) (class color) (min-colors 88)) (:box (:line-width (2 . 2) :color "grey40" :style released-button))) (t (:inherit (highlight)))))
+ '(mode-line-inactive ((t (:box (:line-width (1 . 1) :color "#373844" :style nil) :inverse-video nil :foreground "#b6b6b2" :background "#282a36"))))
+ '(isearch ((t (:weight bold :inherit (match)))))
+ '(isearch-fail ((t (:foreground "#282a36" :background "#ffb86c"))))
+ '(lazy-highlight ((t (:foreground "#e2e2dc" :background "#373844"))))
+ '(match ((t (:foreground "#282a36" :background "#f1fa8c"))))
+ '(next-error ((t (:inherit (region)))))
+ '(query-replace ((t (:inherit (isearch)))))
+ '(default ((t (:family "Hack Nerd Font" :foundry "SRC" :width normal :height 113 :weight normal :slant normal :underline nil :overline nil :extend nil :strike-through nil :box nil :inverse-video nil :foreground "#F8F8F2" :background "#262626" :stipple nil :inherit nil)))))
+
+(provide-theme 'dracula-custom)
+
diff --git a/init.el b/init.el
new file mode 100644
index 0000000..123c374
--- /dev/null
+++ b/init.el
@@ -0,0 +1,44 @@
+;; set load-path
+(add-to-list 'load-path "~/.emacs.d/lisp")
+
+;; Make emacs startup faster
+(setq gc-cons-threshold 402653184
+ gc-cons-percentage 0.6)
+
+(defvar startup/file-name-handler-alist file-name-handler-alist)
+(setq file-name-handler-alist nil)
+
+(defun startup/revert-file-name-handler-alist ()
+ (setq file-name-handler-alist startup/file-name-handler-alist))
+
+(defun startup/reset-gc ()
+ (setq gc-cons-threshold 16777216
+ gc-cons-percentage 0.1))
+
+(add-hook 'emacs-startup-hook 'startup/revert-file-name-handler-alist)
+(add-hook 'emacs-startup-hook 'startup/reset-gc)
+;;
+
+;; Initialize melpa repo
+(require 'package)
+(setq package-enable-at-startup nil)
+(add-to-list 'package-archives
+ '("melpa" . "https://melpa.org/packages/"))
+(package-initialize)
+
+;; Initialize use-package
+(unless (package-installed-p 'use-package)
+ (package-refresh-contents)
+ (package-install 'use-package))
+
+;; Initialize rainbow-delimiters
+(require 'rainbow-delimiters)
+
+(set-default-file-modes #o700)
+
+(load-theme 'dracula-custom t)
+
+(org-babel-load-file (expand-file-name "~/.emacs.d/config.org"))
+
+(setq custom-file (locate-user-emacs-file "custom-vars.el"))
+(load custom-file 'noerror 'nomessage)
diff --git a/lisp/rainbow-delimiters.el b/lisp/rainbow-delimiters.el
new file mode 100644
index 0000000..8d89868
--- /dev/null
+++ b/lisp/rainbow-delimiters.el
@@ -0,0 +1,310 @@
+;;; rainbow-delimiters.el --- Highlight brackets according to their depth -*- lexical-binding: t -*-
+
+;; Copyright (C)
+;; 2010-2013 Jeremy Rayman
+;; 2013-2021 Fanael Linithien
+;; Author: Jeremy Rayman <opensource@jeremyrayman.com>
+;; Fanael Linithien <fanael4@gmail.com>
+;; Maintainer: Fanael Linithien <fanael4@gmail.com>
+;; Created: 2010-09-02
+;; Version: 2.1.5
+;; Keywords: faces, convenience, lisp, tools
+;; Homepage: https://github.com/Fanael/rainbow-delimiters
+
+;; Note: despite `lexical-binding', there's no Emacs 24 dependency.
+;; This is merely an optimization for Emacs 24+, the code is supposed to work
+;; with *both* dynamic and lexical binding.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Installation:
+
+;; The recommended way is to use MELPA (http://melpa.org/) or MELPA Stable
+;; (http://stable.melpa.org/). If either is in your `package-archives', do
+;; M-x package-install RET rainbow-delimiters RET
+;; Otherwise, open `rainbow-delimiters.el' in Emacs and use
+;; M-x package-install-from-buffer
+;; Any other methods of installation are unsupported.
+
+;;; Commentary:
+;;
+;; Rainbow-delimiters is a "rainbow parentheses"-like mode which highlights
+;; parentheses, brackets, and braces according to their depth. Each
+;; successive level is highlighted in a different color. This makes it easy
+;; to spot matching delimiters, orient yourself in the code, and tell which
+;; statements are at a given level.
+;;
+;; Great care has been taken to make this mode fast. You shouldn't see
+;; any discernible change in scrolling or editing speed while using it,
+;; even in delimiter-rich languages like Clojure, Lisp, and Scheme.
+;;
+;; Usage:
+;;
+;; To toggle the mode in the current buffer:
+;; M-x rainbow-delimiters-mode
+;; To start the mode automatically in `foo-mode', add the following to your init
+;; file:
+;; (add-hook 'foo-mode-hook #'rainbow-delimiters-mode)
+;; To start the mode automatically in most programming modes (Emacs 24 and
+;; above):
+;; (add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
+;;
+;; Customization:
+;;
+;; To customize various options, including the color theme:
+;; M-x customize-group rainbow-delimiters
+;;
+;; You can specify custom colors by customizing following faces:
+;; - Faces take the form `rainbow-delimiters-depth-N-face', with N being the
+;; depth. Depth begins at 1, the outermost color. Faces exist for depths 1-9.
+;; - The unmatched delimiter face: `rainbow-delimiters-unmatched-face'.
+;; - The mismatched delimiter face: `rainbow-delimiters-mismatched-face'.
+
+;;; Code:
+
+(defgroup rainbow-delimiters nil
+ "Highlight nested parentheses, brackets, and braces according to their depth."
+ :prefix "rainbow-delimiters-"
+ :link '(url-link :tag "Website for rainbow-delimiters"
+ "https://github.com/Fanael/rainbow-delimiters")
+ :group 'applications)
+
+(defgroup rainbow-delimiters-faces nil
+ "Faces for successively nested pairs of delimiters.
+
+When depth exceeds innermost defined face, colors cycle back through."
+ :group 'rainbow-delimiters
+ :group 'faces
+ :link '(custom-group-link "rainbow-delimiters")
+ :prefix "rainbow-delimiters-")
+
+(defcustom rainbow-delimiters-pick-face-function
+ #'rainbow-delimiters-default-pick-face
+ "The function used to pick a face used to highlight a delimiter.
+The function should take three arguments (DEPTH MATCH LOC), where:
+ - DEPTH is the delimiter depth; when zero or negative, it's an unmatched
+ delimiter.
+ - MATCH is nil iff the delimiter is a mismatched closing delimiter.
+ - LOC is the location of the delimiter.
+The function should return a value suitable to use as a value of the `face' text
+property, or nil, in which case the delimiter is not highlighted.
+The function should not move the point or mark or change the match data."
+ :tag "Pick face function"
+ :type 'function
+ :group 'rainbow-delimiters)
+
+(defface rainbow-delimiters-base-face
+ '((default (:inherit unspecified)))
+ "Face inherited by all other rainbow-delimiter faces."
+ :group 'rainbow-delimiters-faces)
+
+(defface rainbow-delimiters-base-error-face
+ '((default (:inherit rainbow-delimiters-base-face))
+ (t (:foreground "#88090B")))
+ "Face inherited by all other rainbow-delimiter error faces."
+ :group 'rainbow-delimiters-faces)
+
+(defface rainbow-delimiters-unmatched-face
+ '((default (:inherit rainbow-delimiters-base-error-face)))
+ "Face to highlight unmatched closing delimiters in."
+ :group 'rainbow-delimiters-faces)
+
+(defface rainbow-delimiters-mismatched-face
+ '((default (:inherit rainbow-delimiters-unmatched-face)))
+ "Face to highlight mismatched closing delimiters in."
+ :group 'rainbow-delimiters-faces)
+
+(eval-when-compile
+ (defmacro rainbow-delimiters--define-depth-faces ()
+ (let ((faces '())
+ (light-colors ["#707183" "#7388d6" "#909183" "#709870" "#907373"
+ "#6276ba" "#858580" "#80a880" "#887070"])
+ (dark-colors ["grey55" "#93a8c6" "#b0b1a3" "#97b098" "#aebed8"
+ "#b0b0b3" "#90a890" "#a2b6da" "#9cb6ad"]))
+ (dotimes (i 9)
+ (push `(defface ,(intern (format "rainbow-delimiters-depth-%d-face" (1+ i)))
+ '((default (:inherit rainbow-delimiters-base-face))
+ (((class color) (background light)) :foreground ,(aref light-colors i))
+ (((class color) (background dark)) :foreground ,(aref dark-colors i)))
+ ,(format "Nested delimiter face, depth %d." (1+ i))
+ :group 'rainbow-delimiters-faces)
+ faces))
+ `(progn ,@faces))))
+(rainbow-delimiters--define-depth-faces)
+
+(defcustom rainbow-delimiters-max-face-count 9
+ "Number of faces defined for highlighting delimiter levels.
+
+Determines depth at which to cycle through faces again.
+
+It's safe to change this variable provided that for all integers from 1 to the
+new value inclusive, a face `rainbow-delimiters-depth-N-face' is defined."
+ :type 'integer
+ :group 'rainbow-delimiters)
+
+(defcustom rainbow-delimiters-outermost-only-face-count 0
+ "Number of faces to be used only for N outermost delimiter levels.
+
+This should be smaller than `rainbow-delimiters-max-face-count'."
+ :type 'integer
+ :group 'rainbow-delimiters)
+
+
+(defun rainbow-delimiters-default-pick-face (depth match _loc)
+ "Return a face name appropriate for nesting depth DEPTH.
+DEPTH and MATCH are as in `rainbow-delimiters-pick-face-function'.
+
+The returned value is either `rainbow-delimiters-unmatched-face',
+`rainbow-delimiters-mismatched-face', or one of the
+`rainbow-delimiters-depth-N-face' faces, obeying
+`rainbow-delimiters-max-face-count' and
+`rainbow-delimiters-outermost-only-face-count'."
+ (cond
+ ((<= depth 0)
+ 'rainbow-delimiters-unmatched-face)
+ ((not match)
+ 'rainbow-delimiters-mismatched-face)
+ (t
+ (intern-soft
+ (concat "rainbow-delimiters-depth-"
+ (number-to-string
+ (if (<= depth rainbow-delimiters-max-face-count)
+ ;; Our nesting depth has a face defined for it.
+ depth
+ ;; Deeper than # of defined faces; cycle back through to
+ ;; `rainbow-delimiters-outermost-only-face-count' + 1.
+ ;; Return face # that corresponds to current nesting level.
+ (+ 1 rainbow-delimiters-outermost-only-face-count
+ (mod (- depth rainbow-delimiters-max-face-count 1)
+ (- rainbow-delimiters-max-face-count
+ rainbow-delimiters-outermost-only-face-count)))))
+ "-face")))))
+
+(defun rainbow-delimiters--apply-color (loc depth match)
+ "Highlight a single delimiter at LOC according to DEPTH.
+
+LOC is the location of the character to add text properties to.
+DEPTH is the nested depth at LOC, which determines the face to use.
+MATCH is nil iff it's a mismatched closing delimiter."
+ (let ((face (funcall rainbow-delimiters-pick-face-function depth match loc)))
+ (when face
+ (font-lock-prepend-text-property loc (1+ loc) 'face face))))
+
+(defun rainbow-delimiters--char-ineligible-p (loc ppss delim-syntax-code)
+ "Return t if char at LOC should not be highlighted.
+PPSS is the `parse-partial-sexp' state at LOC.
+DELIM-SYNTAX-CODE is the `car' of a raw syntax descriptor at LOC.
+
+Returns t if char at loc meets one of the following conditions:
+- Inside a string.
+- Inside a comment.
+- Is an escaped char, e.g. ?\)"
+ (or
+ (nth 3 ppss) ; inside string?
+ (nth 4 ppss) ; inside comment?
+ (nth 5 ppss) ; escaped according to the syntax table?
+ ;; Note: no need to consider single-char openers, they're already handled
+ ;; by looking at ppss.
+ (cond
+ ;; Two character opener, LOC at the first character?
+ ((/= 0 (logand #x10000 delim-syntax-code))
+ (/= 0 (logand #x20000 (or (car (syntax-after (1+ loc))) 0))))
+ ;; Two character opener, LOC at the second character?
+ ((/= 0 (logand #x20000 delim-syntax-code))
+ (/= 0 (logand #x10000 (or (car (syntax-after (1- loc))) 0))))
+ (t
+ nil))))
+
+;; Main function called by font-lock.
+(defun rainbow-delimiters--propertize (end)
+ "Highlight delimiters in region between point and END.
+
+Used by font-lock for dynamic highlighting."
+ (when (bound-and-true-p mmm-current-submode)
+ ;; `mmm-mode' is weird and apparently needs this hack, because otherwise we
+ ;; may end up thinking matched parentheses are mismatched.
+ (widen))
+ (let* ((last-ppss-pos (point))
+ (ppss (syntax-ppss)))
+ (while (> end (progn (skip-syntax-forward "^()" end)
+ (point)))
+ (let* ((delim-pos (point))
+ (delim-syntax (syntax-after delim-pos)))
+ (setq ppss (parse-partial-sexp last-ppss-pos delim-pos nil nil ppss))
+ (setq last-ppss-pos delim-pos)
+ ;; `skip-syntax-forward' leaves the point at the delimiter, move past
+ ;; it.
+ (forward-char)
+ (let ((delim-syntax-code (car delim-syntax)))
+ (cond
+ ((rainbow-delimiters--char-ineligible-p delim-pos ppss delim-syntax-code)
+ nil)
+ ((= 4 (logand #xFFFF delim-syntax-code))
+ ;; The (1+ ...) is needed because `parse-partial-sexp' returns the
+ ;; depth at the opening delimiter, not in the block being started.
+ (rainbow-delimiters--apply-color delim-pos (1+ (nth 0 ppss)) t))
+ (t
+ ;; Not an opening delimiter, so it's a closing delimiter.
+ (let ((matches-p (eq (cdr delim-syntax) (char-after (nth 1 ppss)))))
+ (rainbow-delimiters--apply-color delim-pos (nth 0 ppss) matches-p))))))))
+ ;; We already fontified the delimiters, tell font-lock there's nothing more
+ ;; to do.
+ nil)
+
+;; NB: no face defined here because we apply the faces ourselves instead of
+;; leaving that to font-lock.
+(defconst rainbow-delimiters--font-lock-keywords
+ '(rainbow-delimiters--propertize))
+
+;;;###autoload
+(define-minor-mode rainbow-delimiters-mode
+ "Highlight nested parentheses, brackets, and braces according to their depth."
+ :init-value nil
+ :lighter "" ; No modeline lighter - it's already obvious when the mode is on.
+ :keymap nil
+ (font-lock-remove-keywords nil rainbow-delimiters--font-lock-keywords)
+ (when rainbow-delimiters-mode
+ (font-lock-add-keywords nil rainbow-delimiters--font-lock-keywords 'append)
+ (set (make-local-variable 'jit-lock-contextually) t)
+ (when (or (bound-and-true-p syntax-begin-function)
+ (bound-and-true-p font-lock-beginning-of-syntax-function))
+ ;; We're going to modify `syntax-begin-function', so flush the cache to
+ ;; avoid getting cached values that used the old value.
+ (syntax-ppss-flush-cache 0))
+ ;; `syntax-begin-function' may break the assumption we rely on that
+ ;; `syntax-ppss' is exactly equivalent to `parse-partial-sexp' from
+ ;; `point-min'. Just don't use it, the performance hit should be negligible.
+ (when (boundp 'syntax-begin-function)
+ (set (make-local-variable 'syntax-begin-function) nil))
+ ;; Obsolete equivalent of `syntax-begin-function'.
+ (when (boundp 'font-lock-beginning-of-syntax-function)
+ (set (make-local-variable 'font-lock-beginning-of-syntax-function) nil)))
+ (when font-lock-mode
+ (if (fboundp 'font-lock-flush)
+ (font-lock-flush)
+ (with-no-warnings (font-lock-fontify-buffer)))))
+
+;;;###autoload
+(defun rainbow-delimiters-mode-enable ()
+ "Enable `rainbow-delimiters-mode'."
+ (rainbow-delimiters-mode 1))
+
+;;;###autoload
+(defun rainbow-delimiters-mode-disable ()
+ "Disable `rainbow-delimiters-mode'."
+ (rainbow-delimiters-mode 0))
+
+(provide 'rainbow-delimiters)
+;;; rainbow-delimiters.el ends here
+