2428 lines
93 KiB
EmacsLisp
2428 lines
93 KiB
EmacsLisp
|
;;; ourcomments-util.el --- Utility routines
|
||
|
;;
|
||
|
;; Author: Lennart Borgman <lennart dot borgman at gmail dot com>
|
||
|
;; Created: Wed Feb 21 2007
|
||
|
(defconst ourcomments-util:version "0.25") ;;Version:
|
||
|
;; Last-Updated: 2009-08-04 Tue
|
||
|
;; Keywords:
|
||
|
;; Compatibility: Emacs 22
|
||
|
;;
|
||
|
;; Features that might be required by this library:
|
||
|
;;
|
||
|
;; None
|
||
|
;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;
|
||
|
;;; Commentary:
|
||
|
;;
|
||
|
;; The functionality given by these small routines should in my
|
||
|
;; opinion be part of Emacs (but they are not that currently).
|
||
|
;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;
|
||
|
;;; Change log:
|
||
|
;;
|
||
|
;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;
|
||
|
;; 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; see the file COPYING. If not, write to the
|
||
|
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||
|
;; Boston, MA 02111-1307, USA.
|
||
|
;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;
|
||
|
;;; Code:
|
||
|
|
||
|
(eval-when-compile (require 'apropos))
|
||
|
(eval-when-compile (require 'bookmark))
|
||
|
(eval-when-compile (require 'cl))
|
||
|
(eval-when-compile (require 'grep))
|
||
|
(eval-when-compile (require 'ido))
|
||
|
(eval-when-compile (require 'org))
|
||
|
(eval-when-compile (require 'recentf))
|
||
|
(eval-when-compile (require 'uniquify))
|
||
|
|
||
|
(require 'cus-edit)
|
||
|
|
||
|
;; (ourcomments-indirect-fun 'html-mumamo)
|
||
|
;; (ourcomments-indirect-fun 'html-mumamo-mode)
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-indirect-fun (fun)
|
||
|
"Get the alias symbol for function FUN if any."
|
||
|
;; This code is from `describe-function-1'.
|
||
|
(when (and (symbolp fun)
|
||
|
(functionp fun))
|
||
|
(let ((def (symbol-function fun)))
|
||
|
(when (symbolp def)
|
||
|
(while (and (fboundp def)
|
||
|
(symbolp (symbol-function def)))
|
||
|
(setq def (symbol-function def)))
|
||
|
def))))
|
||
|
|
||
|
(defun ourcomments-goto-line (line)
|
||
|
"A version of `goto-line' for use in elisp code."
|
||
|
(save-restriction
|
||
|
(widen)
|
||
|
(goto-char (point-min))
|
||
|
(forward-line (1- line))))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Popups etc.
|
||
|
|
||
|
(defun point-to-coord (point)
|
||
|
"Return coordinates of POINT in selected window.
|
||
|
The coordinates are in the form \(\(XOFFSET YOFFSET) WINDOW).
|
||
|
This form is suitable for `popup-menu'."
|
||
|
;; Fix-me: showtip.el adds (window-inside-pixel-edges
|
||
|
;; (selected-window)). Why?
|
||
|
(let* ((pn (posn-at-point point))
|
||
|
(x-y (posn-x-y pn))
|
||
|
(x (car x-y))
|
||
|
(y (cdr x-y))
|
||
|
(pos (list (list x (+ y 20)) (selected-window))))
|
||
|
pos))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun popup-menu-at-point (menu &optional prefix)
|
||
|
"Popup the given menu at point.
|
||
|
This is similar to `popup-menu' and MENU and PREFIX has the same
|
||
|
meaning as there. The position for the popup is however where
|
||
|
the window point is."
|
||
|
(let ((where (point-to-coord (point))))
|
||
|
(popup-menu menu where prefix)))
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Toggles in menus
|
||
|
|
||
|
;;;###autoload
|
||
|
(defmacro define-toggle (symbol value doc &rest args)
|
||
|
"Declare SYMBOL as a customizable variable with a toggle function.
|
||
|
The purpose of this macro is to define a defcustom and a toggle
|
||
|
function suitable for use in a menu.
|
||
|
|
||
|
The arguments have the same meaning as for `defcustom' with these
|
||
|
restrictions:
|
||
|
|
||
|
- The :type keyword cannot be used. Type is always 'boolean.
|
||
|
- VALUE must be t or nil.
|
||
|
|
||
|
DOC and ARGS are just passed to `defcustom'.
|
||
|
|
||
|
A `defcustom' named SYMBOL with doc-string DOC and a function
|
||
|
named SYMBOL-toggle is defined. The function toggles the value
|
||
|
of SYMBOL. It takes no parameters.
|
||
|
|
||
|
To create a menu item something similar to this can be used:
|
||
|
|
||
|
\(define-key map [SYMBOL]
|
||
|
\(list 'menu-item \"Toggle nice SYMBOL\"
|
||
|
'SYMBOL-toggle
|
||
|
:button '(:toggle . SYMBOL)))"
|
||
|
(declare
|
||
|
(doc-string 3)
|
||
|
(debug t))
|
||
|
(let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
|
||
|
(SYMBOL-name (symbol-name symbol))
|
||
|
(var-doc doc)
|
||
|
(fun-doc (concat "Toggles the \(boolean) value of `"
|
||
|
SYMBOL-name
|
||
|
"'.\n"
|
||
|
"For how to set it permanently see this variable.\n"
|
||
|
)))
|
||
|
(let ((var (append `(defcustom ,symbol ,value ,var-doc)
|
||
|
args
|
||
|
nil))
|
||
|
(fun `(defun ,SYMBOL-toggle ()
|
||
|
,fun-doc
|
||
|
(interactive)
|
||
|
(customize-set-variable (quote ,symbol) (not ,symbol)))))
|
||
|
;;(message "\nvar=%S\nfun=%S\n" var fun)
|
||
|
;; Fix-me: I am having problems with this one, see
|
||
|
;; http://lists.gnu.org/archive/html/help-gnu-emacs/2009-12/msg00608.html
|
||
|
`(progn ,var ,fun)
|
||
|
)))
|
||
|
|
||
|
;;(macroexpand '(define-toggle my-toggle t "doc" :tag "Short help" :group 'popcmp))
|
||
|
;;(macroexpand-all (define-toggle my-toggle t "doc" :tag "Short help" :group 'popcmp))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defmacro define-toggle-old (symbol value doc &rest args)
|
||
|
(declare (doc-string 3))
|
||
|
(list
|
||
|
'progn
|
||
|
(let ((var-decl (list 'custom-declare-variable
|
||
|
(list 'quote symbol)
|
||
|
(list 'quote value)
|
||
|
doc)))
|
||
|
(while args
|
||
|
(let ((arg (car args)))
|
||
|
(setq args (cdr args))
|
||
|
(unless (symbolp arg)
|
||
|
(error "Junk in args %S" args))
|
||
|
(let ((keyword arg)
|
||
|
(value (car args)))
|
||
|
(unless args
|
||
|
(error "Keyword %s is missing an argument" keyword))
|
||
|
(setq args (cdr args))
|
||
|
(cond
|
||
|
((not (memq keyword '(:type)))
|
||
|
(setq var-decl (append var-decl (list keyword value))))
|
||
|
(t
|
||
|
(lwarn '(define-toggle) :error "Keyword %s can't be used here"
|
||
|
keyword))))))
|
||
|
(when (assoc :type var-decl) (error ":type is set. Should not happen!"))
|
||
|
(setq var-decl (append var-decl (list :type '(quote boolean))))
|
||
|
var-decl)
|
||
|
(let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
|
||
|
(SYMBOL-name (symbol-name symbol))
|
||
|
(fun-doc (concat "Toggles the \(boolean) value of `"
|
||
|
SYMBOL-name
|
||
|
"'.\n"
|
||
|
"For how to set it permanently see this variable.\n"
|
||
|
;;"\nDescription of `" SYMBOL-name "':\n" doc
|
||
|
)))
|
||
|
`(defun ,SYMBOL-toggle ()
|
||
|
,fun-doc
|
||
|
(interactive)
|
||
|
(customize-set-variable (quote ,symbol) (not ,symbol)))
|
||
|
)))
|
||
|
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Indentation of regions
|
||
|
|
||
|
;; From an idea by weber <hugows@gmail.com>
|
||
|
;; (defun indent-line-or-region ()
|
||
|
;; "Indent line or region.
|
||
|
;; Only do this if indentation seems bound to \\t.
|
||
|
|
||
|
;; Call `indent-region' if region is active, otherwise
|
||
|
;; `indent-according-to-mode'."
|
||
|
;; (interactive)
|
||
|
;; ;; Do a wild guess if we should indent or not ...
|
||
|
;; (let* ((indent-region-mode)
|
||
|
;; ;; The above hides the `indent-line-or-region' binding
|
||
|
;; (t-bound (key-binding [?\t])))
|
||
|
;; (if (not
|
||
|
;; (save-match-data
|
||
|
;; (string-match "indent" (symbol-name t-bound))))
|
||
|
;; (call-interactively t-bound t)
|
||
|
;; (if (and mark-active ;; there is a visible region selected
|
||
|
;; transient-mark-mode)
|
||
|
;; (indent-region (region-beginning) (region-end))
|
||
|
;; (indent-according-to-mode))))) ;; indent line
|
||
|
|
||
|
;; (define-minor-mode indent-region-mode
|
||
|
;; "Use \\t to indent line or region.
|
||
|
;; The key \\t is bound to `indent-line-or-region' if this mode is
|
||
|
;; on."
|
||
|
;; :global t
|
||
|
;; :keymap '(([?\t] . indent-line-or-region)))
|
||
|
;; (when indent-region-mode (indent-region-mode 1))
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Minor modes
|
||
|
|
||
|
;; (defmacro define-globalized-minor-mode-with-on-off (global-mode mode
|
||
|
;; turn-on turn-off
|
||
|
;; &rest keys)
|
||
|
;; "Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE.
|
||
|
;; This is a special variant of `define-globalized-minor-mode' for
|
||
|
;; mumamo. It let bounds the variable GLOBAL-MODE-checking before
|
||
|
;; calling TURN-ON or TURN-OFF.
|
||
|
|
||
|
;; TURN-ON is a function that will be called with no args in every buffer
|
||
|
;; and that should try to turn MODE on if applicable for that buffer.
|
||
|
;; TURN-OFF is a function that turns off MODE in a buffer.
|
||
|
;; KEYS is a list of CL-style keyword arguments. As the minor mode
|
||
|
;; defined by this function is always global, any :global keyword is
|
||
|
;; ignored. Other keywords have the same meaning as in `define-minor-mode',
|
||
|
;; which see. In particular, :group specifies the custom group.
|
||
|
;; The most useful keywords are those that are passed on to the
|
||
|
;; `defcustom'. It normally makes no sense to pass the :lighter
|
||
|
;; or :keymap keywords to `define-globalized-minor-mode', since these
|
||
|
;; are usually passed to the buffer-local version of the minor mode.
|
||
|
|
||
|
;; If MODE's set-up depends on the major mode in effect when it was
|
||
|
;; enabled, then disabling and reenabling MODE should make MODE work
|
||
|
;; correctly with the current major mode. This is important to
|
||
|
;; prevent problems with derived modes, that is, major modes that
|
||
|
;; call another major mode in their body."
|
||
|
|
||
|
;; (let* ((global-mode-name (symbol-name global-mode))
|
||
|
;; (pretty-name (easy-mmode-pretty-mode-name mode))
|
||
|
;; (pretty-global-name (easy-mmode-pretty-mode-name global-mode))
|
||
|
;; (group nil)
|
||
|
;; (extra-keywords nil)
|
||
|
;; (MODE-buffers (intern (concat global-mode-name "-buffers")))
|
||
|
;; (MODE-enable-in-buffers
|
||
|
;; (intern (concat global-mode-name "-enable-in-buffers")))
|
||
|
;; (MODE-check-buffers
|
||
|
;; (intern (concat global-mode-name "-check-buffers")))
|
||
|
;; (MODE-cmhh (intern (concat global-mode-name "-cmhh")))
|
||
|
;; (MODE-major-mode (intern (concat (symbol-name mode)
|
||
|
;; "-major-mode")))
|
||
|
;; (MODE-checking (intern (concat global-mode-name "-checking")))
|
||
|
;; keyw)
|
||
|
|
||
|
;; ;; Check keys.
|
||
|
;; (while (keywordp (setq keyw (car keys)))
|
||
|
;; (setq keys (cdr keys))
|
||
|
;; (case keyw
|
||
|
;; (:group (setq group (nconc group (list :group (pop keys)))))
|
||
|
;; (:global (setq keys (cdr keys)))
|
||
|
;; (t (push keyw extra-keywords) (push (pop keys) extra-keywords))))
|
||
|
|
||
|
;; (unless group
|
||
|
;; ;; We might as well provide a best-guess default group.
|
||
|
;; (setq group
|
||
|
;; `(:group ',(intern (replace-regexp-in-string
|
||
|
;; "-mode\\'" "" (symbol-name mode))))))
|
||
|
|
||
|
;; `(progn
|
||
|
|
||
|
;; ;; Define functions for the global mode first so that it can be
|
||
|
;; ;; turned on during load:
|
||
|
|
||
|
;; ;; List of buffers left to process.
|
||
|
;; (defvar ,MODE-buffers nil)
|
||
|
|
||
|
;; ;; The function that calls TURN-ON in each buffer.
|
||
|
;; (defun ,MODE-enable-in-buffers ()
|
||
|
;; (let ((,MODE-checking nil))
|
||
|
;; (dolist (buf ,MODE-buffers)
|
||
|
;; (when (buffer-live-p buf)
|
||
|
;; (with-current-buffer buf
|
||
|
;; (if ,mode
|
||
|
;; (unless (eq ,MODE-major-mode major-mode)
|
||
|
;; (setq ,MODE-checking t)
|
||
|
;; (,mode -1)
|
||
|
;; (,turn-on)
|
||
|
;; (setq ,MODE-checking nil)
|
||
|
;; (setq ,MODE-major-mode major-mode))
|
||
|
;; (setq ,MODE-checking t)
|
||
|
;; (,turn-on)
|
||
|
;; (setq ,MODE-checking nil)
|
||
|
;; (setq ,MODE-major-mode major-mode)))))))
|
||
|
;; (put ',MODE-enable-in-buffers 'definition-name ',global-mode)
|
||
|
|
||
|
;; (defun ,MODE-check-buffers ()
|
||
|
;; (,MODE-enable-in-buffers)
|
||
|
;; (setq ,MODE-buffers nil)
|
||
|
;; (remove-hook 'post-command-hook ',MODE-check-buffers))
|
||
|
;; (put ',MODE-check-buffers 'definition-name ',global-mode)
|
||
|
|
||
|
;; ;; The function that catches kill-all-local-variables.
|
||
|
;; (defun ,MODE-cmhh ()
|
||
|
;; (add-to-list ',MODE-buffers (current-buffer))
|
||
|
;; (add-hook 'post-command-hook ',MODE-check-buffers))
|
||
|
;; (put ',MODE-cmhh 'definition-name ',global-mode)
|
||
|
|
||
|
|
||
|
;; (defvar ,MODE-major-mode nil)
|
||
|
;; (make-variable-buffer-local ',MODE-major-mode)
|
||
|
|
||
|
;; ;; The actual global minor-mode
|
||
|
;; (define-minor-mode ,global-mode
|
||
|
;; ,(format "Toggle %s in every possible buffer.
|
||
|
;; With prefix ARG, turn %s on if and only if ARG is positive.
|
||
|
;; %s is enabled in all buffers where `%s' would do it.
|
||
|
;; See `%s' for more information on %s."
|
||
|
;; pretty-name pretty-global-name pretty-name turn-on
|
||
|
;; mode pretty-name)
|
||
|
;; :global t ,@group ,@(nreverse extra-keywords)
|
||
|
|
||
|
;; ;; Setup hook to handle future mode changes and new buffers.
|
||
|
;; (if ,global-mode
|
||
|
;; (progn
|
||
|
;; (add-hook 'after-change-major-mode-hook
|
||
|
;; ',MODE-enable-in-buffers)
|
||
|
;; ;;(add-hook 'find-file-hook ',MODE-check-buffers)
|
||
|
;; (add-hook 'find-file-hook ',MODE-cmhh)
|
||
|
;; (add-hook 'change-major-mode-hook ',MODE-cmhh))
|
||
|
;; (remove-hook 'after-change-major-mode-hook ',MODE-enable-in-buffers)
|
||
|
;; ;;(remove-hook 'find-file-hook ',MODE-check-buffers)
|
||
|
;; (remove-hook 'find-file-hook ',MODE-cmhh)
|
||
|
;; (remove-hook 'change-major-mode-hook ',MODE-cmhh))
|
||
|
|
||
|
;; ;; Go through existing buffers.
|
||
|
;; (let ((,MODE-checking t))
|
||
|
;; (dolist (buf (buffer-list))
|
||
|
;; (with-current-buffer buf
|
||
|
;; ;;(if ,global-mode (,turn-on) (when ,mode (,mode -1)))
|
||
|
;; (if ,global-mode (,turn-on) (,turn-off))
|
||
|
;; ))))
|
||
|
|
||
|
;; )))
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Unfilling
|
||
|
;;
|
||
|
;; The idea is from
|
||
|
;; http://interglacial.com/~sburke/pub/emacs/sburke_dot_emacs.config
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun unfill-paragraph ()
|
||
|
"Unfill the current paragraph."
|
||
|
(interactive) (with-unfilling 'fill-paragraph))
|
||
|
;;(defalias 'unwrap-paragraph 'unfill-paragraph)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun unfill-region ()
|
||
|
"Unfill the current region."
|
||
|
(interactive) (with-unfilling 'fill-region))
|
||
|
;;(defalias 'unwrap-region 'unfill-region)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun unfill-individual-paragraphs ()
|
||
|
"Unfill individual paragraphs in the current region."
|
||
|
(interactive) (with-unfilling 'fill-individual-paragraphs))
|
||
|
;;(defalias 'unwrap-individual-paragraphs 'unfill-individual-paragraphs)
|
||
|
|
||
|
(defun with-unfilling (fn)
|
||
|
"Unfill using the fill function FN."
|
||
|
(let ((fill-column (1+ (point-max)))) (call-interactively fn)))
|
||
|
|
||
|
(defvar fill-dwim-state nil)
|
||
|
(defvar fill-dwim-mark nil)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun fill-dwim (arg)
|
||
|
"Fill or unfill paragraph or region.
|
||
|
With prefix ARG fill only current line."
|
||
|
(interactive "P")
|
||
|
(or arg
|
||
|
(not fill-dwim-mark)
|
||
|
(equal (point-marker) fill-dwim-mark)
|
||
|
(setq fill-dwim-state nil))
|
||
|
(if mark-active
|
||
|
;; This avoids deactivating the mark
|
||
|
(progn
|
||
|
(if fill-dwim-state
|
||
|
(call-interactively 'unfill-region)
|
||
|
(call-interactively 'fill-region))
|
||
|
(setq deactivate-mark nil))
|
||
|
(if arg
|
||
|
(fill-region (line-beginning-position) (line-end-position))
|
||
|
(if fill-dwim-state
|
||
|
(call-interactively 'unfill-paragraph)
|
||
|
(call-interactively 'fill-paragraph))))
|
||
|
(setq fill-dwim-mark (copy-marker (point)))
|
||
|
(unless arg
|
||
|
(setq fill-dwim-state (not fill-dwim-state))))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Widgets
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-mark-whole-buffer-or-field ()
|
||
|
"Mark whole buffer or editable field at point."
|
||
|
(interactive)
|
||
|
(let* ((field (widget-field-at (point)))
|
||
|
(from (when field (widget-field-start field)))
|
||
|
(to (when field (widget-field-end field)))
|
||
|
(size (when field (widget-get field :size))))
|
||
|
(if (not field)
|
||
|
(mark-whole-buffer)
|
||
|
(while (and size
|
||
|
(not (zerop size))
|
||
|
(> to from)
|
||
|
(eq (char-after (1- to)) ?\s))
|
||
|
(setq to (1- to)))
|
||
|
(push-mark (point))
|
||
|
(push-mark from nil t)
|
||
|
(goto-char to))))
|
||
|
|
||
|
;; (rassq 'genshi-nxhtml-mumamo-mode mumamo-defined-turn-on-functions)
|
||
|
;; (major-modep 'nxhtml-mode)
|
||
|
;; (major-modep 'nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'jsp-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'gsp-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'asp-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'django-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'eruby-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'eruby-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'smarty-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'embperl-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'laszlo-nxml-mumamo-mode)
|
||
|
;; (major-modep 'genshi-nxhtml-mumamo-mode)
|
||
|
;; (major-modep 'javascript-mode)
|
||
|
;; (major-modep 'espresso-mode)
|
||
|
;; (major-modep 'css-mode)
|
||
|
;; (major-modep 'js-mode)
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Lines
|
||
|
|
||
|
;; Changed from move-beginning-of-line to beginning-of-line to support
|
||
|
;; physical-line-mode.
|
||
|
;; Fix-me: use end-of-visual-line etc.
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-move-beginning-of-line(arg)
|
||
|
"Move point to beginning of line or indentation.
|
||
|
See `beginning-of-line' for ARG.
|
||
|
|
||
|
If `line-move-visual' is non-nil then the visual line beginning
|
||
|
is first tried.
|
||
|
|
||
|
If in a widget field stay in that."
|
||
|
(interactive "p")
|
||
|
(let ((pos (point))
|
||
|
vis-pos
|
||
|
(field (widget-field-at (point))))
|
||
|
(when line-move-visual
|
||
|
(line-move-visual -1 t)
|
||
|
(beginning-of-line)
|
||
|
(setq vis-pos (point))
|
||
|
(goto-char pos))
|
||
|
(call-interactively 'beginning-of-line arg)
|
||
|
(when (and vis-pos
|
||
|
(= vis-pos (point)))
|
||
|
(while (and (> pos (point))
|
||
|
(not (eobp)))
|
||
|
(let (last-command)
|
||
|
(line-move-visual 1 t)))
|
||
|
(line-move-visual -1 t))
|
||
|
(when (= pos (point))
|
||
|
(if (= 0 (current-column))
|
||
|
(skip-chars-forward " \t")
|
||
|
(backward-char)
|
||
|
(beginning-of-line)))
|
||
|
(when (and field
|
||
|
(< (point) (widget-field-start field)))
|
||
|
(goto-char (widget-field-start field)))))
|
||
|
(put 'ourcomments-move-beginning-of-line 'CUA 'move)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-move-end-of-line(arg)
|
||
|
"Move point to end of line or after last non blank char.
|
||
|
See `end-of-line' for ARG.
|
||
|
|
||
|
Similar to `ourcomments-move-beginning-of-line' but for end of
|
||
|
line."
|
||
|
(interactive "p")
|
||
|
(or arg (setq arg 1))
|
||
|
(let ((pos (point))
|
||
|
vis-pos
|
||
|
eol-pos)
|
||
|
(when line-move-visual
|
||
|
(let (last-command) (line-move-visual 1 t))
|
||
|
(end-of-line)
|
||
|
(setq vis-pos (point))
|
||
|
(goto-char pos))
|
||
|
(call-interactively 'end-of-line arg)
|
||
|
(when (and vis-pos
|
||
|
(= vis-pos (point)))
|
||
|
(setq eol-pos (point))
|
||
|
(beginning-of-line)
|
||
|
(let (last-command) (line-move-visual 1 t))
|
||
|
;; move backwards if we moved to a new line
|
||
|
(unless (= (point) eol-pos)
|
||
|
(backward-char)))
|
||
|
(when (= pos (point))
|
||
|
(if (= (line-end-position) (point))
|
||
|
(skip-chars-backward " \t")
|
||
|
(forward-char)
|
||
|
(end-of-line)))))
|
||
|
(put 'ourcomments-move-end-of-line 'CUA 'move)
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Keymaps
|
||
|
|
||
|
(defun ourcomments-find-keymap-variables (key--- binding--- keymap---)
|
||
|
"Return a list of matching keymap variables.
|
||
|
They should have key KEY--- bound to BINDING--- and have value
|
||
|
KEYMAP---.
|
||
|
|
||
|
Ignore `special-event-map', `global-map', `overriding-local-map'
|
||
|
and `overriding-terminal-local-map'."
|
||
|
(let ((vars--- nil)
|
||
|
(ancestors--- nil))
|
||
|
(let ((parent (keymap-parent keymap---)))
|
||
|
(while parent
|
||
|
(setq ancestors--- (cons parent ancestors---))
|
||
|
(setq parent (keymap-parent parent))))
|
||
|
(mapatoms (lambda (symbol)
|
||
|
(unless (memq symbol '(keymap---
|
||
|
ancestors---
|
||
|
vars---
|
||
|
special-event-map
|
||
|
global-map
|
||
|
overriding-local-map
|
||
|
overriding-terminal-local-map
|
||
|
))
|
||
|
(let (val)
|
||
|
(if (boundp symbol)
|
||
|
(setq val (symbol-value symbol))
|
||
|
(when (keymapp symbol)
|
||
|
(setq val (symbol-function symbol))))
|
||
|
(when (and val
|
||
|
(keymapp val)
|
||
|
(eq binding--- (lookup-key val key--- t)))
|
||
|
(if (equal val keymap---)
|
||
|
(push symbol vars---)
|
||
|
(when ancestors---
|
||
|
(catch 'found
|
||
|
(dolist (ancestor ancestors---)
|
||
|
(when (equal val ancestor)
|
||
|
(push symbol vars---)
|
||
|
(throw 'found nil)))))))))))
|
||
|
;;; (let ((childs nil))
|
||
|
;;; (dolist (var vars---)
|
||
|
;;; (dolist (ancestor ancestors---)
|
||
|
;;; (when (equal (keymap-parent var)
|
||
|
;;; (
|
||
|
vars---))
|
||
|
|
||
|
;; This is modelled after `current-active-maps'.
|
||
|
(defun key-bindings (key &optional olp position)
|
||
|
"Return list of bindings for key sequence KEY in current keymaps.
|
||
|
The first binding is the active binding and the others are
|
||
|
bindings shadowed by this in the order of their priority level
|
||
|
\(see Info node `(elisp) Searching Keymaps').
|
||
|
|
||
|
The entries in the list have the form
|
||
|
|
||
|
\(BINDING (MAPS) MORE-INFO)
|
||
|
|
||
|
where BINDING is the command bound to and MAPS are matching maps
|
||
|
\(according to `ourcomments-find-keymap-variables').
|
||
|
|
||
|
MORE-INFO is a list with more information
|
||
|
|
||
|
\(PRIORITY-LEVEL \[ACTIVE-WHEN])
|
||
|
|
||
|
where PRIORITY-LEVEL is a symbol matching the level where the
|
||
|
keymap is found and ACTIVE-WHEN is a symbol which must be non-nil
|
||
|
for the keymap to be active \(minor mode levels only)."
|
||
|
;;(message "\nkey-bindings %s %s %s" key olp position)
|
||
|
(let* ((bindings nil)
|
||
|
(maps (current-active-maps))
|
||
|
map
|
||
|
map-sym
|
||
|
map-rec
|
||
|
binding
|
||
|
keymaps
|
||
|
minor-maps
|
||
|
where
|
||
|
map-where
|
||
|
where-map
|
||
|
(local-map (current-local-map))
|
||
|
(pt (or position (point)))
|
||
|
(point-keymap (get-char-property pt 'keymap))
|
||
|
(point-local-map (get-char-property pt 'local-map))
|
||
|
)
|
||
|
(setq keymaps
|
||
|
(cons (list global-map 'global-map)
|
||
|
keymaps))
|
||
|
(when overriding-terminal-local-map
|
||
|
(setq keymaps
|
||
|
(cons (list overriding-terminal-local-map 'overriding-terminal-local-map)
|
||
|
keymaps)))
|
||
|
(when overriding-local-map
|
||
|
(setq keymaps
|
||
|
(cons (list overriding-local-map 'overriding-local-map)
|
||
|
keymaps)))
|
||
|
(unless (cdr keymaps)
|
||
|
(when point-local-map
|
||
|
(setq keymaps
|
||
|
(cons (list point-local-map 'point-local-map)
|
||
|
keymaps)))
|
||
|
;; Fix-me:
|
||
|
;;/* If on a mode line string with a local keymap,
|
||
|
|
||
|
(when local-map
|
||
|
(setq keymaps
|
||
|
(cons (list local-map 'local-map)
|
||
|
keymaps)))
|
||
|
|
||
|
;; Minor-modes
|
||
|
;;(message "================ Minor-modes")
|
||
|
(dolist (list '(emulation-mode-map-alists
|
||
|
minor-mode-overriding-map-alist
|
||
|
minor-mode-map-alist))
|
||
|
;;(message "------- %s" list)
|
||
|
(let ((alists (if (eq list 'emulation-mode-map-alists)
|
||
|
(symbol-value list)
|
||
|
(list (symbol-value list)))))
|
||
|
(dolist (alist alists)
|
||
|
;;(message "\n(symbolp alist)=%s alist= %s (symbol-value alist)=%s" (symbolp alist) "dum" "dum2") ;alist "dummy");(when (symbolp alist) (symbol-value alist)))
|
||
|
(when (symbolp alist)
|
||
|
(setq alist (symbol-value alist)))
|
||
|
(dolist (assoc alist)
|
||
|
(let* (;(assoc (car alist-rec))
|
||
|
(var (when (consp assoc) (car assoc)))
|
||
|
(val (when (and (symbolp var)
|
||
|
(boundp var))
|
||
|
(symbol-value var))))
|
||
|
;;(message "var= %s, val= %s" var val)
|
||
|
(when (and
|
||
|
val
|
||
|
(or (not (eq list 'minor-mode-map-alist))
|
||
|
(not (assq var minor-mode-overriding-map-alist))))
|
||
|
;;(message "** Adding this")
|
||
|
(setq minor-maps
|
||
|
(cons (list (cdr assoc) list var)
|
||
|
minor-maps)))
|
||
|
)))))
|
||
|
(dolist (map minor-maps)
|
||
|
;;(message "cdr map= %s" (cdr map))
|
||
|
(setq keymaps
|
||
|
(cons map
|
||
|
keymaps)))
|
||
|
(when point-keymap
|
||
|
(setq keymaps
|
||
|
(cons (list point-keymap 'point-keymap)
|
||
|
keymaps))))
|
||
|
|
||
|
;; Fix-me: compare with current-active-maps
|
||
|
(let ((ca-maps (current-active-maps))
|
||
|
(wh-maps keymaps)
|
||
|
ca
|
||
|
wh)
|
||
|
(while (or ca-maps wh-maps)
|
||
|
(setq ca (car ca-maps))
|
||
|
(setq wh (car wh-maps))
|
||
|
(setq ca-maps (cdr ca-maps))
|
||
|
(setq wh-maps (cdr wh-maps))
|
||
|
;;(message "\nca= %s" ca)
|
||
|
;;(message "cdr wh= %s" (cdr wh))
|
||
|
(unless (equal ca (car wh))
|
||
|
(error "Did not match: %s" (cdr wh)))))
|
||
|
|
||
|
(while keymaps
|
||
|
(setq map-rec (car keymaps))
|
||
|
(setq map (car map-rec))
|
||
|
(when (setq binding (lookup-key map key t))
|
||
|
(setq map-sym (ourcomments-find-keymap-variables key binding map))
|
||
|
(setq map-sym (delq 'map map-sym))
|
||
|
(setq map-sym (delq 'local-map map-sym))
|
||
|
(setq map-sym (delq 'point-keymap map-sym))
|
||
|
(setq map-sym (delq 'point-local-map map-sym))
|
||
|
(setq bindings (cons (list binding map-sym (cdr map-rec)) bindings)))
|
||
|
(setq keymaps (cdr keymaps)))
|
||
|
|
||
|
(nreverse bindings)))
|
||
|
|
||
|
(defun describe-keymap-placement (keymap-sym)
|
||
|
"Find minor mode keymap KEYMAP-SYM in the keymaps searched for key lookup.
|
||
|
See Info node `Searching Keymaps'."
|
||
|
;;(info "(elisp) Searching Keymaps")
|
||
|
(interactive (list (ourcomments-read-symbol "Describe minor mode keymap symbol"
|
||
|
(lambda (sym)
|
||
|
(and (boundp sym)
|
||
|
(keymapp (symbol-value sym)))))))
|
||
|
(unless (symbolp keymap-sym)
|
||
|
(error "Argument KEYMAP-SYM must be a symbol"))
|
||
|
(unless (keymapp (symbol-value keymap-sym))
|
||
|
(error "The value of argument KEYMAP-SYM must be a keymap"))
|
||
|
(with-output-to-temp-buffer (help-buffer)
|
||
|
(help-setup-xref (list #'describe-keymap-placement keymap-sym) (interactive-p))
|
||
|
(with-current-buffer (help-buffer)
|
||
|
(insert "Placement of keymap `")
|
||
|
(insert-text-button (symbol-name keymap-sym)
|
||
|
'action
|
||
|
(lambda (btn)
|
||
|
(describe-variable keymap-sym)))
|
||
|
(insert "'\nin minor modes activation maps:\n")
|
||
|
(let (found)
|
||
|
(dolist (map-root '(emulation-mode-map-alists
|
||
|
minor-mode-overriding-map-alist
|
||
|
minor-mode-map-alist
|
||
|
))
|
||
|
(dolist (emul-alist (symbol-value map-root))
|
||
|
;;(message "emul-alist=%s" emul-alist)
|
||
|
(dolist (keymap-alist
|
||
|
(if (memq map-root '(emulation-mode-map-alists))
|
||
|
(symbol-value emul-alist)
|
||
|
(list emul-alist)))
|
||
|
(let* ((map (cdr keymap-alist))
|
||
|
(first (catch 'first
|
||
|
(map-keymap (lambda (key def)
|
||
|
(throw 'first (cons key def)))
|
||
|
map)))
|
||
|
(key (car first))
|
||
|
(def (cdr first))
|
||
|
(keymap-variables (when (and key def)
|
||
|
(ourcomments-find-keymap-variables
|
||
|
(vector key) def map)))
|
||
|
(active-var (car keymap-alist))
|
||
|
)
|
||
|
(assert (keymapp map))
|
||
|
;;(message "keymap-alist=%s, %s" keymap-alist first)
|
||
|
;;(message "active-var=%s, %s" active-var keymap-variables)
|
||
|
(when (memq keymap-sym keymap-variables)
|
||
|
(setq found t)
|
||
|
(insert (format "\n`%s' " map-root))
|
||
|
(insert (propertize "<= Minor mode keymap list holding this map"
|
||
|
'face 'font-lock-doc-face))
|
||
|
(insert "\n")
|
||
|
(when (symbolp emul-alist)
|
||
|
(insert (format " `%s' " emul-alist))
|
||
|
(insert (propertize "<= Keymap alist variable" 'face 'font-lock-doc-face))
|
||
|
(insert "\n"))
|
||
|
;;(insert (format " `%s'\n" keymap-alist))
|
||
|
(insert (format " `%s' " active-var))
|
||
|
(insert (propertize "<= Activation variable" 'face 'font-lock-doc-face))
|
||
|
(insert "\n")
|
||
|
)))))
|
||
|
(unless found
|
||
|
(insert (propertize "Not found." 'face 'font-lock-warning-face)))
|
||
|
))))
|
||
|
|
||
|
;; This is a replacement for describe-key-briefly.
|
||
|
;;(global-set-key [f1 ?c] 'describe-key-and-map-briefly)
|
||
|
;;;###autoload
|
||
|
(defun describe-key-and-map-briefly (&optional key insert untranslated)
|
||
|
"Try to print names of keymap from which KEY fetch its definition.
|
||
|
Look in current active keymaps and find keymap variables with the
|
||
|
same value as the keymap where KEY is bound. Print a message
|
||
|
with those keymap variable names. Return a list with the keymap
|
||
|
variable symbols.
|
||
|
|
||
|
When called interactively prompt for KEY.
|
||
|
|
||
|
INSERT and UNTRANSLATED should normall be nil (and I am not sure
|
||
|
what they will do ;-)."
|
||
|
;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||
|
;; From describe-key-briefly. Keep this as it is for easier update.
|
||
|
(interactive
|
||
|
(let ((enable-disabled-menus-and-buttons t)
|
||
|
(cursor-in-echo-area t)
|
||
|
saved-yank-menu)
|
||
|
(unwind-protect
|
||
|
(let (key)
|
||
|
;; If yank-menu is empty, populate it temporarily, so that
|
||
|
;; "Select and Paste" menu can generate a complete event.
|
||
|
(when (null (cdr yank-menu))
|
||
|
(setq saved-yank-menu (copy-sequence yank-menu))
|
||
|
(menu-bar-update-yank-menu "(any string)" nil))
|
||
|
(setq key (read-key-sequence "Describe key (or click or menu item): "))
|
||
|
;; If KEY is a down-event, read and discard the
|
||
|
;; corresponding up-event. Note that there are also
|
||
|
;; down-events on scroll bars and mode lines: the actual
|
||
|
;; event then is in the second element of the vector.
|
||
|
(and (vectorp key)
|
||
|
(let ((last-idx (1- (length key))))
|
||
|
(and (eventp (aref key last-idx))
|
||
|
(memq 'down (event-modifiers (aref key last-idx)))))
|
||
|
(read-event))
|
||
|
(list
|
||
|
key
|
||
|
(if current-prefix-arg (prefix-numeric-value current-prefix-arg))
|
||
|
1
|
||
|
))
|
||
|
;; Put yank-menu back as it was, if we changed it.
|
||
|
(when saved-yank-menu
|
||
|
(setq yank-menu (copy-sequence saved-yank-menu))
|
||
|
(fset 'yank-menu (cons 'keymap yank-menu))))))
|
||
|
(if (numberp untranslated)
|
||
|
(setq untranslated (this-single-command-raw-keys)))
|
||
|
(let* ((event (if (and (symbolp (aref key 0))
|
||
|
(> (length key) 1)
|
||
|
(consp (aref key 1)))
|
||
|
(aref key 1)
|
||
|
(aref key 0)))
|
||
|
(modifiers (event-modifiers event))
|
||
|
(standard-output (if insert (current-buffer) t))
|
||
|
(mouse-msg (if (or (memq 'click modifiers) (memq 'down modifiers)
|
||
|
(memq 'drag modifiers)) " at that spot" ""))
|
||
|
(defn (key-binding key t))
|
||
|
key-desc)
|
||
|
;; Handle the case where we faked an entry in "Select and Paste" menu.
|
||
|
(if (and (eq defn nil)
|
||
|
(stringp (aref key (1- (length key))))
|
||
|
(eq (key-binding (substring key 0 -1)) 'yank-menu))
|
||
|
(setq defn 'menu-bar-select-yank))
|
||
|
;; Don't bother user with strings from (e.g.) the select-paste menu.
|
||
|
(if (stringp (aref key (1- (length key))))
|
||
|
(aset key (1- (length key)) "(any string)"))
|
||
|
(if (and (> (length untranslated) 0)
|
||
|
(stringp (aref untranslated (1- (length untranslated)))))
|
||
|
(aset untranslated (1- (length untranslated)) "(any string)"))
|
||
|
;; Now describe the key, perhaps as changed.
|
||
|
(setq key-desc (help-key-description key untranslated))
|
||
|
;;
|
||
|
;; End of part from describe-key-briefly.
|
||
|
;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||
|
|
||
|
;;(message "bindings=%s" (key-bindings key)) (sit-for 2)
|
||
|
;; Find the keymap:
|
||
|
(let* ((maps (current-active-maps))
|
||
|
ret
|
||
|
lk)
|
||
|
(if (or (null defn) (integerp defn) (equal defn 'undefined))
|
||
|
(setq ret 'not-defined)
|
||
|
(catch 'mapped
|
||
|
(while (< 1 (length maps))
|
||
|
(setq lk (lookup-key (car maps) key t))
|
||
|
(when (and lk (not (numberp lk)))
|
||
|
(setq ret (ourcomments-find-keymap-variables key lk (car maps)))
|
||
|
(when ret
|
||
|
(throw 'mapped (car maps))))
|
||
|
(setq maps (cdr maps))))
|
||
|
(unless ret
|
||
|
(setq lk (lookup-key global-map key t))
|
||
|
(when (and lk (not (numberp lk)))
|
||
|
(setq ret '(global-map)))))
|
||
|
(cond
|
||
|
((eq ret 'not-defined)
|
||
|
(message "%s%s not defined in any keymap" key-desc mouse-msg))
|
||
|
((listp ret)
|
||
|
(if (not ret)
|
||
|
(message "%s%s is bound to `%s', but don't know where"
|
||
|
key-desc mouse-msg defn)
|
||
|
(if (= 1 (length ret))
|
||
|
(message "%s%s is bound to `%s' in `%s'"
|
||
|
key-desc mouse-msg defn (car ret))
|
||
|
(message "%s%s is bound to `%s' in keymap variables `%s'"
|
||
|
key-desc mouse-msg defn ret))))
|
||
|
(t
|
||
|
(error "ret=%s" ret)))
|
||
|
ret)))
|
||
|
|
||
|
;; (ourcomments-find-keymap-variables (current-local-map))
|
||
|
;; (keymapp 'ctl-x-4-prefix)
|
||
|
;; (equal 'ctl-x-4-prefix (current-local-map))
|
||
|
;;
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Fringes.
|
||
|
|
||
|
(defvar better-bottom-angles-defaults nil)
|
||
|
(defun better-fringes-bottom-angles (on)
|
||
|
;;(bottom bottom-left-angle bottom-right-angle top-right-angle top-left-angle)
|
||
|
(if (not on)
|
||
|
(when better-bottom-angles-defaults
|
||
|
(set-default 'fringe-indicator-alist better-bottom-angles-defaults))
|
||
|
(unless better-bottom-angles-defaults
|
||
|
(setq better-bottom-angles-defaults fringe-indicator-alist))
|
||
|
(let ((better
|
||
|
'(bottom
|
||
|
bottom-right-angle bottom-right-angle
|
||
|
bottom-left-angle bottom-left-angle
|
||
|
))
|
||
|
;;(indicators (copy-list fringe-indicator-alist)))
|
||
|
(indicators (copy-sequence fringe-indicator-alist)))
|
||
|
(setq indicators (assq-delete-all 'bottom indicators))
|
||
|
(set-default 'fringe-indicator-alist (cons better indicators)))))
|
||
|
|
||
|
(defun better-fringes-faces (face face-important)
|
||
|
(dolist (bitmap '(bottom-left-angle
|
||
|
bottom-right-angle
|
||
|
top-left-angle
|
||
|
top-right-angle
|
||
|
|
||
|
right-curly-arrow
|
||
|
left-arrow right-arrow
|
||
|
left-curly-arrow right-curly-arrow
|
||
|
up-arrow
|
||
|
down-arrow
|
||
|
left-bracket right-bracket
|
||
|
empty-line))
|
||
|
(set-fringe-bitmap-face bitmap face))
|
||
|
(dolist (bitmap '(right-triangle
|
||
|
question-mark))
|
||
|
(set-fringe-bitmap-face bitmap face-important)))
|
||
|
|
||
|
(defface better-fringes-bitmap
|
||
|
'((t (:foreground "dark khaki")))
|
||
|
"Face for bitmap fringes."
|
||
|
:group 'better-fringes
|
||
|
:group 'nxhtml)
|
||
|
|
||
|
(defface better-fringes-important-bitmap
|
||
|
'((t (:foreground "red")))
|
||
|
"Face for bitmap fringes."
|
||
|
:group 'better-fringes
|
||
|
:group 'nxhtml)
|
||
|
|
||
|
;;;###autoload
|
||
|
(define-minor-mode better-fringes-mode
|
||
|
"Choose another fringe bitmap color and bottom angle."
|
||
|
:global t
|
||
|
:group 'better-fringes
|
||
|
(if better-fringes-mode
|
||
|
(progn
|
||
|
(better-fringes-faces 'better-fringes-bitmap
|
||
|
'better-fringes-important-bitmap)
|
||
|
(better-fringes-bottom-angles t))
|
||
|
(better-fringes-faces nil nil)
|
||
|
(better-fringes-bottom-angles nil)))
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Copy+paste
|
||
|
|
||
|
;; After an idea from andrea on help-gnu-emacs
|
||
|
|
||
|
(defvar ourcomments-copy+paste-point nil)
|
||
|
|
||
|
;;(global-set-key [(control ?c) ?y] 'ourcomments-copy+paste-set-point)
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-copy+paste-set-point ()
|
||
|
"Set point for copy+paste here.
|
||
|
Enable temporary minor mode `ourcomments-copy+paste-mode'.
|
||
|
However if point for copy+paste already is set then cancel it and
|
||
|
disable the minor mode.
|
||
|
|
||
|
The purpose of this command is to make it easy to grab a piece of
|
||
|
text and paste it at current position. After this command you
|
||
|
should select a piece of text to copy and then call the command
|
||
|
`ourcomments-copy+paste'."
|
||
|
(interactive)
|
||
|
(if ourcomments-copy+paste-point
|
||
|
(ourcomments-copy+paste-mode -1)
|
||
|
(setq ourcomments-copy+paste-point (list (copy-marker (point))
|
||
|
(selected-window)
|
||
|
(current-frame-configuration)
|
||
|
))
|
||
|
(ourcomments-copy+paste-mode 1)
|
||
|
(let ((key (where-is-internal 'ourcomments-copy+paste))
|
||
|
(ckeys (key-description (this-command-keys))))
|
||
|
(setq key (if key (key-description (car key))
|
||
|
"M-x ourcomments-copy+paste"))
|
||
|
(when (> (length ckeys) 12)
|
||
|
(setq ckeys "this command"))
|
||
|
(message "Paste point set; select region and do %s to copy+paste (or cancel with %s)" key ckeys))))
|
||
|
|
||
|
(defvar ourcomments-copy+paste-mode-map
|
||
|
(let ((map (make-sparse-keymap)))
|
||
|
;; Bind the copy+paste command to C-S-v which reminds of cua-paste
|
||
|
;; binding and is hopefully not bound.
|
||
|
(define-key map [(control shift ?v)] 'ourcomments-copy+paste)
|
||
|
map))
|
||
|
|
||
|
(define-minor-mode ourcomments-copy+paste-mode
|
||
|
"Temporary mode for copy+paste.
|
||
|
This minor mode is enabled by `ourcomments-copy+paste-set-point'.
|
||
|
|
||
|
When this mode is active there is a key binding for
|
||
|
`ourcomments-copy+paste':
|
||
|
\\<ourcomments-copy+paste-mode-map>
|
||
|
\\[ourcomments-copy+paste]
|
||
|
|
||
|
You should not turn on this minor mode yourself. It is turned on
|
||
|
by `ourcomments-copy+paste-set-point'. For more information see
|
||
|
that command."
|
||
|
:lighter " COPY+PASTE"
|
||
|
:global t
|
||
|
:group 'ourcomments-util
|
||
|
(if ourcomments-copy+paste-mode
|
||
|
(unless ourcomments-copy+paste-point
|
||
|
(message "Do not call this minor mode, use `ourcomments-copy+paste-set-point'.")
|
||
|
(setq ourcomments-copy+paste-mode nil))
|
||
|
(when ourcomments-copy+paste-point
|
||
|
(setq ourcomments-copy+paste-point nil)
|
||
|
(message "Canceled copy+paste mode"))))
|
||
|
|
||
|
(defvar ourcomments-copy+paste-ovl nil)
|
||
|
|
||
|
(defun ourcomments-copy+paste-cancel-highlight ()
|
||
|
(when (overlayp ourcomments-copy+paste-ovl)
|
||
|
(delete-overlay ourcomments-copy+paste-ovl))
|
||
|
(setq ourcomments-copy+paste-ovl nil))
|
||
|
|
||
|
(defun ourcomments-copy+paste (restore-frames)
|
||
|
"Copy region to copy+paste point set by `ourcomments-copy+paste-set-point'.
|
||
|
Also if prefix argument is given then restore frame configuration
|
||
|
at the time that command was called. Otherwise look for the
|
||
|
buffer for copy+paste point in current frame. If found select
|
||
|
that window. If not then use `switch-to-buffer-other-window' to
|
||
|
display it."
|
||
|
(interactive "P")
|
||
|
(cond
|
||
|
((not ourcomments-copy+paste-point)
|
||
|
(let ((key (where-is-internal 'ourcomments-copy+paste-set-point)))
|
||
|
(setq key (if key (key-description (car key))
|
||
|
"M-x ourcomments-copy+paste-set-point"))
|
||
|
(message "Please select destination of copy+paste first with %s" key)))
|
||
|
((not mark-active)
|
||
|
(message "Please select a region to copy+paste first"))
|
||
|
(t
|
||
|
;;(copy-region-as-kill (region-beginning) (region-end))
|
||
|
(clipboard-kill-ring-save (region-beginning) (region-end))
|
||
|
(let* ((marker (nth 0 ourcomments-copy+paste-point))
|
||
|
(orig-win (nth 1 ourcomments-copy+paste-point))
|
||
|
(orig-fcfg (nth 2 ourcomments-copy+paste-point))
|
||
|
(buf (marker-buffer marker))
|
||
|
(win (or (when (window-live-p orig-win) orig-win)
|
||
|
(get-buffer-window buf))))
|
||
|
(message "win=%s, buf=%s" win buf)
|
||
|
(cond (restore-frames
|
||
|
(set-frame-configuration orig-fcfg))
|
||
|
((and win (eq (window-buffer win) buf))
|
||
|
(select-window win))
|
||
|
(t
|
||
|
(switch-to-buffer-other-window buf)))
|
||
|
(goto-char marker))
|
||
|
(let ((here (point))
|
||
|
ovl)
|
||
|
(yank)
|
||
|
(setq ovl (make-overlay here (point)))
|
||
|
(overlay-put ovl 'face 'highlight)
|
||
|
(run-with-idle-timer 2 nil 'ourcomments-copy+paste-cancel-highlight)
|
||
|
(setq ourcomments-copy+paste-ovl ovl))
|
||
|
(setq ourcomments-copy+paste-point nil)
|
||
|
(ourcomments-copy+paste-mode -1))))
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Misc.
|
||
|
|
||
|
;;(describe-timers)
|
||
|
;;;###autoload
|
||
|
(defun describe-timers ()
|
||
|
"Show timers with readable time format."
|
||
|
(interactive)
|
||
|
(with-output-to-temp-buffer (help-buffer)
|
||
|
(help-setup-xref (list #'ourcommenst-show-timers) (interactive-p))
|
||
|
(with-current-buffer (help-buffer)
|
||
|
(insert (format-time-string "Timers at %Y-%m-%d %H:%M:%S\n\n" (current-time)))
|
||
|
(if (not timer-list)
|
||
|
(insert " None\n")
|
||
|
(insert (propertize
|
||
|
" When Rpt What\n"
|
||
|
'face 'font-lock-doc-face))
|
||
|
(dolist (tmr timer-list)
|
||
|
(let* ((hi-sec (timer--high-seconds tmr))
|
||
|
(lo-sec (timer--low-seconds tmr))
|
||
|
(mi-sec (timer--usecs tmr))
|
||
|
(fun (timer--function tmr))
|
||
|
(args (timer--args tmr))
|
||
|
(idle-d (timer--idle-delay tmr))
|
||
|
(rpt-d (timer--repeat-delay tmr))
|
||
|
(time (concat (format-time-string " %Y-%m-%d %H:%M:%S" (list hi-sec lo-sec 0))
|
||
|
(substring
|
||
|
(format "%.1f" (/ mi-sec 1000000.0))
|
||
|
1))))
|
||
|
(assert (not idle-d) t)
|
||
|
(insert (format "%s %4s (`%-3s' %S)\n" time rpt-d fun args)))))
|
||
|
(insert "\nIdle timers:\n\n")
|
||
|
(if (not timer-idle-list)
|
||
|
(insert " None\n")
|
||
|
(insert (propertize
|
||
|
" After Rpt What\n"
|
||
|
'face 'font-lock-doc-face))
|
||
|
(dolist (tmr timer-idle-list)
|
||
|
(let* ((hi-sec (timer--high-seconds tmr))
|
||
|
(lo-sec (timer--low-seconds tmr))
|
||
|
(mi-sec (timer--usecs tmr))
|
||
|
(fun (timer--function tmr))
|
||
|
(args (timer--args tmr))
|
||
|
(idle-d (timer--idle-delay tmr))
|
||
|
(rpt-d (timer--repeat-delay tmr))
|
||
|
(time (+ (* hi-sec 256 256) lo-sec (/ mi-sec 1000000.0)))
|
||
|
)
|
||
|
(assert (not (not idle-d)) t)
|
||
|
(insert (format " %.2f sec %3s (`%s' %S)\n" time rpt-d fun args))))))))
|
||
|
|
||
|
(defcustom ourcomments-insert-date-and-time "%Y-%m-%d %R"
|
||
|
"Time format for command `ourcomments-insert-date-and-time'.
|
||
|
See `format-time-string'."
|
||
|
:type 'string
|
||
|
:group 'ourcomments-util)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-insert-date-and-time ()
|
||
|
"Insert date and time.
|
||
|
See option `ourcomments-insert-date-and-time' for how to
|
||
|
customize it."
|
||
|
(interactive)
|
||
|
(insert (format-time-string ourcomments-insert-date-and-time)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun find-emacs-other-file (display-file)
|
||
|
"Find corresponding file to source or installed elisp file.
|
||
|
If you have checked out and compiled Emacs yourself you may have
|
||
|
Emacs lisp files in two places, the checked out source tree and
|
||
|
the installed Emacs tree. If buffer contains an Emacs elisp file
|
||
|
in one of these places then find the corresponding elisp file in
|
||
|
the other place. Return the file name of this file.
|
||
|
|
||
|
Rename current buffer using your `uniquify-buffer-name-style' if
|
||
|
it is set.
|
||
|
|
||
|
When DISPLAY-FILE is non-nil display this file in other window
|
||
|
and go to the same line number as in the current buffer."
|
||
|
(interactive (list t))
|
||
|
(unless (buffer-file-name)
|
||
|
(error "This buffer is not visiting a file"))
|
||
|
(unless source-directory
|
||
|
(error "Can't find the checked out Emacs sources"))
|
||
|
(let* ((installed-directory (file-name-as-directory
|
||
|
(expand-file-name ".." exec-directory)))
|
||
|
(relative-installed (file-relative-name
|
||
|
(buffer-file-name) installed-directory))
|
||
|
(relative-source (file-relative-name
|
||
|
(buffer-file-name) source-directory))
|
||
|
(name-nondir (file-name-nondirectory (buffer-file-name)))
|
||
|
source-file
|
||
|
installed-file
|
||
|
other-file
|
||
|
(line-num (save-restriction
|
||
|
(widen)
|
||
|
(line-number-at-pos))))
|
||
|
(cond
|
||
|
((and relative-installed
|
||
|
(not (string= name-nondir relative-installed))
|
||
|
(not (file-name-absolute-p relative-installed))
|
||
|
(not (string= ".." (substring relative-installed 0 2))))
|
||
|
(setq source-file (expand-file-name relative-installed source-directory)))
|
||
|
((and relative-source
|
||
|
(not (string= name-nondir relative-source))
|
||
|
(not (file-name-absolute-p relative-source))
|
||
|
(not (string= ".." (substring relative-source 0 2))))
|
||
|
(setq installed-file (expand-file-name relative-source installed-directory))))
|
||
|
(setq other-file (or source-file installed-file))
|
||
|
(unless other-file
|
||
|
(error "This file is not in Emacs source or installed lisp tree"))
|
||
|
(unless (file-exists-p other-file)
|
||
|
(error "Can't find the corresponding file %s" other-file))
|
||
|
(when display-file
|
||
|
(when uniquify-buffer-name-style
|
||
|
(rename-buffer (file-name-nondirectory buffer-file-name) t))
|
||
|
(find-file-other-window other-file)
|
||
|
(ourcomments-goto-line line-num))
|
||
|
other-file))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-ediff-files (def-dir file-a file-b)
|
||
|
"In directory DEF-DIR run `ediff-files' on files FILE-A and FILE-B.
|
||
|
The purpose of this function is to make it eaiser to start
|
||
|
`ediff-files' from a shell through Emacs Client.
|
||
|
|
||
|
This is used in EmacsW32 in the file ediff.cmd where Emacs Client
|
||
|
is called like this:
|
||
|
|
||
|
@%emacs_client% -e \"(setq default-directory \\\"%emacs_cd%\\\")\"
|
||
|
@%emacs_client% -n -e \"(ediff-files \\\"%f1%\\\" \\\"%f2%\\\")\"
|
||
|
|
||
|
It can of course be done in a similar way with other shells."
|
||
|
(let ((default-directory def-dir))
|
||
|
(ediff-files file-a file-b)))
|
||
|
|
||
|
|
||
|
(defun ourcomments-latest-changelog ()
|
||
|
"not ready"
|
||
|
(let ((changelogs
|
||
|
'("ChangeLog"
|
||
|
"admin/ChangeLog"
|
||
|
"doc/emacs/ChangeLog"
|
||
|
"doc/lispintro/ChangeLog"
|
||
|
"doc/lispref/ChangeLog"
|
||
|
"doc/man/ChangeLog"
|
||
|
"doc/misc/ChangeLog"
|
||
|
"etc/ChangeLog"
|
||
|
"leim/ChangeLog"
|
||
|
"lib-src/ChangeLog"
|
||
|
"lisp/ChangeLog"
|
||
|
"lisp/erc/ChangeLog"
|
||
|
"lisp/gnus/ChangeLog"
|
||
|
"lisp/mh-e/ChangeLog"
|
||
|
"lisp/org/ChangeLog"
|
||
|
"lisp/url/ChangeLog"
|
||
|
"lwlib/ChangeLog"
|
||
|
"msdos/ChangeLog"
|
||
|
"nextstep/ChangeLog"
|
||
|
"nt/ChangeLog"
|
||
|
"oldXMenu/ChangeLog"
|
||
|
"src/ChangeLog"
|
||
|
"test/ChangeLog"))
|
||
|
(emacs-root (expand-file-name ".." exec-directory)
|
||
|
))))
|
||
|
|
||
|
(defun ourcomments-read-symbol (prompt predicate)
|
||
|
"Basic function for reading a symbol for describe-* functions.
|
||
|
Prompt with PROMPT and show only symbols satisfying function
|
||
|
PREDICATE. PREDICATE takes one argument, the symbol."
|
||
|
(let* ((symbol (symbol-at-point))
|
||
|
(enable-recursive-minibuffers t)
|
||
|
val)
|
||
|
(when predicate
|
||
|
(unless (and symbol
|
||
|
(symbolp symbol)
|
||
|
(funcall predicate symbol))
|
||
|
(setq symbol nil)))
|
||
|
(setq val (completing-read (if symbol
|
||
|
(format
|
||
|
"%s (default %s): " prompt symbol)
|
||
|
(format "%s: " prompt))
|
||
|
obarray
|
||
|
predicate
|
||
|
t nil nil
|
||
|
(if symbol (symbol-name symbol))))
|
||
|
(if (equal val "") symbol (intern val))))
|
||
|
|
||
|
(defun ourcomments-command-at-point ()
|
||
|
(let ((fun (function-called-at-point)))
|
||
|
(when (commandp fun)
|
||
|
fun)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun describe-command (command)
|
||
|
"Like `describe-function', but prompts only for interactive commands."
|
||
|
(interactive
|
||
|
(let* ((fn (ourcomments-command-at-point))
|
||
|
(prompt (if fn
|
||
|
(format "Describe command (default %s): " fn)
|
||
|
"Describe command: "))
|
||
|
(enable-recursive-minibuffers t)
|
||
|
val)
|
||
|
(setq val (completing-read prompt
|
||
|
obarray 'commandp t nil nil
|
||
|
(and fn (symbol-name fn))))
|
||
|
(list (if (equal val "") fn (intern val)))))
|
||
|
(describe-function command))
|
||
|
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun buffer-narrowed-p ()
|
||
|
"Return non-nil if the current buffer is narrowed."
|
||
|
(/= (buffer-size)
|
||
|
(- (point-max)
|
||
|
(point-min))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun narrow-to-comment ()
|
||
|
(interactive)
|
||
|
(let* ((here (point-marker))
|
||
|
(size 1000)
|
||
|
(beg (progn (forward-comment (- size))
|
||
|
;; It looks like the wrong syntax-table is used here:
|
||
|
;;(message "skipped %s " (skip-chars-forward "[:space:]"))
|
||
|
;; See Emacs bug 3823, http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3823
|
||
|
(message "skipped %s " (skip-chars-forward " \t\r\n"))
|
||
|
(point)))
|
||
|
(end (progn (forward-comment size)
|
||
|
;;(message "skipped %s " (skip-chars-backward "[:space:]"))
|
||
|
(message "skipped %s " (skip-chars-backward " \t\r\n"))
|
||
|
(point))))
|
||
|
(goto-char here)
|
||
|
(if (not (and (>= here beg)
|
||
|
(<= here end)))
|
||
|
(error "Not in a comment")
|
||
|
(narrow-to-region beg end))))
|
||
|
|
||
|
(defvar describe-symbol-alist nil)
|
||
|
|
||
|
(defun describe-symbol-add-known(property description)
|
||
|
(when (assq property describe-symbol-alist)
|
||
|
(error "Already known property"))
|
||
|
(setq describe-symbol-alist
|
||
|
(cons (list property description)
|
||
|
describe-symbol-alist)))
|
||
|
|
||
|
;;(describe-symbol-add-known 'variable-documentation "Doc for variable")
|
||
|
;;(describe-symbol-add-known 'cl-struct-slots "defstruct slots")
|
||
|
|
||
|
(defun property-list-keys (plist)
|
||
|
"Return list of key names in property list PLIST."
|
||
|
(let ((keys))
|
||
|
(while plist
|
||
|
(setq keys (cons (car plist) keys))
|
||
|
(setq plist (cddr plist)))
|
||
|
keys))
|
||
|
|
||
|
(defun ourcomments-symbol-type (symbol)
|
||
|
"Return a list of types where symbol SYMBOL is used.
|
||
|
The can include 'variable, 'function and variaus 'cl-*."
|
||
|
(symbol-file symbol)
|
||
|
)
|
||
|
|
||
|
(defun ourcomments-defstruct-p (symbol)
|
||
|
"Return non-nil if symbol SYMBOL is a CL defstruct."
|
||
|
(let ((plist (symbol-plist symbol)))
|
||
|
(and (plist-member plist 'cl-struct-slots)
|
||
|
(plist-member plist 'cl-struct-type)
|
||
|
(plist-member plist 'cl-struct-include)
|
||
|
(plist-member plist 'cl-struct-print))))
|
||
|
|
||
|
(defun ourcomments-defstruct-slots (symbol)
|
||
|
(unless (ourcomments-defstruct-p symbol)
|
||
|
(error "Not a CL defstruct symbol: %s" symbol))
|
||
|
(let ((cl-struct-slots (get symbol 'cl-struct-slots)))
|
||
|
(delq 'cl-tag-slot
|
||
|
(loop for rec in cl-struct-slots
|
||
|
collect (nth 0 rec)))))
|
||
|
|
||
|
;; (ourcomments-defstruct-slots 'ert-test)
|
||
|
|
||
|
(defun ourcomments-defstruct-file (symbol)
|
||
|
(unless (ourcomments-defstruct-p symbol)
|
||
|
(error "Not a CL defstruct symbol: %s" symbol))
|
||
|
)
|
||
|
|
||
|
(defun ourcomments-member-defstruct (symbol)
|
||
|
"Return defstruct name if member."
|
||
|
(when (and (functionp symbol)
|
||
|
(plist-member (symbol-plist symbol) 'cl-compiler-macro))
|
||
|
(let* (in-defstruct
|
||
|
(symbol-file (symbol-file symbol))
|
||
|
buf
|
||
|
was-here)
|
||
|
(unless symbol-file
|
||
|
(error "Can't check if defstruct member since don't know symbol file"))
|
||
|
(setq buf (find-buffer-visiting symbol-file))
|
||
|
(setq was-here (with-current-buffer buf (point)))
|
||
|
(unless buf
|
||
|
(setq buf (find-file-noselect symbol-file)))
|
||
|
(with-current-buffer buf
|
||
|
(save-restriction
|
||
|
(widen)
|
||
|
(let* ((buf-point (find-definition-noselect symbol nil)))
|
||
|
(goto-char (cdr buf-point))
|
||
|
(save-match-data
|
||
|
(when (looking-at "(defstruct (?\\(\\(?:\\sw\\|\\s_\\)+\\)")
|
||
|
(setq in-defstruct (match-string-no-properties 1))))))
|
||
|
(if was-here
|
||
|
(goto-char was-here)
|
||
|
(kill-buffer (current-buffer))))
|
||
|
in-defstruct)))
|
||
|
;; (ourcomments-member-defstruct 'ert-test-name)
|
||
|
;; (ourcomments-member-defstruct 'ert-test-error-condition)
|
||
|
|
||
|
(defun ourcomments-custom-group-p (symbol)
|
||
|
(and (intern-soft symbol)
|
||
|
(or (and (get symbol 'custom-loads)
|
||
|
(not (get symbol 'custom-autoload)))
|
||
|
(get symbol 'custom-group))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun describe-custom-group (symbol)
|
||
|
"Describe customization group SYMBOL."
|
||
|
(interactive
|
||
|
(list
|
||
|
(ourcomments-read-symbol "Customization group"
|
||
|
'ourcomments-custom-group-p)))
|
||
|
;; Fix-me:
|
||
|
(message "g=%s" symbol))
|
||
|
;; nxhtml
|
||
|
|
||
|
;; Added this to current-load-list in cl-macs.el
|
||
|
;; (describe-defstruct 'ert-stats)
|
||
|
;;;###autoload
|
||
|
(defun describe-defstruct (symbol)
|
||
|
(interactive (list (ourcomments-read-symbol "Describe defstruct"
|
||
|
'ourcomments-defstruct-p)))
|
||
|
(if (not (ourcomments-defstruct-p symbol))
|
||
|
(message "%s is not a CL defstruct." symbol)
|
||
|
(with-output-to-temp-buffer (help-buffer)
|
||
|
(help-setup-xref (list #'describe-defstruct symbol) (interactive-p))
|
||
|
(with-current-buffer (help-buffer)
|
||
|
(insert "This is a description of a CL thing.")
|
||
|
(insert "\n\n")
|
||
|
(insert (format "%s is a CL `defstruct'" symbol))
|
||
|
(let ((file (symbol-file symbol)))
|
||
|
(if file
|
||
|
;; Fix-me: .elc => .el
|
||
|
(let ((name (file-name-nondirectory file)))
|
||
|
(insert "defined in file %s.\n" (file-name-nondirectory file)))
|
||
|
(insert ".\n")))
|
||
|
(insert "\n\nIt has the following slot functions:\n")
|
||
|
(let ((num-slot-funs 0)
|
||
|
(slots (ourcomments-defstruct-slots symbol)))
|
||
|
(dolist (slot slots)
|
||
|
(if (not (fboundp (intern-soft (format "%s-%s" symbol slot))))
|
||
|
(insert (format " Do not know function for slot %s\n" slot))
|
||
|
(setq num-slot-funs (1+ num-slot-funs))
|
||
|
(insert (format " `%s-%s'\n" symbol slot))))
|
||
|
(unless (= num-slot-funs (length slots))
|
||
|
(insert " No information about some slots, maybe :conc-name was used\n")))))))
|
||
|
|
||
|
;;(defun describe-deftype (type)
|
||
|
;;;###autoload
|
||
|
(defun describe-symbol(symbol)
|
||
|
"Show information about SYMBOL.
|
||
|
Show SYMBOL plist and whether is is a variable or/and a
|
||
|
function."
|
||
|
(interactive (list (ourcomments-read-symbol "Describe symbol" nil)))
|
||
|
;;; (let* ((s (symbol-at-point))
|
||
|
;;; (val (completing-read (if (and (symbolp s)
|
||
|
;;; (not (eq s nil)))
|
||
|
;;; (format
|
||
|
;;; "Describe symbol (default %s): " s)
|
||
|
;;; "Describe symbol: ")
|
||
|
;;; obarray
|
||
|
;;; nil
|
||
|
;;; t nil nil
|
||
|
;;; (if (symbolp s) (symbol-name s)))))
|
||
|
;;; (list (if (equal val "") s (intern val)))))
|
||
|
(require 'apropos)
|
||
|
(with-output-to-temp-buffer (help-buffer)
|
||
|
(help-setup-xref (list #'describe-symbol symbol) (interactive-p))
|
||
|
(with-current-buffer (help-buffer)
|
||
|
(insert (format "Description of symbol %s\n\n" symbol))
|
||
|
(when (plist-get (symbol-plist symbol) 'cl-compiler-macro)
|
||
|
(insert "(Looks like a CL thing.)\n"))
|
||
|
(if (boundp symbol)
|
||
|
(insert (format "- There is a variable `%s'.\n" symbol))
|
||
|
(insert "- This symbol is not a variable.\n"))
|
||
|
(if (fboundp symbol)
|
||
|
(progn
|
||
|
(insert (format "- There is a function `%s'" symbol))
|
||
|
(when (ourcomments-member-defstruct symbol)
|
||
|
(let ((ds-name (ourcomments-member-defstruct symbol)))
|
||
|
(insert "\n which is a member of defstruct ")
|
||
|
(insert-text-button (format "%s" ds-name)
|
||
|
'symbol (intern-soft ds-name)
|
||
|
'action (lambda (button)
|
||
|
(describe-symbol
|
||
|
(button-get button 'symbol))))))
|
||
|
(insert ".\n"))
|
||
|
(insert "- This symbol is not a function.\n"))
|
||
|
(if (facep symbol)
|
||
|
(insert (format "- There is a face `%s'.\n" symbol))
|
||
|
(insert "- This symbol is not a face.\n"))
|
||
|
(if (ourcomments-custom-group-p symbol)
|
||
|
(progn
|
||
|
(insert "- There is a customization group ")
|
||
|
(insert-text-button (format "%s" symbol)
|
||
|
'symbol symbol
|
||
|
'action (lambda (button)
|
||
|
(describe-custom-group
|
||
|
(button-get button 'symbol))))
|
||
|
(insert ".\n"))
|
||
|
(insert "- This symbol is not a customization group.\n"))
|
||
|
(if (ourcomments-defstruct-p symbol)
|
||
|
(progn
|
||
|
(insert (format "- There is a CL defstruct %s with setf-able slots:\n" symbol))
|
||
|
(let ((num-slot-funs 0)
|
||
|
(slots (ourcomments-defstruct-slots symbol)))
|
||
|
(dolist (slot slots)
|
||
|
(if (not (fboundp (intern-soft (format "%s-%s" symbol slot))))
|
||
|
(insert (format " Do not know function for slot %s\n" slot))
|
||
|
(setq num-slot-funs (1+ num-slot-funs))
|
||
|
(insert (format " `%s-%s'\n" symbol slot))))
|
||
|
(unless (= num-slot-funs (length slots))
|
||
|
(insert " No information about some slots, maybe :conc-name was used\n"))))
|
||
|
(insert "- This symbol is not a CL defstruct.\n"))
|
||
|
(insert "\n")
|
||
|
(let* ((pl (symbol-plist symbol))
|
||
|
(pl-not-known (property-list-keys pl))
|
||
|
any-known)
|
||
|
(if (not pl)
|
||
|
(insert (format "Symbol %s has no property list\n\n" symbol))
|
||
|
;; Known properties
|
||
|
(dolist (rec describe-symbol-alist)
|
||
|
(let ((prop (nth 0 rec))
|
||
|
(desc (nth 1 rec)))
|
||
|
(when (plist-member pl prop)
|
||
|
(setq any-known (cons prop any-known))
|
||
|
(setq pl-not-known (delq prop pl-not-known))
|
||
|
(insert
|
||
|
"The following keys in the property list are known:\n\n")
|
||
|
(insert (format "* %s: %s\n" prop desc))
|
||
|
)))
|
||
|
(unless any-known
|
||
|
(insert "The are no known keys in the property list.\n"))
|
||
|
(let ((pl (ourcomments-format-plist pl "\n ")))
|
||
|
;;(insert (format "plist=%s\n" (symbol-plist symbol)))
|
||
|
;;(insert (format "pl-not-known=%s\n" pl-not-known))
|
||
|
(insert "\nFull property list:\n\n (")
|
||
|
(insert (propertize pl 'face 'default))
|
||
|
(insert ")\n\n")))))))
|
||
|
|
||
|
(defun ourcomments-format-plist (pl sep &optional compare)
|
||
|
(when (symbolp pl)
|
||
|
(setq pl (symbol-plist pl)))
|
||
|
(let (p desc p-out)
|
||
|
(while pl
|
||
|
(setq p (format "%s" (car pl)))
|
||
|
(if (or (not compare) (string-match apropos-regexp p))
|
||
|
(if apropos-property-face
|
||
|
(put-text-property 0 (length (symbol-name (car pl)))
|
||
|
'face apropos-property-face p))
|
||
|
(setq p nil))
|
||
|
(if p
|
||
|
(progn
|
||
|
(and compare apropos-match-face
|
||
|
(put-text-property (match-beginning 0) (match-end 0)
|
||
|
'face apropos-match-face
|
||
|
p))
|
||
|
(setq desc (pp-to-string (nth 1 pl)))
|
||
|
(setq desc (split-string desc "\n"))
|
||
|
(if (= 1 (length desc))
|
||
|
(setq desc (concat " " (car desc)))
|
||
|
(let* ((indent " ")
|
||
|
(ind-nl (concat "\n" indent)))
|
||
|
(setq desc
|
||
|
(concat
|
||
|
ind-nl
|
||
|
(mapconcat 'identity desc ind-nl)))))
|
||
|
(setq p-out (concat p-out (if p-out sep) p desc))))
|
||
|
(setq pl (nthcdr 2 pl)))
|
||
|
p-out))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; ido
|
||
|
|
||
|
(defvar ourcomments-ido-visit-method nil)
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-ido-buffer-other-window ()
|
||
|
"Show buffer in other window."
|
||
|
(interactive)
|
||
|
(setq ourcomments-ido-visit-method 'other-window)
|
||
|
(call-interactively 'ido-exit-minibuffer))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-ido-buffer-other-frame ()
|
||
|
"Show buffer in other frame."
|
||
|
(interactive)
|
||
|
(setq ourcomments-ido-visit-method 'other-frame)
|
||
|
(call-interactively 'ido-exit-minibuffer))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-ido-buffer-raise-frame ()
|
||
|
"Raise frame showing buffer."
|
||
|
(interactive)
|
||
|
(setq ourcomments-ido-visit-method 'raise-frame)
|
||
|
(call-interactively 'ido-exit-minibuffer))
|
||
|
|
||
|
(defun ourcomments-ido-switch-buffer-or-next-entry ()
|
||
|
(interactive)
|
||
|
(if (active-minibuffer-window)
|
||
|
(ido-next-match)
|
||
|
(ido-switch-buffer)))
|
||
|
|
||
|
(defun ourcomments-ido-mode-advice()
|
||
|
(when (memq ido-mode '(both buffer))
|
||
|
(let ((the-ido-minor-map (cdr ido-minor-mode-map-entry)))
|
||
|
;;(define-key the-ido-minor-map [(control tab)] 'ido-switch-buffer))
|
||
|
(define-key the-ido-minor-map [(control tab)] 'ourcomments-ido-switch-buffer-or-next-entry))
|
||
|
(dolist (the-map (list ido-buffer-completion-map ido-completion-map ido-common-completion-map))
|
||
|
(when the-map
|
||
|
(let ((map the-map))
|
||
|
(define-key map [(control tab)] 'ido-next-match)
|
||
|
(define-key map [(control shift tab)] 'ido-prev-match)
|
||
|
(define-key map [(control backtab)] 'ido-prev-match)
|
||
|
(define-key map [(shift return)] 'ourcomments-ido-buffer-other-window)
|
||
|
(define-key map [(control return)] 'ourcomments-ido-buffer-other-frame)
|
||
|
(define-key map [(meta return)] 'ourcomments-ido-buffer-raise-frame))))))
|
||
|
|
||
|
;; (defun ourcomments-ido-setup-completion-map ()
|
||
|
;; "Set up the keymap for `ido'."
|
||
|
|
||
|
;; (ourcomments-ido-mode-advice)
|
||
|
|
||
|
;; ;; generated every time so that it can inherit new functions.
|
||
|
;; (let ((map (make-sparse-keymap))
|
||
|
;; (viper-p (if (boundp 'viper-mode) viper-mode)))
|
||
|
|
||
|
;; (when viper-p
|
||
|
;; (define-key map [remap viper-intercept-ESC-key] 'ignore))
|
||
|
|
||
|
;; (cond
|
||
|
;; ((memq ido-cur-item '(file dir))
|
||
|
;; (when ido-context-switch-command
|
||
|
;; (define-key map "\C-x\C-b" ido-context-switch-command)
|
||
|
;; (define-key map "\C-x\C-d" 'ignore))
|
||
|
;; (when viper-p
|
||
|
;; (define-key map [remap viper-backward-char] 'ido-delete-backward-updir)
|
||
|
;; (define-key map [remap viper-del-backward-char-in-insert] 'ido-delete-backward-updir)
|
||
|
;; (define-key map [remap viper-delete-backward-word] 'ido-delete-backward-word-updir))
|
||
|
;; (set-keymap-parent map
|
||
|
;; (if (eq ido-cur-item 'file)
|
||
|
;; ido-file-completion-map
|
||
|
;; ido-file-dir-completion-map)))
|
||
|
|
||
|
;; ((eq ido-cur-item 'buffer)
|
||
|
;; (when ido-context-switch-command
|
||
|
;; (define-key map "\C-x\C-f" ido-context-switch-command))
|
||
|
;; (set-keymap-parent map ido-buffer-completion-map))
|
||
|
|
||
|
;; (t
|
||
|
;; (set-keymap-parent map ido-common-completion-map)))
|
||
|
|
||
|
;; ;; ctrl-tab etc
|
||
|
;; (define-key map [(control tab)] 'ido-next-match)
|
||
|
;; (define-key map [(control shift tab)] 'ido-prev-match)
|
||
|
;; (define-key map [(control backtab)] 'ido-prev-match)
|
||
|
;; (define-key map [(shift return)] 'ourcomments-ido-buffer-other-window)
|
||
|
;; (define-key map [(control return)] 'ourcomments-ido-buffer-other-frame)
|
||
|
;; (define-key map [(meta return)] 'ourcomments-ido-buffer-raise-frame)
|
||
|
|
||
|
;; (setq ido-completion-map map)))
|
||
|
|
||
|
;; (defadvice ido-setup-completion-map (around
|
||
|
;; ourcomments-advice-ido-setup-completion-map
|
||
|
;; disable)
|
||
|
;; (setq ad-return-value (ourcomments-ido-setup-completion-map))
|
||
|
;; )
|
||
|
|
||
|
;;(add-hook 'ido-setup-hook 'ourcomments-ido-mode-advice)
|
||
|
;;(remove-hook 'ido-setup-hook 'ourcomments-ido-mode-advice)
|
||
|
(defvar ourcomments-ido-adviced nil)
|
||
|
(unless ourcomments-ido-adviced
|
||
|
(defadvice ido-mode (after
|
||
|
ourcomments-advice-ido-mode
|
||
|
;;activate
|
||
|
;;compile
|
||
|
disable)
|
||
|
"Add C-tab to ido buffer completion."
|
||
|
(ourcomments-ido-mode-advice)
|
||
|
;;ad-return-value
|
||
|
)
|
||
|
;; (ad-activate 'ido-mode)
|
||
|
;; (ad-deactivate 'ido-mode)
|
||
|
|
||
|
(defadvice ido-visit-buffer (before
|
||
|
ourcomments-advice-ido-visit-buffer
|
||
|
;;activate
|
||
|
;;compile
|
||
|
disable)
|
||
|
"Advice to show buffers in other window, frame etc."
|
||
|
(when ourcomments-ido-visit-method
|
||
|
(ad-set-arg 1 ourcomments-ido-visit-method)
|
||
|
(setq ourcomments-ido-visit-method nil)
|
||
|
))
|
||
|
(setq ourcomments-ido-adviced t)
|
||
|
)
|
||
|
|
||
|
;;(message "after advising ido")
|
||
|
;;(ad-deactivate 'ido-visit-buffer)
|
||
|
;;(ad-activate 'ido-visit-buffer)
|
||
|
|
||
|
(defvar ourcomments-ido-old-state ido-mode)
|
||
|
|
||
|
(defun ourcomments-ido-ctrl-tab-activate ()
|
||
|
;;(message "ourcomments-ido-ctrl-tab-activate running")
|
||
|
;;(ad-update 'ido-visit-buffer)
|
||
|
;;(unless (ad-get-advice-info 'ido-visit-buffer)
|
||
|
;; Fix-me: The advice must be enabled before activation. Send bug report.
|
||
|
(ad-enable-advice 'ido-visit-buffer 'before 'ourcomments-advice-ido-visit-buffer)
|
||
|
(unless (cdr (assoc 'active (ad-get-advice-info 'ido-visit-buffer)))
|
||
|
(ad-activate 'ido-visit-buffer))
|
||
|
;; (ad-enable-advice 'ido-setup-completion-map 'around 'ourcomments-advice-ido-setup-completion-map)
|
||
|
;; (unless (cdr (assoc 'active (ad-get-advice-info 'ido-setup-completion-map)))
|
||
|
;; (ad-activate 'ido-setup-completion-map))
|
||
|
;;(ad-update 'ido-mode)
|
||
|
(ad-enable-advice 'ido-mode 'after 'ourcomments-advice-ido-mode)
|
||
|
(unless (cdr (assoc 'active (ad-get-advice-info 'ido-mode)))
|
||
|
(ad-activate 'ido-mode))
|
||
|
(setq ourcomments-ido-old-state ido-mode)
|
||
|
(ido-mode (or ido-mode 'buffer)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(define-minor-mode ourcomments-ido-ctrl-tab
|
||
|
"Enable buffer switching using C-Tab with function `ido-mode'.
|
||
|
This changes buffer switching with function `ido-mode' the
|
||
|
following way:
|
||
|
|
||
|
- You can use C-Tab.
|
||
|
|
||
|
- You can show the selected buffer in three ways independent of
|
||
|
how you entered function `ido-mode' buffer switching:
|
||
|
|
||
|
* S-return: other window
|
||
|
* C-return: other frame
|
||
|
* M-return: raise frame
|
||
|
|
||
|
Those keys are selected to at least be a little bit reminiscent
|
||
|
of those in for example common web browsers."
|
||
|
:global t
|
||
|
:group 'emacsw32
|
||
|
:group 'convenience
|
||
|
(if ourcomments-ido-ctrl-tab
|
||
|
(ourcomments-ido-ctrl-tab-activate)
|
||
|
(ad-disable-advice 'ido-visit-buffer 'before
|
||
|
'ourcomments-advice-ido-visit-buffer)
|
||
|
(ad-disable-advice 'ido-mode 'after
|
||
|
'ourcomments-advice-ido-mode)
|
||
|
;; For some reason this little complicated construct is
|
||
|
;; needed. If they are not there the defadvice
|
||
|
;; disappears. Huh.
|
||
|
;;(if ourcomments-ido-old-state
|
||
|
;; (ido-mode ourcomments-ido-old-state)
|
||
|
;; (when ido-mode (ido-mode -1)))
|
||
|
))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; New Emacs instance
|
||
|
|
||
|
(defun ourcomments-find-emacs ()
|
||
|
(locate-file invocation-name
|
||
|
(list invocation-directory)
|
||
|
exec-suffixes
|
||
|
;; 1 ;; Fix-me: This parameter is depreceated, but used
|
||
|
;; in executable-find, why?
|
||
|
))
|
||
|
|
||
|
(defvar ourcomments-restart-server-mode nil)
|
||
|
|
||
|
(defun emacs-restart-in-kill ()
|
||
|
"Last step in restart Emacs and start `server-mode' if on before."
|
||
|
(let* ((restart-args (when ourcomments-restart-server-mode
|
||
|
;; Delay 3+2 sec to be sure the old server has stopped.
|
||
|
(list "--eval=(run-with-idle-timer 5 nil 'server-mode 1)")))
|
||
|
;; Fix-me: There is an Emacs bug here, default-directory shows
|
||
|
;; up in load-path in the new Eamcs if restart-args is like
|
||
|
;; this, but not otherwise. And it has w32 file syntax. The
|
||
|
;; work around below is the best I can find at the moment.
|
||
|
(first-path (catch 'first
|
||
|
(dolist (p load-path)
|
||
|
(when (file-directory-p p)
|
||
|
(throw 'first p)))))
|
||
|
(default-directory (file-name-as-directory (expand-file-name first-path))))
|
||
|
;; Fix-me: Adding -nw to restart in console does not work. Any way to fix it?
|
||
|
(unless window-system (setq restart-args (cons "-nw" restart-args)))
|
||
|
;;(apply 'call-process (ourcomments-find-emacs) nil 0 nil restart-args)
|
||
|
(apply 'emacs restart-args)
|
||
|
;; Wait to give focus to new Emacs instance:
|
||
|
(sleep-for 3)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs-restart ()
|
||
|
"Restart Emacs and start `server-mode' if on before."
|
||
|
(interactive)
|
||
|
(if (not window-system)
|
||
|
(message "Can't restart emacs if window-system is nil")
|
||
|
(let ((wait 4))
|
||
|
(while (> (setq wait (1- wait)) 0)
|
||
|
(message (propertize (format "Will restart Emacs in %d seconds..." wait)
|
||
|
'face 'secondary-selection))
|
||
|
(sit-for 1)))
|
||
|
(setq ourcomments-restart-server-mode server-mode)
|
||
|
(add-hook 'kill-emacs-hook 'emacs-restart-in-kill t)
|
||
|
(save-buffers-kill-emacs)))
|
||
|
|
||
|
(defvar ourcomments-started-emacs-use-output-buffer nil
|
||
|
"If non-nil then save output form `emacs'.
|
||
|
Set this to `t' to debug problems with starting a new Emacs.
|
||
|
|
||
|
If non-nil save output to buffer 'call-process emacs output'.
|
||
|
Note that this will lock the Emacs calling `emacs' until the new
|
||
|
Emacs has finished.")
|
||
|
;;(setq ourcomments-started-emacs-use-output-buffer t)
|
||
|
;;(defun my-test () (interactive) (emacs-Q "-bad-arg"))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs (&rest args)
|
||
|
"Start a new Emacs with default parameters.
|
||
|
Additional ARGS are passed to the new Emacs.
|
||
|
|
||
|
See also `ourcomments-started-emacs-use-output-buffer'."
|
||
|
(interactive)
|
||
|
(recentf-save-list)
|
||
|
(let* ((out-buf (when ourcomments-started-emacs-use-output-buffer
|
||
|
(get-buffer-create "call-process emacs output")))
|
||
|
(buf-arg (or out-buf 0))
|
||
|
(args-text (mapconcat 'identity (cons "" args) " "))
|
||
|
ret
|
||
|
(fin-msg ""))
|
||
|
(when out-buf
|
||
|
(display-buffer out-buf)
|
||
|
(setq fin-msg ". Finished.")
|
||
|
(message "Started 'emacs%s' => %s. Locked until this is finished." args-text ret fin-msg)
|
||
|
(redisplay))
|
||
|
(setq ret (apply 'call-process (ourcomments-find-emacs) nil buf-arg nil args))
|
||
|
(message "Started 'emacs%s' => %s%s" args-text ret fin-msg)
|
||
|
ret))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs-buffer-file()
|
||
|
"Start a new Emacs showing current buffer file.
|
||
|
Go to the current line and column in that file.
|
||
|
If there is no buffer file then instead start with `dired'.
|
||
|
|
||
|
This calls the function `emacs' with argument --no-desktop and
|
||
|
the file or a call to dired."
|
||
|
(interactive)
|
||
|
(recentf-save-list)
|
||
|
(let ((file (buffer-file-name))
|
||
|
(lin (line-number-at-pos))
|
||
|
(col (current-column)))
|
||
|
(if file
|
||
|
(apply 'emacs "--no-desktop" (format "+%d:%d" lin col) file nil)
|
||
|
(applay 'emacs "--no-desktop" "--eval" (format "(dired \"%s\")" default-directory nil)))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs--debug-init(&rest args)
|
||
|
"Start a new Emacs with --debug-init parameter.
|
||
|
This calls the function `emacs' with added arguments ARGS."
|
||
|
(interactive)
|
||
|
(apply 'emacs "--debug-init" args))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs--no-desktop (&rest args)
|
||
|
"Start a new Emacs with --no-desktop parameter.
|
||
|
This calls the function `emacs' with added arguments ARGS."
|
||
|
(interactive)
|
||
|
(apply 'emacs "--no-desktop" args))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs-Q (&rest args)
|
||
|
"Start a new Emacs with -Q parameter.
|
||
|
Start new Emacs without any customization whatsoever.
|
||
|
This calls the function `emacs' with added arguments ARGS."
|
||
|
(interactive)
|
||
|
(apply 'emacs "-Q" args))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun emacs-Q-nxhtml(&rest args)
|
||
|
"Start new Emacs with -Q and load nXhtml.
|
||
|
This calls the function `emacs' with added arguments ARGS."
|
||
|
(interactive)
|
||
|
(let ((autostart (if (boundp 'nxhtml-install-dir)
|
||
|
(expand-file-name "autostart.el" nxhtml-install-dir)
|
||
|
(expand-file-name "../../EmacsW32/nxhtml/autostart.el"
|
||
|
exec-directory))))
|
||
|
(apply 'emacs-Q "--debug-init" "--load" autostart args)))
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Searching
|
||
|
|
||
|
(defun grep-get-buffer-files ()
|
||
|
"Return list of files in a `grep-mode' buffer."
|
||
|
(or (and (compilation-buffer-p (current-buffer))
|
||
|
(derived-mode-p 'grep-mode))
|
||
|
(error "Not in a grep buffer"))
|
||
|
(let ((here (point))
|
||
|
files
|
||
|
loc)
|
||
|
(font-lock-fontify-buffer)
|
||
|
(goto-char (point-min))
|
||
|
(while (setq loc
|
||
|
(condition-case err
|
||
|
(compilation-next-error 1)
|
||
|
(error
|
||
|
;; This should be the end, but give a message for
|
||
|
;; easier debugging.
|
||
|
(message "%s" err)
|
||
|
nil)))
|
||
|
;;(message "here =%s, loc=%s" (point) loc)
|
||
|
(let ((file (caar (nth 2 (car loc)))))
|
||
|
(setq file (expand-file-name file))
|
||
|
(add-to-list 'files file)))
|
||
|
(goto-char here)
|
||
|
;;(message "files=%s" files)
|
||
|
files))
|
||
|
|
||
|
(defvar grep-query-replace-defaults nil
|
||
|
"Default values of FROM-STRING and TO-STRING for `grep-query-replace'.
|
||
|
This is a cons cell (FROM-STRING . TO-STRING), or nil if there is
|
||
|
no default value.")
|
||
|
|
||
|
;; Mostly copied from `dired-do-query-replace-regexp'. Fix-me: finish, test
|
||
|
;;;###autoload
|
||
|
(defun grep-query-replace(from to &optional delimited)
|
||
|
"Do `query-replace-regexp' of FROM with TO, on all files in *grep*.
|
||
|
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
|
||
|
If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
|
||
|
with the command \\[tags-loop-continue]."
|
||
|
(interactive
|
||
|
(let ((common
|
||
|
;; Use the regexps that have been used in grep
|
||
|
(let ((query-replace-from-history-variable 'grep-regexp-history)
|
||
|
(query-replace-defaults (or grep-query-replace-defaults
|
||
|
query-replace-defaults)))
|
||
|
(query-replace-read-args
|
||
|
"Query replace regexp in files in *grep*" t t))))
|
||
|
(setq grep-query-replace-defaults (cons (nth 0 common)
|
||
|
(nth 1 common)))
|
||
|
(list (nth 0 common) (nth 1 common) (nth 2 common))))
|
||
|
(dolist (file (grep-get-buffer-files))
|
||
|
(let ((buffer (get-file-buffer file)))
|
||
|
(if (and buffer (with-current-buffer buffer
|
||
|
buffer-read-only))
|
||
|
(error "File `%s' is visited read-only" file))))
|
||
|
(tags-query-replace from to delimited
|
||
|
'(grep-get-buffer-files)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ldir-query-replace (from to files dir &optional delimited)
|
||
|
"Replace FROM with TO in FILES in directory DIR.
|
||
|
This runs `query-replace-regexp' in files matching FILES in
|
||
|
directory DIR.
|
||
|
|
||
|
See `tags-query-replace' for DELIMETED and more information."
|
||
|
(interactive (dir-replace-read-parameters nil nil))
|
||
|
(message "%s" (list from to files dir delimited))
|
||
|
;;(let ((files (directory-files root nil file-regexp))) (message "files=%s" files))
|
||
|
(tags-query-replace from to delimited
|
||
|
`(directory-files ,dir t ,files)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun rdir-query-replace (from to file-regexp root &optional delimited)
|
||
|
"Replace FROM with TO in FILES in directory tree ROOT.
|
||
|
This runs `query-replace-regexp' in files matching FILES in
|
||
|
directory tree ROOT.
|
||
|
|
||
|
See `tags-query-replace' for DELIMETED and more information."
|
||
|
(interactive (dir-replace-read-parameters nil t))
|
||
|
(message "%s" (list from to file-regexp root delimited))
|
||
|
;;(let ((files (directory-files root nil file-regexp))) (message "files=%s" files))
|
||
|
(tags-query-replace from to delimited
|
||
|
`(rdir-get-files ,root ,file-regexp)))
|
||
|
|
||
|
;; (rdir-get-files ".." "^a.*\.el$")
|
||
|
(defun rdir-get-files (root file-regexp)
|
||
|
(let ((files (directory-files root t file-regexp))
|
||
|
(subdirs (directory-files root t)))
|
||
|
(dolist (subdir subdirs)
|
||
|
(when (and (file-directory-p subdir)
|
||
|
(not (or (string= "/." (substring subdir -2))
|
||
|
(string= "/.." (substring subdir -3)))))
|
||
|
(setq files (append files (rdir-get-files subdir file-regexp) nil))))
|
||
|
files))
|
||
|
|
||
|
(defun dir-replace-read-parameters (has-dir recursive)
|
||
|
(let* ((common
|
||
|
(let (;;(query-replace-from-history-variable 'grep-regexp-history)
|
||
|
;;(query-replace-defaults (or grep-query-replace-defaults
|
||
|
;; query-replace-defaults))
|
||
|
)
|
||
|
(query-replace-read-args
|
||
|
"Query replace regexp in files" t t)))
|
||
|
(from (nth 0 common))
|
||
|
(to (nth 1 common))
|
||
|
(delimited (nth 2 common))
|
||
|
(files (replace-read-files from to))
|
||
|
(root (unless has-dir (read-directory-name (if recursive "Root directory: "
|
||
|
"In single directory: ")))))
|
||
|
(list from to files root delimited)))
|
||
|
|
||
|
;; Mostly copied from `grep-read-files'. Could possible be merged with
|
||
|
;; that.
|
||
|
(defvar replace-read-files-history nil)
|
||
|
;;;###autoload
|
||
|
(defun replace-read-files (regexp &optional replace)
|
||
|
"Read files arg for replace."
|
||
|
(let* ((bn (or (buffer-file-name) (buffer-name)))
|
||
|
(fn (and bn
|
||
|
(stringp bn)
|
||
|
(file-name-nondirectory bn)))
|
||
|
(default
|
||
|
(let ((pre-default
|
||
|
(or (and fn
|
||
|
(let ((aliases grep-files-aliases)
|
||
|
alias)
|
||
|
(while aliases
|
||
|
(setq alias (car aliases)
|
||
|
aliases (cdr aliases))
|
||
|
(if (string-match (wildcard-to-regexp
|
||
|
(cdr alias)) fn)
|
||
|
(setq aliases nil)
|
||
|
(setq alias nil)))
|
||
|
(cdr alias)))
|
||
|
(and fn
|
||
|
(let ((ext (file-name-extension fn)))
|
||
|
(and ext (concat "^.*\." ext))))
|
||
|
(car replace-read-files-history)
|
||
|
(car (car grep-files-aliases)))))
|
||
|
(if (string-match-p "^\\*\\.[a-zA-Z0-9]*$" pre-default)
|
||
|
(concat "\\." (substring pre-default 2) "$")
|
||
|
pre-default)))
|
||
|
(files (read-string
|
||
|
(if replace
|
||
|
(concat "Replace \"" regexp
|
||
|
"\" with \"" replace "\" in files"
|
||
|
(if default (concat " (default " default
|
||
|
", regexp or *.EXT)"))
|
||
|
": ")
|
||
|
(concat "Search for \"" regexp
|
||
|
"\" in files"
|
||
|
(if default (concat " (default " default ")"))
|
||
|
": "))
|
||
|
nil 'replace-read-files-history default)))
|
||
|
(let ((pattern (and files
|
||
|
(or (cdr (assoc files grep-files-aliases))
|
||
|
files))))
|
||
|
(if (and pattern
|
||
|
(string-match-p "^\\*\\.[a-zA-Z0-9]*$" pattern))
|
||
|
(concat "\\." (substring pattern 2) "$")
|
||
|
pattern))))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Info
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun info-open-file (info-file)
|
||
|
"Open an info file in `Info-mode'."
|
||
|
(interactive
|
||
|
(let ((name (read-file-name "Info file: "
|
||
|
nil ;; dir
|
||
|
nil ;; default-filename
|
||
|
t ;; mustmatch
|
||
|
nil ;; initial
|
||
|
;; predicate:
|
||
|
(lambda (file)
|
||
|
(or (file-directory-p file)
|
||
|
(string-match ".*\\.info\\'" file))))))
|
||
|
(list name)))
|
||
|
(info info-file))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Exec path etc
|
||
|
|
||
|
(defun ourcomments-which (prog)
|
||
|
"Look for first program PROG in `exec-path' using `exec-suffixes'.
|
||
|
Return full path if found."
|
||
|
(interactive "sProgram: ")
|
||
|
(let ((path (executable-find prog)))
|
||
|
(when (with-no-warnings (called-interactively-p))
|
||
|
(message "%s found in %s" prog path))
|
||
|
path))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Custom faces and keys
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun use-custom-style ()
|
||
|
"Setup like in `Custom-mode', but without things specific to Custom."
|
||
|
(make-local-variable 'widget-documentation-face)
|
||
|
(setq widget-documentation-face 'custom-documentation)
|
||
|
(make-local-variable 'widget-button-face)
|
||
|
(setq widget-button-face custom-button)
|
||
|
(setq show-trailing-whitespace nil)
|
||
|
|
||
|
;; We need this because of the "More" button on docstrings.
|
||
|
;; Otherwise clicking on "More" can push point offscreen, which
|
||
|
;; causes the window to recenter on point, which pushes the
|
||
|
;; newly-revealed docstring offscreen; which is annoying. -- cyd.
|
||
|
(set (make-local-variable 'widget-button-click-moves-point) t)
|
||
|
|
||
|
(set (make-local-variable 'widget-button-pressed-face) custom-button-pressed)
|
||
|
(set (make-local-variable 'widget-mouse-face) custom-button-mouse)
|
||
|
|
||
|
;; When possible, use relief for buttons, not bracketing. This test
|
||
|
;; may not be optimal.
|
||
|
(when custom-raised-buttons
|
||
|
(set (make-local-variable 'widget-push-button-prefix) "")
|
||
|
(set (make-local-variable 'widget-push-button-suffix) "")
|
||
|
(set (make-local-variable 'widget-link-prefix) "")
|
||
|
(set (make-local-variable 'widget-link-suffix) ""))
|
||
|
|
||
|
;; From widget-keymap
|
||
|
(local-set-key "\t" 'widget-forward)
|
||
|
(local-set-key "\e\t" 'widget-backward)
|
||
|
(local-set-key [(shift tab)] 'advertised-widget-backward)
|
||
|
(local-set-key [backtab] 'widget-backward)
|
||
|
(local-set-key [down-mouse-2] 'widget-button-click)
|
||
|
(local-set-key [down-mouse-1] 'widget-button-click)
|
||
|
(local-set-key [(control ?m)] 'widget-button-press)
|
||
|
;; From custom-mode-map
|
||
|
(local-set-key " " 'scroll-up)
|
||
|
(local-set-key "\177" 'scroll-down)
|
||
|
(local-set-key "n" 'widget-forward)
|
||
|
(local-set-key "p" 'widget-backward))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Bookmarks
|
||
|
|
||
|
(defun bookmark-next-marked ()
|
||
|
(interactive)
|
||
|
(let ((bb (get-buffer "*Bookmark List*"))
|
||
|
pos)
|
||
|
(when bb
|
||
|
(with-current-buffer bb
|
||
|
(setq pos (re-search-forward "^>" nil t))
|
||
|
(unless pos
|
||
|
(goto-char (point-min))
|
||
|
(setq pos (re-search-forward "^>" nil t)))))
|
||
|
(if pos
|
||
|
(with-current-buffer bb
|
||
|
;; Defined in bookmark.el, should be loaded now.
|
||
|
(bookmark-bmenu-this-window))
|
||
|
(call-interactively 'bookmark-bmenu-list)
|
||
|
(message "Please select bookmark for bookmark next command, then press n"))))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Org Mode
|
||
|
|
||
|
(defun ourcomments-org-complete-and-replace-file-link ()
|
||
|
"If on a org file link complete file name and replace it."
|
||
|
(interactive)
|
||
|
(require 'org)
|
||
|
(let* ((here (point-marker))
|
||
|
(on-link (eq 'org-link (get-text-property (point) 'face)))
|
||
|
(link-beg (when on-link
|
||
|
(previous-single-property-change (1+ here) 'face)))
|
||
|
(link-end (when on-link
|
||
|
(next-single-property-change here 'face)))
|
||
|
(link (when on-link (buffer-substring-no-properties link-beg link-end)))
|
||
|
type+link
|
||
|
link-link
|
||
|
link-link-beg
|
||
|
link-link-end
|
||
|
new-link
|
||
|
dir
|
||
|
ovl)
|
||
|
(when (and on-link
|
||
|
(string-match (rx string-start "[["
|
||
|
(group (0+ (not (any "]"))))) link))
|
||
|
(setq type+link (match-string 1 link))
|
||
|
(when (string-match "^file:\\(.*\\)" type+link)
|
||
|
(setq link-link (match-string 1 type+link))
|
||
|
(setq link-link-beg (+ 2 link-beg (match-beginning 1)))
|
||
|
(setq link-link-end (+ 2 link-beg (match-end 1)))
|
||
|
(unwind-protect
|
||
|
(progn
|
||
|
(setq ovl (make-overlay link-link-beg link-link-end))
|
||
|
(overlay-put ovl 'face 'highlight)
|
||
|
(when link-link
|
||
|
(setq link-link (org-link-unescape link-link))
|
||
|
(setq dir (when (and link-link (> (length link-link) 0))
|
||
|
(file-name-directory link-link)))
|
||
|
(setq new-link (read-file-name "Org file:" dir nil nil (file-name-nondirectory link-link)))
|
||
|
(delete-overlay ovl)
|
||
|
(setq new-link (expand-file-name new-link))
|
||
|
(setq new-link (file-relative-name new-link))
|
||
|
(delete-region link-link-beg link-link-end)
|
||
|
(goto-char link-link-beg)
|
||
|
(insert (org-link-escape new-link))
|
||
|
t))
|
||
|
(delete-overlay ovl)
|
||
|
(goto-char here))))))
|
||
|
|
||
|
;; (defun ourcomments-org-paste-html-link (html-link)
|
||
|
;; "If there is an html link on clipboard paste it as an org link.
|
||
|
;; If you have this on the clipboard
|
||
|
;; <a href=\"http://my.site.org/\">My Site</a>
|
||
|
;; It will paste this
|
||
|
;; [[http://my.site.org/][My Site]]
|
||
|
;; If the URL is to a local file it will create an org link to the
|
||
|
;; file.
|
||
|
;; Tip: You can use the Firefox plugin Copy as HTML Link, see URL
|
||
|
;; `https://addons.mozilla.org/en-US/firefox/addon/2617'.
|
||
|
;; "
|
||
|
;; (interactive (list (current-kill 0)))
|
||
|
;; (let ((conv-link (ourcomments-org-convert-html-link html-link)))
|
||
|
;; (if (not conv-link)
|
||
|
;; (message (propertize "No html link on clipboard" 'face 'font-lock-warning-face))
|
||
|
;; (insert conv-link))))
|
||
|
|
||
|
;; (defun ourcomments-org-convert-html-link (html-link)
|
||
|
;; (let (converted url str)
|
||
|
;; (save-match-data
|
||
|
;; (while (string-match ourcomments-org-paste-html-link-regexp html-link)
|
||
|
;; (setq converted t)
|
||
|
;; (setq url (match-string 1 html-link))
|
||
|
;; (setq str (match-string 2 html-link))
|
||
|
;; ;;(setq str (concat str (format "%s" (setq temp-n (1+ temp-n)))))
|
||
|
;; (setq html-link (replace-match (concat "[[" url "][" str "]]") nil nil html-link 0))))
|
||
|
;; (when converted
|
||
|
;; html-link)))
|
||
|
|
||
|
(defconst ourcomments-org-paste-html-link-regexp
|
||
|
"\\`\\(?:<a [^>]*?href=\"\\(.*?\\)\"[^>]*?>\\([^<]*\\)</a>\\)\\'")
|
||
|
|
||
|
;;(string-match-p ourcomments-org-paste-html-link-regexp "<a href=\"link\">text</a>")
|
||
|
|
||
|
;;(defvar temp-n 0)
|
||
|
(defun ourcomments-org-convert-html-links-in-buffer (beg end)
|
||
|
"Convert html link between BEG and END to org mode links.
|
||
|
If there is an html link in the buffer
|
||
|
|
||
|
<a href=\"http://my.site.org/\">My Site</a>
|
||
|
|
||
|
that starts at BEG and ends at END then convert it to this
|
||
|
|
||
|
[[http://my.site.org/][My Site]]
|
||
|
|
||
|
If the URL is to a local file and the buffer is visiting a file
|
||
|
make the link relative.
|
||
|
|
||
|
However, if the html link is inside an #+BEGIN - #+END block or a
|
||
|
variant of such blocks then leave the link as it is."
|
||
|
(when (derived-mode-p 'org-mode)
|
||
|
(save-match-data
|
||
|
(let ((here (copy-marker (point)))
|
||
|
url str converted
|
||
|
lit-beg lit-end)
|
||
|
(goto-char beg)
|
||
|
(save-restriction
|
||
|
(widen)
|
||
|
(setq lit-beg (search-backward "#+BEGIN" nil t))
|
||
|
(when lit-beg
|
||
|
(goto-char lit-beg)
|
||
|
(setq lit-end (or (search-forward "#+END" nil t)
|
||
|
(point-max)))))
|
||
|
(when (or (not lit-beg)
|
||
|
(> beg lit-end))
|
||
|
(goto-char beg)
|
||
|
(when (save-restriction
|
||
|
(narrow-to-region beg end)
|
||
|
(looking-at ourcomments-org-paste-html-link-regexp))
|
||
|
(setq converted t)
|
||
|
(setq url (match-string-no-properties 1))
|
||
|
(setq str (match-string-no-properties 2))
|
||
|
;; Check if the URL is to a local file and absolute. And we
|
||
|
;; have a buffer.
|
||
|
(when (and (buffer-file-name)
|
||
|
(> (length url) 5)
|
||
|
(string= (substring url 0 6) "file:/"))
|
||
|
(let ((abs-file-url
|
||
|
(if (not (memq system-type '(windows-nt ms-dos)))
|
||
|
(substring url 8)
|
||
|
(if (string= (substring url 0 8) "file:///")
|
||
|
(substring url 8)
|
||
|
;; file://c:/some/where.txt
|
||
|
(substring url 7)))))
|
||
|
(setq url (concat "file:"
|
||
|
(file-relative-name abs-file-url
|
||
|
(file-name-directory
|
||
|
(buffer-file-name)))))))
|
||
|
(replace-match (concat "[[" url "][" str "]]") nil nil nil 0)))
|
||
|
(goto-char here)
|
||
|
nil))))
|
||
|
|
||
|
(defvar ourcomments-paste-with-convert-hook nil
|
||
|
"Normal hook run after certain paste commands.
|
||
|
These paste commands are in the list
|
||
|
`ourcomments-paste-with-convert-commands'.
|
||
|
|
||
|
Each function in this hook is called with two parameters, the
|
||
|
start and end of the pasted text, until a function returns
|
||
|
non-nil.")
|
||
|
(add-hook 'ourcomments-paste-with-convert-hook 'ourcomments-org-convert-html-links-in-buffer)
|
||
|
|
||
|
(defvar ourcomments-paste-beg) ;; dyn var
|
||
|
(defvar ourcomments-paste-end) ;; dyn var
|
||
|
(defun ourcomments-grab-paste-bounds (beg end len)
|
||
|
(setq ourcomments-paste-beg (min beg ourcomments-paste-beg))
|
||
|
(setq ourcomments-paste-end (max end ourcomments-paste-end)))
|
||
|
|
||
|
(defmacro ourcomments-advice-paste-command (paste-command)
|
||
|
(let ((adv-name (make-symbol (concat "ourcomments-org-ad-"
|
||
|
(symbol-name paste-command)))))
|
||
|
`(defadvice ,paste-command (around
|
||
|
,adv-name)
|
||
|
(let ((ourcomments-paste-beg (point-max)) ;; dyn var
|
||
|
(ourcomments-paste-end (point-min))) ;; dyn var
|
||
|
(add-hook 'after-change-functions `ourcomments-grab-paste-bounds nil t)
|
||
|
ad-do-it ;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
(remove-hook 'after-change-functions `ourcomments-grab-paste-bounds t)
|
||
|
(run-hook-with-args-until-success 'ourcomments-paste-with-convert-hook
|
||
|
ourcomments-paste-beg
|
||
|
ourcomments-paste-end)))))
|
||
|
|
||
|
(defcustom ourcomments-paste-with-convert-commands '(yank cua-paste viper-put-back viper-Put-back)
|
||
|
"Commands for which past converting is done.
|
||
|
See `ourcomments-paste-with-convert-mode' for more information."
|
||
|
:type '(repeat function)
|
||
|
:group 'ourcomments-util)
|
||
|
|
||
|
;;;###autoload
|
||
|
(define-minor-mode ourcomments-paste-with-convert-mode
|
||
|
"Pasted text may be automatically converted in this mode.
|
||
|
The functions in `ourcomments-paste-with-convert-hook' are run
|
||
|
after commands in `ourcomments-paste-with-convert-commands' if any
|
||
|
of the functions returns non-nil that text is inserted instead of
|
||
|
the original text.
|
||
|
|
||
|
For exampel when this mode is on and you paste an html link in an
|
||
|
`org-mode' buffer it will be directly converted to an org style
|
||
|
link. \(This is the default behaviour.)
|
||
|
|
||
|
Tip: The Firefox plugin Copy as HTML Link is handy, see URL
|
||
|
`https://addons.mozilla.org/en-US/firefox/addon/2617'.
|
||
|
|
||
|
Note: This minor mode will defadvice the paste commands."
|
||
|
:global t
|
||
|
:group 'cua
|
||
|
:group 'viper
|
||
|
:group 'ourcomments-util
|
||
|
(if ourcomments-paste-with-convert-mode
|
||
|
(progn
|
||
|
(dolist (command ourcomments-paste-with-convert-commands)
|
||
|
(eval `(ourcomments-advice-paste-command ,command))
|
||
|
(ad-activate command)))
|
||
|
(dolist (command ourcomments-paste-with-convert-commands)
|
||
|
(ad-unadvise command))))
|
||
|
|
||
|
;; (ourcomments-advice-paste-command cua-paste)
|
||
|
;; (ad-activate 'cua-paste)
|
||
|
;; (ad-deactivate 'cua-paste)
|
||
|
;; (ad-update 'cua-paste)
|
||
|
;; (ad-unadvise 'cua-paste)
|
||
|
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Menu commands to M-x history
|
||
|
|
||
|
;; (where-is-internal 'mumamo-mark-chunk nil nil)
|
||
|
;; (where-is-internal 'mark-whole-buffer nil nil)
|
||
|
;; (where-is-internal 'save-buffer nil nil)
|
||
|
;; (where-is-internal 'revert-buffer nil nil)
|
||
|
;; (setq extended-command-history nil)
|
||
|
(defun ourcomments-M-x-menu-pre ()
|
||
|
"Add menu command to M-x history."
|
||
|
(let ((is-menu-command (equal '(menu-bar)
|
||
|
(when (< 0 (length (this-command-keys-vector)))
|
||
|
(elt (this-command-keys-vector) 0))))
|
||
|
(pre-len (length extended-command-history)))
|
||
|
(when (and is-menu-command
|
||
|
(not (memq this-command '(ourcomments-M-x-menu-mode))))
|
||
|
(pushnew (symbol-name this-command) extended-command-history)
|
||
|
(when (< pre-len (length extended-command-history))
|
||
|
;; This message is given pre-command and is therefore likely
|
||
|
;; to be overwritten, but that is ok in this case. If the user
|
||
|
;; has seen one of these messages s?he knows.
|
||
|
(message (propertize "(Added %s to M-x history so you can run it from there)"
|
||
|
'face 'file-name-shadow)
|
||
|
this-command)))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(define-minor-mode ourcomments-M-x-menu-mode
|
||
|
"Add commands started from Emacs menus to M-x history.
|
||
|
The purpose of this is to make it easier to redo them and easier
|
||
|
to learn how to do them from the command line \(which is often
|
||
|
faster if you know how to do it).
|
||
|
|
||
|
Only commands that are not already in M-x history are added."
|
||
|
:global t
|
||
|
(if ourcomments-M-x-menu-mode
|
||
|
(add-hook 'pre-command-hook 'ourcomments-M-x-menu-pre)
|
||
|
(remove-hook 'pre-command-hook 'ourcomments-M-x-menu-pre)))
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;; Warnings etc
|
||
|
|
||
|
(defvar ourcomments-warnings nil)
|
||
|
|
||
|
(defun ourcomments-display-warnings ()
|
||
|
(condition-case err
|
||
|
(let ((msg (mapconcat 'identity (reverse ourcomments-warnings) "\n")))
|
||
|
(setq ourcomments-warnings nil)
|
||
|
(message "%s" (propertize msg 'face 'secondary-selection)))
|
||
|
(error (message "ourcomments-display-warnings: %s" err))))
|
||
|
|
||
|
(defun ourcomments-warning-post ()
|
||
|
(condition-case err
|
||
|
(run-with-idle-timer 0.5 nil 'ourcomments-display-warnings)
|
||
|
(error (message "ourcomments-warning-post: %s" err))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun ourcomments-warning (format-string &rest args)
|
||
|
(setq ourcomments-warnings (cons (apply 'format format-string args)
|
||
|
ourcomments-warnings))
|
||
|
(add-hook 'post-command-hook 'ourcomments-warning-post))
|
||
|
|
||
|
|
||
|
|
||
|
(provide 'ourcomments-util)
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;; ourcomments-util.el ends here
|