PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/elisp/mode-info/mi-util.el

https://bitbucket.org/ina299/dotfiles
Emacs Lisp | 255 lines | 194 code | 38 blank | 23 comment | 7 complexity | 41580579951dcc890fc11429c8282043 MD5 | raw file
  1. ;;; mi-util.el --- Utility functions of mode-info
  2. ;; Copyright (C) 2002 TSUCHIYA Masatoshi <tsuchiya@namazu.org>
  3. ;; Authors: TSUCHIYA Masatoshi <tsuchiya@namazu.org>
  4. ;; Keywords: info
  5. ;; This file is a part of mode-info.
  6. ;; This program is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 2, or (at your option)
  9. ;; any later version.
  10. ;; This program is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with this program; if not, you can either send email to this
  16. ;; program's maintainer or write to: The Free Software Foundation,
  17. ;; Inc.; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. ;;; Commentary:
  19. ;; This file provides utility functions and an object system of
  20. ;; mode-info.
  21. ;;; Code:
  22. (eval-when-compile
  23. (require 'cl))
  24. (eval-and-compile
  25. (cond
  26. ((boundp 'MULE)
  27. (require 'poe)
  28. (require 'pcustom))))
  29. (defconst mode-info-titles-type
  30. '(repeat (choice (string :tag "Title")
  31. (repeat :tag "Aliases" (string :tag "Title"))))
  32. "A widget type for editing `mode-info-*-titles'.")
  33. (put 'mode-info-static-if 'edebug-form-spec '(form form body))
  34. (put 'mode-info-static-if 'lisp-indent-function 2)
  35. (defmacro mode-info-static-if (cond then &rest else)
  36. "Like `if', but evaluate COND at compile time."
  37. (if (eval cond) then `(progn ,@else)))
  38. (put 'mode-info-static-when 'edebug-form-spec '(form body))
  39. (put 'mode-info-static-when 'lisp-indent-function 1)
  40. (defmacro mode-info-static-when (cond &rest body)
  41. "Like `when', but evaluate COND at compile time."
  42. (if (eval cond) `(progn ,@body)))
  43. (put 'mode-info-save-syntax-table 'edebug-form-spec '(body))
  44. (put 'mode-info-save-syntax-table 'lisp-indent-function 0)
  45. (defmacro mode-info-save-syntax-table (&rest body)
  46. "Save syntax table of this current buffer; execute BODY; restore it."
  47. (let ((orig-table (make-symbol "orig-table")))
  48. `(let ((,orig-table (syntax-table)))
  49. (unwind-protect
  50. (progn
  51. (set-syntax-table (copy-syntax-table))
  52. ,@body)
  53. (set-syntax-table ,orig-table)))))
  54. (eval-and-compile
  55. (unless (fboundp 'match-string-no-properties)
  56. (defun match-string-no-properties (num &optional string)
  57. "Return string of text matched by last search, without text properties.
  58. NUM specifies which parenthesized expression in the last regexp.
  59. Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
  60. Zero means the entire text matched by the whole regexp or whole string.
  61. STRING should be given if the last search was by `string-match' on STRING."
  62. (if (match-beginning num)
  63. (if string
  64. (let ((result
  65. (substring string (match-beginning num) (match-end num))))
  66. (set-text-properties 0 (length result) nil result)
  67. result)
  68. (buffer-substring-no-properties (match-beginning num)
  69. (match-end num)))))))
  70. (unless (fboundp 'line-beginning-position)
  71. (if (fboundp 'point-at-bol)
  72. (defalias 'line-beginning-position 'point-at-bol)
  73. (defun line-beginning-position (&optional N)
  74. "Return the character position of the first character on the current line.
  75. With argument N not nil or 1, move forward N - 1 lines first. If scan
  76. reaches end of buffer, return that position."
  77. (save-excursion
  78. (forward-line (if N (1- N) 0))
  79. (point)))))
  80. (mode-info-static-if (featurep 'xemacs)
  81. (defalias 'mode-info-key-or-menu-binding 'key-or-menu-binding)
  82. (defun mode-info-key-or-menu-binding (key)
  83. "Return the binding for command KEY in current keymaps."
  84. (save-excursion
  85. (let ((modifiers (event-modifiers (aref key 0)))
  86. window position)
  87. (when (or (memq 'click modifiers)
  88. (memq 'down modifiers)
  89. (memq 'drag modifiers))
  90. (setq window (posn-window (event-start (aref key 0)))
  91. position (posn-point (event-start (aref key 0)))))
  92. (when (windowp window)
  93. (set-buffer (window-buffer window))
  94. (goto-char position))
  95. (mode-info-static-if (fboundp 'string-key-binding)
  96. (or (string-key-binding key) (key-binding key))
  97. (key-binding key))))))
  98. ;;; Object System:
  99. (eval-and-compile
  100. (defvar mode-info-obarray
  101. (let ((obarray (make-vector 31 0)))
  102. (intern "mode-info" obarray) ;; mode-info means the base object.
  103. obarray)
  104. "Table of mode-info-classes.")
  105. (defvar mode-info-method-obarray (make-vector 63 0)
  106. "Method table of mode-info-classes."))
  107. (defconst mode-info-prefix "mode-info-")
  108. (defmacro mode-info-defclass (class &rest parents)
  109. "Define CLASS as a mode-info-class."
  110. `(eval-and-compile
  111. (mode-info-defclass-1 (quote ,class) (quote ,parents))))
  112. (eval-and-compile
  113. (defmacro mode-info-parents (class)
  114. "Return parents of CLASS."
  115. `(get ,class '*parents*)))
  116. (defun mode-info-defclass-1 (class parents)
  117. (setf (mode-info-parents
  118. (setq class (intern (symbol-name class) mode-info-obarray)))
  119. (append
  120. (mapcar (lambda (p)
  121. (intern (symbol-name p) mode-info-obarray))
  122. parents)
  123. '(mode-info)))
  124. class)
  125. (defmacro mode-info-method-symbol-name (method class)
  126. "Generate a unique name from METHOD and CLASS."
  127. `(concat (symbol-name ,class) "@" (symbol-name ,method)))
  128. (defun mode-info-find-class (name)
  129. "Return class has NAME."
  130. (intern-soft (if (symbolp name) (symbol-name name) name)
  131. mode-info-obarray))
  132. (defmacro mode-info-class (entity)
  133. "Return class of ENTITY."
  134. `(intern-soft (symbol-name ,entity) mode-info-obarray))
  135. (defun mode-info-class-name (class)
  136. "Return the CLASS name."
  137. (symbol-name class))
  138. (defun mode-info-method-search (name class)
  139. "Search the method which is named NAME for CLASS."
  140. (or (intern-soft (mode-info-method-symbol-name name class)
  141. mode-info-method-obarray)
  142. (let ((method)
  143. (classes (mode-info-parents class)))
  144. (while (and (not method) classes)
  145. (setq method
  146. (mode-info-method-search name (pop classes))))
  147. method)))
  148. (put 'mode-info-void-method 'error-conditions
  149. '(error void-function mode-info-void-method))
  150. (put 'mode-info-void-method 'error-message
  151. "Symbol's method definition is void")
  152. (put 'mode-info-defgeneric 'lisp-indent-function 'defun)
  153. (defmacro mode-info-defgeneric (name args &optional document)
  154. "Define a function NAME that provides a generic interface to the method NAME.
  155. ARGS is the argument list for NAME. The first element of ARGS is an
  156. entity."
  157. `(defun ,(intern (concat mode-info-prefix (symbol-name name))) ,args
  158. ,@(if document (list document) nil)
  159. (let ((method (mode-info-method-search
  160. (quote ,name) (mode-info-class ,(car args)))))
  161. (if method
  162. (,(if (memq '&rest args)
  163. 'apply
  164. 'funcall)
  165. method
  166. ,@(delq '&rest (delq '&optional (copy-sequence args))))
  167. (signal 'mode-info-void-method
  168. (make-symbol
  169. (mode-info-method-symbol-name (quote ,name)
  170. ,(car args))))))))
  171. (eval-and-compile
  172. (defun mode-info-method-search-next (name class)
  173. "Search the next method which is named NAME for CLASS."
  174. (let ((method)
  175. (classes (mode-info-parents class)))
  176. (while (and (not method) classes)
  177. (setq method (mode-info-method-search name (pop classes))))
  178. method)))
  179. (put 'mode-info-defmethod 'lisp-indent-function 'defun)
  180. (put 'mode-info-defmethod 'edebug-form-spec
  181. '(&define name
  182. ((arg symbolp)
  183. [&rest arg]
  184. [&optional ["&optional" arg &rest arg]]
  185. &optional ["&rest" arg])
  186. [&optional stringp]
  187. [&optional ("interactive" interactive)]
  188. def-body))
  189. (defmacro mode-info-defmethod (name spec &rest body)
  190. "Define NAME as a method of a mode-info-class."
  191. (let* ((class (nth 1 (car spec)))
  192. (args (cons (caar spec) (cdr spec)))
  193. (next (mode-info-method-search-next name (mode-info-class class))))
  194. `(fset (intern (eval-when-compile
  195. (mode-info-method-symbol-name (quote ,name)
  196. (quote ,class)))
  197. mode-info-method-obarray)
  198. ,(if next
  199. `(function
  200. (lambda ,args
  201. (labels ((mode-info-method-next
  202. nil
  203. (,(if (memq '&rest args)
  204. 'apply
  205. 'funcall)
  206. (intern ,(symbol-name next)
  207. mode-info-method-obarray)
  208. ,@(delq '&rest (delq '&optional
  209. (copy-sequence args))))))
  210. ,@body)))
  211. `(function (lambda ,args ,@body))))))
  212. (defun mode-info-method-next (&rest args)
  213. "Call the next method in the current method function.
  214. IMPORTANT NOTICE: It is disabled using this function out of methods."
  215. (signal 'mode-info-void-method nil))
  216. (provide 'mi-util)
  217. ;;; mi-util.el ends here