idlw-complete-structtag.el 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. ;;; idlw-complete-structtag.el --- Completion of structure tags.
  2. ;; Copyright (C) 2001-2012 Free Software Foundation, Inc.
  3. ;; Author: Carsten Dominik <dominik@astro.uva.nl>
  4. ;; Maintainer: J.D. Smith <jdsmith@as.arizona.edu>
  5. ;; Version: 1.2
  6. ;; Keywords: languages
  7. ;; Package: idlwave
  8. ;; This file is part of GNU Emacs.
  9. ;; GNU Emacs is free software: you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation, either version 3 of the License, or
  12. ;; (at your option) any later version.
  13. ;; GNU Emacs is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; Completion of structure tags can be done automatically in the
  21. ;; shell, since the list of tags can be determined dynamically through
  22. ;; interaction with IDL.
  23. ;; Completion of structure tags in a source buffer is highly ambiguous
  24. ;; since you never know what kind of structure a variable will hold at
  25. ;; runtime. To make this feature useful in source buffers, we need a
  26. ;; special assumption/convention. We will assume that the structure is
  27. ;; defined in the same buffer and directly assigned to the correct
  28. ;; variable. This is mainly useful for applications in which there is one
  29. ;; main structure which contains a large amount of information (and many
  30. ;; tags). For example, many widget applications define a "state" structure
  31. ;; that contains all important data about the application. The different
  32. ;; routines called by the event handler then use this structure. If you
  33. ;; use the same variable name for this structure throughout your
  34. ;; application (a good idea for many reasons), IDLWAVE can support
  35. ;; completion for its tags.
  36. ;;
  37. ;; This file is a completion plugin which implements this kind of
  38. ;; completion. It is also an example which shows how completion plugins
  39. ;; should be programmed.
  40. ;;
  41. ;; New versions of IDLWAVE, documentation, and more information available
  42. ;; from:
  43. ;; http://idlwave.org
  44. ;;
  45. ;; INSTALLATION
  46. ;; ============
  47. ;; Put this file on the emacs load path and load it with the following
  48. ;; line in your .emacs file:
  49. ;;
  50. ;; (add-hook 'idlwave-load-hook
  51. ;; (lambda () (require 'idlw-complete-structtag)))
  52. ;;
  53. ;; DESCRIPTION
  54. ;; ===========
  55. ;; Suppose your IDL program contains something like
  56. ;;
  57. ;; myvar = state.a*
  58. ;;
  59. ;; where the star marks the cursor position. If you now press the
  60. ;; completion key M-TAB, IDLWAVE searches the current file for a
  61. ;; structure definition
  62. ;;
  63. ;; state = {tag1:val1, tag2:val2, ...}
  64. ;;
  65. ;; and offers the tags for completion.
  66. ;;
  67. ;; In the idlwave shell, idlwave sends a "print,tag_names()" for the
  68. ;; variable to idl and determines the current tag list dynamically.
  69. ;;
  70. ;; Notes
  71. ;; -----
  72. ;; - The structure definition assignment "state = {...}" must use the
  73. ;; same variable name as the completion location "state.*".
  74. ;; - The structure definition must be in the same file.
  75. ;; - The structure definition is searched backwards and then forward
  76. ;; from the current position, until a definition with tags is found.
  77. ;; - The file is parsed again for each new completion variable and location.
  78. ;; - You can force an update of the tag list with the usual command
  79. ;; to update routine info in IDLWAVE: C-c C-i
  80. (require 'idlwave)
  81. (declare-function idlwave-shell-buffer "idlw-shell")
  82. ;; Some variables to identify the previously used structure
  83. (defvar idlwave-current-tags-var nil)
  84. (defvar idlwave-current-tags-buffer nil)
  85. (defvar idlwave-current-tags-completion-pos nil)
  86. ;; The tag list used for completion will be stored in the following vars
  87. (defvar idlwave-current-struct-tags nil)
  88. (defvar idlwave-sint-structtags nil)
  89. ;; Create the sintern type for structure talks
  90. (declare-function idlwave-sintern-structtag "idlw-complete-structtag" t t)
  91. (idlwave-new-sintern-type 'structtag)
  92. ;; Hook the plugin into idlwave
  93. (add-to-list 'idlwave-complete-special 'idlwave-complete-structure-tag)
  94. (add-hook 'idlwave-update-rinfo-hook 'idlwave-structtag-reset)
  95. ;;; The main code follows below
  96. (defvar idlwave-completion-help-info)
  97. (defun idlwave-complete-structure-tag ()
  98. "Complete a structure tag.
  99. This works by looking in the current file for a structure assignment to a
  100. variable with the same name and takes the tags from there. Quite useful
  101. for big structures like the state variables of a widget application.
  102. In the idlwave shell, the current content of the variable is used to get
  103. an up-to-date completion list."
  104. (interactive)
  105. (let ((pos (point))
  106. start
  107. (case-fold-search t))
  108. (if (save-excursion
  109. ;; Check if the context is right.
  110. ;; In the shell, this could be extended to expressions like
  111. ;; x[i+4].name.g*. But it is complicated because we would have
  112. ;; to really parse this expression. For now, we allow only
  113. ;; substructures, like "aaa.bbb.ccc.ddd"
  114. (skip-chars-backward "[a-zA-Z0-9._$]")
  115. (setq start (point)) ;; remember the start of the completion pos.
  116. (and (< (point) pos)
  117. (not (equal (char-before) ?!)) ; no sysvars
  118. (looking-at "\\([a-zA-Z][.a-zA-Z0-9_]*\\)\\.")
  119. (>= pos (match-end 0))
  120. (not (string= (downcase (match-string 1)) "self"))))
  121. (let* ((var (downcase (match-string 1))))
  122. ;; Check if we need to update the "current" structure. Basically we
  123. ;; do it always, except for subsequent completions at the same
  124. ;; spot, to save a bit of time. Implementation: We require
  125. ;; an update if
  126. ;; - the variable is different or
  127. ;; - the buffer is different or
  128. ;; - we are completing at a different position
  129. (if (or (not (string= var (or idlwave-current-tags-var "@")))
  130. (not (eq (current-buffer) idlwave-current-tags-buffer))
  131. (not (equal start idlwave-current-tags-completion-pos)))
  132. (idlwave-prepare-structure-tag-completion var))
  133. (setq idlwave-current-tags-completion-pos start)
  134. (setq idlwave-completion-help-info
  135. (list 'idlwave-complete-structure-tag-help))
  136. (idlwave-complete-in-buffer 'structtag 'structtag
  137. idlwave-current-struct-tags nil
  138. "Select a structure tag" "structure tag")
  139. t) ; we did the completion: return t to skip other completions
  140. nil))) ; return nil to allow looking for other ways to complete
  141. (defun idlwave-structtag-reset ()
  142. "Force an update of the current structure tag list upon next use."
  143. (setq idlwave-current-tags-buffer nil))
  144. (defvar idlwave-structtag-struct-location nil
  145. "The location of the structure definition, for help display.")
  146. (defun idlwave-prepare-structure-tag-completion (var)
  147. "Find and parse the tag list for structure tag completion."
  148. ;; This works differently in source buffers and in the shell
  149. (if (derived-mode-p 'idlwave-shell-mode)
  150. ;; OK, we are in the shell, do it dynamically
  151. (progn
  152. (message "preparing shell tags")
  153. ;; The following call puts the tags into `idlwave-current-struct-tags'
  154. (idlwave-complete-structure-tag-query-shell var)
  155. ;; initialize
  156. (setq idlwave-sint-structtags nil
  157. idlwave-current-tags-buffer (current-buffer)
  158. idlwave-current-tags-var var
  159. idlwave-structtag-struct-location (point)
  160. idlwave-current-struct-tags
  161. (mapcar (lambda (x)
  162. (list (idlwave-sintern-structtag x 'set)))
  163. idlwave-current-struct-tags))
  164. (if (not idlwave-current-struct-tags)
  165. (error "Cannot complete structure tags of variable %s" var)))
  166. ;; Not the shell, so probably a source buffer.
  167. (unless
  168. (catch 'exit
  169. (save-excursion
  170. (goto-char (point-max))
  171. ;; Find possible definitions of the structure.
  172. (while (idlwave-find-structure-definition var nil 'all)
  173. (let ((tags (idlwave-struct-tags)))
  174. (when tags
  175. ;; initialize
  176. (setq idlwave-sint-structtags nil
  177. idlwave-current-tags-buffer (current-buffer)
  178. idlwave-current-tags-var var
  179. idlwave-structtag-struct-location (point)
  180. idlwave-current-struct-tags
  181. (mapcar (lambda (x)
  182. (list (idlwave-sintern-structtag x 'set)))
  183. tags))
  184. (throw 'exit t))))))
  185. (error "Cannot complete structure tags of variable %s" var))))
  186. (defun idlwave-complete-structure-tag-query-shell (var)
  187. "Ask the shell for the tags of the structure in variable or expression VAR."
  188. (idlwave-shell-send-command
  189. (format "if size(%s,/TYPE) eq 8 then print,tag_names(%s)" var var)
  190. 'idlwave-complete-structure-tag-get-tags-from-help
  191. 'hide 'wait))
  192. (defvar idlwave-shell-prompt-pattern)
  193. (defvar idlwave-shell-command-output)
  194. (defun idlwave-complete-structure-tag-get-tags-from-help ()
  195. "Filter structure tag name output, result to `idlwave-current-struct-tags'."
  196. (setq idlwave-current-struct-tags
  197. (if (string-match (concat "tag_names(.*) *\n"
  198. "\\(\\(.*[\r\n]?\\)*\\)"
  199. "\\(" idlwave-shell-prompt-pattern "\\)")
  200. idlwave-shell-command-output)
  201. (split-string (match-string 1 idlwave-shell-command-output)))))
  202. ;; Fake help in the source buffer for structure tags.
  203. ;; idlw-help-kwd is a global-variable (from idlwave-do-mouse-completion-help).
  204. (defvar idlw-help-kwd)
  205. (defvar idlwave-help-do-struct-tag)
  206. (defun idlwave-complete-structure-tag-help (mode word)
  207. (cond
  208. ((eq mode 'test)
  209. ;; fontify only in source buffers, not in the shell.
  210. (not (equal idlwave-current-tags-buffer
  211. (get-buffer (idlwave-shell-buffer)))))
  212. ((eq mode 'set)
  213. (setq idlw-help-kwd word
  214. idlwave-help-do-struct-tag idlwave-structtag-struct-location))
  215. (t (error "This should not happen"))))
  216. (provide 'idlw-complete-structtag)
  217. ;;; idlw-complete-structtag.el ends here