From 79d9dce3e180816518d3e5c76e803c98bfb8e5e7 Mon Sep 17 00:00:00 2001 From: Kienan Stewart Date: Fri, 11 Nov 2016 17:10:03 -0500 Subject: [PATCH] Replacing config with cask including dependencies --- Cask | 7 + init.el | 100 +- misc/flymake.el | 2170 ------------------- misc/multi-term.el | 794 ------- modes/drupal-mode.el | 17 - modes/kivy-mode.el | 290 --- modes/markdown-mode.el | 4669 ---------------------------------------- modes/php-mode.el | 1103 ---------- modes/scss-mode.el | 123 -- 9 files changed, 14 insertions(+), 9259 deletions(-) delete mode 100644 misc/flymake.el delete mode 100644 misc/multi-term.el delete mode 100644 modes/drupal-mode.el delete mode 100644 modes/kivy-mode.el delete mode 100644 modes/markdown-mode.el delete mode 100644 modes/php-mode.el delete mode 100644 modes/scss-mode.el diff --git a/Cask b/Cask index af2e7a4..d114328 100644 --- a/Cask +++ b/Cask @@ -5,22 +5,29 @@ (depends-on "cask") (depends-on "dash") (depends-on "drag-stuff") +(depends-on "drupal-mode") (depends-on "exec-path-from-shell") (depends-on "expand-region") (depends-on "f") (depends-on "flycheck") (depends-on "flycheck-cask") +(depends-on "flycheck-pyflakes") (depends-on "htmlize") (depends-on "idle-highlight-mode") +(depends-on "js2-mode") +(depends-on "kivy-mode") (depends-on "magit") +(depends-on "markdown-mode") (depends-on "multiple-cursors") (depends-on "nyan-mode") (depends-on "pallet") +(depends-on "php-mode") (depends-on "popwin") (depends-on "prodigy") (depends-on "projectile") (depends-on "puppet-mode") (depends-on "s") +(depends-on "scss-mode") (depends-on "smartparens") (depends-on "smex") (depends-on "use-package") diff --git a/init.el b/init.el index d019adf..a2a63d2 100644 --- a/init.el +++ b/init.el @@ -1,12 +1,15 @@ +;; Load cask info +(require 'cask "~/local/share/cask/cask.el") +(cask-initialize) + +;; Enable flycheck +(add-hook 'after-init-hook #'global-flycheck-mode) + ;; Generic Emacs stuff (add-to-list 'load-path "~/.emacs.d/modes/") (add-to-list 'load-path "~/.emacs.d/misc/") (show-paren-mode 1) -;; multi-term -;;(require 'multi-term) -;;(setq multi-term-program "/bin/bash") - ;; CSS Mode needs to be applied to scss files. (add-to-list 'auto-mode-alist '("\\.scss" . css-mode)) (setq-default css-indent-offset 2) @@ -24,97 +27,8 @@ (setq-default whitespace-line-column 80) (global-whitespace-mode 1) -;; Markdown http://jblevins.org/projects/markdown-mode/markdown-mode.el -(autoload 'markdown-mode "markdown-mode" - "Major mode for editing Markdown files" t) -(add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode)) -(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode)) -(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) -(add-to-list 'auto-mode-alist '("\\.mdwn\\'" . markdown-mode)) - ;; C, use k&r style by default (naev) (setq-default c-default-style "k&r" c-basic-offset 3) -;; Kivy (ref:https://github.com/kivy/kivy/blob/master/kivy/tools/highlight/kivy-mode.el) -(require 'kivy-mode) -(add-to-list 'auto-mode-alist '("\\.kv$" . kivy-mode)) - - -;; Python! -;; Prevent ropemacs from overriding emacs shortcuts -;;(setq ropemacs-enable-shortcuts nil) -;;(setq ropemacs-local-prefix "C-c C-p") -;; Load of a bunch of stuff for pymacs : http://pymacs.progiciels-bpi.ca/pymacs.html#installation -;;(autoload 'pymacs-apply "pymacs") -;;(autoload 'pymacs-call "pymacs") -;;(autoload 'pymacs-eval "pymacs" nil t) -;;(autoload 'pymacs-exec "pymacs" nil t) -;;(autoload 'pymacs-load "pymacs" nil t) -;;(autoload 'pymacs-autoload "pymacs") -;;(eval-after-load "pymacs" -;; '(add-to-list 'pymacs-load-path YOUR-PYMACS-DIRECTORY")) -;;(require 'pymacs) -;; Load ropemacs -;;(pymacs-load "ropemacs" "rope-") - -;; SCSS -;;(autoload 'scss-mode "scss-mode") -;;(add-to-list 'auto-mode-alist '("\\.scss\\'" . scss-mode)) -;;(setq-default scss-compile-at-save nil) - -;; PHP and Drupal-Modes -;; http://stackoverflow.com/questions/898063/making-php-mode-and-other-cc-mode-derived-modes-compatible-with-emacs-23 -;; Use autoload for php-mode and drupal-mode to avoid occasionaly errors on some -;; systems when loading from init. See the above question on stack overflow -(autoload 'php-mode "php-mode" "Major mode for editing php code." t) -(autoload 'drupal-mode "drupal-mode" "Major mode for editing drupal php files." t) -;(require 'php-mode) -;(require 'drupal-mode) -(add-to-list 'auto-mode-alist '("\\.\\(module\\|test\\|install\\|theme\\)$" . drupal-mode)) -(add-to-list 'auto-mode-alist '("\\.\\(php\\|inc\\)$" . php-mode)) -(add-to-list 'auto-mode-alist '("\\.info" . conf-windows-mode)) -(defun my-php-hook-function () - (set (make-local-variable 'compile-command) (format "phpcs --report=emacs --standard=PEAR %s" (buffer-file-name)))) -(add-hook 'php-mode-hook 'my-php-hook-function) -(defun my-drupal-hook-function () - (set (make-local-variable 'compile-command) (format "phpcs --report=emacs --extensions=php,module,inc,install,test,profile,theme --standard=Drupal %s" (buffer-file-name)))) -(add-hook 'drupal-mode-hook 'my-drupal-hook-function) -(autoload 'js2-mode "js2-mode" nil t) (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)) -;; Synax checking for PHP with flymake -;; http://sachachua.com/blog/2008/07/emacs-and-php-on-the-fly-syntax-checking-with-flymake/ -;; https://github.com/illusori/emacs-flymake -;; http://www.emacswiki.org/emacs/FlyMake -(require 'flymake) -(defun flymake-php-init () - "Use php to check the syntax of the current file." - (let* ((temp (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)) - (local (file-relative-name temp (file-name-directory buffer-file-name)))) - (list "php" (list "-f" local "-l")))) -(add-to-list 'flymake-err-line-patterns - '("\\(Parse\\|Fatal\\) error: +\\(.*?\\) in \\(.*?\\) on line \\([0-9]+\\)$" 3 4 nil 2)) -(add-to-list 'flymake-allowed-file-name-masks '("\\.php$" flymake-php-init)) -;; Drupal-type extensions -(add-to-list 'flymake-allowed-file-name-masks - '("\\.\\(inc\\|module\\|test\\|install\\|theme\\)$" - flymake-php-init)) -(add-hook 'php-mode-hook (lambda () (flymake-mode 1))) -(add-hook 'php-mode-hook (lambda () - (define-key php-mode-map '[M-S-up] - 'flymake-goto-prev-error))) -(add-hook 'php-mode-hook (lambda () - (define-key php-mode-map '[M-S-down] - 'flymake-goto-next-error))) -(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. - ) -(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. - '(flymake-errline ((((class color) (background light)) (:background "magenta" :foreground "red"))))) diff --git a/misc/flymake.el b/misc/flymake.el deleted file mode 100644 index 02bdf9d..0000000 --- a/misc/flymake.el +++ /dev/null @@ -1,2170 +0,0 @@ -;;; flymake.el --- a universal on-the-fly syntax checker - -;; Copyright (C) 2003-2012 Free Software Foundation, Inc. - -;; Author: Pavel Kobyakov -;; Maintainer: Sam Graham -;; Version: 0.4.13 -;; Keywords: c languages tools - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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. - -;; GNU Emacs 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 GNU Emacs. If not, see . - -;;; Commentary: -;; -;; Flymake is a minor Emacs mode performing on-the-fly syntax -;; checks using the external syntax check tool (for C/C++ this -;; is usually the compiler) - -;;; Bugs/todo: - -;; - Only uses "Makefile", not "makefile" or "GNUmakefile" -;; (from http://bugs.debian.org/337339). - -;;; Code: - -(require 'cc-defs) -(eval-when-compile (require 'cl)) -(eval-when-compile (require 'tramp)) -(if (featurep 'xemacs) (require 'overlay)) - -(defvar flymake-is-running nil - "If t, flymake syntax check process is running for the current buffer.") -(make-variable-buffer-local 'flymake-is-running) - -(defvar flymake-buffers 0 - "Refcount of number of buffers in Flymake mode, when zero the last-change timer is disabled.") - -(defvar flymake-timer nil - "Timer for starting syntax check.") - -(defvar flymake-last-change-time nil - "Time of last buffer change.") -(make-variable-buffer-local 'flymake-last-change-time) - -(defvar flymake-check-start-time nil - "Time at which syntax check was started.") -(make-variable-buffer-local 'flymake-check-start-time) - -(defvar flymake-check-was-interrupted nil - "Non-nil if syntax check was killed by `flymake-compile'.") -(make-variable-buffer-local 'flymake-check-was-interrupted) - -(defvar flymake-check-should-restart nil - "Non-nil if syntax check should restart after terminating.") -(make-variable-buffer-local 'flymake-check-should-restart) - -(defvar flymake-err-info nil - "Sorted list of line numbers and lists of err info in the form (file, err-text).") -(make-variable-buffer-local 'flymake-err-info) - -(defvar flymake-new-err-info nil - "Same as `flymake-err-info', effective when a syntax check is in progress.") -(make-variable-buffer-local 'flymake-new-err-info) - -(defcustom flymake-start-syntax-check-on-find-file t - "Start syntax check on find file." - :group 'flymake - :type 'boolean) - -(defcustom flymake-run-in-place t - "If nil, flymake will run on copies in `temporary-file-directory' rather -than the same directory as the original file. - -If the file makes use of relative include paths it's quite possible that -setting this to nil will cause compilation errors. On the other hand, leaving -it set to t will trigger any automated file creation detection that is -watching your project directory. YMMV. - -When editing a remote file via Tramp, this flag also has the side-effect of -determining whether the syntax check is run in the same place as the original -file (and thus on the remote machine), or in the same place as -`temporary-file-directory' (usually the local machine)." - :group 'flymake - :type 'boolean) - -;;;###autoload -(define-minor-mode flymake-mode - "Toggle on-the-fly syntax checking. -With a prefix argument ARG, enable the mode if ARG is positive, -and disable it otherwise. If called from Lisp, enable the mode -if ARG is omitted or nil." - :group 'flymake :lighter flymake-mode-line - (cond - - ;; Turning the mode ON. - (flymake-mode - (cond - ((not buffer-file-name) - (message "Flymake unable to run without a buffer file name")) - ((not (flymake-can-syntax-check-file buffer-file-name)) - (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name))) - (t - (setq flymake-buffers (1+ flymake-buffers)) - (add-hook 'after-change-functions 'flymake-after-change-function nil t) - (add-hook 'after-save-hook 'flymake-after-save-hook nil t) - (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t) - ;;+(add-hook 'find-file-hook 'flymake-find-file-hook) - - (flymake-report-status "" "") - - (when (and (> flymake-buffers 0) - (not flymake-timer)) - (setq flymake-timer (run-at-time nil 1 'flymake-on-timer-event))) - - (when flymake-start-syntax-check-on-find-file - (flymake-start-syntax-check))))) - - ;; Turning the mode OFF. - (t - (remove-hook 'after-change-functions 'flymake-after-change-function t) - (remove-hook 'after-save-hook 'flymake-after-save-hook t) - (remove-hook 'kill-buffer-hook 'flymake-kill-buffer-hook t) - ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t) - - (flymake-delete-own-overlays) - - (setq flymake-buffers (1- flymake-buffers)) - - (when (and (<= flymake-buffers 0) - flymake-timer) - (cancel-timer flymake-timer) - (setq flymake-timer nil)) - - (setq flymake-is-running nil)))) - -;;;; [[ cross-emacs compatibility routines -(defsubst flymake-makehash (&optional test) - (if (fboundp 'make-hash-table) - (if test (make-hash-table :test test) (make-hash-table)) - (with-no-warnings - (makehash test)))) - -(defalias 'flymake-float-time - (if (fboundp 'float-time) - 'float-time - (if (featurep 'xemacs) - (lambda () - (multiple-value-bind (s0 s1 s2) (values-list (current-time)) - (+ (* (float (ash 1 16)) s0) (float s1) (* 0.0000001 s2))))))) - -(defalias 'flymake-replace-regexp-in-string - (if (eval-when-compile (fboundp 'replace-regexp-in-string)) - 'replace-regexp-in-string - (lambda (regexp rep str) - (replace-in-string str regexp rep)))) - -(defalias 'flymake-split-string - (if (condition-case nil (equal (split-string " bc " " " t) '("bc")) - (error nil)) - (lambda (str pattern) (split-string str pattern t)) - (lambda (str pattern) - "Split STR into a list of substrings bounded by PATTERN. -Zero-length substrings at the beginning and end of the list are omitted." - (let ((split (split-string str pattern))) - (while (equal (car split) "") (setq split (cdr split))) - (setq split (nreverse split)) - (while (equal (car split) "") (setq split (cdr split))) - (nreverse split))))) - -(defalias 'flymake-get-temp-dir - (if (fboundp 'temp-directory) - 'temp-directory - (lambda () temporary-file-directory))) - -(defun flymake-posn-at-point-as-event (&optional position window dx dy) - "Return pixel position of top left corner of glyph at POSITION, -relative to top left corner of WINDOW, as a mouse-1 click -event (identical to the event that would be triggered by clicking -mouse button 1 at the top left corner of the glyph). - -POSITION and WINDOW default to the position of point in the -selected window. - -DX and DY specify optional offsets from the top left of the glyph." - (unless window (setq window (selected-window))) - (unless position (setq position (window-point window))) - (unless dx (setq dx 0)) - (unless dy (setq dy 0)) - - (let* ((pos (posn-at-point position window)) - (x-y (posn-x-y pos)) - (edges (window-inside-pixel-edges window)) - (win-x-y (window-pixel-edges window))) - ;; adjust for window edges - (setcar (nthcdr 2 pos) - (cons (+ (car x-y) (car edges) (- (car win-x-y)) dx) - (+ (cdr x-y) (cadr edges) (- (cadr win-x-y)) dy))) - (list 'mouse-1 pos))) - -(defun flymake-popup-menu (menu-data) - "Pop up the flymake menu at point, using the data MENU-DATA. -POS is a list of the form ((X Y) WINDOW), where X and Y are -pixels positions from the top left corner of WINDOW's frame. -MENU-DATA is a list of error and warning messages returned by -`flymake-make-err-menu-data'." - (if (featurep 'xemacs) - (let* ((pos (flymake-get-point-pixel-pos)) - (x-pos (nth 0 pos)) - (y-pos (nth 1 pos)) - (fake-event-props '(button 1 x 1 y 1))) - (setq fake-event-props (plist-put fake-event-props 'x x-pos)) - (setq fake-event-props (plist-put fake-event-props 'y y-pos)) - (popup-menu (flymake-make-xemacs-menu menu-data) - (make-event 'button-press fake-event-props))) - (x-popup-menu (if (eval-when-compile (fboundp 'posn-at-point)) - (flymake-posn-at-point-as-event) - (list (flymake-get-point-pixel-pos) (selected-window))) - (flymake-make-emacs-menu menu-data)))) - -(defun flymake-make-emacs-menu (menu-data) - "Return a menu specifier using MENU-DATA. -MENU-DATA is a list of error and warning messages returned by -`flymake-make-err-menu-data'. -See `x-popup-menu' for the menu specifier format." - (let* ((menu-title (nth 0 menu-data)) - (menu-items (nth 1 menu-data)) - (menu-commands (mapcar (lambda (foo) - (cons (nth 0 foo) (nth 1 foo))) - menu-items))) - (list menu-title (cons "" menu-commands)))) - -(if (featurep 'xemacs) (progn - -(defun flymake-nop ()) - -(defun flymake-make-xemacs-menu (menu-data) - "Return a menu specifier using MENU-DATA." - (let* ((menu-title (nth 0 menu-data)) - (menu-items (nth 1 menu-data)) - (menu-commands nil)) - (setq menu-commands (mapcar (lambda (foo) - (vector (nth 0 foo) (or (nth 1 foo) '(flymake-nop)) t)) - menu-items)) - (cons menu-title menu-commands))) - -)) ;; xemacs - -(unless (eval-when-compile (fboundp 'posn-at-point)) - -(defun flymake-current-row () - "Return current row number in current frame." - (if (fboundp 'window-edges) - (+ (car (cdr (window-edges))) (count-lines (window-start) (point))) - (count-lines (window-start) (point)))) - -(defun flymake-selected-frame () - (if (fboundp 'window-edges) - (selected-frame) - (selected-window))) - -(defun flymake-get-point-pixel-pos () - "Return point position in pixels: (x, y)." - (let ((mouse-pos (mouse-position)) - (pixel-pos nil) - (ret nil)) - (if (car (cdr mouse-pos)) - (progn - (set-mouse-position (flymake-selected-frame) (current-column) (flymake-current-row)) - (setq pixel-pos (mouse-pixel-position)) - (set-mouse-position (car mouse-pos) (car (cdr mouse-pos)) (cdr (cdr mouse-pos))) - (setq ret (list (car (cdr pixel-pos)) (cdr (cdr pixel-pos))))) - (progn - (setq ret '(0 0)))) - (flymake-log 3 "mouse pos is %s" ret) - ret)) - -) ;; End of (unless (fboundp 'posn-at-point) - -;;;; ]] - -(defcustom flymake-log-level -1 - "Logging level, only messages with level lower or equal will be logged. --1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG - - See `flymake-log-file-name' if you want to control where the log is created." - :group 'flymake - :type 'integer) - -;; Yes, this is an awful default. -(defcustom flymake-log-file-name "~/flymake.log" - "Where to put the flymake log if logging is enabled. - - See `flymake-log-level' if you want to control what is logged." - :group 'flymake - :type 'string) - -(defun flymake-enquote-log-string (string) - "Prepends > on each line of STRING." - (concat "\n > " (flymake-replace-regexp-in-string "\n" "\n > " string t t))) - -(defun flymake-log (level text &rest args) - "Log a message at level LEVEL. -If LEVEL is higher than `flymake-log-level', the message is -ignored. Otherwise, it is printed using `message'. -TEXT is a format control string, and the remaining arguments ARGS -are the string substitutions (see `format')." - (if (<= level flymake-log-level) - (let* ((msg (apply 'format text args)) - ;; Surely there's a better way to do this? - (time (current-time)) - (timestamp (concat (format-time-string "%Y-%m-%d %T" time) - "." - (format "%06d" (third time))))) - (message "%s" msg) - (make-directory (file-name-directory flymake-log-file-name) 1) - (write-region (concat "[" timestamp "] " msg "\n") nil flymake-log-file-name t 566)))) - -(defun flymake-ins-after (list pos val) - "Insert VAL into LIST after position POS." - (let ((tmp (copy-sequence list))) ; (???) - (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp))) - tmp)) - -(defun flymake-set-at (list pos val) - "Set VAL at position POS in LIST." - (let ((tmp (copy-sequence list))) ; (???) - (setcar (nthcdr pos tmp) val) - tmp)) - -(defvar flymake-processes nil - "List of currently active flymake processes.") - -(defvar flymake-output-residual nil) - -(make-variable-buffer-local 'flymake-output-residual) - -(defgroup flymake nil - "A universal on-the-fly syntax checker." - :version "23.1" - :group 'tools) - -(defcustom flymake-allowed-file-name-masks - '(("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'" flymake-simple-make-init) - ("\\.xml\\'" flymake-xml-init) - ("\\.html?\\'" flymake-xml-init) - ("\\.cs\\'" flymake-simple-make-init) - ("\\.p[ml]\\'" flymake-perl-init) - ("\\.php[345]?\\'" flymake-php-init) - ("\\.js\\'" flymake-javascript-init) - ("\\.css\\'" flymake-css-init) - ("\\.h\\'" flymake-master-make-header-init flymake-master-cleanup) - ("\\.java\\'" flymake-simple-make-java-init flymake-simple-java-cleanup) - ("[0-9]+\\.tex\\'" flymake-master-tex-init flymake-master-cleanup) - ("\\.tex\\'" flymake-simple-tex-init) - ("\\.idl\\'" flymake-simple-make-init) - ("\\.spec\\'" flymake-specfile-init) - ("\\.po\\'" flymake-pofile-init) - ;; ("\\.cpp\\'" 1) - ;; ("\\.java\\'" 3) - ;; ("\\.h\\'" 2 ("\\.cpp\\'" "\\.c\\'") - ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)) - ;; ("\\.idl\\'" 1) - ;; ("\\.odl\\'" 1) - ;; ("[0-9]+\\.tex\\'" 2 ("\\.tex\\'") - ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 )) - ;; ("\\.tex\\'" 1) - ) - "Files syntax checking is allowed for." - :group 'flymake - :type '(repeat (string symbol symbol symbol))) - -(defun flymake-get-file-name-mode-and-masks (file-name) - "Return the corresponding entry from `flymake-allowed-file-name-masks'." - (unless (stringp file-name) - (error "Invalid file-name")) - (let ((fnm flymake-allowed-file-name-masks) - (mode-and-masks nil)) - (while (and (not mode-and-masks) fnm) - (if (string-match (car (car fnm)) file-name) - (setq mode-and-masks (cdr (car fnm)))) - (setq fnm (cdr fnm))) - (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks)) - mode-and-masks)) - -(defun flymake-can-syntax-check-file (file-name) - "Determine whether we can syntax check FILE-NAME. -Return nil if we cannot, non-nil if we can." - (if (flymake-get-init-function file-name) t nil)) - -(defun flymake-get-init-function (file-name) - "Return init function to be used for the file." - (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name)))) - ;;(flymake-log 0 "calling %s" init-f) - ;;(funcall init-f (current-buffer)) - init-f)) - -(defun flymake-get-cleanup-function (file-name) - "Return cleanup function to be used for the file." - (or (nth 1 (flymake-get-file-name-mode-and-masks file-name)) - 'flymake-simple-cleanup)) - -(defun flymake-get-real-file-name-function (file-name) - (or (nth 2 (flymake-get-file-name-mode-and-masks file-name)) - 'flymake-get-real-file-name)) - -(defvar flymake-find-buildfile-cache (flymake-makehash 'equal)) - -(defun flymake-get-buildfile-from-cache (dir-name) - (gethash dir-name flymake-find-buildfile-cache)) - -(defun flymake-add-buildfile-to-cache (dir-name buildfile) - (puthash dir-name buildfile flymake-find-buildfile-cache)) - -(defun flymake-clear-buildfile-cache () - (clrhash flymake-find-buildfile-cache)) - -(defun flymake-find-buildfile (buildfile-name source-dir-name) - "Find buildfile starting from current directory. -Buildfile includes Makefile, build.xml etc. -Return its file name if found, or nil if not found." - (or (flymake-get-buildfile-from-cache source-dir-name) - (let* ((file (locate-dominating-file source-dir-name buildfile-name))) - (if file - (progn - (flymake-log 3 "found buildfile at %s" file) - (flymake-add-buildfile-to-cache source-dir-name file) - file) - (progn - (flymake-log 3 "buildfile for %s not found" source-dir-name) - nil))))) - -(defun flymake-fix-file-name (name) - "Replace all occurrences of '\' with '/'." - (when name - (setq name (expand-file-name name)) - (setq name (abbreviate-file-name name)) - (setq name (directory-file-name name)) - name)) - -(defun flymake-same-files (file-name-one file-name-two) - "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file. -Return t if so, nil if not." - (equal (flymake-fix-file-name file-name-one) - (flymake-fix-file-name file-name-two))) - -(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest") - "Dirs where to look for master files." - :group 'flymake - :type '(repeat (string))) - -(defcustom flymake-master-file-count-limit 32 - "Max number of master files to check." - :group 'flymake - :type 'integer) - -;; This is bound dynamically to pass a parameter to a sort predicate below -(defvar flymake-included-file-name) - -(defun flymake-find-possible-master-files (file-name master-file-dirs masks) - "Find (by name and location) all possible master files. -Master files include .cpp and .c for .h. Files are searched for -starting from the .h directory and max max-level parent dirs. -File contents are not checked." - (let* ((dirs master-file-dirs) - (files nil) - (done nil)) - - (while (and (not done) dirs) - (let* ((dir (expand-file-name (car dirs) (file-name-directory file-name))) - (masks masks)) - (while (and (file-exists-p dir) (not done) masks) - (let* ((mask (car masks)) - (dir-files (directory-files dir t mask))) - - (flymake-log 3 "dir %s, %d file(s) for mask %s" - dir (length dir-files) mask) - (while (and (not done) dir-files) - (when (not (file-directory-p (car dir-files))) - (setq files (cons (car dir-files) files)) - (when (>= (length files) flymake-master-file-count-limit) - (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit) - (setq done t))) - (setq dir-files (cdr dir-files)))) - (setq masks (cdr masks)))) - (setq dirs (cdr dirs))) - (when files - (let ((flymake-included-file-name (file-name-nondirectory file-name))) - (setq files (sort files 'flymake-master-file-compare)))) - (flymake-log 3 "found %d possible master file(s)" (length files)) - files)) - -(defun flymake-master-file-compare (file-one file-two) - "Compare two files specified by FILE-ONE and FILE-TWO. -This function is used in sort to move most possible file names -to the beginning of the list (File.h -> File.cpp moved to top)." - (and (equal (file-name-sans-extension flymake-included-file-name) - (file-name-sans-extension (file-name-nondirectory file-one))) - (not (equal file-one file-two)))) - -(defcustom flymake-check-file-limit 8192 - "Max number of chars to look at when checking possible master file. -Nil means search the entire file." - :group 'flymake - :type '(choice (const :tag "No limit" nil) - (integer :tag "Characters"))) - -(defun flymake-check-patch-master-file-buffer - (master-file-temp-buffer - master-file-name patched-master-file-name - source-file-name patched-source-file-name - include-dirs regexp) - "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME. -If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME -instead of SOURCE-FILE-NAME. - -For example, foo.cpp is a master file if it includes foo.h. - -Whether a buffer for MATER-FILE-NAME exists, use it as a source -instead of reading master file from disk." - (let* ((source-file-nondir (file-name-nondirectory source-file-name)) - (source-file-extension (file-name-extension source-file-nondir)) - (source-file-nonext (file-name-sans-extension source-file-nondir)) - (found nil) - (inc-name nil) - (search-limit flymake-check-file-limit)) - (setq regexp - (format regexp ; "[ \t]*#[ \t]*include[ \t]*\"\\(.*%s\\)\"" - ;; Hack for tex files, where \include often excludes .tex. - ;; Maybe this is safe generally. - (if (and (> (length source-file-extension) 1) - (string-equal source-file-extension "tex")) - (format "%s\\(?:\\.%s\\)?" - (regexp-quote source-file-nonext) - (regexp-quote source-file-extension)) - (regexp-quote source-file-nondir)))) - (unwind-protect - (with-current-buffer master-file-temp-buffer - (when (or (not search-limit) - (> search-limit (point-max))) - (setq search-limit (point-max))) - (flymake-log 3 "checking %s against regexp %s" - master-file-name regexp) - (goto-char (point-min)) - (while (and (< (point) search-limit) - (re-search-forward regexp search-limit t)) - (let ((match-beg (match-beginning 1)) - (match-end (match-end 1))) - - (flymake-log 3 "found possible match for %s" source-file-nondir) - (setq inc-name (match-string 1)) - (and (> (length source-file-extension) 1) - (string-equal source-file-extension "tex") - (not (string-match (format "\\.%s\\'" source-file-extension) - inc-name)) - (setq inc-name (concat inc-name "." source-file-extension))) - (when (eq t (compare-strings - source-file-nondir nil nil - inc-name (- (length inc-name) - (length source-file-nondir)) nil)) - (flymake-log 3 "inc-name=%s" inc-name) - (when (flymake-check-include source-file-name inc-name - include-dirs) - (setq found t) - ;; replace-match is not used here as it fails in - ;; XEmacs with 'last match not a buffer' error as - ;; check-includes calls replace-in-string - (flymake-replace-region - match-beg match-end - (file-name-nondirectory patched-source-file-name)))) - (forward-line 1))) - (when found - (flymake-save-buffer-in-file patched-master-file-name))) - ;;+(flymake-log 3 "killing buffer %s" - ;; (buffer-name master-file-temp-buffer)) - (kill-buffer master-file-temp-buffer)) - ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found) - (when found - (flymake-log 2 "found master file %s" master-file-name)) - found)) - -(defun flymake-replace-region (beg end rep) - "Replace text in BUFFER in region (BEG END) with REP." - (save-excursion - (goto-char end) - ;; Insert before deleting, so as to better preserve markers's positions. - (insert rep) - (delete-region beg end))) - -(defun flymake-read-file-to-temp-buffer (file-name) - "Insert contents of FILE-NAME into newly created temp buffer." - (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name)))))) - (with-current-buffer temp-buffer - (insert-file-contents file-name)) - temp-buffer)) - -(defun flymake-copy-buffer-to-temp-buffer (buffer) - "Copy contents of BUFFER into newly created temp buffer." - (with-current-buffer - (get-buffer-create (generate-new-buffer-name - (concat "flymake:" (buffer-name buffer)))) - (insert-buffer-substring buffer) - (current-buffer))) - -(defun flymake-check-include (source-file-name inc-name include-dirs) - "Check if SOURCE-FILE-NAME can be found in include path. -Return t if it can be found via include path using INC-NAME." - (if (file-name-absolute-p inc-name) - (flymake-same-files source-file-name inc-name) - (while (and include-dirs - (not (flymake-same-files - source-file-name - (concat (file-name-directory source-file-name) - "/" (car include-dirs) - "/" inc-name)))) - (setq include-dirs (cdr include-dirs))) - include-dirs)) - -(defun flymake-find-buffer-for-file (file-name) - "Check if there exists a buffer visiting FILE-NAME. -Return t if so, nil if not." - (let ((buffer-name (get-file-buffer file-name))) - (if buffer-name - (get-buffer buffer-name)))) - -(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp) - "Save SOURCE-FILE-NAME with a different name. -Find master file, patch and save it." - (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks)) - (master-file-count (length possible-master-files)) - (idx 0) - (temp-buffer nil) - (master-file-name nil) - (patched-master-file-name nil) - (found nil)) - - (while (and (not found) (< idx master-file-count)) - (setq master-file-name (nth idx possible-master-files)) - (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master")) - (if (flymake-find-buffer-for-file master-file-name) - (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name))) - (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name))) - (setq found - (flymake-check-patch-master-file-buffer - temp-buffer - master-file-name - patched-master-file-name - source-file-name - patched-source-file-name - (funcall get-incl-dirs-f (file-name-directory master-file-name)) - include-regexp)) - (setq idx (1+ idx))) - (if found - (list master-file-name patched-master-file-name) - (progn - (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count - (file-name-nondirectory source-file-name)) - nil)))) - -(defun flymake-save-buffer-in-file (file-name) - (make-directory (file-name-directory file-name) 1) - (write-region nil nil file-name nil 566) - (flymake-log 3 "saved buffer %s in file %s" (buffer-name) file-name)) - -(defun flymake-save-string-to-file (file-name data) - "Save string DATA to file FILE-NAME." - (write-region data nil file-name nil 566)) - -(defun flymake-read-file-to-string (file-name) - "Read contents of file FILE-NAME and return as a string." - (with-temp-buffer - (insert-file-contents file-name) - (buffer-substring (point-min) (point-max)))) - -(defun flymake-process-filter (process output) - "Parse OUTPUT and highlight error lines. -It's flymake process filter." - (let ((source-buffer (process-buffer process))) - - (flymake-log 3 "received %d byte(s) of output from process %d" - (length output) (process-id process)) - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - (flymake-parse-output-and-residual output))))) - -(defun flymake-process-sentinel (process _event) - "Sentinel for syntax check buffers." - (when (memq (process-status process) '(signal exit)) - (let* ((exit-status (process-exit-status process)) - (command (process-command process)) - (source-buffer (process-buffer process)) - (tramp-verbose -1) - (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer)))) - - (flymake-log 2 "process %d exited with code %d" - (process-id process) exit-status) - (condition-case err - (progn - (flymake-log 3 "cleaning up using %s" cleanup-f) - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - (funcall cleanup-f))) - - (delete-process process) - (setq flymake-processes (delq process flymake-processes)) - - (when (buffer-live-p source-buffer) - (with-current-buffer source-buffer - - (flymake-parse-residual) - (flymake-post-syntax-check exit-status command) - (setq flymake-is-running nil) - (when flymake-check-should-restart - (flymake-log 2 "restarting syntax check") - (flymake-start-syntax-check))))) - (error - (let ((err-str (format "Error in process sentinel for buffer %s: %s" - source-buffer (error-message-string err)))) - (flymake-log 0 err-str) - (with-current-buffer source-buffer - (setq flymake-is-running nil)))))) - (flymake-run-next-queued-syntax-check))) - -(defcustom flymake-after-syntax-check-hook '() - "Hook run each time Flymake completes a syntax check and updates its list of errors." - :type 'hook - :group 'flymake) - -(defun flymake-post-syntax-check (exit-status command) - (setq flymake-err-info flymake-new-err-info) - (setq flymake-new-err-info nil) - (setq flymake-err-info - (flymake-fix-line-numbers - flymake-err-info 1 (flymake-count-lines))) - (flymake-delete-own-overlays) - (flymake-highlight-err-lines flymake-err-info) - (let (err-count warn-count info-count) - (setq err-count (flymake-get-err-count flymake-err-info "e")) - (setq warn-count (flymake-get-err-count flymake-err-info "w")) - (setq info-count (flymake-get-err-count flymake-err-info "i")) - (flymake-log 2 "%s: %d error(s), %d warning(s), %d info in %.2f second(s)" - (buffer-name) err-count warn-count info-count - (- (flymake-float-time) flymake-check-start-time)) - (setq flymake-check-start-time nil) - - (if (and (equal 0 err-count) (equal 0 warn-count) (equal 0 info-count)) - (if (equal 0 exit-status) - (flymake-report-status "" "") ; PASSED - (if (not flymake-check-was-interrupted) - (flymake-report-fatal-status "CFGERR" - (format "Configuration error has occurred while running %s" command)) - (flymake-report-status nil ""))) ; "STOPPED" - (flymake-report-status (format "%d/%d/%d" err-count warn-count info-count) ""))) - (run-hooks 'flymake-after-syntax-check-hook)) - -(defun flymake-parse-output-and-residual (output) - "Split OUTPUT into lines, merge in residual if necessary." - (flymake-log 3 "received process output: %s" (flymake-enquote-log-string output)) - (let* ((buffer-residual flymake-output-residual) - (total-output (if buffer-residual (concat buffer-residual output) output)) - (lines-and-residual (flymake-split-output total-output)) - (lines (nth 0 lines-and-residual)) - (new-residual (nth 1 lines-and-residual))) - (setq flymake-output-residual new-residual) - (setq flymake-new-err-info - (flymake-parse-err-lines - flymake-new-err-info lines)))) - -(defun flymake-parse-residual () - "Parse residual if it's non empty." - (when flymake-output-residual - (setq flymake-new-err-info - (flymake-parse-err-lines - flymake-new-err-info - (list flymake-output-residual))) - (setq flymake-output-residual nil))) - -(defun flymake-er-make-er (line-no line-err-info-list) - (list line-no line-err-info-list)) - -(defun flymake-er-get-line (err-info) - (nth 0 err-info)) - -(defun flymake-er-get-line-err-info-list (err-info) - (nth 1 err-info)) - -(defstruct (flymake-ler - (:constructor nil) - (:constructor flymake-ler-make-ler (file line type text &optional full-file))) - file line type text full-file) - -(defun flymake-ler-set-file (line-err-info file) - (flymake-ler-make-ler file - (flymake-ler-line line-err-info) - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - (flymake-ler-full-file line-err-info))) - -(defun flymake-ler-set-full-file (line-err-info full-file) - (flymake-ler-make-ler (flymake-ler-file line-err-info) - (flymake-ler-line line-err-info) - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - full-file)) - -(defun flymake-ler-set-line (line-err-info line) - (flymake-ler-make-ler (flymake-ler-file line-err-info) - line - (flymake-ler-type line-err-info) - (flymake-ler-text line-err-info) - (flymake-ler-full-file line-err-info))) - -(defun flymake-get-line-err-count (line-err-info-list type) - "Return number of errors of specified TYPE. -Value of TYPE is either \"e\", \"w\" or \"i\"." - (let* ((idx 0) - (count (length line-err-info-list)) - (err-count 0)) - - (while (< idx count) - (when (equal type (flymake-ler-type (nth idx line-err-info-list))) - (setq err-count (1+ err-count))) - (setq idx (1+ idx))) - err-count)) - -(defun flymake-get-err-count (err-info-list type) - "Return number of errors of specified TYPE for ERR-INFO-LIST." - (let* ((idx 0) - (count (length err-info-list)) - (err-count 0)) - (while (< idx count) - (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type))) - (setq idx (1+ idx))) - err-count)) - -(defun flymake-fix-line-numbers (err-info-list min-line max-line) - "Replace line numbers with fixed value. -If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE. -If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE. -The reason for this fix is because some compilers might report -line number outside the file being compiled." - (let* ((count (length err-info-list)) - (err-info nil) - (line 0)) - (while (> count 0) - (setq err-info (nth (1- count) err-info-list)) - (setq line (flymake-er-get-line err-info)) - (when (or (< line min-line) (> line max-line)) - (setq line (if (< line min-line) min-line max-line)) - (setq err-info-list (flymake-set-at err-info-list (1- count) - (flymake-er-make-er line - (flymake-er-get-line-err-info-list err-info))))) - (setq count (1- count)))) - err-info-list) - -(defun flymake-highlight-err-lines (err-info-list) - "Highlight error lines in BUFFER using info from ERR-INFO-LIST." - (save-excursion - (dolist (err err-info-list) - (flymake-highlight-line (car err) (nth 1 err))))) - -(defun flymake-overlay-p (ov) - "Determine whether overlay OV was created by flymake." - (and (overlayp ov) (overlay-get ov 'flymake-overlay))) - -(defun flymake-make-overlay (beg end tooltip-text face mouse-face) - "Allocate a flymake overlay in range BEG and END." - (when (not (flymake-region-has-flymake-overlays beg end)) - (let ((ov (make-overlay beg end nil t t))) - (overlay-put ov 'face face) - (overlay-put ov 'mouse-face mouse-face) - (overlay-put ov 'help-echo tooltip-text) - (overlay-put ov 'flymake-overlay t) - (overlay-put ov 'priority 100) - ;;+(flymake-log 3 "created overlay %s" ov) - ov) - (flymake-log 3 "created an overlay at (%d-%d) with face %s" beg end face))) - -(defun flymake-delete-own-overlays () - "Delete all flymake overlays in BUFFER." - (dolist (ol (overlays-in (point-min) (point-max))) - (when (flymake-overlay-p ol) - (delete-overlay ol) - ;;+(flymake-log 3 "deleted overlay %s" ol) - ))) - -(defun flymake-region-has-flymake-overlays (beg end) - "Check if region specified by BEG and END has overlay. -Return t if it has at least one flymake overlay, nil if no overlay." - (let ((ov (overlays-in beg end)) - (has-flymake-overlays nil)) - (while (consp ov) - (when (flymake-overlay-p (car ov)) - (setq has-flymake-overlays t)) - (setq ov (cdr ov))) - has-flymake-overlays)) - -(defface flymake-errline - '((((class color) (background dark)) (:background "Firebrick4")) - (((class color) (background light)) (:background "LightPink")) - (t (:bold t))) - "Face used for marking error lines." - :group 'flymake) - -(defface flymake-warnline - '((((class color) (background dark)) (:background "DarkBlue")) - (((class color) (background light)) (:background "LightBlue2")) - (t (:bold t))) - "Face used for marking warning lines." - :group 'flymake) - -(defface flymake-infoline - '((((class color) (background dark)) (:background "DarkGreen")) - (((class color) (background light)) (:background "LightGreen")) - (t (:bold t))) - "Face used for marking info lines." - :group 'flymake) - -(defcustom flymake-number-of-errors-to-display 1 - "Number of flymake errors to display in the tooltip if there are more than one. - -If set to nil, all errors for the line will be displayed." - :group 'flymake - :type '(choice integer (const nil))) - -(defun flymake-highlight-line (line-no line-err-info-list) - "Highlight line LINE-NO in current buffer. -Perhaps use text from LINE-ERR-INFO-LIST to enhance highlighting." - (goto-char (point-min)) - (forward-line (1- line-no)) - (when (and flymake-number-of-errors-to-display - (> (length line-err-info-list) flymake-number-of-errors-to-display)) - (setq line-err-info-list (butlast line-err-info-list (- (length line-err-info-list) flymake-number-of-errors-to-display)))) - (let* ((line-beg (point-at-bol)) - (line-end (point-at-eol)) - (beg line-beg) - (end line-end) - (tooltip-text (mapconcat 'flymake-ler-text line-err-info-list "\n")) - (face nil)) - - (goto-char line-beg) - (while (looking-at "[ \t]") - (forward-char)) - - (setq beg (point)) - - (goto-char line-end) - (while (and (looking-at "[ \t\r\n]") (> (point) 1)) - (backward-char)) - - (setq end (1+ (point))) - - (when (<= end beg) - (setq beg line-beg) - (setq end line-end)) - - (when (= end beg) - (goto-char end) - (forward-line) - (setq end (point))) - - (if (> (flymake-get-line-err-count line-err-info-list "e") 0) - (setq face 'flymake-errline) - (if (> (flymake-get-line-err-count line-err-info-list "w") 0) - (setq face 'flymake-warnline) - (setq face 'flymake-infoline))) - - (flymake-make-overlay beg end tooltip-text face nil))) - -(defun flymake-parse-err-lines (err-info-list lines) - "Parse err LINES, store info in ERR-INFO-LIST." - (let* ((count (length lines)) - (idx 0) - (line-err-info nil) - (real-file-name nil) - (source-file-name buffer-file-name) - (get-real-file-name-f (flymake-get-real-file-name-function source-file-name))) - - (while (< idx count) - (setq line-err-info (flymake-parse-line (nth idx lines))) - (when line-err-info - (setq real-file-name (funcall get-real-file-name-f - (flymake-ler-file line-err-info))) - (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name)) - - (when (flymake-same-files real-file-name source-file-name) - (setq line-err-info (flymake-ler-set-file line-err-info nil)) - (setq err-info-list (flymake-add-err-info err-info-list line-err-info)))) - (flymake-log 3 "parsed '%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no")) - (setq idx (1+ idx))) - err-info-list)) - -(defun flymake-split-output (output) - "Split OUTPUT into lines. -Return last one as residual if it does not end with newline char. -Returns ((LINES) RESIDUAL)." - (when (and output (> (length output) 0)) - (let* ((lines (flymake-split-string output "[\n\r]+")) - (complete (equal "\n" (char-to-string (aref output (1- (length output)))))) - (residual nil)) - (when (not complete) - (setq residual (car (last lines))) - (setq lines (butlast lines))) - (list lines residual)))) - -(defun flymake-reformat-err-line-patterns-from-compile-el (original-list) - "Grab error line patterns from ORIGINAL-LIST in compile.el format. -Convert it to flymake internal format." - (let* ((converted-list '())) - (dolist (item original-list) - (setq item (cdr item)) - (let ((regexp (nth 0 item)) - (file (nth 1 item)) - (line (nth 2 item)) - (col (nth 3 item))) - (if (consp file) (setq file (car file))) - (if (consp line) (setq line (car line))) - (if (consp col) (setq col (car col))) - - (when (not (functionp line)) - (setq converted-list (cons (list regexp file line col) converted-list))))) - converted-list)) - -(require 'compile) - -(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text - (append - '( - ;; MS Visual C++ 6.0 - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; jikes - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; MS midl - ("midl[ ]*:[ ]*\\(command line error .*\\)" - nil nil nil 1) - ;; MS C# - ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+)\: \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)" - 1 3 nil 4) - ;; perl - ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1) - ;; PHP - ("\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)" 2 3 nil 1) - ;; JSHint/CSSLint - ("\\(.+\\): line \\([0-9]+\\), col \\([0-9]+\\), \\(.+\\)" 1 2 3 4) - ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1) - ;; gcc after 4.5 (includes column number) - (" *\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)" - 1 3 4 5) - ;; ant/javac, also matches gcc prior to 4.5 - (" *\\(\\[javac\\] *\\)?\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)" - 2 4 nil 5)) - ;; compilation-error-regexp-alist) - (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist)) - "Patterns for matching error/warning lines. Each pattern has the form -\(REGEXP FILE-IDX LINE-IDX COL-IDX ERR-TEXT-IDX). -Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns -from compile.el") - -;;(defcustom flymake-err-line-patterns -;; '( -;; ; MS Visual C++ 6.0 -;; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)" -;; 1 3 4) -;; ; jikes -;; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\):[ \t\n]*\\(.+\\)\\)" -;; 1 3 4)) -;; "patterns for matching error/warning lines, (regexp file-idx line-idx err-text-idx)" -;; :group 'flymake -;; :type '(repeat (string number number number)) -;;) - -(defcustom flymake-warn-line-regexp "^[wW]arning" - "Regexp pattern for detecting if an error line is of class \"warning\" rather than \"error\"." - :group 'flymake - :type 'string) - -(defcustom flymake-info-line-regexp "^[iI]nfo" - "Regexp pattern for detecting if an error line is of class \"info\" rather than \"error\"." - :group 'flymake - :type 'string) - -(defun flymake-parse-line (line) - "Parse LINE to see if it is an error or warning. -Return its components if so, nil otherwise." - (let ((raw-file-name nil) - (line-no 0) - (err-type "e") - (err-text nil) - (patterns flymake-err-line-patterns) - (matched nil)) - (while (and patterns (not matched)) - (when (string-match (car (car patterns)) line) - (let* ((file-idx (nth 1 (car patterns))) - (line-idx (nth 2 (car patterns)))) - - (setq raw-file-name (if file-idx (match-string file-idx line) nil)) - (setq line-no (if line-idx (string-to-number (match-string line-idx line)) 0)) - (setq err-text (if (> (length (car patterns)) 4) - (match-string (nth 4 (car patterns)) line) - (flymake-patch-err-text (substring line (match-end 0))))) - (or err-text (setq err-text "")) - (if (and err-text (string-match flymake-warn-line-regexp err-text)) - (setq err-type "w")) - (if (and err-text (string-match flymake-info-line-regexp err-text)) - (setq err-type "i")) - (flymake-log 3 "parse line: type=%s file-idx=%s line-idx=%s file=%s line=%s text=%s" - err-type file-idx line-idx raw-file-name line-no err-text) - (setq matched t))) - (setq patterns (cdr patterns))) - (if matched - (flymake-ler-make-ler raw-file-name line-no err-type err-text) - ()))) - -(defun flymake-find-err-info (err-info-list line-no) - "Find (line-err-info-list pos) for specified LINE-NO." - (if err-info-list - (let* ((line-err-info-list nil) - (pos 0) - (count (length err-info-list))) - - (while (and (< pos count) (< (car (nth pos err-info-list)) line-no)) - (setq pos (1+ pos))) - (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no)) - (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list)))) - (list line-err-info-list pos)) - '(nil 0))) - -(defun flymake-line-err-info-is-less-or-equal (line-one line-two) - (or (string< (flymake-ler-type line-one) (flymake-ler-type line-two)) - (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) - (not (flymake-ler-file line-one)) (flymake-ler-file line-two)) - (and (string= (flymake-ler-type line-one) (flymake-ler-type line-two)) - (or (and (flymake-ler-file line-one) (flymake-ler-file line-two)) - (and (not (flymake-ler-file line-one)) (not (flymake-ler-file line-two))))))) - -(defun flymake-add-line-err-info (line-err-info-list line-err-info) - "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO. -For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'. -The new element is inserted in the proper position, according to -the predicate `flymake-line-err-info-is-less-or-equal'. -The updated value of LINE-ERR-INFO-LIST is returned." - (if (not line-err-info-list) - (list line-err-info) - (let* ((count (length line-err-info-list)) - (idx 0)) - (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info)) - (setq idx (1+ idx))) - (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list))) - (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info)))) - line-err-info-list))) - -(defun flymake-add-err-info (err-info-list line-err-info) - "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order. -Returns the updated value of ERR-INFO-LIST. -For the format of ERR-INFO-LIST, see `flymake-err-info'. -For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'." - (let* ((line-no (if (flymake-ler-file line-err-info) 1 (flymake-ler-line line-err-info))) - (info-and-pos (flymake-find-err-info err-info-list line-no)) - (exists (car info-and-pos)) - (pos (nth 1 info-and-pos)) - (line-err-info-list nil) - (err-info nil)) - - (if exists - (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list))))) - (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info)) - - (setq err-info (flymake-er-make-er line-no line-err-info-list)) - (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info))) - ((equal 0 pos) (setq err-info-list (cons err-info err-info-list))) - (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info)))) - err-info-list)) - -(defun flymake-get-project-include-dirs-imp (basedir) - "Include dirs for the project current file belongs to." - (if (flymake-get-project-include-dirs-from-cache basedir) - (progn - (flymake-get-project-include-dirs-from-cache basedir)) - ;;else - (let* ((command-line (concat "make -C " - (shell-quote-argument basedir) - " DUMPVARS=INCLUDE_DIRS dumpvars")) - (output (shell-command-to-string command-line)) - (lines (flymake-split-string output "\n")) - (count (length lines)) - (idx 0) - (inc-dirs nil)) - (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines)))) - (setq idx (1+ idx))) - (when (< idx count) - (let* ((inc-lines (flymake-split-string (nth idx lines) " *-I")) - (inc-count (length inc-lines))) - (while (> inc-count 0) - (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines))) - (push (flymake-replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs)) - (setq inc-count (1- inc-count))))) - (flymake-add-project-include-dirs-to-cache basedir inc-dirs) - inc-dirs))) - -(defcustom flymake-get-project-include-dirs-function 'flymake-get-project-include-dirs-imp - "Function used to get project include dirs, one parameter: basedir name." - :group 'flymake - :type 'function) - -(defun flymake-get-project-include-dirs (basedir) - (funcall flymake-get-project-include-dirs-function basedir)) - -(defun flymake-get-system-include-dirs () - "System include dirs - from the 'INCLUDE' env setting." - (let* ((includes (getenv "INCLUDE"))) - (if includes (flymake-split-string includes path-separator) nil))) - -(defvar flymake-project-include-dirs-cache (flymake-makehash 'equal)) - -(defun flymake-get-project-include-dirs-from-cache (base-dir) - (gethash base-dir flymake-project-include-dirs-cache)) - -(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs) - (puthash base-dir include-dirs flymake-project-include-dirs-cache)) - -(defun flymake-clear-project-include-dirs-cache () - (clrhash flymake-project-include-dirs-cache)) - -(defun flymake-get-include-dirs (base-dir) - "Get dirs to use when resolving local file names." - (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs)))) - include-dirs)) - -;; (defun flymake-restore-formatting () -;; "Remove any formatting made by flymake." -;; ) - -;; (defun flymake-get-program-dir (buffer) -;; "Get dir to start program in." -;; (unless (bufferp buffer) -;; (error "Invalid buffer")) -;; (with-current-buffer buffer -;; default-directory)) - -(defun flymake-safe-delete-file (file-name) - (when (and file-name (file-exists-p file-name)) - (delete-file file-name) - (flymake-log 1 "deleted file %s" file-name))) - -(defun flymake-safe-delete-directory (dir-name) - (condition-case nil - (progn - (delete-directory dir-name) - (flymake-log 1 "deleted dir %s" dir-name)) - (error - (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name)))) - -(defcustom flymake-compilation-prevents-syntax-check t - "If non-nil, don't start syntax check if compilation is running." - :group 'flymake - :type 'boolean) - -(defcustom flymake-max-parallel-syntax-checks 4 - "If non-nil, the maximum number of syntax checks to run in parallel before queuing." - :group 'flymake - :type 'integer) - -(defvar flymake-syntax-check-queue () - "Queue of pending buffers to run flymake on if flymake-max-parallel-syntax-checks is exceeded.") - -(defun flymake-ready-for-next-syntax-check () - "Returns t if flymake is running less than flymake-max-parallel-syntax-checks checks, nil otherwise." - (or (not flymake-max-parallel-syntax-checks) - (< (length flymake-processes) flymake-max-parallel-syntax-checks))) - -(defun flymake-queue-syntax-check (buffer) - "Queue a syntax check on BUFFER to run later once number of parallel runs is low enough." - (flymake-log 3 "flymake syntax check queued for buffer: %s" buffer) - ;; For responsiveness to current activity we run as a LIFO stack rather than FIFO pipe - (setq flymake-syntax-check-queue (delete buffer flymake-syntax-check-queue)) - (push buffer flymake-syntax-check-queue) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (flymake-report-status nil ":Queued"))) - (flymake-log 3 "flymake syntax check queue is now: %s" flymake-syntax-check-queue)) - -(defun flymake-remove-queued-syntax-check (buffer) - "Remove a syntax check for BUFFER from the queue." - (flymake-log 3 "flymake syntax check removed from queue for buffer: %s" buffer) - (setq flymake-syntax-check-queue (delete buffer flymake-syntax-check-queue)) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (flymake-report-status nil nil))) - (flymake-log 3 "flymake syntax check queue is now: %s" flymake-syntax-check-queue)) - -(defun flymake-pop-next-live-buffer-in-queue () - "Pop the next still-existing buffer from the queue of pending syntax checks." - (while (and flymake-syntax-check-queue - (not (buffer-live-p (car flymake-syntax-check-queue)))) - (pop flymake-syntax-check-queue)) - (let ((buffer (pop flymake-syntax-check-queue))) - (flymake-log 3 "flymake syntax check popped for buffer: %s" buffer) - (flymake-log 3 "flymake syntax check queue is now: %s" flymake-syntax-check-queue) - buffer)) - -(defun flymake-run-next-queued-syntax-check () - "Run the next queued syntax check to run later once number of parallel runs is low enough." - (interactive) - (when (flymake-ready-for-next-syntax-check) - (let ((buffer (flymake-pop-next-live-buffer-in-queue))) - (when buffer - (with-current-buffer buffer - (flymake-start-syntax-check)))))) - -(defun flymake-start-syntax-check () - "Start syntax checking for current buffer. Once the syntax checking is -complete the `flymake-after-syntax-check-hook' hook will be run." - (interactive) - (flymake-log 3 "flymake is running: %s" flymake-is-running) - (when (and (not flymake-is-running) - (flymake-can-syntax-check-file buffer-file-name)) - (if (flymake-ready-for-next-syntax-check) - (when (or (not flymake-compilation-prevents-syntax-check) - (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP") - (flymake-clear-buildfile-cache) - (flymake-clear-project-include-dirs-cache) - - (setq flymake-check-was-interrupted nil) - (setq flymake-check-should-restart nil) - - (let* ((source-file-name buffer-file-name) - (init-f (flymake-get-init-function source-file-name)) - (cleanup-f (flymake-get-cleanup-function source-file-name)) - (tramp-verbose -1) - (cmd-and-args (funcall init-f)) - (cmd (nth 0 cmd-and-args)) - (args (nth 1 cmd-and-args)) - (dir (nth 2 cmd-and-args))) - (if (not cmd-and-args) - (progn - (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name) - (funcall cleanup-f)) - (progn - (setq flymake-last-change-time nil) - (flymake-start-syntax-check-process cmd args dir))))) - (flymake-queue-syntax-check (current-buffer))))) - -(defun flymake-syntax-check-directory (dir) - "Try to determine least-broken directory to use as the working directory -to run the syntax check command from. - -If DIR is supplied from the init function for the file type then that will -be used. - -Otherwise if `flymake-run-in-place' is nil and `default-directory' appears -to be a tramp file, we use `temporary-file-directory' as a least-worst -compromise to ensure the tempoary flymake copy of the buffer is on the same -machine as where the syntax check command is being run. - -Otherwise we fall through to using `default-directory'." - (or dir (if (and (not flymake-run-in-place) - (featurep 'tramp) - tramp-mode - (tramp-tramp-file-p default-directory)) - temporary-file-directory - default-directory))) - -(defun flymake-start-syntax-check-process (cmd args dir) - "Start syntax check process." - (condition-case err - ;; Attempt to preserve the buffer against output leaking before the - ;; process-filter is set up, this can occur when the process is - ;; started over a remote tramp connection. - ;; I'm fairly certain this is a bug in `tramp-handle-start-file-process' - ;; but I'm damned if I can figure out what, so this is a workaround. - (c-save-buffer-state () - (save-excursion - (save-restriction - (narrow-to-region (point-max) (point-max)) - ;; For some reason this insert is needed to prevent - ;; tramp-mode from inserting any MOTD on the remote - ;; machine outside the narrowed region. - ;; With this insert it puts the MOTD in the narrowed - ;; region and we can delete it safely. - ;; Beats me, and I'm not entirely comfortable with it. - (insert "\n") - (let* ((tramp-verbose -1) - (process - (let ((default-directory (flymake-syntax-check-directory dir))) - (flymake-log 3 "starting process on dir %s" default-directory) - (apply 'start-file-process "flymake-proc" (current-buffer) cmd args)))) - (set-process-query-on-exit-flag process nil) - (set-process-sentinel process 'flymake-process-sentinel) - (set-process-filter process 'flymake-process-filter) - (push process flymake-processes) - ;; Clean up any output that has leaked. Fixes issues with Tramp. - ;;(flymake-log 3 "buffer-string %s" (flymake-enquote-log-string (buffer-string))) - (delete-region (point-min) (point-max)) - - (setq flymake-is-running t) - (setq flymake-last-change-time nil) - (setq flymake-check-start-time (flymake-float-time)) - - (flymake-report-status nil "*") - (flymake-log 2 "started process %d, command=%s" - (process-id process) (process-command process)) - process)))) - (error - (let* ((err-str (format "Failed to launch syntax check process '%s' with args %s: %s" - cmd args (error-message-string err))) - (source-file-name buffer-file-name) - (cleanup-f (flymake-get-cleanup-function source-file-name)) - (tramp-verbose -1)) - (flymake-log 0 err-str) - (funcall cleanup-f) - (flymake-report-fatal-status "PROCERR" err-str))))) - -(defun flymake-kill-process (proc) - "Kill process PROC." - (kill-process proc) - (let* ((buf (process-buffer proc))) - (when (buffer-live-p buf) - (with-current-buffer buf - (setq flymake-check-was-interrupted t)))) - (flymake-log 1 "killed process %d" (process-id proc))) - -(defun flymake-stop-syntax-check (&optional buffer) - "Kill any queued or running syntax check for BUFFER. -Defaults to `current-buffer' if not supplied. - -NOTE: Stopping a syntax check will not complete until the spawned process has -been terminated, this happens asynchronously and it is highly likely that -immediately after calling `flymake-stop-syntax-check' the process will still -be running. Among other things, this will prevent starting a new syntax check -in the buffer until the process terminates. If you want to queue up a new -syntax check, you should look at `flymake-restart-syntax-check' which handles -this async delay correctly for you." - (interactive) - (let ((buffer (or buffer (current-buffer)))) - (flymake-remove-queued-syntax-check buffer) - (dolist (proc flymake-processes) - (if (equal (process-buffer proc) buffer) (flymake-kill-process proc))))) - -(defun flymake-stop-all-syntax-checks () - "Kill all syntax check processes." - (interactive) - (while flymake-syntax-check-queue - (flymake-remove-queued-syntax-check (car flymake-syntax-check-queue))) - (while flymake-processes - (flymake-kill-process (pop flymake-processes)))) - -(defun flymake-restart-syntax-check (&optional buffer) - "Kill any queued or running syntax check for BUFFER and start a new one. -Defaults to `current-buffer' if not supplied." - (interactive) - (let ((buffer (or buffer (current-buffer)))) - (flymake-remove-queued-syntax-check buffer) - (dolist (proc flymake-processes) - (when (equal (process-buffer proc) buffer) - (with-current-buffer buffer - (setq flymake-check-should-restart t)) - (flymake-kill-process proc))))) - -(defun flymake-compilation-is-running () - (and (boundp 'compilation-in-progress) - compilation-in-progress)) - -(defun flymake-compile () - "Kill all flymake syntax checks, start compilation." - (interactive) - (flymake-stop-all-syntax-checks) - (call-interactively 'compile)) - -(defcustom flymake-no-changes-timeout 0.5 - "Time to wait after last change before starting compilation." - :group 'flymake - :type 'number) - -(defun flymake-on-timer-event () - "Start a syntax check for current buffer if necessary." - (when (and flymake-mode - (not flymake-is-running) - flymake-last-change-time - (> (- (flymake-float-time) flymake-last-change-time) - flymake-no-changes-timeout)) - - (setq flymake-last-change-time nil) - (flymake-log 3 "starting syntax check as more than %f second(s) passed since last change" - flymake-no-changes-timeout) - (flymake-start-syntax-check))) - -(defun flymake-current-line-no () - "Return number of current line in current buffer." - (count-lines (point-min) (if (eobp) (point) (1+ (point))))) - -(defun flymake-count-lines () - "Return number of lines in buffer BUFFER." - (count-lines (point-min) (point-max))) - -(defun flymake-display-err-menu-for-current-line () - "Display a menu with errors/warnings for current line if it has errors and/or warnings." - (interactive) - (let* ((line-no (flymake-current-line-no)) - (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no))) - (menu-data (flymake-make-err-menu-data line-no line-err-info-list)) - (choice nil)) - (if menu-data - (progn - (setq choice (flymake-popup-menu menu-data)) - (flymake-log 3 "choice=%s" choice) - (when choice - (eval choice))) - (flymake-log 1 "no errors for line %d" line-no)))) - -(defun flymake-make-err-menu-data (line-no line-err-info-list) - "Make a (menu-title (item-title item-action)*) list with errors/warnings from LINE-ERR-INFO-LIST." - (let* ((menu-items nil)) - (when line-err-info-list - (let* ((count (length line-err-info-list)) - (menu-item-text nil)) - (while (> count 0) - (setq menu-item-text (flymake-ler-text (nth (1- count) line-err-info-list))) - (let* ((file (flymake-ler-file (nth (1- count) line-err-info-list))) - (full-file (flymake-ler-full-file (nth (1- count) line-err-info-list))) - (line (flymake-ler-line (nth (1- count) line-err-info-list)))) - (if file - (setq menu-item-text (concat menu-item-text " - " file "(" (format "%d" line) ")"))) - (setq menu-items (cons (list menu-item-text - (if file (list 'flymake-goto-file-and-line full-file line) nil)) - menu-items))) - (setq count (1- count))) - (flymake-log 3 "created menu-items with %d item(s)" (length menu-items)))) - (if menu-items - (let* ((menu-title (format "Line %d: %d error(s), %d warning(s), %d info" line-no - (flymake-get-line-err-count line-err-info-list "e") - (flymake-get-line-err-count line-err-info-list "w") - (flymake-get-line-err-count line-err-info-list "i")))) - (list menu-title menu-items)) - nil))) - -(defun flymake-goto-file-and-line (file line) - "Try to get buffer for FILE and goto line LINE in it." - (if (not (file-exists-p file)) - (flymake-log 1 "File %s does not exist" file) - (find-file file) - (goto-char (point-min)) - (forward-line (1- line)))) - -;; flymake minor mode declarations -(defvar flymake-mode-line nil) - -(make-variable-buffer-local 'flymake-mode-line) - -(defvar flymake-mode-line-e-w nil) - -(make-variable-buffer-local 'flymake-mode-line-e-w) - -(defvar flymake-mode-line-status nil) - -(make-variable-buffer-local 'flymake-mode-line-status) - -(defun flymake-report-status (e-w &optional status) - "Show status in mode line." - (when e-w - (setq flymake-mode-line-e-w e-w)) - (when status - (setq flymake-mode-line-status status)) - (let* ((mode-line " Flymake")) - (when (> (length flymake-mode-line-e-w) 0) - (setq mode-line (concat mode-line ":" flymake-mode-line-e-w))) - (setq mode-line (concat mode-line flymake-mode-line-status)) - (setq flymake-mode-line mode-line) - (force-mode-line-update))) - -(defun flymake-display-warning (warning) - "Display a warning to user." - (message-box warning)) - -(defcustom flymake-gui-warnings-enabled t - "Enables/disables GUI warnings." - :group 'flymake - :type 'boolean) - -(defun flymake-report-fatal-status (status warning) - "Display a warning and switch flymake mode off." - (when flymake-gui-warnings-enabled - (flymake-display-warning (format "Flymake: %s. Flymake will be switched OFF" warning))) - (flymake-mode 0) - (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s" - (buffer-name) status warning)) - -;;;###autoload -(defun flymake-mode-on () - "Turn flymake mode on." - (flymake-mode 1) - (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name))) - -;;;###autoload -(defun flymake-mode-off () - "Turn flymake mode off." - (flymake-mode 0) - (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name))) - -(defcustom flymake-start-syntax-check-on-newline t - "Start syntax check if newline char was added/removed from the buffer." - :group 'flymake - :type 'boolean) - -(defun flymake-after-change-function (start stop _len) - "Start syntax check for current buffer if it isn't already running." - ;;+(flymake-log 0 "setting change time to %s" (flymake-float-time)) - (let((new-text (buffer-substring start stop))) - (when (and flymake-start-syntax-check-on-newline (equal new-text "\n")) - (flymake-log 3 "starting syntax check as new-line has been seen") - (flymake-start-syntax-check)) - (setq flymake-last-change-time (flymake-float-time)))) - -(defun flymake-after-save-hook () - (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved? - (progn - (flymake-log 3 "starting syntax check as buffer was saved") - (flymake-start-syntax-check)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???) - -(defun flymake-kill-buffer-hook () - (when flymake-timer - (cancel-timer flymake-timer) - (setq flymake-timer nil))) - -;;;###autoload -(defun flymake-find-file-hook () - ;;+(when flymake-start-syntax-check-on-find-file - ;;+ (flymake-log 3 "starting syntax check on file open") - ;;+ (flymake-start-syntax-check) - ;;+) - (when (and (not (local-variable-p 'flymake-mode (current-buffer))) - (flymake-can-syntax-check-file buffer-file-name)) - (flymake-mode) - (flymake-log 3 "automatically turned ON flymake mode"))) - -(defun flymake-get-first-err-line-no (err-info-list) - "Return first line with error." - (when err-info-list - (flymake-er-get-line (car err-info-list)))) - -(defun flymake-get-last-err-line-no (err-info-list) - "Return last line with error." - (when err-info-list - (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list)))) - -(defun flymake-get-next-err-line-no (err-info-list line-no) - "Return next line with error." - (when err-info-list - (let* ((count (length err-info-list)) - (idx 0)) - (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list)))) - (setq idx (1+ idx))) - (if (< idx count) - (flymake-er-get-line (nth idx err-info-list)))))) - -(defun flymake-get-prev-err-line-no (err-info-list line-no) - "Return previous line with error." - (when err-info-list - (let* ((count (length err-info-list))) - (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list)))) - (setq count (1- count))) - (if (> count 0) - (flymake-er-get-line (nth (1- count) err-info-list)))))) - -(defun flymake-skip-whitespace () - "Move forward until non-whitespace is reached." - (while (looking-at "[ \t]") - (forward-char))) - -(defcustom flymake-goto-error-hook '() - "Hook run each time `flymake-goto-next-error' and `flymake-goto-prev-error' -are called." - :type 'hook - :group 'flymake) - -(defcustom flymake-goto-error-skip-whitespace t - "Whether to skip leading whitespace on the line when using -`flymake-goto-next-error' and `flymake-goto-prev-error'." - :type 'boolean - :group 'flymake) - -(defun flymake-goto-line (line-no) - "Go to line LINE-NO. -If `flymake-goto-error-skip-whitespace' is t also move past leading whitespace -on the line. -The hook `flymake-goto-error-hook' is run after moving to the new position." - (goto-char (point-min)) - (forward-line (1- line-no)) - (if flymake-goto-error-skip-whitespace - (flymake-skip-whitespace)) - (run-hooks 'flymake-goto-error-hook)) - -(defun flymake-goto-next-error () - "Go to next error in error ring. -The hook `flymake-goto-error-hook' is run after moving to the new position." - (interactive) - (let ((line-no (flymake-get-next-err-line-no flymake-err-info (flymake-current-line-no)))) - (when (not line-no) - (setq line-no (flymake-get-first-err-line-no flymake-err-info)) - (flymake-log 1 "passed end of file")) - (if line-no - (flymake-goto-line line-no) - (flymake-log 1 "no errors in current buffer")))) - -(defun flymake-goto-prev-error () - "Go to previous error in errror ring. -The hook `flymake-goto-error-hook' is run after moving to the new position." - (interactive) - (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (flymake-current-line-no)))) - (when (not line-no) - (setq line-no (flymake-get-last-err-line-no flymake-err-info)) - (flymake-log 1 "passed beginning of file")) - (if line-no - (flymake-goto-line line-no) - (flymake-log 1 "no errors in current buffer")))) - -(defun flymake-patch-err-text (string) - (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string) - (match-string 1 string) - string)) - -;;;; general init-cleanup and helper routines -;; TODO: rename these to something sane and deprecate the current names. -(defun flymake-create-temp-copy (file-name prefix) - "Make filename for a temporary copy of FILE-NAME. - -If `flymake-run-in-place' is true it will use `flymake-create-temp-inplace', -otherwise it will use `flymake-create-temp-intemp'. - -Note that this function, despite its name, does not actually create a -copy of the file: it only choses and returns a filename for the temp -copy." - (if flymake-run-in-place - (flymake-create-temp-inplace file-name prefix) - (flymake-create-temp-intemp file-name prefix))) - -(defun flymake-create-temp-inplace (file-name prefix) - "Return filename in the same directory as FILE-NAME for a -temporary copy of the buffer editing FILE-NAME. - -Despite the name of the argument, PREFIX will be appended to the -filename as a suffix to ensure we don't overwrite the original. -This usually defaults to \"flymake\". - -Note that this function, despite its name, does not actually create a -copy of the file: it only choses and returns a filename for the temp -copy." - (unless (stringp file-name) - (error "Invalid file-name")) - (or prefix - (setq prefix "flymake")) - (let* ((temp-name (file-truename (concat (file-name-sans-extension file-name) - "_" prefix - (and (file-name-extension file-name) - (concat "." (file-name-extension file-name))))))) - (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name) - temp-name)) - -;; This was lifted from various blogs, I'm not sure who the original -;; author was - whoever it was: thank you! -;; I got it from http://blog.urth.org/2011/06/flymake-versus-the-catalyst-restarter.html -;; but Dave Rolsky indicates he got it from elsewhere. -(defun flymake-create-temp-intemp (file-name prefix) - "Return filename in temporary directory for a temporary -copy of the buffer editing FILE-NAME. This is a replacement for -`flymake-create-temp-inplace'. The difference is that it gives -a file name in `temporary-file-directory' instead of the same -directory as FILE-NAME. - -For the use of PREFIX see that function. - -Note that not making the temporary file in another directory -\(like here) will not work if the file you are checking depends -relative paths to other files \(for the type of checks flymake -makes). - -Note that this function, despite its name, does not actually create a -copy of the file: it only choses and returns a filename for the temp -copy." - (unless (stringp file-name) - (error "Invalid file-name")) - (or prefix - (setq prefix "flymake")) - (let* ((name (concat - (file-name-nondirectory (file-name-sans-extension file-name)) - "_" prefix)) - (ext (concat "." (file-name-extension file-name))) - (temp-name (file-truename (make-temp-file name nil ext)))) - (flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name) - temp-name)) - -(defun flymake-create-temp-with-folder-structure (file-name prefix) - (unless (stringp file-name) - (error "Invalid file-name")) - - (let* ((dir (file-name-directory file-name)) - ;; Not sure what this slash-pos is all about, but I guess it's just - ;; trying to remove the leading / of absolute file names. - (slash-pos (string-match "/" dir)) - (temp-dir (expand-file-name (substring dir (1+ slash-pos)) - (flymake-get-temp-dir)))) - - (file-truename (expand-file-name (file-name-nondirectory file-name) - temp-dir)))) - -(defun flymake-delete-temp-directory (dir-name) - "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error." - (let* ((dir-name (file-truename dir-name)) - (temp-dir (file-truename (flymake-get-temp-dir))) - (suffix (substring dir-name (length temp-dir)))) - - (while (> (length suffix) 0) - (setq suffix (directory-file-name suffix)) - ;;(flymake-log 0 "suffix=%s" suffix) - ;;(flymake-log 0 "delete=%s" (file-truename (expand-file-name suffix temp-dir))) - (flymake-safe-delete-directory - (file-truename (expand-file-name suffix temp-dir))) - (setq suffix (file-name-directory suffix))))) - -(defvar flymake-temp-source-file-name nil) -(make-variable-buffer-local 'flymake-temp-source-file-name) - -(defvar flymake-master-file-name nil) -(make-variable-buffer-local 'flymake-master-file-name) - -(defvar flymake-temp-master-file-name nil) -(make-variable-buffer-local 'flymake-temp-master-file-name) - -(defvar flymake-base-dir nil) -(make-variable-buffer-local 'flymake-base-dir) - -(defun flymake-init-create-temp-buffer-copy (create-temp-f) - "Make a temporary copy of the current buffer, save its name in buffer data and return the name." - (let* ((source-file-name buffer-file-name) - (temp-source-file-name (funcall create-temp-f source-file-name "flymake"))) - - (flymake-save-buffer-in-file temp-source-file-name) - (setq flymake-temp-source-file-name temp-source-file-name) - temp-source-file-name)) - -(defun flymake-simple-cleanup () - "Do cleanup after `flymake-init-create-temp-buffer-copy'. -Delete temp file." - (flymake-safe-delete-file flymake-temp-source-file-name) - (setq flymake-last-change-time nil)) - -(defun flymake-get-real-file-name (file-name-from-err-msg) - "Translate file name from error message to \"real\" file name. -Return full-name. Names are real, not patched." - (let* ((real-name nil) - (source-file-name buffer-file-name) - (master-file-name flymake-master-file-name) - (temp-source-file-name flymake-temp-source-file-name) - (temp-master-file-name flymake-temp-master-file-name) - (base-dirs - (list flymake-base-dir - (file-name-directory source-file-name) - (if master-file-name (file-name-directory master-file-name)))) - (files (list (list source-file-name source-file-name) - (list temp-source-file-name source-file-name) - (list master-file-name master-file-name) - (list temp-master-file-name master-file-name)))) - - (when (equal 0 (length file-name-from-err-msg)) - (setq file-name-from-err-msg source-file-name)) - - (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files)) - ;; if real-name is nil, than file name from err msg is none of the files we've patched - (if (not real-name) - (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs))) - (if (not real-name) - (setq real-name file-name-from-err-msg)) - (setq real-name (flymake-fix-file-name real-name)) - (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name) - real-name)) - -(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files) - (let* ((base-dirs-count (length base-dirs)) - (file-count (length files)) - (real-name nil)) - - (while (and (not real-name) (> base-dirs-count 0)) - (setq file-count (length files)) - (while (and (not real-name) (> file-count 0)) - (let* ((this-dir (nth (1- base-dirs-count) base-dirs)) - (this-file (nth 0 (nth (1- file-count) files))) - (this-real-name (nth 1 (nth (1- file-count) files)))) - ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg) - (when (and this-dir this-file (flymake-same-files - (expand-file-name file-name-from-err-msg this-dir) - this-file)) - (setq real-name this-real-name))) - (setq file-count (1- file-count))) - (setq base-dirs-count (1- base-dirs-count))) - real-name)) - -(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs) - (let* ((real-name nil)) - (if (file-name-absolute-p file-name-from-err-msg) - (setq real-name file-name-from-err-msg) - (let* ((base-dirs-count (length base-dirs))) - (while (and (not real-name) (> base-dirs-count 0)) - (let* ((full-name (expand-file-name file-name-from-err-msg - (nth (1- base-dirs-count) base-dirs)))) - (if (file-exists-p full-name) - (setq real-name full-name)) - (setq base-dirs-count (1- base-dirs-count)))))) - real-name)) - -(defun flymake-init-find-buildfile-dir (source-file-name buildfile-name) - "Find buildfile, store its dir in buffer data and return its dir, if found." - (let* ((buildfile-dir - (flymake-find-buildfile buildfile-name - (file-name-directory source-file-name)))) - (if buildfile-dir - (setq flymake-base-dir buildfile-dir) - (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name) - (flymake-report-fatal-status - "NOMK" (format "No buildfile (%s) found for %s" - buildfile-name source-file-name))))) - -(defun flymake-init-create-temp-source-and-master-buffer-copy (get-incl-dirs-f create-temp-f master-file-masks include-regexp) - "Find master file (or buffer), create its copy along with a copy of the source file." - (let* ((source-file-name buffer-file-name) - (temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)) - (master-and-temp-master (flymake-create-master-file - source-file-name temp-source-file-name - get-incl-dirs-f create-temp-f - master-file-masks include-regexp))) - - (if (not master-and-temp-master) - (progn - (flymake-log 1 "cannot find master file for %s" source-file-name) - (flymake-report-status "!" "") ; NOMASTER - nil) - (setq flymake-master-file-name (nth 0 master-and-temp-master)) - (setq flymake-temp-master-file-name (nth 1 master-and-temp-master))))) - -(defun flymake-master-cleanup () - (flymake-simple-cleanup) - (flymake-safe-delete-file flymake-temp-master-file-name)) - -;;;; make-specific init-cleanup routines -(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f) - "Create a command line for syntax check using GET-CMD-LINE-F." - (funcall get-cmd-line-f - (if use-relative-source - (file-relative-name source-file-name base-dir) - source-file-name) - (if use-relative-base-dir - (file-relative-name base-dir - (file-name-directory source-file-name)) - base-dir))) - -(defun flymake-get-make-cmdline (source base-dir) - (list "make" - (list "-s" - "-C" - base-dir - (concat "CHK_SOURCES=" source) - "SYNTAX_CHECK_MODE=1" - "check-syntax"))) - -(defun flymake-get-ant-cmdline (source base-dir) - (list "ant" - (list "-buildfile" - (concat base-dir "/" "build.xml") - (concat "-DCHK_SOURCES=" source) - "check-syntax"))) - -(defun flymake-simple-make-init-impl (create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f) - "Create syntax check command line for a directly checked source file. -Use CREATE-TEMP-F for creating temp copy." - (let* ((args nil) - (source-file-name buffer-file-name) - (buildfile-dir (flymake-init-find-buildfile-dir source-file-name build-file-name))) - (if buildfile-dir - (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f))) - (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir - use-relative-base-dir use-relative-source - get-cmdline-f)))) - args)) - -(defun flymake-simple-make-init () - (flymake-simple-make-init-impl 'flymake-create-temp-copy - flymake-run-in-place t "Makefile" 'flymake-get-make-cmdline)) - -(defun flymake-master-make-init (get-incl-dirs-f master-file-masks include-regexp) - "Create make command line for a source file checked via master file compilation." - (let* ((make-args nil) - (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy - get-incl-dirs-f 'flymake-create-temp-copy - master-file-masks include-regexp))) - (when temp-master-file-name - (let* ((buildfile-dir (flymake-init-find-buildfile-dir temp-master-file-name "Makefile"))) - (if buildfile-dir - (setq make-args (flymake-get-syntax-check-program-args - temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline))))) - make-args)) - -(defun flymake-find-make-buildfile (source-dir) - (flymake-find-buildfile "Makefile" source-dir)) - -;;;; .h/make specific -(defun flymake-master-make-header-init () - (flymake-master-make-init - 'flymake-get-include-dirs - '("\\.\\(?:c\\(?:pp\\|xx\\|\\+\\+\\)?\\|CC\\)\\'") - "[ \t]*#[ \t]*include[ \t]*\"\\([[:word:]0-9/\\_.]*%s\\)\"")) - -;;;; .java/make specific -(defun flymake-simple-make-java-init () - (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline)) - -(defun flymake-simple-ant-java-init () - (flymake-simple-make-init-impl 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline)) - -(defun flymake-simple-java-cleanup () - "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs." - (flymake-safe-delete-file flymake-temp-source-file-name) - (when flymake-temp-source-file-name - (flymake-delete-temp-directory - (file-name-directory flymake-temp-source-file-name)))) - -;;;; perl-specific init-cleanup routines -(defun flymake-perlbrew-path-sync () - "Sync $PATH in the environment of the current Emacs process with modifications -made by perlbrew in other shell processes. - -Detection of perlbrew relies on $PERLBREW_ROOT being set in the environment, if -you're using a GUI-launched Emacs such as Emacs.app then you may need to take -steps to set this manually." - (when (getenv "PERLBREW_ROOT") - ;; This is pretty ugly, we need to run a bash intepreter, source - ;; the perlbrew path hacking, then echo the modified path. - ;; The antics with PATH=... is to try to make sure we don't trash - ;; $PATH in the event that the command errors for some reason - don't - ;; want our path set to the error message. - (let ((raw-modified-path (shell-command-to-string (concat "bash -c '. " (getenv "PERLBREW_ROOT") "/etc/bashrc;echo \"PATH=$PATH\"'")))) - (string-match "PATH=\\(.+\\)$" raw-modified-path) - (let ((modified-path (match-string 1 raw-modified-path))) - (if modified-path - (progn - (flymake-log 2 "Updating $PATH to match perlbrew $PATH: \"%s\"" modified-path) - (setenv "PATH" modified-path)) - (flymake-log 1 "Unable to parse perlbrew $PATH output \"%s\"" raw-modified-path)))))) - -(defcustom flymake-perl-lib-dir nil - "Path to override Flymake's attempt to find the Perl include dir -for a project with `flymake-find-perl-lib-dir`." - :group 'flymake - :type 'string) - -(defun flymake-find-perl-lib-dir (source-dir) - "Look for a directory to push onto the Perl include directories with -the -I option. - -Looks up the directory tree from the source file for a directory containing -either a \"Makefile.PL\" or a \"Build.PL\" file, or a directory named \"lib\", -then uses the \"lib\" subdirectory of that project directory. - -Alternatively you may override this behaviour by customizing the -`flymake-perl-lib-dir` variable to give the exact directory name you -wish to have supplied to Perl -I." - (or - (if flymake-perl-lib-dir (expand-file-name flymake-perl-lib-dir)) - (let ((project-root-dir - (or (flymake-find-buildfile "Makefile.PL" source-dir) - (flymake-find-buildfile "Build.PL" source-dir) - (flymake-find-buildfile "lib" source-dir)))) - (when project-root-dir - (expand-file-name (concat project-root-dir "lib")))))) - -(defun flymake-perl-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name))) - (include-dir (flymake-find-perl-lib-dir buffer-file-name))) - (flymake-perlbrew-path-sync) - (list "perl" (append - (list "-wc") - (if include-dir (list "-I" include-dir)) - (list local-file))))) - -;;;; php-specific init-cleanup routines -(defun flymake-php-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "php" (list "-f" local-file "-l")))) - -;;;; javascript-specific init-cleanup routines -(defun flymake-javascript-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "jshint" (list local-file)))) - -;;;; css-specific init-cleanup routines -(defun flymake-css-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "csslint" (list "--format=compact" local-file)))) - -;; rpm spec files with rpmlint -(defun flymake-specfile-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "rpmlint" (list local-file)))) - -;; check po files with msgfmt -c -(defun flymake-pofile-init () - (let* ((temp-file (flymake-init-create-temp-buffer-copy - 'flymake-create-temp-copy)) - (local-file (file-relative-name - temp-file - (file-name-directory buffer-file-name)))) - (list "msgfmt" (list "-c" local-file)))) - - -;;;; tex-specific init-cleanup routines -(defun flymake-get-tex-args (file-name) - ;;(list "latex" (list "-c-style-errors" file-name)) - (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name))) - -(defun flymake-simple-tex-init () - (flymake-get-tex-args (flymake-init-create-temp-buffer-copy 'flymake-create-temp-copy))) - -(defun flymake-master-tex-init () - (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy - 'flymake-get-include-dirs-dot 'flymake-create-temp-copy - '("\\.tex\\'") - "[ \t]*\\in\\(?:put\\|clude\\)[ \t]*{\\(.*%s\\)}"))) - (when temp-master-file-name - (flymake-get-tex-args temp-master-file-name)))) - -(defun flymake-get-include-dirs-dot (_base-dir) - '(".")) - -;;;; xml-specific init-cleanup routines -(defun flymake-xml-init () - (list "xmlstarlet" (list "val" "-e" (flymake-init-create-temp-buffer-copy 'flymake-create-temp-copy)))) - -(provide 'flymake) - -;;; flymake.el ends here diff --git a/misc/multi-term.el b/misc/multi-term.el deleted file mode 100644 index 780e382..0000000 --- a/misc/multi-term.el +++ /dev/null @@ -1,794 +0,0 @@ -;;; multi-term.el --- Managing multiple terminal buffers in Emacs. - -;; Author: Andy Stewart -;; Maintainer: ahei -;; Copyright (C) 2008, 2009, Andy Stewart, all rights reserved. -;; Copyright (C) 2010, ahei, all rights reserved. -;; Created: <2008-09-19 23:02:42> -;; Version: 0.8.9 -;; Last-Updated: <2013-01-08 10:11:43 Tuesday by jpkotta> -;; URL: http://www.emacswiki.org/emacs/download/multi-term.el -;; Keywords: term, terminal, multiple buffer -;; Compatibility: GNU Emacs 23.2.1 - -;; 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, 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; see the file COPYING. If not, write to -;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth -;; Floor, Boston, MA 02110-1301, USA. - -;; Features that might be required by this library: -;; -;; `term' `cl' `advice' -;; - -;;; Commentary: -;; -;; This package is for creating and managing multiple terminal buffers in Emacs. -;; -;; By default, term.el provides a great terminal emulator in Emacs. -;; But I have some troubles with term-mode: -;; -;; 1. term.el just provides commands `term' or `ansi-term' -;; for creating a terminal buffer. -;; And there is no special command to create or switch -;; between multiple terminal buffers quickly. -;; -;; 2. By default, the keystrokes of term.el conflict with global-mode keystrokes, -;; which makes it difficult for the user to integrate term.el with Emacs. -;; -;; 3. By default, executing *NIX command “exit” from term-mode, -;; it will leave an unused buffer. -;; -;; 4. term.el won’t quit running sub-process when you kill terminal buffer forcibly. -;; -;; 5. Haven’t a dedicated window for debug program. -;; -;; And multi-term.el is enhanced with those features. -;; - -;;; Installation: -;; -;; Copy multi-term.el to your load-path and add to your ~/.emacs -;; -;; (require 'multi-term) -;; -;; And setup program that `multi-term' will need: -;; -;; (setq multi-term-program "/bin/bash") -;; -;; or setup like me "/bin/zsh" ;) -;; -;; Below are the commands you can use: -;; -;; `multi-term' Create a new term buffer. -;; `multi-term-next' Switch to next term buffer. -;; `multi-term-prev' Switch to previous term buffer. -;; `multi-term-dedicated-open' Open dedicated term window. -;; `multi-term-dedicated-close' Close dedicated term window. -;; `multi-term-dedicated-toggle' Toggle dedicated term window. -;; `multi-term-dedicated-select' Select dedicated term window. -;; -;; Tips: -;; -;; You can type `C-u' before command `multi-term' or `multi-term-dedicated-open' -;; then will prompt you shell name for creating terminal buffer. -;; - -;;; Customize: -;; -;; `multi-term-program' default is nil, so when creating new term buffer, -;; send environment variable of `SHELL' (`ESHELL', `/bin/sh') to `make-term'. -;; -;; And you can set it to your liking, like me: ;-) -;; -;; (setq multi-term-program "/bin/zsh") -;; -;; `multi-term-default-dir' default is `~/', only use when current buffer -;; is not in a real directory. -;; -;; `multi-term-buffer-name' is the name of term buffer. -;; -;; `multi-term-scroll-show-maximum-output' controls how interpreter -;; output causes window to scroll. -;; -;; `multi-term-scroll-to-bottom-on-output' controls whether interpreter -;; output causes window to scroll. -;; -;; `multi-term-switch-after-close' try to switch other `multi-term' buffer -;; after close current one. -;; If you don't like this feature just set it with nil. -;; -;; `term-unbind-key-list' is a key list to unbind some keystroke. -;; -;; `term-bind-key-alist' is a key alist that binds some keystroke. -;; If you don't like default, modify it. -;; -;; `multi-term-dedicated-window-height' the height of a dedicated term window. -;; -;; `multi-term-dedicated-max-window-height' the max height limit that dedicated -;; window is allowed. -;; -;; `multi-term-dedicated-skip-other-window-p' whether skip dedicated term -;; window when use command `other-window' to cycle windows order. -;; -;; All of the above can be customize by: -;; M-x customize-group RET multi-term RET -;; - -;;; Change log: -;; 2013/01/08 -;; * Fix customize group of `multi-term-try-create'. -;; * Add autoloads. -;; * Add new commands `term-send-quote' and `term-send-M-x'. -;; -;; 2009/07/04 -;; * Add new option `multi-term-dedicated-select-after-open-p'. -;; -;; 2009/06/29 -;; * Fix regexp bug. -;; -;; 2009/04/21 -;; * Fix a bug that bring at `2009/03/28': -;; It will kill sub-process in other multi-term buffer -;; when we kill current multi-term buffer. -;; -;; 2009/03/29 -;; * Add new command `term-send-reverse-search-history'. -;; -;; 2009/03/28 -;; * Add new option `multi-term-switch-after-close'. -;; -;; 2009/02/18 -;; * Fix bug between ECB and `multi-term-dedicated-close'. -;; -;; 2009/02/05 -;; * Prompt user shell name when type `C-u' before command -;; `multi-term' or `multi-term-dedicated-open'. -;; * Fix doc. -;; -;; 2009/01/29 -;; * Use `term-quit-subjob' instead `term-interrupt-subjob'. -;; * Fix doc. -;; -;; 2009/01/13 -;; * Rewrite advice for `pop-to-buffer' to avoid `pop-to-buffer' not effect -;; when have many dedicated window in current frame. -;; * Rewrite advice for `delete-other-windows' to avoid use common variable -;; `delete-protected-window-list' and use `window-dedicated-p' instead. -;; Remove variable `delete-protected-window-list' and function -;; `multi-term-dedicated-match-protected-window-p'. -;; -;; 2009/01/06 -;; * Improve document. -;; -;; 2008/12/29 -;; * Remove option `multi-term-current-window-height' and -;; function `multi-term-current-directory'. -;; * Add some functions to make get dedicated term buffer, -;; those functions is beginning with `multi-term-dedicated-'. -;; * Modified advice `delete-window', make command `delete-window' -;; and delete dedicated window, but will remember window height -;; before deleted. -;; * Don't remember dedicated window height if larger than max value. -;; * Fix some bug with `delete-other-windows' and window configuration. -;; And this bug exists with another extension `sr-speedbar'. -;; * Add new variable `delete-protected-window-list' for protected -;; special window that won't be deleted. -;; This variable is common for any extension that use dedicated -;; window. -;; * Fix doc. -;; -;; 2008/12/21 -;; * Default bind `C-m' with `term-send-input'. -;; -;; 2008/12/10 -;; * Improve customize interface. -;; * Setup customize automatically, don't need to user setup it up. -;; * Add option `multi-term-try-create'. -;; * Make function `multi-term-switch' accept offset argument. -;; * Fix doc. -;; -;; 2008/10/22 -;; * Add variable `multi-term-current-window-height'. -;; * Add variable `multi-term-buffer-name'. -;; * Add variable `term-unbind-key-list'. -;; * Add variable `term-rebind-key-alist'. -;; * Move key setup and some extension from `term-extension.el'. -;; * Create new function `multi-term-keystroke-setup'. -;; * Fix doc. -;; -;; 2008/09/19 -;; * First released. -;; - -;;; Acknowledgments: -;; -;; Mark Triggs -;; For create multi-shell.el -;; Aaron S. Hawley -;; For improve document. -;; - -;;; Bug -;; -;; - -;;; TODO -;; -;; -;; - -;;; Require: -(require 'term) -(require 'cl) -(require 'advice) - -;;; Code: - -;;; Customize - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Customize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defgroup multi-term nil - "Multi term manager." - :group 'term) - -(defcustom multi-term-program nil - "The program of term. -If this is nil, setup to environment variable of `SHELL'." - :type 'string - :group 'multi-term) - -(defcustom multi-term-program-switches nil - "The command-line switches to pass to the term program." - :type 'string - :group 'multi-term) - -(defcustom multi-term-try-create t - "Try to create a new term buffer when switch. - -When use `multi-term-next' or `multi-term-prev', switch term buffer, -and try to create a new term buffer if no term buffers exist." - :type 'boolean - :group 'multi-term) - -(defcustom multi-term-default-dir "~/" - "The default directory for terms if current directory doesn't exist." - :type 'string - :group 'multi-term) - -(defcustom multi-term-buffer-name "terminal" - "The buffer name of term buffer." - :type 'string - :group 'multi-term) - -(defcustom multi-term-scroll-show-maximum-output nil - "*Controls how interpreter output causes window to scroll. -If non-nil, then show the maximum output when the window is scrolled. - -See variable `multi-term-scroll-to-bottom-on-output'." - :type 'boolean - :group 'multi-term) - -(defcustom multi-term-scroll-to-bottom-on-output nil - "*Controls whether interpreter output causes window to scroll. -If nil, then do not scroll. If t or `all', scroll all windows showing buffer. -If `this', scroll only the selected window. -If `others', scroll only those that are not the selected window. - -The default is nil. - -See variable `multi-term-scroll-show-maximum-output'." - :type 'boolean - :group 'multi-term) - -(defcustom multi-term-switch-after-close 'NEXT - "Try to switch other `multi-term' buffer after close current one. -If this option is 'NEXT, switch to next `multi-term' buffer; -If this option is 'PREVIOUS, switch to previous `multi-term' buffer. -If this option is nil, don't switch other `multi-term' buffer." - :type 'symbol - :group 'multi-term) - -(defcustom term-unbind-key-list - '("C-z" "C-x" "C-c" "C-h" "C-y" "") - "The key list that will need to be unbind." - :type 'list - :group 'multi-term) - -(defcustom term-bind-key-alist - '( - ("C-c C-c" . term-interrupt-subjob) - ("C-p" . previous-line) - ("C-n" . next-line) - ("C-s" . isearch-forward) - ("C-r" . isearch-backward) - ("C-m" . term-send-raw) - ("M-f" . term-send-forward-word) - ("M-b" . term-send-backward-word) - ("M-o" . term-send-backspace) - ("M-p" . term-send-up) - ("M-n" . term-send-down) - ("M-M" . term-send-forward-kill-word) - ("M-N" . term-send-backward-kill-word) - ("M-r" . term-send-reverse-search-history) - ("M-," . term-send-input) - ("M-." . comint-dynamic-complete)) - "The key alist that will need to be bind. -If you do not like default setup, modify it, with (KEY . COMMAND) format." - :type 'alist - :group 'multi-term) - -(defcustom multi-term-dedicated-window-height 14 - "The height of `multi-term' dedicated window." - :type 'integer - :group 'multi-term) - -(defcustom multi-term-dedicated-max-window-height 30 - "The max height limit of `multi-term' dedicated window. -Default, when hide `multi-term' dedicated window, will remember -window height before hide, except height is larger than this.`" - :type 'integer - :group 'multi-term) - -(defcustom multi-term-dedicated-skip-other-window-p nil - "Default, can have `other-window' select window in cyclic ordering of windows. -In cases you don't want to select `multi-term' dedicated window, use `other-window' -and make `multi-term' dedicated window as a viewable sidebar. - -So please turn on this option if you want to skip `multi-term' dedicated window with `other-window'. - -Default is nil." - :type 'boolean - :set (lambda (symbol value) - (set symbol value) - (when (ad-advised-definition-p 'other-window) - (multi-term-dedicated-handle-other-window-advice value))) - :group 'multi-term) - -(defcustom multi-term-dedicated-select-after-open-p nil - "Default, multi-term won't focus terminal window after you open dedicated window. -Please make this option with t if you want focus terminal window. - -Default is nil." - :type 'boolean - :group 'multi-term) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Constant ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defconst multi-term-dedicated-buffer-name "MULTI-TERM-DEDICATED" - "The buffer name of dedicated `multi-term'.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Variable ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defvar multi-term-dedicated-window nil - "The dedicated `multi-term' window.") - -(defvar multi-term-dedicated-buffer nil - "The dedicated `multi-term' buffer.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Interactive Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;;###autoload -(defun multi-term () - "Create new term buffer. -Will prompt you shell name when you type `C-u' before this command." - (interactive) - (let (term-buffer) - ;; Set buffer. - (setq term-buffer (multi-term-get-buffer current-prefix-arg)) - (set-buffer term-buffer) - ;; Internal handle for `multi-term' buffer. - (multi-term-internal) - ;; Switch buffer - (switch-to-buffer term-buffer))) - -;;;###autoload -(defun multi-term-next (&optional offset) - "Go to the next term buffer. -If OFFSET is `non-nil', will goto next term buffer with OFFSET." - (interactive "P") - (multi-term-switch 'NEXT (or offset 1))) - -;;;###autoload -(defun multi-term-prev (&optional offset) - "Go to the previous term buffer. -If OFFSET is `non-nil', will goto previous term buffer with OFFSET." - (interactive "P") - (multi-term-switch 'PREVIOUS (or offset 1))) - -;;;###autoload -(defun multi-term-dedicated-open () - "Open dedicated `multi-term' window. -Will prompt you shell name when you type `C-u' before this command." - (interactive) - (if (not (multi-term-dedicated-exist-p)) - (let ((current-window (selected-window))) - (if (multi-term-buffer-exist-p multi-term-dedicated-buffer) - (unless (multi-term-window-exist-p multi-term-dedicated-window) - (multi-term-dedicated-get-window)) - ;; Set buffer. - (setq multi-term-dedicated-buffer (multi-term-get-buffer current-prefix-arg t)) - (set-buffer (multi-term-dedicated-get-buffer-name)) - ;; Get dedicate window. - (multi-term-dedicated-get-window) - ;; Whether skip `other-window'. - (multi-term-dedicated-handle-other-window-advice multi-term-dedicated-skip-other-window-p) - ;; Internal handle for `multi-term' buffer. - (multi-term-internal)) - (set-window-buffer multi-term-dedicated-window (get-buffer (multi-term-dedicated-get-buffer-name))) - (set-window-dedicated-p multi-term-dedicated-window t) - ;; Select window. - (select-window - (if multi-term-dedicated-select-after-open-p - ;; Focus dedicated terminal window if option `multi-term-dedicated-select-after-open-p' is enable. - multi-term-dedicated-window - ;; Otherwise focus current window. - current-window))) - (message "`multi-term' dedicated window has exist."))) - -(defun multi-term-dedicated-close () - "Close dedicated `multi-term' window." - (interactive) - (if (multi-term-dedicated-exist-p) - (let ((current-window (selected-window))) - ;; Remember height. - (multi-term-dedicated-select) - (multi-term-dedicated-remember-window-height) - ;; Close window. - (if (and (require 'ecb nil t) - ecb-activated-window-configuration) - ;; Toggle ECB window when ECB window activated. - (progn - (ecb-deactivate) - (ecb-activate)) - ;; Otherwise delete dedicated window. - (delete-window multi-term-dedicated-window) - (if (multi-term-window-exist-p current-window) - (select-window current-window)))) - (message "`multi-term' window is not exist."))) - -(defun multi-term-dedicated-remember-window-height () - "Remember window height." - (let ((win-height (multi-term-current-window-take-height))) - (if (and (multi-term-dedicated-window-p) ;in `multi-term' window - (> win-height 1) - (<= win-height multi-term-dedicated-max-window-height)) - (setq multi-term-dedicated-window-height win-height)))) - -;;;###autoload -(defun multi-term-dedicated-toggle () - "Toggle dedicated `multi-term' window." - (interactive) - (if (multi-term-dedicated-exist-p) - (multi-term-dedicated-close) - (multi-term-dedicated-open))) - -;;;###autoload -(defun multi-term-dedicated-select () - "Select the `multi-term' dedicated window." - (interactive) - (if (multi-term-dedicated-exist-p) - (select-window multi-term-dedicated-window) - (message "`multi-term' window is not exist."))) - -(defun term-send-backward-kill-word () - "Backward kill word in term mode." - (interactive) - (term-send-raw-string "\C-w")) - -(defun term-send-forward-kill-word () - "Kill word in term mode." - (interactive) - (term-send-raw-string "\ed")) - -(defun term-send-backward-word () - "Move backward word in term mode." - (interactive) - (term-send-raw-string "\eb")) - -(defun term-send-forward-word () - "Move forward word in term mode." - (interactive) - (term-send-raw-string "\ef")) - -(defun term-send-reverse-search-history () - "Search history reverse." - (interactive) - (term-send-raw-string "\C-r")) - -(defun term-send-quote () - "Quote the next character in term-mode. -Similar to how `quoted-insert' works in a regular buffer." - (interactive) - (term-send-raw-string "\C-v")) - -(defun term-send-M-x () - "Type M-x in term-mode." - (interactive) - (term-send-raw-string "\ex")) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utilise Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun multi-term-internal () - "Internal handle for `multi-term' buffer." - ;; Add customize keystroke with `term-mode-hook' - (remove-hook 'term-mode-hook 'multi-term-keystroke-setup) - (add-hook 'term-mode-hook 'multi-term-keystroke-setup) - ;; Load term mode - (term-mode) - (term-char-mode) - ;; Handle term buffer close - (multi-term-handle-close) - ;; Handle `output' variable. - (setq term-scroll-show-maximum-output multi-term-scroll-show-maximum-output - term-scroll-to-bottom-on-output multi-term-scroll-to-bottom-on-output) - ;; Add hook to be sure `term' quit subjob before buffer killed. - (add-hook 'kill-buffer-hook 'multi-term-kill-buffer-hook)) - -(defun multi-term-get-buffer (&optional special-shell dedicated-window) - "Get term buffer. -If option SPECIAL-SHELL is `non-nil', will use shell from user input. -If option DEDICATED-WINDOW is `non-nil' will create dedicated `multi-term' window ." - (with-temp-buffer - (let ((shell-name (or multi-term-program ;shell name - (getenv "SHELL") - (getenv "ESHELL") - "/bin/sh")) - term-list-length ;get length of term list - index ;setup new term index - term-name) ;term name - (if dedicated-window - (setq term-name multi-term-dedicated-buffer-name) - ;; Compute index. - (setq term-list-length (length (multi-term-list))) - (setq index (if term-list-length (1+ term-list-length) 1)) - ;; switch to current local directory, - ;; if in-existence, switch to `multi-term-default-dir'. - (cd (or default-directory (expand-file-name multi-term-default-dir))) - ;; adjust value N when max index of term buffer is less than length of term list - (while (buffer-live-p (get-buffer (format "*%s<%s>*" multi-term-buffer-name index))) - (setq index (1+ index))) - (setq term-name (format "%s<%s>" multi-term-buffer-name index))) - ;; Try get other shell name if `special-shell' is non-nil. - (if special-shell - (setq shell-name (read-from-minibuffer "Run program: " shell-name))) - ;; Make term, details to see function `make-term' in `term.el'. - (if multi-term-program-switches - (make-term term-name shell-name nil multi-term-program-switches) - (make-term term-name shell-name))))) - - -(defun multi-term-handle-close () - "Close current term buffer when `exit' from term buffer." - (when (ignore-errors (get-buffer-process (current-buffer))) - (set-process-sentinel (get-buffer-process (current-buffer)) - (lambda (proc change) - (when (string-match "\\(finished\\|exited\\)" change) - (kill-buffer (process-buffer proc))))))) - -(defun multi-term-kill-buffer-hook () - "Function that hook `kill-buffer-hook'." - (when (eq major-mode 'term-mode) - ;; Quit the current subjob - ;; when have alive process with current term buffer. - ;; Must do this job BEFORE `multi-term-switch-after-close' action. - (when (term-check-proc (current-buffer)) - ;; Quit sub-process. - (term-quit-subjob)) - ;; Remember dedicated window height. - (multi-term-dedicated-remember-window-height) - ;; Try to switch other multi-term buffer - ;; when option `multi-term-switch-after-close' is non-nil. - (when multi-term-switch-after-close - (multi-term-switch-internal multi-term-switch-after-close 1)))) - -(defun multi-term-list () - "List term buffers presently active." - ;; Autload command `remove-if-not'. - (autoload 'remove-if-not "cl-seq") - (sort - (remove-if-not (lambda (b) - (setq case-fold-search t) - (string-match - (format "^\\\*%s<[0-9]+>\\\*$" multi-term-buffer-name) - (buffer-name b))) - (buffer-list)) - (lambda (a b) - (< (string-to-number - (cadr (split-string (buffer-name a) "[<>]"))) - (string-to-number - (cadr (split-string (buffer-name b) "[<>]"))))))) - -(defun multi-term-switch (direction offset) - "Switch `multi-term' buffers. -If DIRECTION is `NEXT', switch to the next term. -If DIRECTION `PREVIOUS', switch to the previous term. -Option OFFSET for skip OFFSET number term buffer." - (unless (multi-term-switch-internal direction offset) - (if multi-term-try-create - (progn - (multi-term) - (message "Create a new `multi-term' buffer.")) - (message "Haven't any `multi-term' buffer exist.")))) - -(defun multi-term-switch-internal (direction offset) - "Internal `multi-term' buffers switch function. -If DIRECTION is `NEXT', switch to the next term. -If DIRECTION `PREVIOUS', switch to the previous term. -Option OFFSET for skip OFFSET number term buffer." - (let (terms this-buffer) - (setq terms (multi-term-list)) - (if (consp terms) - (progn - (setf (cdr (last terms)) terms) - (setq this-buffer (position (current-buffer) (multi-term-list))) - (if this-buffer - (if (eql direction 'NEXT) - (switch-to-buffer (nth (+ this-buffer offset) terms)) - (switch-to-buffer (nth (+ (- (length (multi-term-list)) offset) - this-buffer) terms))) - (switch-to-buffer (car terms))) - t) - nil))) - -(defun multi-term-keystroke-setup () - "Keystroke setup of `term-char-mode'. - -By default, the key bindings of `term-char-mode' conflict with user's keystroke. -So this function unbinds some keys with `term-raw-map', -and binds some keystroke with `term-raw-map'." - (let (bind-key bind-command) - ;; Unbind base key that conflict with user's keys-tokes. - (dolist (unbind-key term-unbind-key-list) - (cond - ((stringp unbind-key) (setq unbind-key (read-kbd-macro unbind-key))) - ((vectorp unbind-key) nil) - (t (signal 'wrong-type-argument (list 'array unbind-key)))) - (define-key term-raw-map unbind-key nil)) - ;; Add some i use keys. - ;; If you don't like my keystroke, - ;; just modified `term-bind-key-alist' - (dolist (element term-bind-key-alist) - (setq bind-key (car element)) - (setq bind-command (cdr element)) - (cond - ((stringp bind-key) (setq bind-key (read-kbd-macro bind-key))) - ((vectorp bind-key) nil) - (t (signal 'wrong-type-argument (list 'array bind-key)))) - (define-key term-raw-map bind-key bind-command)))) - -(defun multi-term-dedicated-handle-other-window-advice (activate) - "Handle advice for function `other-window'. -If ACTIVATE is `non-nil', will enable advice -`multi-term-dedicated-other-window-advice'. -Otherwise, disable it." - (if activate - (ad-enable-advice 'other-window 'after 'multi-term-dedicated-other-window-advice) - (ad-disable-advice 'other-window 'after 'multi-term-dedicated-other-window-advice)) - (ad-activate 'other-window)) - -(defun multi-term-current-window-take-height (&optional window) - "Return the height the `window' takes up. -Not the value of `window-height', it returns usable rows available for WINDOW. -If `window' is nil, get current window." - (let ((edges (window-edges window))) - (- (nth 3 edges) (nth 1 edges)))) - -(defun multi-term-dedicated-get-window () - "Get `multi-term' dedicated window." - (setq multi-term-dedicated-window - (split-window - (selected-window) - (- (multi-term-current-window-take-height) multi-term-dedicated-window-height)))) - -(defun multi-term-dedicated-get-buffer-name () - "Get the buffer name of `multi-term' dedicated window." - (format "*%s*" multi-term-dedicated-buffer-name)) - -(defun multi-term-dedicated-exist-p () - "Return `non-nil' if `multi-term' dedicated window exist." - (and (multi-term-buffer-exist-p multi-term-dedicated-buffer) - (multi-term-window-exist-p multi-term-dedicated-window))) - -(defun multi-term-window-exist-p (window) - "Return `non-nil' if WINDOW exist. -Otherwise return nil." - (and window (window-live-p window))) - -(defun multi-term-buffer-exist-p (buffer) - "Return `non-nil' if `BUFFER' exist. -Otherwise return nil." - (and buffer (buffer-live-p buffer))) - -(defun multi-term-dedicated-window-p () - "Return `non-nil' if current window is `multi-term' dedicated window. -Otherwise return nil." - (equal (multi-term-dedicated-get-buffer-name) (buffer-name (window-buffer)))) - -(defun multi-term-window-dedicated-only-one-p () - "Only have one non-dedicated window." - (interactive) - (let ((window-number 0) - (dedicated-window-number 0)) - (walk-windows - (lambda (w) - (with-selected-window w - (incf window-number) - (if (window-dedicated-p w) - (incf dedicated-window-number))))) - (if (and (> dedicated-window-number 0) - (= (- window-number dedicated-window-number) 1)) - t nil))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Advice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defadvice delete-other-windows (around multi-term-delete-other-window-advice activate) - "This is advice to make `multi-term' avoid dedicated window deleted. -Dedicated window can't deleted by command `delete-other-windows'." - (let ((multi-term-dedicated-active-p (multi-term-window-exist-p multi-term-dedicated-window))) - (if multi-term-dedicated-active-p - (let ((current-window (selected-window))) - (dolist (win (window-list)) - (when (and (window-live-p win) - (not (eq current-window win)) - (not (window-dedicated-p win))) - (delete-window win)))) - ad-do-it))) - -(defadvice delete-window (before multi-term-delete-window-advice activate) - "Use `delete-window' delete `multi-term' dedicated window. -Have same effect as command `multi-term-dedicated-close'. -This advice to remember `multi-term' dedicated window height before deleting." - ;; Remember window height before deleted. - (multi-term-dedicated-remember-window-height)) - -(defadvice pop-to-buffer (before multi-term-pop-to-buffer-advice activate) - "This advice fix the problem between `pop-to-buffer' and dedicated window. -By default, function `display-buffer' can't display buffer in selected window -if current window is `dedicated'. - -So function `display-buffer' conflicts with `sr-speedbar' window, because -`sr-speedbar' window is a `dedicated' window. - -That is to say, when current frame just have one `non-dedicated' window, -any functions that uses `display-buffer' can't split windows -to display buffer, even when the option `pop-up-windows' is enabled. - -And the example function that can induce the problem is `pop-to-buffer'. - -This advice will fix this problem when current frame just have one `non-dedicated' window." - (when (and pop-up-windows ;`pop-up-windows' is enable - (multi-term-window-dedicated-only-one-p) ;just have one `non-dedicated' window. - (multi-term-window-exist-p multi-term-dedicated-window) - (not (multi-term-dedicated-window-p))) ;not in `sr-speedbar' window - (split-window-vertically) - (windmove-down))) - -(defadvice other-window (after multi-term-dedicated-other-window-advice) - "Default, can use `other-window' select window in cyclic ordering of windows. -But sometimes we don't want to select `sr-speedbar' window, -but use `other-window' and just make `multi-term' dedicated -window as a viewable sidebar. - -This advice can make `other-window' skip `multi-term' dedicated window." - (let ((count (or (ad-get-arg 0) 1))) - (when (and (multi-term-window-exist-p multi-term-dedicated-window) - (eq multi-term-dedicated-window (selected-window))) - (other-window count)))) - -(provide 'multi-term) - -;; Local Variables: -;; time-stamp-line-limit: 10 -;; time-stamp-start: "Last-Updated: <" -;; time-stamp-end: ">" -;; End: - -;;; multi-term.el ends here - -;;; LocalWords: multi el dir sr Hawley eb ef cd diff --git a/modes/drupal-mode.el b/modes/drupal-mode.el deleted file mode 100644 index ca20ebd..0000000 --- a/modes/drupal-mode.el +++ /dev/null @@ -1,17 +0,0 @@ -;;; drupal-mode.el --- major mode for Drupal coding - -;;;###autoload -(define-derived-mode drupal-mode php-mode "Drupal" - "Major mode for Drupal coding.\n\n\\{drupal-mode-map}" - (setq c-basic-offset 2) - (setq indent-tabs-mode nil) - (setq fill-column 78) - (setq show-trailing-whitespace t) - (add-hook 'before-save-hook 'delete-trailing-whitespace) - (c-set-offset 'case-label '+) - (c-set-offset 'arglist-close 0) - (c-set-offset 'arglist-intro '+) ; for FAPI arrays and DBTNG - (c-set-offset 'arglist-cont-nonempty 'c-lineup-math) ; for DBTNG fields and values - (run-mode-hooks 'drupal-mode-hook) -) -(provide 'drupal-mode) \ No newline at end of file diff --git a/modes/kivy-mode.el b/modes/kivy-mode.el deleted file mode 100644 index 04f4283..0000000 --- a/modes/kivy-mode.el +++ /dev/null @@ -1,290 +0,0 @@ -;;; kivy-mode.el --- Emacs major mode for editing Kivy files -;; -;; Author: Dean Serenevy -;; Version: 0.1.0 -;; -;; This document borrowed heavily from yaml-mode.el by Yoshiki Kurihara and -;; Marshall Vandegrift. -;; -;; This file is not part of Emacs - - -;; This file 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; version 3. - -;; This file 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 GNU Emacs; see the file COPYING. If not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -;; USA. - -;;; Installation: - -;; To install, just drop this file into a directory in your `load-path' and -;; (optionally) byte-compile it. To automatically handle files ending in -;; '.kv', add something like: -;; -;; (require 'kivy-mode) -;; (add-to-list 'auto-mode-alist '("\\.kv$" . kivy-mode)) -;; -;; to your .emacs file. -;; -;; Unlike python-mode, this mode follows the Emacs convention of not -;; binding the ENTER key to `newline-and-indent'. To get this behavior, add -;; the key definition to `kivy-mode-hook': -;; -;; (add-hook 'kivy-mode-hook -;; '(lambda () -;; (define-key kivy-mode-map "\C-m" 'newline-and-indent))) - - -;; User definable variables - -(defgroup kivy nil - "Support for the kivy user interface definition format" - :group 'languages - :prefix "kivy-") - -(defcustom kivy-mode-hook nil - "*Hook run by `kivy-mode'." - :type 'hook - :group 'kivy) - -(defcustom kivy-indent-offset 4 - "*Amount of offset per level of indentation." - :type 'integer - :group 'kivy) - -(defcustom kivy-backspace-function 'backward-delete-char-untabify - "*Function called by `kivy-electric-backspace' when deleting backwards." - :type 'function - :group 'kivy) - -(defface kivy-tab-face - '((((class color)) (:background "red" :foreground "red" :bold t)) - (t (:reverse-video t))) - "Face to use for highlighting tabs in kivy files." - :group 'faces - :group 'kivy) - -(defcustom kivy-imenu-generic-expression - '((nil "^\\([<>a-zA-Z_-]+\\):" 1)) - "The imenu regex to parse an outline of the kivy file." - :type 'string - :group 'kivy) - - -;; Constants - -(defconst kivy-mode-version "0.1.0" "Version of `kivy-mode.'") - -(defconst kivy-blank-line-re "^ *$" - "Regexp matching a line containing only (valid) whitespace.") - -(defconst kivy-comment-re "\\(?:^\\|\\s-+\\)\\(#.*\\)" - "Regexp matching a line containing a kivy comment or delimiter.") - -(defconst kivy-directive-re "^\\(?:#:\\)\\(\\w+ +.*\\)" - "Regexp matching a line contatining a kivy directive.") - -(defconst kivy-tag-re "^ *id: *\\([^ \n]+\\)$" - "Rexexp matching a kivy tag.") - -(defconst kivy-bare-scalar-re - "\\(?:[^-:,#!\n{\\[ ]\\|[^#!\n{\\[ ]\\S-\\)[^#\n]*?" - "Rexexp matching a kivy bare scalar.") - -(defconst kivy-hash-key-re - (concat "^ *" - "\\(" kivy-bare-scalar-re "\\) *:" - "\\(?: +\\|$\\)") - "Regexp matching a single kivy hash key.") - -(defconst kivy-nested-map-re - (concat ".*: *$") - "Regexp matching a line beginning a kivy nested structure.") - -(defconst kivy-constant-scalars-re - (concat "\\(?:^\\|\\(?::\\|-\\|,\\|{\\|\\[\\) +\\) *" - (regexp-opt - '("True" "False" "None") t) - " *$") - "Regexp matching certain scalar constants in scalar context") - - - -;; Mode setup - -(defvar kivy-mode-map () - "Keymap used in `kivy-mode' buffers.") -(if kivy-mode-map - nil - (setq kivy-mode-map (make-sparse-keymap)) - (define-key kivy-mode-map [backspace] 'kivy-electric-backspace) - (define-key kivy-mode-map "\C-c<" 'kivy-indent-shift-left) - (define-key kivy-mode-map "\C-c>" 'kivy-indent-shift-right) - ) - -(defvar kivy-mode-syntax-table nil - "Syntax table in use in kivy-mode buffers.") -(if kivy-mode-syntax-table - nil - (setq kivy-mode-syntax-table (make-syntax-table)) - (modify-syntax-entry ?\' "\"" kivy-mode-syntax-table) - (modify-syntax-entry ?\" "\"" kivy-mode-syntax-table) - (modify-syntax-entry ?# "<" kivy-mode-syntax-table) - (modify-syntax-entry ?\n ">" kivy-mode-syntax-table) - (modify-syntax-entry ?\\ "\\" kivy-mode-syntax-table) - (modify-syntax-entry ?- "_" kivy-mode-syntax-table) - (modify-syntax-entry ?_ "w" kivy-mode-syntax-table) - ) - - -;;;###autoload -(add-to-list 'auto-mode-alist '("\\.kv$" . kivy-mode)) - - -;;;###autoload -(define-derived-mode kivy-mode fundamental-mode "kivy" - "Simple mode to edit kivy. - -\\{kivy-mode-map}" - (set (make-local-variable 'comment-start) "# ") - (set (make-local-variable 'comment-start-skip) "#+ *") - (set (make-local-variable 'indent-line-function) 'kivy-indent-line) - (set (make-local-variable 'font-lock-defaults) - '(kivy-font-lock-keywords - nil nil nil nil - (font-lock-syntactic-keywords)))) - - -;; Font-lock support - -(defvar kivy-font-lock-keywords - (list - (cons kivy-comment-re '(1 font-lock-comment-face)) - (cons kivy-constant-scalars-re '(1 font-lock-constant-face)) - (cons kivy-tag-re '(1 font-lock-function-name-face)) - (cons kivy-hash-key-re '(1 font-lock-variable-name-face t)) - (cons kivy-directive-re '(1 font-lock-builtin-face)) - '("^[\t]+" 0 'kivy-tab-face t)) - "Additional expressions to highlight in kivy mode.") - -(defvar kivy-font-lock-syntactic-keywords - (list '()) - "Additional syntax features to highlight in kivy mode.") - - -;; Indentation and electric keys - -(defun kivy-compute-indentation () - "Calculate the maximum sensible indentation for the current line." - (save-excursion - (beginning-of-line) - (forward-line -1) - (while (and (looking-at kivy-blank-line-re) - (> (point) (point-min))) - (forward-line -1)) - (+ (current-indentation) - (if (looking-at kivy-nested-map-re) kivy-indent-offset 0) - ))) - -(defun kivy-indent-line () - "Indent the current line. -The first time this command is used, the line will be indented to the -maximum sensible indentation. Each immediately subsequent usage will -back-dent the line by `kivy-indent-offset' spaces. On reaching column -0, it will cycle back to the maximum sensible indentation." - (interactive "*") - (let ((ci (current-indentation)) - (cc (current-column)) - (need (kivy-compute-indentation))) - (save-excursion - (beginning-of-line) - (delete-horizontal-space) - (if (and (equal last-command this-command) (/= ci 0)) - (indent-to (* (/ (- ci 1) kivy-indent-offset) kivy-indent-offset)) - (indent-to need))) - (if (< (current-column) (current-indentation)) - (forward-to-indentation 0)))) - -(defun kivy-electric-backspace (arg) - "Delete characters or back-dent the current line. -If invoked following only whitespace on a line, will back-dent to the -immediately previous multiple of `kivy-indent-offset' spaces." - (interactive "*p") - (if (or (/= (current-indentation) (current-column)) (bolp)) - (funcall kivy-backspace-function arg) - (let ((ci (current-column))) - (beginning-of-line) - (delete-horizontal-space) - (indent-to (* (/ (- ci (* arg kivy-indent-offset)) - kivy-indent-offset) - kivy-indent-offset))))) - - -(defun kivy-set-imenu-generic-expression () - (make-local-variable 'imenu-generic-expression) - (make-local-variable 'imenu-create-index-function) - (setq imenu-create-index-function 'imenu-default-create-index-function) - (setq imenu-generic-expression kivy-imenu-generic-expression)) - -(add-hook 'kivy-mode-hook 'kivy-set-imenu-generic-expression) -(add-hook 'kivy-mode-hook - '(lambda () - (setq indent-tabs-mode 'nil))) - - -(defun kivy-mode-version () - "Diplay version of `kivy-mode'." - (interactive) - (message "kivy-mode %s" kivy-mode-version) - kivy-mode-version) - -(defun kivy-indent-shift-left (start end &optional count) - "Shift lines contained in region START END by COUNT columns to the left. -COUNT defaults to `kivy-indent-offset'. If region isn't -active, the current line is shifted. The shifted region includes -the lines in which START and END lie. An error is signaled if -any lines in the region are indented less than COUNT columns." - (interactive - (if mark-active - (list (region-beginning) (region-end) current-prefix-arg) - (list (line-beginning-position) (line-end-position) current-prefix-arg))) - (if count - (setq count (prefix-numeric-value count)) - (setq count kivy-indent-offset)) - (when (> count 0) - (let ((deactivate-mark nil)) - (save-excursion - (goto-char start) - (while (< (point) end) - (if (and (< (current-indentation) count) - (not (looking-at "[ \t]*$"))) - (error "Can't shift all lines enough")) - (forward-line)) - (indent-rigidly start end (- count)))))) - -(defun kivy-indent-shift-right (start end &optional count) - "Shift lines contained in region START END by COUNT columns to the left. -COUNT defaults to `kivy-indent-offset'. If region isn't -active, the current line is shifted. The shifted region includes -the lines in which START and END lie." - (interactive - (if mark-active - (list (region-beginning) (region-end) current-prefix-arg) - (list (line-beginning-position) (line-end-position) current-prefix-arg))) - (let ((deactivate-mark nil)) - (if count - (setq count (prefix-numeric-value count)) - (setq count kivy-indent-offset)) - (indent-rigidly start end count))) - -(provide 'kivy-mode) - -;;; kivy-mode.el ends here diff --git a/modes/markdown-mode.el b/modes/markdown-mode.el deleted file mode 100644 index 78b2965..0000000 --- a/modes/markdown-mode.el +++ /dev/null @@ -1,4669 +0,0 @@ -;;; markdown-mode.el --- Emacs Major mode for Markdown-formatted text files - -;; Copyright (C) 2007-2013 Jason R. Blevins -;; Copyright (C) 2007, 2009 Edward O'Connor -;; Copyright (C) 2007 Conal Elliott -;; Copyright (C) 2008 Greg Bognar -;; Copyright (C) 2008 Dmitry Dzhus -;; Copyright (C) 2008 Bryan Kyle -;; Copyright (C) 2008 Ben Voui -;; Copyright (C) 2009 Ankit Solanki -;; Copyright (C) 2009 Hilko Bengen -;; Copyright (C) 2009 Peter Williams -;; Copyright (C) 2010 George Ogata -;; Copyright (C) 2011 Eric Merritt -;; Copyright (C) 2011 Philippe Ivaldi -;; Copyright (C) 2011 Jeremiah Dodds -;; Copyright (C) 2011 Christopher J. Madsen -;; Copyright (C) 2011 Shigeru Fukaya -;; Copyright (C) 2011 Joost Kremers -;; Copyright (C) 2011-2012 Donald Ephraim Curtis -;; Copyright (C) 2012 Akinori Musha -;; Copyright (C) 2012 Zhenlei Jia -;; Copyright (C) 2012 Peter Jones -;; Copyright (C) 2013 Matus Goljer - -;; Author: Jason R. Blevins -;; Maintainer: Jason R. Blevins -;; Created: May 24, 2007 -;; Version: 2.0 -;; Keywords: Markdown, GitHub Flavored Markdown, itex -;; URL: http://jblevins.org/projects/markdown-mode/ - -;; This file is not part of GNU Emacs. - -;; 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 2, 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, write to the Free Software -;; Foundation, Inc., 51 Franklin Street, Fifth Floor, -;; Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; markdown-mode is a major mode for editing [Markdown][]-formatted -;; text files in GNU Emacs. markdown-mode is free software, licensed -;; under the GNU GPL. -;; -;; [Markdown]: http://daringfireball.net/projects/markdown/ -;; -;; The latest stable version is markdown-mode 2.0, released on March 24, 2013: -;; -;; * [markdown-mode.el][] -;; * [Screenshot][][^theme] -;; * [Release notes][] -;; -;; [markdown-mode.el]: http://jblevins.org/projects/markdown-mode/markdown-mode.el -;; [screenshot]: http://jblevins.org/projects/markdown-mode/screenshots/20130131-002.png -;; [release notes]: http://jblevins.org/projects/markdown-mode/rev-2-0 -;; -;; [^theme]: The theme used in the screenshot is -;; [color-theme-twilight](https://github.com/crafterm/twilight-emacs). -;; -;; markdown-mode is also available in several package managers, including: -;; -;; * Debian and Ubuntu Linux: [emacs-goodies-el][] -;; * RedHat and Fedora Linux: [emacs-goodies][] -;; * OpenBSD: [textproc/markdown-mode][] -;; * Arch Linux (AUR): [emacs-markdown-mode-git][] -;; * MacPorts: [markdown-mode.el][macports-package] ([pending][macports-ticket]) -;; * FreeBSD: [textproc/markdown-mode.el][freebsd-port] -;; -;; [emacs-goodies-el]: http://packages.debian.org/emacs-goodies-el -;; [emacs-goodies]: https://admin.fedoraproject.org/pkgdb/acls/name/emacs-goodies -;; [textproc/markdown-mode]: http://pkgsrc.se/textproc/markdown-mode -;; [emacs-markdown-mode-git]: http://aur.archlinux.org/packages.php?ID=30389 -;; [macports-package]: https://trac.macports.org/browser/trunk/dports/editors/markdown-mode.el/Portfile -;; [macports-ticket]: http://trac.macports.org/ticket/35716 -;; [freebsd-port]: http://svnweb.freebsd.org/ports/head/textproc/markdown-mode.el -;; -;; The latest development version can be downloaded directly -;; ([markdown-mode.el][devel.el]) or it can be obtained from the -;; (browsable and clonable) Git repository at -;; . The entire repository, -;; including the full project history, can be cloned via the Git protocol -;; by running -;; -;; git clone git://jblevins.org/git/markdown-mode.git -;; -;; [devel.el]: http://jblevins.org/git/markdown-mode.git/plain/markdown-mode.el - -;;; Installation: - -;; Make sure to place `markdown-mode.el` somewhere in the load-path and add -;; the following lines to your `.emacs` file to associate markdown-mode -;; with `.text`, `.markdown`, and `.md` files: -;; -;; (autoload 'markdown-mode "markdown-mode" -;; "Major mode for editing Markdown files" t) -;; (add-to-list 'auto-mode-alist '("\\.text\\'" . markdown-mode)) -;; (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode)) -;; (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) -;; -;; There is no official Markdown file extension, nor is there even a -;; _de facto_ standard, so you can easily add, change, or remove any -;; of the file extensions above as needed. - -;;; Usage: - -;; Keybindings are grouped by prefixes based on their function. For -;; example, the commands for inserting links are grouped under `C-c -;; C-a`, where the `C-a` is a mnemonic for the HTML `` tag. In -;; other cases, the connection to HTML is not direct. For example, -;; commands dealing with headings begin with `C-c C-t` (mnemonic: -;; titling). The primary commands in each group will are described -;; below. You can obtain a list of all keybindings by pressing `C-c -;; C-h`. Movement and shifting commands tend to be associated with -;; paired delimiters such as `M-{` and `M-}` or `C-c <` and `C-c >`. -;; Outline navigation keybindings the same as in `org-mode'. Finally, -;; commands for running Markdown or doing maintenance on an open file -;; are grouped under the `C-c C-c` prefix. The most commonly used -;; commands are described below. You can obtain a list of all -;; keybindings by pressing `C-c C-h`. -;; -;; * Hyperlinks: `C-c C-a` -;; -;; In this group, `C-c C-a l` inserts an inline link of the form -;; `[text](url)`. The link text is determined as follows. First, -;; if there is an active region (i.e., when transient mark mode is -;; on and the mark is active), use it as the link text. Second, -;; if the point is at a word, use that word as the link text. In -;; these two cases, the original text will be replaced with the -;; link and point will be left at the position for inserting a -;; URL. Otherwise, insert empty link markup and place the point -;; for inserting the link text. -;; -;; `C-c C-a L` inserts a reference link of the form `[text][label]` -;; and, optionally, a corresponding reference label definition. -;; The link text is determined in the same way as with an inline -;; link (using the region, when active, or the word at the point), -;; but instead of inserting empty markup as a last resort, the -;; link text will be read from the minibuffer. The reference -;; label will be read from the minibuffer in both cases, with -;; completion from the set of currently defined references. To -;; create an implicit reference link, press `RET` to accept the -;; default, an empty label. If the entered referenced label is -;; not defined, additionally prompt for the URL and (optional) -;; title. If a URL is provided, a reference definition will be -;; inserted in accordance with `markdown-reference-location'. -;; If a title is given, it will be added to the end of the -;; reference definition and will be used to populate the title -;; attribute when converted to XHTML. -;; -;; `C-c C-a u` inserts a bare url, delimited by angle brackets. When -;; there is an active region, the text in the region is used as the -;; URL. If the point is at a URL, that url is used. Otherwise, -;; insert angle brackets and position the point in between them -;; for inserting the URL. -;; -;; `C-c C-a f` inserts a footnote marker at the point, inserts a -;; footnote definition below, and positions the point for -;; inserting the footnote text. Note that footnotes are an -;; extension to Markdown and are not supported by all processors. -;; -;; `C-c C-a w` behaves much like the inline link insertion command -;; and inserts a wiki link of the form `[[WikiLink]]`. If there -;; is an active region, use the region as the link text. If the -;; point is at a word, use the word as the link text. If there is -;; no active region and the point is not at word, simply insert -;; link markup. Note that wiki links are an extension to Markdown -;; and are not supported by all processors. -;; -;; * Images: `C-c C-i` -;; -;; `C-c C-i i` inserts markup for an inline image, using the -;; active region or the word at point, if any, as the alt text. -;; `C-c C-i I` behaves similarly and inserts a reference-style -;; image. -;; -;; * Styles: `C-c C-s` -;; -;; `C-c C-s e` inserts markup to make a region or word italic (`e` -;; for `` or emphasis). If there is an active region, make -;; the region italic. If the point is at a non-italic word, make -;; the word italic. If the point is at an italic word or phrase, -;; remove the italic markup. Otherwise, simply insert italic -;; delimiters and place the cursor in between them. Similarly, -;; use `C-c C-s s` for bold (``) and `C-c C-s c` for -;; inline code (``). -;; -;; `C-c C-s b` inserts a blockquote using the active region, if any, -;; or starts a new blockquote. `C-c C-s C-b` is a variation which -;; always operates on the region, regardless of whether it is -;; active or not. The appropriate amount of indentation, if any, -;; is calculated automatically given the surrounding context, but -;; may be adjusted later using the region indentation commands. -;; -;; `C-c C-s p` behaves similarly for inserting preformatted code -;; blocks, with `C-c C-s C-p` being the region-only counterpart. -;; -;; * Headings: `C-c C-t` -;; -;; All heading insertion commands use the text in the active -;; region, if any, as the heading text. Otherwise, if the current -;; line is not blank, they use the text on the current line. -;; Finally, the setext commands will prompt for heading text if -;; there is no active region and the current line is blank. -;; -;; `C-c C-t h` inserts a heading with automatically chosen type and -;; level (both determined by the previous heading). `C-c C-t H` -;; behaves similarly, but uses setext (underlined) headings when -;; possible, still calculating the level automatically. -;; In cases where the automatically-determined level is not what -;; you intended, the level can be quickly promoted or demoted -;; (as described below). Alternatively, a `C-u` prefix can be -;; given to insert a heading promoted by one level or a `C-u C-u` -;; prefix can be given to insert a heading demoted by one level. -;; -;; To insert a heading of a specific level and type, use `C-c C-t 1` -;; through `C-c C-t 6` for atx (hash mark) headings and `C-c C-t !` or -;; `C-c C-t @` for setext headings of level one or two, respectively. -;; Note that `!` is `S-1` and `@` is `S-2`. -;; -;; If the point is at a heading, these commands will replace the -;; existing markup in order to update the level and/or type of the -;; heading. To remove the markup of the heading at the point, -;; press `C-c C-k` to kill the heading and press `C-y` to yank the -;; heading text back into the buffer. -;; -;; * Horizontal Rules: `C-c -` -;; -;; `C-c -` inserts a horizontal rule. By default, insert the -;; first string in the list `markdown-hr-strings' (the most -;; prominent rule). With a `C-u` prefix, insert the last string. -;; With a numeric prefix `N`, insert the string in position `N` -;; (counting from 1). -;; -;; * Markdown and Maintenance Commands: `C-c C-c` -;; -;; *Compile:* `C-c C-c m` will run Markdown on the current buffer -;; and show the output in another buffer. *Preview*: `C-c C-c p` -;; runs Markdown on the current buffer and previews, stores the -;; output in a temporary file, and displays the file in a browser. -;; *Export:* `C-c C-c e` will run Markdown on the current buffer -;; and save the result in the file `basename.html`, where -;; `basename` is the name of the Markdown file with the extension -;; removed. *Export and View:* press `C-c C-c v` to export the -;; file and view it in a browser. **For both export commands, the -;; output file will be overwritten without notice.** -;; *Open:* `C-c C-c o` will open the Markdown source file directly -;; using `markdown-open-command'. -;; -;; To summarize: -;; -;; - `C-c C-c m`: `markdown-command' > `*markdown-output*` buffer. -;; - `C-c C-c p`: `markdown-command' > temporary file > browser. -;; - `C-c C-c e`: `markdown-command' > `basename.html`. -;; - `C-c C-c v`: `markdown-command' > `basename.html` > browser. -;; - `C-c C-c w`: `markdown-command' > kill ring. -;; - `C-c C-c o`: `markdown-open-command'. -;; -;; `C-c C-c c` will check for undefined references. If there are -;; any, a small buffer will open with a list of undefined -;; references and the line numbers on which they appear. In Emacs -;; 22 and greater, selecting a reference from this list and -;; pressing `RET` will insert an empty reference definition at the -;; end of the buffer. Similarly, selecting the line number will -;; jump to the corresponding line. -;; -;; `C-c C-c n` renumbers any ordered lists in the buffer that are -;; out of sequence. -;; -;; `C-c C-c ]` completes all headings and normalizes all horizontal -;; rules in the buffer. -;; -;; * Following Links: `C-c C-o` -;; -;; Press `C-c C-o` when the point is on an inline or reference -;; link to open the URL in a browser. When the point is at a -;; wiki link, open it in another buffer (in the current window, -;; or in the other window with the `C-u` prefix). Use `M-p` and -;; `M-n` to quickly jump to the previous or next link of any type. -;; -;; * Jumping: `C-c C-j` -;; -;; Use `C-c C-j` to jump from the object at point to its counterpart -;; elsewhere in the text, when possible. Jumps between reference -;; links and definitions; between footnote markers and footnote -;; text. If more than one link uses the same reference name, a -;; new buffer will be created containing clickable buttons for jumping -;; to each link. You may press `TAB` or `S-TAB` to jump between -;; buttons in this window. -;; -;; * Promotion and Demotion: `C-c C--` and `C-c C-=` -;; -;; Headings, horizontal rules, and list items can be promoted and -;; demoted, as well as bold and italic text. For headings, -;; "promotion" means *decreasing* the level (i.e., moving from -;; `

` to `

`) while "demotion" means *increasing* the -;; level. For horizontal rules, promotion and demotion means -;; moving backward or forward through the list of rule strings in -;; `markdown-hr-strings'. For bold and italic text, promotion and -;; demotion means changing the markup from underscores to asterisks. -;; Press `C-c C--` or `M-LEFT` to promote the element at the point -;; if possible. -;; -;; To remember these commands, note that `-` is for decreasing the -;; level (promoting), and `=` (on the same key as `+`) is for -;; increasing the level (demoting). Similarly, the left and right -;; arrow keys indicate the direction that the atx heading markup -;; is moving in when promoting or demoting. -;; -;; * Completion: `C-c C-]` -;; -;; Complete markup is in normalized form, which means, for -;; example, that the underline portion of a setext header is the -;; same length as the heading text, or that the number of leading -;; and trailing hash marks of an atx header are equal and that -;; there is no extra whitespace in the header text. `C-c C-]` -;; completes the markup at the point, if it is determined to be -;; incomplete. -;; -;; * Editing Lists: `M-RET`, `M-UP`, `M-DOWN`, `M-LEFT`, and `M-RIGHT` -;; -;; New list items can be inserted with `M-RET`. This command -;; determines the appropriate marker (one of the possible -;; unordered list markers or the next number in sequence for an -;; ordered list) and indentation level by examining nearby list -;; items. If there is no list before or after the point, start a -;; new list. Prefix this command by `C-u` to decrease the -;; indentation by one level. Prefix this command by `C-u C-u` to -;; increase the indentation by one level. -;; -;; Existing list items can be moved up or down with `M-UP` or -;; `M-DOWN` and indented or exdented with `M-RIGHT` or `M-LEFT`. -;; -;; * Shifting the Region: `C-c <` and `C-c >` -;; -;; Text in the region can be indented or exdented as a group using -;; `C-c >` to indent to the next indentation point (calculated in -;; the current context), and `C-c <` to exdent to the previous -;; indentation point. These keybindings are the same as those for -;; similar commands in `python-mode'. -;; -;; * Killing Elements: `C-c C-k` -;; -;; Press `C-c C-k` to kill the thing at point and add important -;; text, without markup, to the kill ring. Possible things to -;; kill include (roughly in order of precedece): inline code, -;; headings, horizonal rules, links (add link text to kill ring), -;; images (add alt text to kill ring), angle URIs, email -;; addresses, bold, italics, reference definitions (add URI to -;; kill ring), footnote markers and text (kill both marker and -;; text, add text to kill ring), and list items. -;; -;; * Outline Navigation: `C-c C-n`, `C-c C-p`, `C-c C-f`, `C-c C-b`, and `C-c C-u` -;; -;; Navigation between headings is possible using `outline-mode'. -;; Use `C-c C-n` and `C-c C-p` to move between the next and previous -;; visible headings. Similarly, `C-c C-f` and `C-c C-b` move to the -;; next and previous visible headings at the same level as the one -;; at the point. Finally, `C-c C-u` will move up to a lower-level -;; (higher precedence) visible heading. -;; -;; * Movement by Paragraph or Block: `M-{` and `M-}` -;; -;; The definition of a "paragraph" is slightly different in -;; markdown-mode than, say, text-mode, because markdown-mode -;; supports filling for list items and respects hard line breaks, -;; both of which break paragraphs. So, markdown-mode overrides -;; the usual paragraph navigation commands `M-{` and `M-}` so that -;; with a `C-u` prefix, these commands jump to the beginning or -;; end of an entire block of text, respectively, where "blocks" -;; are separated by one or more lines. -;; -;; * Movement by Defun: `C-M-a`, `C-M-e`, and `C-M-h` -;; -;; The usual Emacs commands can be used to move by defuns -;; (top-level major definitions). In markdown-mode, a defun is a -;; section. As usual, `C-M-a` will move the point to the -;; beginning of the current or preceding defun, `C-M-e` will move -;; to the end of the current or following defun, and `C-M-h` will -;; put the region around the entire defun. -;; -;; As noted, many of the commands above behave differently depending -;; on whether Transient Mark mode is enabled or not. When it makes -;; sense, if Transient Mark mode is on and the region is active, the -;; command applies to the text in the region (e.g., `C-c C-s s` makes the -;; region bold). For users who prefer to work outside of Transient -;; Mark mode, since Emacs 22 it can be enabled temporarily by pressing -;; `C-SPC C-SPC`. When this is not the case, many commands then -;; proceed to look work with the word or line at the point. -;; -;; When applicable, commands that specifically act on the region even -;; outside of Transient Mark mode have the same keybinding as their -;; standard counterpart, but the letter is uppercase. For example, -;; `markdown-insert-blockquote' is bound to `C-c C-s b` and only acts on -;; the region in Transient Mark mode while `markdown-blockquote-region' -;; is bound to `C-c C-s B` and always applies to the region (when nonempty). -;; -;; Note that these region-specific functions are useful in many -;; cases where it may not be obvious. For example, yanking text from -;; the kill ring sets the mark at the beginning of the yanked text -;; and moves the point to the end. Therefore, the (inactive) region -;; contains the yanked text. So, `C-y` followed by `C-c C-s C-b` will -;; yank text and turn it into a blockquote. -;; -;; markdown-mode attempts to be flexible in how it handles -;; indentation. When you press `TAB` repeatedly, the point will cycle -;; through several possible indentation levels corresponding to things -;; you might have in mind when you press `RET` at the end of a line or -;; `TAB`. For example, you may want to start a new list item, -;; continue a list item with hanging indentation, indent for a nested -;; pre block, and so on. Exdention is handled similarly when backspace -;; is pressed at the beginning of the non-whitespace portion of a line. -;; -;; markdown-mode supports outline-minor-mode as well as org-mode-style -;; visibility cycling for atx- or hash-style headings. There are two -;; types of visibility cycling: Pressing `S-TAB` cycles globally between -;; the table of contents view (headings only), outline view (top-level -;; headings only), and the full document view. Pressing `TAB` while the -;; point is at a heading will cycle through levels of visibility for the -;; subtree: completely folded, visible children, and fully visible. -;; Note that mixing hash and underline style headings will give undesired -;; results. - -;;; Customization: - -;; Although no configuration is *necessary* there are a few things -;; that can be customized. The `M-x customize-mode` command -;; provides an interface to all of the possible customizations: -;; -;; * `markdown-command' - the command used to run Markdown (default: -;; `markdown`). This variable may be customized to pass -;; command-line options to your Markdown processor of choice. -;; -;; * `markdown-command-needs-filename' - set to `t' if -;; `markdown-command' does not accept standard input (default: -;; `nil'). When `nil', `markdown-mode' will pass the Markdown -;; content to `markdown-command' using standard input (`stdin`). -;; When set to `t', `markdown-mode' will pass the name of the file -;; as the final command-line argument to `markdown-command'. Note -;; that in the latter case, you will only be able to run -;; `markdown-command' from buffers which are visiting a file. -;; -;; * `markdown-open-command' - the command used for calling a standalone -;; Markdown previewer which is capable of opening Markdown source files -;; directly (default: `nil'). This command will be called -;; with a single argument, the filename of the current buffer. -;; A representative program is the Mac app [Marked][], a -;; live-updating MultiMarkdown previewer which has a command line -;; utility at `/usr/local/bin/mark`. -;; -;; * `markdown-hr-strings' - list of strings to use when inserting -;; horizontal rules. Different strings will not be distinguished -;; when converted to HTML--they will all be converted to -;; `
`--but they may add visual distinction and style to plain -;; text documents. To maintain some notion of promotion and -;; demotion, keep these sorted from largest to smallest. -;; -;; * `markdown-bold-underscore' - set to a non-nil value to use two -;; underscores for bold instead of two asterisks (default: `nil'). -;; -;; * `markdown-italic-underscore' - set to a non-nil value to use -;; underscores for italic instead of asterisks (default: `nil'). -;; -;; * `markdown-indent-function' - the function to use for automatic -;; indentation (default: `markdown-indent-line'). -;; -;; * `markdown-indent-on-enter' - set to a non-nil value to -;; automatically indent new lines when the enter key is pressed -;; (default: `t') -;; -;; * `markdown-wiki-link-alias-first' - set to a non-nil value to -;; treat aliased wiki links like `[[link text|PageName]]` -;; (default: `t'). When set to nil, they will be treated as -;; `[[PageName|link text]]'. -;; -;; * `markdown-uri-types' - a list of protocol schemes (e.g., "http") -;; for URIs that `markdown-mode' should highlight. -;; -;; * `markdown-enable-math' - syntax highlighting for LaTeX -;; fragments (default: `nil'). Set this to `t' to turn on math -;; support by default. Math support can be toggled later using -;; the function `markdown-enable-math'." -;; -;; * `markdown-css-path' - CSS file to link to in XHTML output -;; (default: `""`). -;; -;; * `markdown-content-type' - when set to a nonempty string, an -;; `http-equiv` attribute will be included in the XHTML `` -;; block (default: `""`). If needed, the suggested values are -;; `application/xhtml+xml` or `text/html`. See also: -;; `markdown-coding-system'. -;; -;; * `markdown-coding-system' - used for specifying the character -;; set identifier in the `http-equiv` attribute when included -;; (default: `nil'). See `markdown-content-type', which must -;; be set before this variable has any effect. When set to `nil', -;; `buffer-file-coding-system' will be used to automatically -;; determine the coding system string (falling back to -;; `iso-8859-1' when unavailable). Common settings are `utf-8' -;; and `iso-latin-1'. -;; -;; * `markdown-xhtml-header-content' - additional content to include -;; in the XHTML `` block (default: `""`). -;; -;; * `markdown-xhtml-standalone-regexp' - a regular expression which -;; `markdown-mode' uses to determine whether the output of -;; `markdown-command' is a standalone XHTML document or an XHTML -;; fragment (default: `"^\\(<\\?xml\\| for Debian packaging. -;; * Conal Elliott for a font-lock regexp patch. -;; * Edward O'Connor for a font-lock regexp fix and -;; GitHub Flavored Markdown mode (`gfm-mode'). -;; * Greg Bognar for menus and running -;; `markdown' with an active region. -;; * Daniel Burrows for filing Debian bug #456592. -;; * Peter S. Galbraith for maintaining `emacs-goodies-el`. -;; * Dmitry Dzhus for undefined reference checking. -;; * Carsten Dominik for `org-mode', from which the -;; visibility cycling functionality was derived, and for a bug fix -;; related to `orgtbl-mode'. -;; * Bryan Kyle for indentation code. -;; * Ben Voui for font-lock face customizations. -;; * Ankit Solanki for `longlines.el` -;; compatibility and custom CSS. -;; * Hilko Bengen for proper XHTML output. -;; * Jose A. Ortega Ruiz for Emacs 23 fixes. -;; * Nelson Minar for `html-helper-mode', from which -;; comment matching functions were derived. -;; * Alec Resnick for bug reports. -;; * Joost Kremers for footnote-handling -;; functions, bug reports regarding indentation, and -;; fixes for byte-compilation warnings. -;; * Peter Williams for `fill-paragraph' -;; enhancements. -;; * George Ogata for fixing several -;; byte-compilation warnings. -;; * Eric Merritt for wiki link features. -;; * Philippe Ivaldi for XHTML preview -;; customizations and XHTML export. -;; * Jeremiah Dodds for supporting -;; Markdown processors which do not accept input from stdin. -;; * Werner Dittmann for bug reports -;; regarding the `cl` dependency and `auto-fill-mode' and indentation. -;; * Scott Pfister for generalizing the space -;; substitution character for mapping wiki links to filenames. -;; * Marcin Kasperski for a patch to -;; escape shell commands. -;; * Christopher J. Madsen for patches to fix a match -;; data bug and to prefer `visual-line-mode' in `gfm-mode'. -;; * Shigeru Fukaya for better adherence to -;; Emacs Lisp coding conventions. -;; * Donald Ephraim Curtis for fixing the `fill-paragraph' -;; regexp, refactoring the compilation and preview functions, -;; heading font-lock generalizations, list renumbering, -;; and kill ring save. -;; * Kevin Porter for wiki link handling in `gfm-mode'. -;; * Max Penet and Peter Eisentraut -;; for an autoload token for `gfm-mode'. -;; * Ian Yang for improving the reference definition regex. -;; * Akinori Musha for an imenu index function. -;; * Michael Sperber for XEmacs fixes. -;; * Francois Gannaz for suggesting charset -;; declaration in XHTML output. -;; * Zhenlei Jia for smart exdention function. -;; * Matus Goljer for improved wiki link following -;; and GFM code block insertion. -;; * Peter Jones for link following functions. -;; * Bryan Fink for a bug report regarding -;; externally modified files. -;; * Vegard Vesterheim for a bug fix -;; related to `orgtbl-mode'. -;; * Makoto Motohashi for before- and after- -;; export hooks and unit test improvements. -;; * Michael Dwyer for `gfm-mode' underscore regexp. -;; * Chris Lott for suggesting reference label -;; completion. - -;;; Bugs: - -;; Although markdown-mode is developed and tested primarily using -;; GNU Emacs 24, compatibility with earlier Emacsen is also a -;; priority. -;; -;; If you find any bugs in markdown-mode, please construct a test case -;; or a patch and email me at . - -;;; History: - -;; markdown-mode was written and is maintained by Jason Blevins. The -;; first version was released on May 24, 2007. -;; -;; * 2007-05-24: Version 1.1 -;; * 2007-05-25: Version 1.2 -;; * 2007-06-05: [Version 1.3][] -;; * 2007-06-29: Version 1.4 -;; * 2007-10-11: [Version 1.5][] -;; * 2008-06-04: [Version 1.6][] -;; * 2009-10-01: [Version 1.7][] -;; * 2011-08-12: [Version 1.8][] -;; * 2011-08-15: [Version 1.8.1][] -;; * 2013-01-25: [Version 1.9][] -;; * 2013-03-18: [Version 2.0][] -;; -;; [Version 1.3]: http://jblevins.org/projects/markdown-mode/rev-1-3 -;; [Version 1.5]: http://jblevins.org/projects/markdown-mode/rev-1-5 -;; [Version 1.6]: http://jblevins.org/projects/markdown-mode/rev-1-6 -;; [Version 1.7]: http://jblevins.org/projects/markdown-mode/rev-1-7 -;; [Version 1.8]: http://jblevins.org/projects/markdown-mode/rev-1-8 -;; [Version 1.8.1]: http://jblevins.org/projects/markdown-mode/rev-1-8-1 -;; [Version 1.9]: http://jblevins.org/projects/markdown-mode/rev-1-9 -;; [Version 2.0]: http://jblevins.org/projects/markdown-mode/rev-2-0 - - -;;; Code: - -(require 'easymenu) -(require 'outline) -(require 'thingatpt) -(eval-when-compile (require 'cl)) - - -;;; Constants ================================================================= - -(defconst markdown-mode-version "2.0" - "Markdown mode version number.") - -(defconst markdown-output-buffer-name "*markdown-output*" - "Name of temporary buffer for markdown command output.") - - -;;; Global Variables ========================================================== - -(defvar markdown-reference-label-history nil - "History of used reference labels.") - - -;;; Customizable Variables ==================================================== - -(defvar markdown-mode-hook nil - "Hook run when entering Markdown mode.") - -(defvar markdown-before-export-hook nil - "Hook run before running Markdown to export XHTML output. -The hook may modify the buffer, which will be restored to it's -original state after exporting is complete.") - -(defvar markdown-after-export-hook nil - "Hook run after XHTML output has been saved. -Any changes to the output buffer made by this hook will be saved.") - -(defgroup markdown nil - "Major mode for editing text files in Markdown format." - :prefix "markdown-" - :group 'wp - :link '(url-link "http://jblevins.org/projects/markdown-mode/")) - -(defcustom markdown-command "markdown" - "Command to run markdown." - :group 'markdown - :type 'string) - -(defcustom markdown-command-needs-filename nil - "Set to non-nil if `markdown-command' does not accept input from stdin. -Instead, it will be passed a filename as the final command line -option. As a result, you will only be able to run Markdown from -buffers which are visiting a file." - :group 'markdown - :type 'boolean) - -(defcustom markdown-open-command nil - "Command used for opening Markdown files directly. -For example, a standalone Markdown previewer. This command will -be called with a single argument: the filename of the current -buffer." - :group 'markdown - :type 'string) - -(defcustom markdown-hr-strings - '("-------------------------------------------------------------------------------" - "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *" - "---------------------------------------" - "* * * * * * * * * * * * * * * * * * * *" - "---------" - "* * * * *") - "Strings to use when inserting horizontal rules. -The first string in the list will be the default when inserting a -horizontal rule. Strings should be listed in decreasing order of -prominence (as in headings from level one to six) for use with -promotion and demotion functions." - :group 'markdown - :type 'list) - -(defcustom markdown-bold-underscore nil - "Use two underscores for bold instead of two asterisks." - :group 'markdown - :type 'boolean) - -(defcustom markdown-italic-underscore nil - "Use underscores for italic instead of asterisks." - :group 'markdown - :type 'boolean) - -(defcustom markdown-indent-function 'markdown-indent-line - "Function to use to indent." - :group 'markdown - :type 'function) - -(defcustom markdown-indent-on-enter t - "Automatically indent new lines when enter key is pressed. -When this variable is set to t, pressing RET will call -`newline-and-indent'. When set to nil, define RET to call -`newline' as usual. In the latter case, you can still use -auto-indentation by pressing \\[newline-and-indent]." - :group 'markdown - :type 'boolean) - -(defcustom markdown-wiki-link-alias-first t - "When non-nil, treat aliased wiki links like [[alias text|PageName]]. -Otherwise, they will be treated as [[PageName|alias text]]." - :group 'markdown - :type 'boolean) - -(defcustom markdown-uri-types - '("acap" "cid" "data" "dav" "fax" "file" "ftp" "gopher" "http" "https" - "imap" "ldap" "mailto" "mid" "modem" "news" "nfs" "nntp" "pop" "prospero" - "rtsp" "service" "sip" "tel" "telnet" "tip" "urn" "vemmi" "wais") - "Link types for syntax highlighting of URIs." - :group 'markdown - :type 'list) - -(defcustom markdown-enable-math nil - "Syntax highlighting for inline LaTeX and itex expressions. -Set this to a non-nil value to turn on math support by default. -Math support can be toggled later using `markdown-enable-math' -or \\[markdown-enable-math]." - :group 'markdown - :type 'boolean - :safe 'booleanp) - -(defcustom markdown-css-path "" - "URL of CSS file to link to in the output XHTML." - :group 'markdown - :type 'string) - -(defcustom markdown-content-type "" - "Content type string for the http-equiv header in XHTML output. -When set to a non-empty string, insert the http-equiv attribute. -Otherwise, this attribute is omitted." - :group 'markdown - :type 'string) - -(defcustom markdown-coding-system nil - "Character set string for the http-equiv header in XHTML output. -Defaults to `buffer-file-coding-system' (and falling back to -`iso-8859-1' when not available). Common settings are `utf-8' -and `iso-latin-1'. Use `list-coding-systems' for more choices." - :group 'markdown - :type 'coding-system) - -(defcustom markdown-xhtml-header-content "" - "Additional content to include in the XHTML block." - :group 'markdown - :type 'string) - -(defcustom markdown-xhtml-standalone-regexp - "^\\(<\\?xml\\|\\).*$" - "Regular expression for matching blockquote lines.") - -(defconst markdown-regex-line-break - "[^ \n\t][ \t]*\\( \\)$" - "Regular expression for matching line breaks.") - -(defconst markdown-regex-wiki-link - "\\(?:^\\|[^\\]\\)\\(\\[\\[\\([^]|]+\\)\\(|\\([^]]+\\)\\)?\\]\\]\\)" - "Regular expression for matching wiki links. -This matches typical bracketed [[WikiLinks]] as well as 'aliased' -wiki links of the form [[PageName|link text]]. In this regular -expression, group 1 matches the entire link, including square -brackets, group 2 matches the first component of the wiki link -and group 4 matches the second component, after the pipe, when -present. The meanings of the first and second components depend -on the value of `markdown-wiki-link-alias-first'.") - -(defconst markdown-regex-uri - (concat (regexp-opt markdown-uri-types) ":[^]\t\n\r<>,;() ]+") - "Regular expression for matching inline URIs.") - -(defconst markdown-regex-angle-uri - (concat "\\(<\\)\\(" (regexp-opt markdown-uri-types) ":[^]\t\n\r<>,;()]+\\)\\(>\\)") - "Regular expression for matching inline URIs in angle brackets.") - -(defconst markdown-regex-email - "<\\(\\(\\sw\\|\\s_\\|\\s.\\)+@\\(\\sw\\|\\s_\\|\\s.\\)+\\)>" - "Regular expression for matching inline email addresses.") - -(defconst markdown-regex-link-generic - (concat "\\(?:" markdown-regex-wiki-link - "\\|" markdown-regex-link-inline - "\\|" markdown-regex-link-reference - "\\|" markdown-regex-angle-uri "\\)") - "Regular expression for matching any recognized link.") - -(defconst markdown-regex-block-separator - "\\(\\`\\|\\(\n[ \t]*\n\\)[^\n \t]\\)" - "Regular expression for matching block boundaries.") - -(defconst markdown-regex-math-inline - "\\(^\\|[^\\]\\)\\(\\$\\($\\([^\\$]\\|\\\\.\\)*\\$\\|\\([^\\$]\\|\\\\.\\)*\\)\\$\\)" - "Regular expression for itex $..$ or $$..$$ math mode expressions.") - -(defconst markdown-regex-math-display - "^\\\\\\[\\(.\\|\n\\)*?\\\\\\]$" - "Regular expression for itex \[..\] display mode expressions.") - -(defconst markdown-regex-multimarkdown-metadata - "^\\([[:alpha:]][[:alpha:] _-]*?\\):[ \t]*\\(.*\\)$" - "Regular expression for matching MultiMarkdown metadata.") - -(defconst markdown-regex-pandoc-metadata - "^\\(%\\)[ \t]*\\(.*\\)$" - "Regular expression for matching Pandoc metadata.") - -(defvar markdown-mode-font-lock-keywords-basic - (list - (cons 'markdown-match-pre-blocks '((0 markdown-pre-face))) - (cons 'markdown-match-fenced-code-blocks '((0 markdown-pre-face))) - (cons markdown-regex-blockquote 'markdown-blockquote-face) - (cons markdown-regex-header-1-setext '((1 markdown-header-face-1) - (2 markdown-header-rule-face))) - (cons markdown-regex-header-2-setext '((1 markdown-header-face-2) - (2 markdown-header-rule-face))) - (cons markdown-regex-header-6-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-6) - (3 markdown-header-delimiter-face))) - (cons markdown-regex-header-5-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-5) - (3 markdown-header-delimiter-face))) - (cons markdown-regex-header-4-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-4) - (3 markdown-header-delimiter-face))) - (cons markdown-regex-header-3-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-3) - (3 markdown-header-delimiter-face))) - (cons markdown-regex-header-2-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-2) - (3 markdown-header-delimiter-face))) - (cons markdown-regex-header-1-atx '((1 markdown-header-delimiter-face) - (2 markdown-header-face-1) - (3 markdown-header-delimiter-face))) - (cons 'markdown-match-multimarkdown-metadata '((1 markdown-metadata-key-face) - (2 markdown-metadata-value-face))) - (cons 'markdown-match-pandoc-metadata '((1 markdown-comment-face) - (2 markdown-metadata-value-face))) - (cons markdown-regex-hr 'markdown-header-face) - (cons 'markdown-match-comments '((0 markdown-comment-face))) - (cons 'markdown-match-code '((0 markdown-inline-code-face))) - (cons markdown-regex-angle-uri 'markdown-link-face) - (cons markdown-regex-uri 'markdown-link-face) - (cons markdown-regex-email 'markdown-link-face) - (cons markdown-regex-list '(2 markdown-list-face)) - (cons markdown-regex-footnote 'markdown-footnote-face) - (cons markdown-regex-link-inline '((1 markdown-link-face t t) - (2 markdown-link-face t) - (4 markdown-url-face t) - (6 markdown-link-title-face t t))) - (cons markdown-regex-link-reference '((1 markdown-link-face t t) - (2 markdown-link-face t) - (4 markdown-reference-face t))) - (cons markdown-regex-reference-definition '((1 markdown-reference-face t) - (2 markdown-url-face t) - (3 markdown-link-title-face t))) - (cons markdown-regex-bold '(2 markdown-bold-face)) - (cons markdown-regex-line-break '(1 markdown-line-break-face prepend)) - ) - "Syntax highlighting for Markdown files.") - -(defvar markdown-mode-font-lock-keywords-core - (list - (cons markdown-regex-italic '(2 markdown-italic-face)) - ) - "Additional syntax highlighting for Markdown files. -Includes features which are overridden by some variants.") - -(defconst markdown-mode-font-lock-keywords-math - (list - ;; Math mode $..$ or $$..$$ - (cons markdown-regex-math-inline '(2 markdown-math-face)) - ;; Display mode equations with brackets: \[ \] - (cons markdown-regex-math-display 'markdown-math-face) - ;; Equation reference (eq:foo) - (cons "(eq:[[:alnum:]:_]+)" 'markdown-reference-face) - ;; Equation reference \eqref{foo} - (cons "\\\\eqref{[[:alnum:]:_]+}" 'markdown-reference-face)) - "Syntax highlighting for LaTeX and itex fragments.") - -(defvar markdown-mode-font-lock-keywords nil - "Default highlighting expressions for Markdown mode. -This variable is defined as a buffer-local variable for dynamic -extension support.") - -;; Footnotes -(defvar markdown-footnote-counter 0 - "Counter for footnote numbers.") -(make-variable-buffer-local 'markdown-footnote-counter) - -(defconst markdown-footnote-chars - "[[:alnum:]-]" - "Regular expression maching any character that is allowed in a footnote identifier.") - - -;;; Compatibility ============================================================= - -(defun markdown-replace-regexp-in-string (regexp rep string) - "Replace ocurrences of REGEXP with REP in STRING. -This is a compatibility wrapper to provide `replace-regexp-in-string' -in XEmacs 21." - (if (featurep 'xemacs) - (replace-in-string string regexp rep) - (replace-regexp-in-string regexp rep string))) - -;; `markdown-use-region-p' is a compatibility function which checks -;; for an active region, with fallbacks for older Emacsen and XEmacs. -(eval-and-compile - (cond - ;; Emacs 23 and newer - ((fboundp 'use-region-p) - (defalias 'markdown-use-region-p 'use-region-p)) - ;; Older Emacsen - ((and (boundp 'transient-mark-mode) (boundp 'mark-active)) - (defun markdown-use-region-p () - "Compatibility wrapper to provide `use-region-p'." - (and transient-mark-mode mark-active))) - ;; XEmacs - ((fboundp 'region-active-p) - (defalias 'markdown-use-region-p 'region-active-p)))) - -(defun markdown-use-buttons-p () - "Determine whether this Emacs supports buttons." - (or (featurep 'button) (locate-library "button"))) - - -;;; Markdown Parsing Functions ================================================ - -(defun markdown-cur-line-blank-p () - "Return t if the current line is blank and nil otherwise." - (save-excursion - (beginning-of-line) - (re-search-forward "^\\s *$" (line-end-position) t))) - -(defun markdown-prev-line-blank-p () - "Return t if the previous line is blank and nil otherwise. -If we are at the first line, then consider the previous line to be blank." - (or (= (line-beginning-position) (point-min)) - (save-excursion - (forward-line -1) - (markdown-cur-line-blank-p)))) - -(defun markdown-next-line-blank-p () - "Return t if the next line is blank and nil otherwise. -If we are at the last line, then consider the next line to be blank." - (or (= (line-end-position) (point-max)) - (save-excursion - (forward-line 1) - (markdown-cur-line-blank-p)))) - -(defun markdown-prev-line-indent-p () - "Return t if the previous line is indented and nil otherwise." - (save-excursion - (forward-line -1) - (goto-char (line-beginning-position)) - (if (re-search-forward "^\\s " (line-end-position) t) t))) - -(defun markdown-cur-line-indent () - "Return the number of leading whitespace characters in the current line." - (save-match-data - (save-excursion - (goto-char (line-beginning-position)) - (re-search-forward "^[ \t]+" (line-end-position) t) - (current-column)))) - -(defun markdown-prev-line-indent () - "Return the number of leading whitespace characters in the previous line." - (save-excursion - (forward-line -1) - (markdown-cur-line-indent))) - -(defun markdown-next-line-indent () - "Return the number of leading whitespace characters in the next line." - (save-excursion - (forward-line 1) - (markdown-cur-line-indent))) - -(defun markdown-cur-non-list-indent () - "Return beginning position of list item text (not including the list marker). -Return nil if the current line is not the beginning of a list item." - (save-match-data - (save-excursion - (beginning-of-line) - (when (re-search-forward markdown-regex-list (line-end-position) t) - (current-column))))) - -(defun markdown-prev-non-list-indent () - "Return position of the first non-list-marker on the previous line." - (save-excursion - (forward-line -1) - (markdown-cur-non-list-indent))) - -(defun markdown-new-baseline-p () - "Determine if the current line begins a new baseline level." - (save-excursion - (beginning-of-line) - (save-match-data - (or (looking-at markdown-regex-header) - (looking-at markdown-regex-hr) - (and (null (markdown-cur-non-list-indent)) - (= (markdown-cur-line-indent) 0) - (markdown-prev-line-blank-p)))))) - -(defun markdown-search-backward-baseline () - "Search backward baseline point with no indentation and not a list item." - (end-of-line) - (let (stop) - (while (not (or stop (bobp))) - (re-search-backward markdown-regex-block-separator nil t) - (when (match-end 2) - (goto-char (match-end 2)) - (cond - ((markdown-new-baseline-p) - (setq stop t)) - ((looking-at markdown-regex-list) - (setq stop nil)) - (t (setq stop t))))))) - -(defun markdown-update-list-levels (marker indent levels) - "Update list levels given list MARKER, block INDENT, and current LEVELS. -Here, MARKER is a string representing the type of list, INDENT is an integer -giving the indentation, in spaces, of the current block, and LEVELS is a -list of the indentation levels of parent list items. When LEVELS is nil, -it means we are at baseline (not inside of a nested list)." - (cond - ;; New list item at baseline. - ((and marker (null levels)) - (setq levels (list indent))) - ;; List item with greater indentation (four or more spaces). - ;; Increase list level. - ((and marker (>= indent (+ (car levels) 4))) - (setq levels (cons indent levels))) - ;; List item with greater or equal indentation (less than four spaces). - ;; Do not increase list level. - ((and marker (>= indent (car levels))) - levels) - ;; Lesser indentation level. - ;; Pop appropriate number of elements off LEVELS list (e.g., lesser - ;; indentation could move back more than one list level). Note - ;; that this block need not be the beginning of list item. - ((< indent (car levels)) - (while (and (> (length levels) 1) - (< indent (+ (cadr levels) 4))) - (setq levels (cdr levels))) - levels) - ;; Otherwise, do nothing. - (t levels))) - -(defun markdown-calculate-list-levels () - "Calculate list levels at point. -Return a list of the form (n1 n2 n3 ...) where n1 is the -indentation of the deepest nested list item in the branch of -the list at the point, n2 is the indentation of the parent -list item, and so on. The depth of the list item is therefore -the length of the returned list. If the point is not at or -immediately after a list item, return nil." - (save-excursion - (let ((first (point)) levels indent pre-regexp) - ;; Find a baseline point with zero list indentation - (markdown-search-backward-baseline) - ;; Search for all list items between baseline and LOC - (while (and (< (point) first) - (re-search-forward markdown-regex-list first t)) - (setq pre-regexp (format "^\\( \\|\t\\)\\{%d\\}" (1+ (length levels)))) - (beginning-of-line) - (cond - ;; Make sure this is not a header or hr - ((markdown-new-baseline-p) (setq levels nil)) - ;; Make sure this is not a line from a pre block - ((looking-at pre-regexp)) - ;; If not, then update levels - (t - (setq indent (markdown-cur-line-indent)) - (setq levels (markdown-update-list-levels (match-string 2) - indent levels)))) - (end-of-line)) - levels))) - -(defun markdown-prev-list-item (level) - "Search backward from point for a list item with indentation LEVEL. -Set point to the beginning of the item, and return point, or nil -upon failure." - (let (bounds indent prev) - (setq prev (point)) - (forward-line -1) - (setq indent (markdown-cur-line-indent)) - (while - (cond - ;; Stop at beginning of buffer - ((bobp) (setq prev nil)) - ;; Continue if current line is blank - ((markdown-cur-line-blank-p) t) - ;; List item - ((and (looking-at markdown-regex-list) - (setq bounds (markdown-cur-list-item-bounds))) - (cond - ;; Continue at item with greater indentation - ((> (nth 3 bounds) level) t) - ;; Stop and return point at item of equal indentation - ((= (nth 3 bounds) level) - (setq prev (point)) - nil) - ;; Stop and return nil at item with lesser indentation - ((< (nth 3 bounds) level) - (setq prev nil) - nil))) - ;; Continue while indentation is the same or greater - ((>= indent level) t) - ;; Stop if current indentation is less than list item - ;; and the next is blank - ((and (< indent level) - (markdown-next-line-blank-p)) - (setq prev nil)) - ;; Stop at a header - ((looking-at markdown-regex-header) (setq prev nil)) - ;; Stop at a horizontal rule - ((looking-at markdown-regex-hr) (setq prev nil)) - ;; Otherwise, continue. - (t t)) - (forward-line -1) - (setq indent (markdown-cur-line-indent))) - prev)) - -(defun markdown-next-list-item (level) - "Search forward from point for the next list item with indentation LEVEL. -Set point to the beginning of the item, and return point, or nil -upon failure." - (let (bounds indent prev next) - (setq next (point)) - (forward-line) - (setq indent (markdown-cur-line-indent)) - (while - (cond - ;; Stop at end of the buffer. - ((eobp) (setq prev nil)) - ;; Continue if the current line is blank - ((markdown-cur-line-blank-p) t) - ;; List item - ((and (looking-at markdown-regex-list) - (setq bounds (markdown-cur-list-item-bounds))) - (cond - ;; Continue at item with greater indentation - ((> (nth 3 bounds) level) t) - ;; Stop and return point at item of equal indentation - ((= (nth 3 bounds) level) - (setq next (point)) - nil) - ;; Stop and return nil at item with lesser indentation - ((< (nth 3 bounds) level) - (setq next nil) - nil))) - ;; Continue while indentation is the same or greater - ((>= indent level) t) - ;; Stop if current indentation is less than list item - ;; and the previous line was blank. - ((and (< indent level) - (markdown-prev-line-blank-p)) - (setq next nil)) - ;; Stop at a header - ((looking-at markdown-regex-header) (setq next nil)) - ;; Stop at a horizontal rule - ((looking-at markdown-regex-hr) (setq next nil)) - ;; Otherwise, continue. - (t t)) - (forward-line) - (setq indent (markdown-cur-line-indent))) - next)) - -(defun markdown-cur-list-item-end (level) - "Move to the end of the current list item with nonlist indentation LEVEL. -If the point is not in a list item, do nothing." - (let (indent) - (forward-line) - (setq indent (markdown-cur-line-indent)) - (while - (cond - ;; Stop at end of the buffer. - ((eobp) nil) - ;; Continue if the current line is blank - ((markdown-cur-line-blank-p) t) - ;; Continue while indentation is the same or greater - ((>= indent level) t) - ;; Stop if current indentation is less than list item - ;; and the previous line was blank. - ((and (< indent level) - (markdown-prev-line-blank-p)) - nil) - ;; Stop at a new list item of the same or lesser indentation - ((looking-at markdown-regex-list) nil) - ;; Stop at a header - ((looking-at markdown-regex-header) nil) - ;; Stop at a horizontal rule - ((looking-at markdown-regex-hr) nil) - ;; Otherwise, continue. - (t t)) - (forward-line) - (setq indent (markdown-cur-line-indent))) - ;; Don't skip over whitespace for empty list items (marker and - ;; whitespace only), just move to end of whitespace. - (if (looking-back (concat markdown-regex-list "\\s-*")) - (goto-char (match-end 3)) - (skip-syntax-backward "-")))) - -(defun markdown-cur-list-item-bounds () - "Return bounds and indentation of the current list item. -Return a list of the form (begin end indent nonlist-indent marker). -If the point is not inside a list item, return nil. -Leave match data intact for `markdown-regex-list'." - (let (cur prev-begin prev-end indent nonlist-indent marker) - ;; Store current location - (setq cur (point)) - ;; Verify that cur is between beginning and end of item - (save-excursion - (end-of-line) - (when (re-search-backward markdown-regex-list nil t) - (setq prev-begin (match-beginning 0)) - (setq indent (length (match-string 1))) - (setq nonlist-indent (length (match-string 0))) - (setq marker (concat (match-string 2) (match-string 3))) - (save-match-data - (markdown-cur-list-item-end nonlist-indent) - (setq prev-end (point))) - (when (and (>= cur prev-begin) - (<= cur prev-end) - nonlist-indent) - (list prev-begin prev-end indent nonlist-indent marker)))))) - -(defun markdown-bounds-of-thing-at-point (thing) - "Call `bounds-of-thing-at-point' for THING with slight modifications. -Does not include trailing newlines when THING is 'line. Handles the -end of buffer case by setting both endpoints equal to the value of -`point-max', since an empty region will trigger empty markup insertion. -Return bounds of form (beg . end) if THING is found, or nil otherwise." - (let* ((bounds (bounds-of-thing-at-point thing)) - (a (car bounds)) - (b (cdr bounds))) - (when bounds - (when (eq thing 'line) - (cond ((and (eobp) (markdown-cur-line-blank-p)) - (setq a b)) - ((char-equal (char-before b) ?\^J) - (setq b (1- b))))) - (cons a b)))) - -(defun markdown-reference-definition (reference) - "Find out whether Markdown REFERENCE is defined. -REFERENCE should include the square brackets, like [this]. -When REFERENCE is defined, return a list of the form (text start end) -containing the definition text itself followed by the start and end -locations of the text. Otherwise, return nil. -Leave match data for `markdown-regex-reference-definition' -intact additional processing." - (let ((reference (downcase reference))) - (save-excursion - (goto-char (point-min)) - (catch 'found - (while (re-search-forward markdown-regex-reference-definition nil t) - (when (string= reference (downcase (match-string-no-properties 1))) - (throw 'found - (list (match-string-no-properties 2) - (match-beginning 2) (match-end 2))))))))) - -(defun markdown-get-defined-references () - "Return a list of all defined reference labels (including square brackets)." - (save-excursion - (goto-char (point-min)) - (let (refs) - (while (re-search-forward markdown-regex-reference-definition nil t) - (let ((target (match-string-no-properties 1))) - (add-to-list 'refs target t))) - refs))) - -(defun markdown-code-at-point-p () - "Return non-nil if the point is at an inline code fragment. -Return nil otherwise. Set match data according to -`markdown-match-code' upon success. -This function searches the block for a code fragment that -contains the point using `markdown-match-code'. We do this -because `thing-at-point-looking-at' does not work reliably with -`markdown-regex-code'." - (interactive) - (save-excursion - (let ((old-point (point)) - (end-of-block (progn (markdown-end-of-block) (point))) - found) - (markdown-beginning-of-block) - (while (and (markdown-match-code end-of-block) - (setq found t) - (< (match-end 0) old-point))) - (and found ; matched something - (<= (match-beginning 0) old-point) ; match contains old-point - (>= (match-end 0) old-point))))) - - -;;; Markdown Font Lock Matching Functions ===================================== - -(defun markdown-match-comments (last) - "Match HTML comments from the point to LAST." - (cond ((search-forward "") - (make-local-variable 'comment-start-skip) - (setq comment-start-skip "