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