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