1;;; idlw-complete-structtag.el --- Completion of structure tags. 2 3;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 4;; Free Software Foundation, Inc. 5 6;; Author: Carsten Dominik <dominik@astro.uva.nl> 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 15;; the Free Software Foundation; either version 2, or (at your option) 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 25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26;; Boston, MA 02110-1301, USA. 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;; ============ 58;; Put this file on the emacs load path and load it with the following 59;; line in your .emacs file: 60;; 61;; (add-hook 'idlwave-load-hook 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 92(require 'idlwave) 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 111(defvar idlwave-completion-help-info) 112(defun idlwave-complete-structure-tag () 113 "Complete a structure tag. 114This works by looking in the current file for a structure assignment to a 115variable with the same name and takes the tags from there. Quite useful 116for big structures like the state variables of a widget application. 117 118In the idlwave shell, the current content of the variable is used to get 119an 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) 150 (setq idlwave-completion-help-info 151 (list 'idlwave-complete-structure-tag-help)) 152 (idlwave-complete-in-buffer 'structtag 'structtag 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 171 (message "preparing shell tags") 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))) 193 (when tags 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 246;; arch-tag: d1f9e55c-e504-4187-9c31-3c3651fa4bfa 247