diff options
| -rw-r--r-- | .gitignore | 12 | ||||
| l--------- | README.org | 1 | ||||
| -rw-r--r-- | config.org | 287 | ||||
| -rw-r--r-- | dracula-custom-theme.el | 53 | ||||
| -rw-r--r-- | init.el | 44 | ||||
| -rw-r--r-- | lisp/rainbow-delimiters.el | 310 |
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) + @@ -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 + |
