1;;; idlw-help.el --- HTML Help code for IDLWAVE 2 3;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 4;; Free Software Foundation, Inc. 5;; 6;; Authors: J.D. Smith <jdsmith@as.arizona.edu> 7;; Carsten Dominik <dominik@science.uva.nl> 8;; Maintainer: J.D. Smith <jdsmith@as.arizona.edu> 9;; Version: 6.1_em22 10 11;; This file is part of GNU Emacs. 12 13;; This file 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;; This file 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;; The help link information for IDLWAVE's online help feature for 31;; system routines is extracted automatically from the IDL 32;; documentation, and is available, along with general routine 33;; information, in the file idlw-rinfo.el. The HTML help file 34;; themselves are not distributable with Emacs, but are available, 35;; along with new versions of IDLWAVE, documentation, and more 36;; information, at: 37;; 38;; http://idlwave.org 39;; 40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 41 42 43 44;;; Code: 45(defvar idlwave-help-browse-url-available nil 46 "Whether browse-url is available") 47 48(setq idlwave-help-browse-url-available 49 (condition-case nil 50 (require 'browse-url) 51 (error nil))) 52 53(defgroup idlwave-online-help nil 54 "Online Help options for IDLWAVE mode." 55 :group 'idlwave) 56 57(defcustom idlwave-html-help-pre-v6 nil 58 "Whether pre or post-v6.0 IDL help documents are being used." 59 :group 'idlwave-online-help 60 :type 'boolean) 61 62(defvar idlwave-html-link-sep 63 (if idlwave-html-help-pre-v6 "#" "#wp")) 64 65(defcustom idlwave-html-system-help-location "help/online_help/" 66 "The directory, relative to idlwave-system-directory, where the idl 67HTML help files live, for IDL 6.2 and later. This location, if found, 68is used in preference to the old idlwave-html-help-location." 69 :group 'idlwave-online-help 70 :type 'directory) 71 72(defcustom idlwave-html-help-location 73 (if (memq system-type '(ms-dos windows-nt)) 74 nil 75 "/usr/local/etc/") 76 "The directory where the idl_html_help/ dir lives. Obsolete for IDL 776.2 or later (see idlwave-html-system-help-location)." 78 :group 'idlwave-online-help 79 :type 'directory) 80 81(defvar idlwave-help-use-hh nil 82 "Obsolete variable.") 83 84(defcustom idlwave-help-use-assistant t 85 "Whether to use the IDL Assistant as the help browser." 86 :group 'idlwave-online-help 87 :type 'boolean) 88 89(defcustom idlwave-help-browser-function browse-url-browser-function 90 "Function to use to display html help. 91Defaults to `browse-url-browser-function', which see." 92 :group 'idlwave-online-help 93 :type 'function) 94 95(defcustom idlwave-help-browser-generic-program browse-url-generic-program 96 "Program to run if using browse-url-generic-program." 97 :group 'idlwave-online-help 98 :type 'string) 99 100(defvar browse-url-generic-args) 101 102(defcustom idlwave-help-browser-generic-args 103 (if (boundp 'browse-url-generic-args) 104 browse-url-generic-args "") 105 "Program args to use if using browse-url-generic-program." 106 :group 'idlwave-online-help 107 :type 'string) 108 109(defcustom idlwave-help-browser-is-local nil 110 "Whether the browser will display locally in an Emacs window. 111Several browsers run and/or display inside Emacs windows, but most are 112external programs. If the browser name contains \"-w3\", it is 113assumed to be local to Emacs. For other local browsers, this variable 114must be explicitly set non-nil in order for the variable 115`idlwave-help-use-dedicated-frame' to function." 116 :group 'idlwave-online-help 117 :type 'boolean) 118 119(defvar idlwave-help-directory "" 120 "Obsolete variable. See idlwave-html-help-location.") 121 122(defcustom idlwave-help-use-dedicated-frame t 123 "*Non-nil means, use a separate frame for Online Help if possible." 124 :group 'idlwave-online-help 125 :type 'boolean) 126 127(defcustom idlwave-help-frame-parameters 128 '((height . 32) (unsplittable . t)) 129 "The frame parameters for the special Online Help frame. 130See also `idlwave-help-use-dedicated-frame'. 131If you do not set the frame width here, the value specified in 132`idlw-help.el' will be used." 133 :group 'idlwave-online-help 134 :type '(repeat 135 (cons symbol sexp))) 136 137(defcustom idlwave-max-popup-menu-items 20 138 "Maximum number of items per pane in popup menus. 139Currently only used for class selection during completion help." 140 :group 'idlwave-online-help 141 :type 'integer) 142 143(defcustom idlwave-extra-help-function 'idlwave-help-with-source 144 "The function to call for online help if the normal help fails. 145Online help works only for system routines which are described in the 146IDL manuals. A function may be specified to access help from other sources. 147 148The function must accept four arguments: NAME, TYPE, CLASS, KEYWORD. 149The Help buffer is current when this function is called, and the help 150text should be loaded into this buffer. If help is found, the 151function should return the buffer position which should be used as 152`window-start' in the help window. Also, the variable 153`idlwave-help-mode-line-indicator' should be set to a useful string, 154which will be displayed in the mode line of the help window. If 155should also set the variable `idlwave-help-min-frame-width' to a 156positive integer. IDLWAVE will ensure that the help frame is at least 157that many columns wide. Failure to find help should be indicated by 158throwing an error. 159 160When this variable is non-nil, IDLWAVE will allow the mouse-3 help click 161for every routine and keyword, even though the item may not be highlighted 162in blue (indicating the availability of system documentation). 163 164The default value for this function is `idlwave-help-with-source' which 165loads the routine source file into the help buffer. If you try to write 166a different function which accesses a special help file or so, it is 167probably a good idea to still call this function as a fallback." 168 :group 'idlwave-online-help 169 :type 'symbol) 170 171(defcustom idlwave-help-fontify-source-code nil 172 "*Non-nil means, fontify source code displayed as help like normal code." 173 :group 'idlwave-online-help 174 :type 'boolean) 175 176(defcustom idlwave-help-source-try-header t 177 "*Non-nil means, try to find help in routine header when displaying source. 178Routines which are not documented in the system manual use their source as 179help text. When this variable is non-nil, we try to find a description of 180the help item in the first routine doclib header above the routine definition. 181If the variable is nil, or if we cannot find/parse the header, the routine 182definition is displayed instead." 183 :group 'idlwave-online-help 184 :type 'boolean) 185 186 187(defcustom idlwave-help-doclib-name "name" 188 "*A regexp for the heading word to search for in doclib headers 189which specifies the `name' section. Can be used for localization 190support." 191 :group 'idlwave-online-help 192 :type 'string) 193 194(defcustom idlwave-help-doclib-keyword "KEYWORD" 195 "*A regexp for the heading word to search for in doclib headers 196which specifies the `keywords' section. Can be used for localization 197support." 198 :group 'idlwave-online-help 199 :type 'string) 200 201(defface idlwave-help-link 202 '((((class color)) (:foreground "Blue")) 203 (t (:weight bold))) 204 "Face for highlighting links into IDLWAVE online help." 205 :group 'idlwave-online-help) 206 207(defvar idlwave-help-activate-links-aggressively nil 208 "Obsolete variable.") 209 210(defvar idlwave-completion-help-info) 211 212(defvar idlwave-help-frame nil 213 "The frame for display of IDL online help.") 214(defvar idlwave-help-frame-width 102 215 "The default width of the help frame.") 216 217(defvar idlwave-html-help-is-available nil 218 "Is the system online help text avaiable?") 219 220(defvar idlwave-help-mode-line-indicator "" 221 "Used for the special mode line in the idlwave-help-mode.") 222 223(defvar idlwave-help-window-configuration nil) 224(defvar idlwave-help-special-topic-words nil) ; defined by get_rinfo 225 226;; Define the key bindings for the Help application 227 228(defvar idlwave-help-mode-map (make-sparse-keymap) 229 "The keymap used in idlwave-help-mode.") 230 231(define-key idlwave-help-mode-map "q" 'idlwave-help-quit) 232(define-key idlwave-help-mode-map "w" 'widen) 233(define-key idlwave-help-mode-map "\C-m" (lambda (arg) 234 (interactive "p") 235 (scroll-up arg))) 236(define-key idlwave-help-mode-map " " 'scroll-up) 237(define-key idlwave-help-mode-map [delete] 'scroll-down) 238(define-key idlwave-help-mode-map "h" 'idlwave-help-find-header) 239(define-key idlwave-help-mode-map "H" 'idlwave-help-find-first-header) 240(define-key idlwave-help-mode-map "." 'idlwave-help-toggle-header-match-and-def) 241(define-key idlwave-help-mode-map "F" 'idlwave-help-fontify) 242(define-key idlwave-help-mode-map "\M-?" 'idlwave-help-return-to-calling-frame) 243(define-key idlwave-help-mode-map "x" 'idlwave-help-return-to-calling-frame) 244 245;; Define the menu for the Help application 246 247(easy-menu-define 248 idlwave-help-menu idlwave-help-mode-map 249 "Menu for Help IDLWAVE system" 250 '("IDLHelp" 251 ["Definition <-> Help Text" idlwave-help-toggle-header-match-and-def t] 252 ["Find DocLib Header" idlwave-help-find-header t] 253 ["Find First DocLib Header" idlwave-help-find-first-header t] 254 ["Fontify help buffer" idlwave-help-fontify t] 255 "--" 256 ["Quit" idlwave-help-quit t])) 257 258(defvar idlwave-help-def-pos) 259(defvar idlwave-help-args) 260(defvar idlwave-help-in-header) 261 262(defun idlwave-help-mode () 263 "Major mode for displaying IDL Help. 264 265This is a VIEW mode for the ASCII version of IDL Help files, 266with some extras. Its main purpose is speed - so don't 267expect a fully hyper-linked help. 268 269Scrolling: SPC DEL RET 270Text Searches: Inside Topic: Use Emacs search functions 271Exit: [q]uit or mouse button 3 will kill the frame 272 273When the hep text is a source file, the following commands are available 274 275Fontification: [F]ontify the buffer like source code 276Jump: [h] to function doclib header 277 [H] to file doclib header 278 [.] back and forward between header and definition 279 280Here are all keybindings. 281\\{idlwave-help-mode-map}" 282 (kill-all-local-variables) 283 (buffer-disable-undo) 284 (setq major-mode 'idlwave-help-mode 285 mode-name "IDLWAVE Help") 286 (use-local-map idlwave-help-mode-map) 287 (easy-menu-add idlwave-help-menu idlwave-help-mode-map) 288 (setq truncate-lines t) 289 (setq case-fold-search t) 290 (setq mode-line-format 291 (list "" 292 'mode-line-modified 293 'mode-line-buffer-identification 294 ": " 'idlwave-help-mode-line-indicator 295 " -%-")) 296 (setq buffer-read-only t) 297 (set (make-local-variable 'idlwave-help-def-pos) nil) 298 (set (make-local-variable 'idlwave-help-args) nil) 299 (set (make-local-variable 'idlwave-help-in-header) nil) 300 (run-hooks 'idlwave-help-mode-hook)) 301 302(defun idlwave-html-help-location () 303 "Return the help directory where HTML files are, or nil if that is unknown." 304 (let ((syshelp-dir (expand-file-name 305 idlwave-html-system-help-location (idlwave-sys-dir))) 306 (help-dir (or (and (stringp idlwave-html-help-location) 307 (> (length idlwave-html-help-location) 0) 308 idlwave-html-help-location) 309 (getenv "IDLWAVE_HELP_LOCATION")))) 310 (if (and syshelp-dir (file-directory-p syshelp-dir)) 311 syshelp-dir 312 (if help-dir 313 (progn 314 (setq help-dir (expand-file-name "idl_html_help" help-dir)) 315 (if (file-directory-p help-dir) help-dir)))))) 316 317(defvar idlwave-help-assistant-available nil) 318 319(defun idlwave-help-check-locations () 320 ;; Check help locations and assistant. 321 (let ((sys-dir (idlwave-sys-dir)) 322 (help-loc (idlwave-html-help-location))) 323 (if (or (not (file-directory-p sys-dir)) 324 (not help-loc) 325 (not (file-directory-p help-loc))) 326 (message 327 "HTML help location not found: try setting `idlwave-system-directory' and/or `idlwave-html-help-location'.")) 328 ;; see if we have the assistant 329 (when (and idlwave-help-use-assistant 330 (not (eq (idlwave-help-assistant-available) t))) 331 (message "Cannot locate IDL Assistant, enabling default browser.") 332 (setq idlwave-help-use-assistant nil) 333 (unless idlwave-help-browse-url-available 334 (error "browse-url is not available; install it or IDL Assistant to use HTML help."))))) 335 336 337(defvar idlwave-current-obj_new-class) 338(defvar idlwave-help-diagnostics) 339(defvar idlwave-experimental) 340(defvar idlwave-last-context-help-pos) 341(defun idlwave-do-context-help (&optional arg) 342 "Wrapper around the call to idlwave-context-help1. 343It collects and prints the diagnostics messages." 344 (let ((marker (list (current-buffer) (point))) 345 (idlwave-help-diagnostics nil)) 346 ;; Check for frame switching. When the command is invoked twice 347 ;; at the same position, we try to switch to the help frame 348 ;; FIXME: Frame switching works only on XEmacs 349 (if (and idlwave-experimental 350 (equal last-command this-command) 351 (equal idlwave-last-context-help-pos marker)) 352 (idlwave-help-select-help-frame) 353 ;; Do the real thing. 354 (setq idlwave-last-context-help-pos marker) 355 (idlwave-do-context-help1 arg) 356 (if idlwave-help-diagnostics 357 (message "%s" (mapconcat 'identity 358 (nreverse idlwave-help-diagnostics) 359 "; ")))))) 360 361(defvar idlwave-help-do-class-struct-tag nil) 362(defvar idlwave-structtag-struct-location) 363(defvar idlwave-help-do-struct-tag nil) 364(defvar idlwave-system-variables-alist) 365(defvar idlwave-executive-commands-alist) 366(defvar idlwave-system-class-info) 367(defun idlwave-do-context-help1 (&optional arg) 368 "The work-horse version of `idlwave-context-help', which see." 369 (save-excursion 370 (if (equal (char-after) ?/) 371 (forward-char 1) 372 (if (equal (char-before) ?=) 373 (backward-char 1))) 374 (let* ((idlwave-query-class nil) 375 (idlwave-force-class-query (equal arg '(4))) 376 (chars "a-zA-Z0-9_$.!") 377 (beg (save-excursion (skip-chars-backward chars) (point))) 378 (end (save-excursion (skip-chars-forward chars) (point))) 379 (this-word (buffer-substring-no-properties beg end)) 380 (st-ass (assoc-string this-word 381 idlwave-help-special-topic-words t)) 382 (classtag (and (string-match "self\\." this-word) 383 (< beg (- end 4)))) 384 (structtag (and (fboundp 'idlwave-complete-structure-tag) 385 (string-match "\\`\\([^.]+\\)\\." this-word) 386 (< beg (- end 4)))) 387 module keyword cw mod1 mod2 mod3) 388 (if (or arg 389 (and (not classtag) 390 (not structtag) 391 (not (member (string-to-char this-word) '(?! ?.))))) 392 ;; Need the module information 393 (progn 394 ;; MODULE is (name type class), for this or any inheriting class 395 (setq module (idlwave-what-module-find-class) 396 cw (nth 2 (idlwave-where))) ;what would we complete here? 397 ;; Correct for OBJ_NEW, we may need an INIT method instead. 398 (if (equal (idlwave-downcase-safe (car module)) "obj_new") 399 (let* ((bos (save-excursion (idlwave-beginning-of-statement) 400 (point))) 401 (str (buffer-substring bos (point)))) 402 (if (string-match "OBJ_NEW([ \t]*['\"]\\([a-zA-Z][a-zA-Z0-9$_]+\\)['\"]" str) 403 (setq module (list "init" 'fun (match-string 1 str)) 404 idlwave-current-obj_new-class (match-string 1 str)) 405 ))))) 406 (cond 407 (arg (setq mod1 module)) 408 409 ;; A special topic -- only system help 410 ((and st-ass (not (memq cw '(function-keyword procedure-keyword)))) 411 (setq mod1 (list (cdr st-ass)))) 412 413 ;; A system variable -- only system help 414 ((string-match 415 "\\`!\\([a-zA-Z0-9_]+\\)\\(\.\\([A-Za-z0-9_]+\\)\\)?" 416 this-word) 417 (let* ((word (match-string-no-properties 1 this-word)) 418 (entry (assq (idlwave-sintern-sysvar word) 419 idlwave-system-variables-alist)) 420 (tag (match-string-no-properties 3 this-word)) 421 (tag-target (if tag 422 (cdr 423 (assq (idlwave-sintern-sysvartag tag) 424 (cdr (assq 'tags entry)))))) 425 (link (nth 1 (assq 'link entry)))) 426 (if tag-target 427 (setq link (idlwave-substitute-link-target link 428 tag-target))) 429 (setq mod1 (list link)))) 430 431 ;; An executive command -- only system help 432 ((string-match "^\\.\\([A-Z_]+\\)" this-word) 433 (let* ((word (match-string 1 this-word)) 434 (link (cdr (assoc-string 435 word 436 idlwave-executive-commands-alist t)))) 437 (setq mod1 (list link)))) 438 439 ;; A class -- system OR in-text help (via class__define). 440 ((and (eq cw 'class) 441 (or (idlwave-in-quote) ; e.g. obj_new 442 (re-search-backward "\\<inherits[ \t]+[A-Za-z0-9_]*\\=" 443 (max (point-min) (- (point) 40)) t))) 444 ;; Class completion inside string delimiters must be 445 ;; the class inside OBJ_NEW. 446 (let* ((entry (assq 447 (idlwave-sintern-class this-word) 448 idlwave-system-class-info)) 449 (name (concat (downcase this-word) "__define")) 450 (link (nth 1 (assq 'link entry)))) 451 (setq mod1 (list link name 'pro)))) 452 453 ;; A class structure tag (self.BLAH) -- only in-text help available 454 (classtag 455 (let ((tag (substring this-word (match-end 0))) 456 class-with found-in) 457 (when (setq class-with 458 (idlwave-class-or-superclass-with-tag 459 (nth 2 (idlwave-current-routine)) 460 tag)) 461 (setq found-in (idlwave-class-found-in class-with)) 462 (if (assq (idlwave-sintern-class class-with) 463 idlwave-system-class-info) 464 (error "No help available for system class tags")) 465 (setq idlwave-help-do-class-struct-tag t) 466 (setq mod1 (list nil 467 (if found-in 468 (cons (concat found-in "__define") class-with) 469 (concat class-with "__define")) 470 'pro 471 nil ; no class.... it's a procedure! 472 tag))))) 473 474 ;; A regular structure tag -- only in text, and if 475 ;; optional `complete-structtag' loaded. 476 (structtag 477 (let ((var (match-string 1 this-word)) 478 (tag (substring this-word (match-end 0)))) 479 ;; Check if we need to update the "current" structure 480 (idlwave-prepare-structure-tag-completion var) 481 (setq idlwave-help-do-struct-tag 482 idlwave-structtag-struct-location 483 mod1 (list nil nil nil nil tag)))) 484 485 ;; A routine keyword -- in text or system help 486 ((and (memq cw '(function-keyword procedure-keyword)) 487 (stringp this-word) 488 (string-match "\\S-" this-word) 489 (not (string-match "!" this-word))) 490 (cond ((or (= (char-before beg) ?/) 491 (save-excursion (goto-char end) 492 (looking-at "[ \t]*="))) 493 ;; Certainly a keyword. Check for abbreviation etc. 494 (setq keyword (idlwave-expand-keyword this-word module)) 495 (cond 496 ((null keyword) 497 (idlwave-help-diagnostics 498 (format "%s does not accept `%s' kwd" 499 (idlwave-make-full-name (nth 2 module) 500 (car module)) 501 (upcase this-word)) 502 'ding)) 503 ((consp keyword) 504 (idlwave-help-diagnostics 505 (format "%d matches for kwd abbrev `%s'" 506 (length keyword) this-word) 507 'ding) 508 ;; We continue anyway with the first match... 509 (setq keyword (car keyword)))) 510 ;; Keyword, or just module 511 (setq mod1 (append (list t) module (list keyword))) 512 (setq mod2 (append (list t) module))) 513 ((equal (char-after end) ?\() 514 ;; A function - what-module will have caught this 515 (setq mod1 (append (list t) module))) 516 (t 517 ;; undecided - try function, keyword, then enclosing mod. 518 ;; Check for keyword abbreviations, but do not report 519 ;; errors, because it might be something else. 520 ;; FIXME: is this a good way to handle this? 521 (setq keyword (idlwave-expand-keyword this-word module)) 522 (if (consp keyword) (setq keyword (car keyword))) 523 (setq mod1 (append (list t) module (list keyword)) 524 mod2 (list t this-word 'fun nil) 525 mod3 (append (list t) module))))) 526 527 ;; Everything else 528 (t 529 (setq mod1 (append (list t) module)))) 530 (if mod3 531 (condition-case nil 532 (apply 'idlwave-online-help mod1) 533 (error (condition-case nil 534 (apply 'idlwave-online-help mod2) 535 (error (apply 'idlwave-online-help mod3))))) 536 (if mod2 537 (condition-case nil 538 (apply 'idlwave-online-help mod1) 539 (error (apply 'idlwave-online-help mod2))) 540 (if mod1 541 (apply 'idlwave-online-help mod1) 542 (error "Don't know which item to show help for"))))))) 543 544(defun idlwave-do-mouse-completion-help (ev) 545 "Display online help on an item in the *Completions* buffer. 546Needs additional info stored in global `idlwave-completion-help-info'." 547 (let* ((cw (selected-window)) 548 (info idlwave-completion-help-info) ; global passed in 549 (what (nth 0 info)) 550 (name (nth 1 info)) 551 (type (nth 2 info)) 552 (class (nth 3 info)) 553 (need-class class) 554 (kwd (nth 4 info)) 555 (sclasses (nth 5 info)) 556 word link) 557 (mouse-set-point ev) 558 559 560 ;; See if we can also find help somewhere, e.g. for multiple classes 561 (setq word (idlwave-this-word)) 562 (if (string= word "") 563 (error "No help item selected")) 564 (setq link (get-text-property 0 'link word)) 565 (select-window cw) 566 (cond 567 ;; Routine name 568 ((memq what '(procedure function routine)) 569 (setq name word) 570 (if (or (eq class t) 571 (and (stringp class) sclasses)) 572 (let* ((classes (idlwave-all-method-classes 573 (idlwave-sintern-method name) 574 type))) 575 (setq link t) ; No specific link valid yet 576 (if sclasses 577 (setq classes (idlwave-members-only 578 classes (cons class sclasses)))) 579 (setq class (idlwave-popup-select ev classes 580 "Select Class" 'sort)))) 581 582 ;; XXX is this necessary, given all-method-classes? 583 (if (stringp class) 584 (setq class (idlwave-find-inherited-class 585 (idlwave-sintern-routine-or-method name class) 586 type (idlwave-sintern-class class))))) 587 588 ;; Keyword 589 ((eq what 'keyword) 590 (setq kwd word) 591 (if (or (eq class t) 592 (and (stringp class) sclasses)) 593 (let ((classes (idlwave-all-method-keyword-classes 594 (idlwave-sintern-method name) 595 (idlwave-sintern-keyword kwd) 596 type))) 597 (setq link t) ; Link can't be correct yet 598 (if sclasses 599 (setq classes (idlwave-members-only 600 classes (cons class sclasses)))) 601 (setq class (idlwave-popup-select ev classes 602 "Select Class" 'sort)) 603 ;; XXX is this necessary, given all-method-keyword-classes? 604 (if (stringp class) 605 (setq class (idlwave-find-inherited-class 606 (idlwave-sintern-routine-or-method name class) 607 type (idlwave-sintern-class class))))) 608 (if (string= (downcase name) "obj_new") 609 (setq class idlwave-current-obj_new-class 610 name "Init")))) 611 612 ;; Class name 613 ((eq what 'class) 614 (setq class word 615 word nil)) 616 617 ;; A special named function to call which sets some of our variables 618 ((and (symbolp what) 619 (fboundp what)) 620 (funcall what 'set word)) 621 622 (t (error "Cannot help with this item"))) 623 (if (and need-class (not class) (not (and link (not (eq link t))))) 624 (error "Cannot help with this item")) 625 (idlwave-online-help link (or name word) type class kwd))) 626 627(defvar idlwave-highlight-help-links-in-completion) 628(defvar idlwave-completion-help-links) 629(defun idlwave-highlight-linked-completions () 630 "Highlight all completions for which help is available and attach link. 631Those words in `idlwave-completion-help-links' have links. The 632`idlwave-help-link' face is used for this." 633 (if idlwave-highlight-help-links-in-completion 634 (with-current-buffer (get-buffer "*Completions*") 635 (save-excursion 636 (let* ((case-fold-search t) 637 (props (list 'face 'idlwave-help-link)) 638 (info idlwave-completion-help-info) ; global passed in 639 (what (nth 0 info)) ; what was completed, or a func 640 (class (nth 3 info)) ; any class 641 word beg end doit) 642 (goto-char (point-min)) 643 (re-search-forward "possible completions are:" nil t) 644 (while (re-search-forward "\\s-\\([A-Za-z0-9_.]+\\)\\(\\s-\\|\\'\\)" 645 nil t) 646 (setq beg (match-beginning 1) end (match-end 1) 647 word (match-string 1) doit nil) 648 ;; Call special completion function test 649 (if (and (symbolp what) 650 (fboundp what)) 651 (setq doit (funcall what 'test word)) 652 ;; Look for special link property passed in help-links 653 (if idlwave-completion-help-links 654 (setq doit (assoc-string 655 word idlwave-completion-help-links t)))) 656 (when doit 657 (if (consp doit) 658 (setq props (append props `(link ,(cdr doit))))) 659 (let ((buffer-read-only nil)) 660 (add-text-properties beg end props))) 661 (goto-char end))))))) 662 663;; Arrange for this function to be called after completion 664(add-hook 'idlwave-completion-setup-hook 665 'idlwave-highlight-linked-completions) 666 667(defvar idlwave-help-return-frame nil 668 "The frame to return to from the help frame.") 669 670(defun idlwave-help-quit () 671 "Exit IDLWAVE Help buffer. Kill the dedicated frame if any." 672 (interactive) 673 (cond ((and idlwave-help-use-dedicated-frame 674 (eq (selected-frame) idlwave-help-frame)) 675 (if (and idlwave-experimental 676 (frame-live-p idlwave-help-return-frame)) 677 ;; Try to select the return frame. 678 ;; This can crash on slow network connections, obviously when 679 ;; we kill the help frame before the return-frame is selected. 680 ;; To protect the workings, we wait for up to one second 681 ;; and check if the return-frame *is* now selected. 682 ;; This is marked "eperimental" since we are not sure when its OK. 683 (let ((maxtime 1.0) (time 0.) (step 0.1)) 684 (select-frame idlwave-help-return-frame) 685 (while (and (sit-for step) 686 (not (eq (selected-frame) 687 idlwave-help-return-frame)) 688 (< (setq time (+ time step)) maxtime))))) 689 (delete-frame idlwave-help-frame)) 690 ((window-configuration-p idlwave-help-window-configuration) 691 (set-window-configuration idlwave-help-window-configuration) 692 (select-window (previous-window))) 693 (t (kill-buffer (idlwave-help-get-help-buffer))))) 694 695 696(defvar default-toolbar-visible-p) 697 698(defun idlwave-help-display-help-window (&optional pos-or-func) 699 "Display the help window. 700Move window start to POS-OR-FUNC, if passed as a position, or call it 701if passed as a function. See `idlwave-help-use-dedicated-frame'." 702 (let ((cw (selected-window)) 703 (buf (idlwave-help-get-help-buffer))) 704 (if (and window-system idlwave-help-use-dedicated-frame) 705 (progn 706 (idlwave-help-show-help-frame) 707 (switch-to-buffer buf)) 708 ;; Do it in this frame and save the window configuration 709 (if (not (get-buffer-window buf nil)) 710 (setq idlwave-help-window-configuration 711 (current-window-configuration))) 712 (display-buffer buf nil (selected-frame)) 713 (select-window (get-buffer-window buf))) 714 (raise-frame) 715 (if pos-or-func 716 (if (functionp pos-or-func) 717 (funcall pos-or-func) 718 (goto-char pos-or-func) 719 (recenter 0))) 720 (select-window cw))) 721 722(defun idlwave-help-select-help-frame () 723 "Select the help frame." 724 (if (and (frame-live-p idlwave-help-frame) 725 (not (eq (selected-frame) idlwave-help-frame))) 726 (progn 727 (setq idlwave-help-return-frame (selected-frame)) 728 (select-frame idlwave-help-frame)))) 729 730(defun idlwave-help-return-to-calling-frame () 731 "Select the frame from which the help frame was selected." 732 (interactive) 733 (if (and (frame-live-p idlwave-help-return-frame) 734 (not (eq (selected-frame) idlwave-help-return-frame))) 735 (select-frame idlwave-help-return-frame))) 736 737(defun idlwave-online-help (link &optional name type class keyword) 738 "Display HTML or other special help on a certain topic. 739Either loads an HTML link, if LINK is non-nil, or gets special-help on 740the optional arguments, if any special help is defined. If LINK is 741`t', first look up the optional arguments in the routine info list to 742see if a link is set for it. Try extra help functions if necessary." 743 ;; Lookup link 744 (if (eq link t) 745 (let ((entry (idlwave-best-rinfo-assoc name type class 746 (idlwave-routines) nil t))) 747 (if entry 748 (cond 749 ;; Try keyword link 750 ((and keyword 751 (setq link (cdr 752 (idlwave-entry-find-keyword entry keyword))))) 753 ;; Default, regular entry link 754 (t (setq link (idlwave-entry-has-help entry)))) 755 (if (and 756 class 757 ;; Check for system class help 758 (setq entry (assq (idlwave-sintern-class class) 759 idlwave-system-class-info) 760 link (nth 1 (assq 'link entry)))) 761 (message 762 (concat "No routine info for %s" 763 ", falling back on class help.") 764 (idlwave-make-full-name class name)))))) 765 766 (cond 767 ;; An explicit link 768 ((stringp link) 769 (idlwave-help-html-link link)) 770 771 ;; Any extra help 772 (idlwave-extra-help-function 773 (idlwave-help-get-special-help name type class keyword)) 774 775 ;; Nothing worked 776 (t (idlwave-help-error name type class keyword)))) 777 778 779(defun idlwave-help-get-special-help (name type class keyword) 780 "Call the function given by `idlwave-extra-help-function'." 781 (let* ((cw (selected-window)) 782 (help-pos (save-excursion 783 (set-buffer (idlwave-help-get-help-buffer)) 784 (let ((buffer-read-only nil)) 785 (funcall idlwave-extra-help-function 786 name type class keyword))))) 787 (if help-pos 788 (idlwave-help-display-help-window help-pos) 789 (idlwave-help-error name type class keyword)) 790 (select-window cw))) 791 792(defun idlwave-help-html-link (link) 793 "Get html help on a given LINK." 794 (let ((browse-url-browser-function idlwave-help-browser-function) 795 (help-loc (idlwave-html-help-location)) 796 (browse-url-generic-program idlwave-help-browser-generic-program) 797 ;(browse-url-generic-args idlwave-help-browser-generic-args) 798 full-link) 799 800 ;; Just a regular file name (+ anchor name) 801 (unless (and (stringp help-loc) 802 (file-directory-p help-loc)) 803 (error "Invalid help location.")) 804 (setq full-link (browse-url-file-url (expand-file-name link help-loc))) 805 806 ;; Select the browser 807 (cond 808 (idlwave-help-use-assistant 809 (idlwave-help-assistant-open-link link)) 810 811 ((or idlwave-help-browser-is-local 812 (string-match "w3" (symbol-name idlwave-help-browser-function))) 813 (idlwave-help-display-help-window '(lambda () (browse-url full-link)))) 814 815 (t (browse-url full-link))))) 816 817;; A special help routine for source-level syntax help in files. 818(defvar idlwave-help-fontify-source-code) 819(defvar idlwave-help-source-try-header) 820(defvar idlwave-current-tags-buffer) 821(defvar idlwave-current-tags-class) 822(defun idlwave-help-with-source (name type class keyword) 823 "Provide help for routines not documented in the IDL manuals. Works 824by loading the routine source file into the help buffer. Depending on 825the value of `idlwave-help-source-try-header', it attempts to show the 826routine definition or the header description. If 827`idlwave-help-do-class-struct-tag' is non-nil, keyword is a tag to 828show help on from the class definition structure. If 829`idlwave-help-do-struct-tag' is non-nil, show help from the matching 830structure tag definition. 831 832This function can be used as `idlwave-extra-help-function'." 833 (let* ((class-struct-tag idlwave-help-do-class-struct-tag) 834 (struct-tag idlwave-help-do-struct-tag) 835 (case-fold-search t) 836 (real-class (if (consp name) (cdr name))) 837 (name (if (consp name) (car name) name)) 838 (class-only (and (stringp class) (not (stringp name)))) 839 file header-pos def-pos in-buf) 840 (if class-only ;Help with class? Using "Init" as source. 841 (setq name "Init" 842 type 'fun)) 843 (if (not struct-tag) 844 (setq file 845 (idlwave-routine-source-file 846 (nth 3 (idlwave-best-rinfo-assoc 847 name (or type t) class (idlwave-routines)))))) 848 (setq idlwave-help-def-pos nil 849 idlwave-help-args (list name type class keyword) 850 idlwave-help-in-header nil 851 idlwave-help-do-struct-tag nil 852 idlwave-help-do-class-struct-tag nil) 853 (if (or struct-tag (stringp file)) 854 (progn 855 (setq in-buf ; structure-tag completion is always in current buffer 856 (if struct-tag 857 idlwave-current-tags-buffer 858 (idlwave-get-buffer-visiting file))) 859 ;; see if file is in a visited buffer, insert those contents 860 (if in-buf 861 (progn 862 (setq file (buffer-file-name in-buf)) 863 (erase-buffer) 864 (insert-buffer-substring in-buf)) 865 (if (file-exists-p file) ;; otherwise just load the file 866 (progn 867 (erase-buffer) 868 (insert-file-contents file nil nil nil 'replace)) 869 (idlwave-help-error name type class keyword))) 870 (goto-char (point-min)) 871 (if (and idlwave-help-fontify-source-code (not in-buf)) 872 (idlwave-help-fontify))) 873 (idlwave-help-error name type class keyword)) 874 (setq idlwave-help-mode-line-indicator file) 875 876 ;; Try to find a good place to display 877 (setq def-pos 878 ;; Find the class structure tag if that's what we're after 879 (cond 880 ;; Class structure tags: find the class or named structure 881 ;; definition 882 (class-struct-tag 883 (save-excursion 884 (setq class 885 (if (string-match "[a-zA-Z0-9]\\(__\\)" name) 886 (substring name 0 (match-beginning 1)) 887 idlwave-current-tags-class)) 888 (and 889 (idlwave-find-class-definition class nil real-class) 890 (idlwave-find-struct-tag keyword)))) 891 892 ;; Generic structure tags: the structure definition 893 ;; location within the file has been recorded in 894 ;; `struct-tag' 895 (struct-tag 896 (save-excursion 897 (and 898 (integerp struct-tag) 899 (goto-char struct-tag) 900 (idlwave-find-struct-tag keyword)))) 901 902 ;; Just find the routine definition 903 (t 904 (if class-only (point-min) 905 (idlwave-help-find-routine-definition name type class keyword)))) 906 idlwave-help-def-pos def-pos) 907 908 (if (and idlwave-help-source-try-header 909 (not (or struct-tag class-struct-tag))) 910 ;; Check if we can find the header 911 (save-excursion 912 (goto-char (or def-pos (point-max))) 913 (setq header-pos (idlwave-help-find-in-doc-header 914 name type class keyword 'exact) 915 idlwave-help-in-header header-pos))) 916 917 (if (or header-pos def-pos) 918 (progn 919 (if (boundp 'idlwave-help-min-frame-width) 920 (setq idlwave-help-min-frame-width 80)) 921 (goto-char (or header-pos def-pos))) 922 (idlwave-help-error name type class keyword)) 923 924 (point))) 925 926 927(defun idlwave-help-find-routine-definition (name type class keyword) 928 "Find the definition of routine CLASS::NAME in current buffer. 929KEYWORD is ignored. Returns the point of match if successful, nil otherwise." 930 (save-excursion 931 (goto-char (point-max)) 932 (if (re-search-backward 933 (concat "^[ \t]*" 934 (if (eq type 'pro) "pro" 935 (if (eq type 'fun) "function" 936 "\\(pro\\|function\\)")) 937 "[ \t]+" 938 (regexp-quote (downcase (idlwave-make-full-name class name))) 939 "[, \t\r\n]") 940 nil t) 941 (match-beginning 0) 942 nil))) 943 944(defvar idlwave-doclib-start) 945(defvar idlwave-doclib-end) 946(defun idlwave-help-find-in-doc-header (name type class keyword 947 &optional exact) 948 "Find the requested help in the doc-header above point. 949 950First checks if there is a doc-lib header which describes the correct 951routine. Then tries to find the KEYWORDS section and the KEYWORD, if 952given. Returns the point which should be window start of the help 953window. If EXACT is non-nil, the full help position must be found - 954down to the keyword requested. This setting is for context help, if 955the exact spot is needed. 956 957If EXACT is nil, the position of the header is returned if it 958describes the correct routine - even if the keyword description cannot 959be found. TYPE is ignored. 960 961This function expects a more or less standard routine header. In 962particlar it looks for the `NAME:' tag, either with a colon, or alone 963on a line. Then `NAME:' must be followed by the routine name on the 964same or the next line. When KEYWORD is non-nil, looks first for a 965`KEYWORDS' section. It is amazing how inconsisten this is through 966some IDL libraries I have seen. We settle for a line containing an 967upper case \"KEYWORD\" string. If this line is not fould we search 968for the keyword anyway to increase the hit-rate 969 970When one of these sections exists we check for a line starting with any of 971 972 /KEYWORD KEYWORD- KEYWORD= KEYWORD 973 974with spaces allowed between the keyword and the following dash or equal sign. 975If there is a match, we assume it is the keyword description." 976 (let* ((case-fold-search t) 977 (rname (if (stringp class) 978 (concat 979 "\\(" 980 ;; Traditional name or class::name 981 "\\(" 982 "\\(" (regexp-quote (downcase class)) "::\\)?" 983 (regexp-quote (downcase name)) 984 "\\>\\)" 985 (concat 986 "\\|" 987 ;; class__define or just class 988 (regexp-quote (downcase class)) "\\(__define\\)?") 989 "\\)") 990 (regexp-quote (downcase name)))) 991 992 ;; NAME tag plus the routine name. The new version is from JD. 993 (name-re (concat 994 "\\(^;+\\*?[ \t]*" 995 idlwave-help-doclib-name 996 "\\([ \t]*:\\|[ \t]*$\\)[ \t]*\\(\n;+[ \t]*\\)*" 997 rname 998 "\\|" 999 "^;+[ \t]*" 1000 rname 1001 ":[ \t]*$\\)")) 1002 1003 ;; Header start plus name 1004 (header-re (concat "\\(" idlwave-doclib-start "\\).*\n" 1005 "\\(^;+.*\n\\)*" 1006 "\\(" name-re "\\)")) 1007 ;; A keywords section 1008 (kwds-re (concat ; forgiving 1009 "^;+\\*?[ \t]*" 1010 "\\([-A-Z_ ]*" 1011 idlwave-help-doclib-keyword 1012 "[-A-Z_ ]*\\)" 1013 "\\(:\\|[ \t]*\n\\)")) 1014 1015 ;; The individual keyword description line. 1016 (kwd-re (if keyword ; hard (well...) 1017 (concat 1018 "^;+[ \t]+" 1019 "\\(/" (regexp-quote (upcase keyword)) 1020 "\\|" (regexp-quote (upcase keyword)) "[ \t]*[-=:\n]" 1021 "\\)"))) 1022 (kwd-re2 (if keyword ; forgiving 1023 (concat 1024 "^;+[ \t]+" 1025 (regexp-quote (upcase keyword)) 1026 "\\>"))) 1027 dstart dend name-pos kwds-pos kwd-pos) 1028 (catch 'exit 1029 (save-excursion 1030 (goto-char (point-min)) 1031 (while (and (setq dstart (re-search-forward idlwave-doclib-start nil t)) 1032 (setq dend (re-search-forward idlwave-doclib-end nil t))) 1033 ;; found a routine header 1034 (goto-char dstart) 1035 (if (setq name-pos (re-search-forward name-re dend t)) 1036 (progn 1037 (if keyword 1038 ;; We do need a keyword 1039 (progn 1040 ;; Try to find a keyword section, but don't force it. 1041 (goto-char name-pos) 1042 (if (let ((case-fold-search nil)) 1043 (re-search-forward kwds-re dend t)) 1044 (setq kwds-pos (match-beginning 0))) 1045 ;; Find the keyword description 1046 (if (or (let ((case-fold-search nil)) 1047 (re-search-forward kwd-re dend t)) 1048 (re-search-forward kwd-re dend t) 1049 (let ((case-fold-search nil)) 1050 (re-search-forward kwd-re2 dend t)) 1051 (re-search-forward kwd-re2 dend t)) 1052 (setq kwd-pos (match-beginning 0)) 1053 (if exact 1054 (progn 1055 (idlwave-help-diagnostics 1056 (format "Could not find description of kwd %s" 1057 (upcase keyword))) 1058 (throw 'exit nil)))))) 1059 ;; Return the best position we got 1060 (throw 'exit (or kwd-pos kwds-pos name-pos dstart))) 1061 (goto-char dend)))) 1062 (idlwave-help-diagnostics "Could not find doclib header") 1063 (throw 'exit nil)))) 1064 1065(defun idlwave-help-diagnostics (string &optional ding) 1066 "Add a diagnostics string to the list. 1067When DING is non-nil, ring the bell as well." 1068 (if (boundp 'idlwave-help-diagnostics) 1069 (progn 1070 (setq idlwave-help-diagnostics 1071 (cons string idlwave-help-diagnostics)) 1072 (if ding (ding))))) 1073 1074(defun idlwave-help-toggle-header-top-and-def (arg) 1075 (interactive "P") 1076 (let (pos) 1077 (if idlwave-help-in-header 1078 ;; Header was the last thing displayed 1079 (progn 1080 (setq idlwave-help-in-header nil) 1081 (setq pos idlwave-help-def-pos)) 1082 ;; Try to display header 1083 (setq pos (idlwave-help-find-in-doc-header 1084 (nth 0 idlwave-help-args) 1085 (nth 1 idlwave-help-args) 1086 (nth 2 idlwave-help-args) 1087 nil)) 1088 (if pos 1089 (setq idlwave-help-in-header t) 1090 (error "Cannot find doclib header for routine %s" 1091 (idlwave-make-full-name (nth 2 idlwave-help-args) 1092 (nth 0 idlwave-help-args))))) 1093 (if pos 1094 (progn 1095 (goto-char pos) 1096 (recenter 0))))) 1097 1098(defun idlwave-help-find-first-header (arg) 1099 (interactive "P") 1100 (let (pos) 1101 (save-excursion 1102 (goto-char (point-min)) 1103 (if (re-search-forward idlwave-doclib-start nil t) 1104 (setq pos (match-beginning 0)))) 1105 (if pos 1106 (progn 1107 (goto-char pos) 1108 (recenter 0)) 1109 (error "No DocLib Header in current file")))) 1110 1111(defun idlwave-help-find-header (arg) 1112 "Jump to the DocLib Header." 1113 (interactive "P") 1114 (if arg 1115 (idlwave-help-find-first-header nil) 1116 (setq idlwave-help-in-header nil) 1117 (idlwave-help-toggle-header-match-and-def arg 'top))) 1118 1119(defun idlwave-help-toggle-header-match-and-def (arg &optional top) 1120 (interactive "P") 1121 (let ((args idlwave-help-args) 1122 pos) 1123 (if idlwave-help-in-header 1124 ;; Header was the last thing displayed 1125 (progn 1126 (setq idlwave-help-in-header nil) 1127 (setq pos idlwave-help-def-pos)) 1128 ;; Try to display header 1129 (setq pos (apply 'idlwave-help-find-in-doc-header 1130 (if top 1131 (list (car args) (nth 1 args) (nth 2 args) nil) 1132 args))) 1133 (if pos 1134 (setq idlwave-help-in-header t) 1135 (error "Cannot find doclib header for routine %s" 1136 (idlwave-make-full-name (nth 2 idlwave-help-args) 1137 (nth 0 idlwave-help-args))))) 1138 (if pos 1139 (progn 1140 (goto-char pos) 1141 (recenter 0))))) 1142 1143(defvar font-lock-verbose) 1144(defvar idlwave-mode-syntax-table) 1145(defvar idlwave-font-lock-defaults) 1146(defun idlwave-help-fontify () 1147 "Fontify the Help buffer as source code. 1148Useful when source code is displayed as help. See the option 1149`idlwave-help-fontify-source-code'." 1150 (interactive) 1151 (if (featurep 'font-lock) 1152 (let ((major-mode 'idlwave-mode) 1153 (font-lock-verbose 1154 (if (interactive-p) font-lock-verbose nil)) 1155 (syntax-table (syntax-table))) 1156 (unwind-protect 1157 (progn 1158 (set-syntax-table idlwave-mode-syntax-table) 1159 (set (make-local-variable 'font-lock-defaults) 1160 idlwave-font-lock-defaults) 1161 (font-lock-fontify-buffer)) 1162 (set-syntax-table syntax-table))))) 1163 1164 1165(defun idlwave-help-error (name type class keyword) 1166 (error "Can't find help on %s%s %s" 1167 (or (and (or class name) (idlwave-make-full-name class name)) 1168 "<unknown>") 1169 (if keyword (format ", keyword %s" (upcase keyword)) "") 1170 (if idlwave-html-help-location 1171 "" 1172 "(help location unknown)"))) 1173 1174(defun idlwave-help-show-help-frame () 1175 "Show the help frame, creating it if necessary" 1176 ;; Use a special frame for this 1177 (unless (frame-live-p idlwave-help-frame) 1178 (setq idlwave-help-frame 1179 (make-frame idlwave-help-frame-parameters)) 1180 ;; Strip menubar (?) and toolbar from the Help frame. 1181 (if (fboundp 'set-specifier) 1182 (progn 1183 ;; XEmacs 1184 (let ((sval (cons idlwave-help-frame nil))) 1185 ;; (set-specifier menubar-visible-p sval) 1186 (set-specifier default-toolbar-visible-p sval))) 1187 ;; Emacs 1188 (modify-frame-parameters idlwave-help-frame 1189 '(;;(menu-bar-lines . 0) 1190 (tool-bar-lines . 0))))) 1191 (select-frame idlwave-help-frame)) 1192 1193(defun idlwave-help-get-help-buffer () 1194 "Return the IDLWAVE Help buffer. Make it first if necessary." 1195 (let ((buf (get-buffer "*IDLWAVE Help*"))) 1196 (if buf 1197 nil 1198 (setq buf (get-buffer-create "*IDLWAVE Help*")) 1199 (save-excursion 1200 (set-buffer buf) 1201 (idlwave-help-mode))) 1202 buf)) 1203 1204(defun idlwave-grep (regexp list) 1205 (let (rtn) 1206 (while list 1207 (if (string-match regexp (car list)) 1208 (setq rtn (cons (car list) rtn))) 1209 (setq list (cdr list))) 1210 (nreverse rtn))) 1211 1212(defun idlwave-entry-has-help (entry) 1213 (and entry (car (nth 5 entry)))) 1214 1215(defun idlwave-has-help (name type class) 1216 "Does this have help associated with it?" 1217 (let ((entry (idlwave-best-rinfo-assoc name type class (idlwave-routines)))) 1218 (idlwave-entry-has-help entry))) 1219 1220;;----- Control the IDL Assistant, which shipped with IDL v6.2 1221(defvar idlwave-help-assistant-process nil) 1222(defvar idlwave-help-assistant-socket nil) 1223 1224;; The Windows version does not have a !DIR/bin/* set of front-end 1225;; scripts, but instead only links directly to bin.x86. As a result, 1226;; we must pass the -profile argument as well. 1227(defvar idlwave-help-assistant-command 1228 (if (memq system-type '(ms-dos windows-nt)) 1229 "bin/bin.x86/idl_assistant.exe" 1230 "bin/idl_assistant") 1231 "The command, rooted at idlwave-system-directory, which invokes the 1232IDL assistant.") 1233 1234(defun idlwave-help-assistant-available () 1235 (if idlwave-help-assistant-available 1236 (eq idlwave-help-assistant-available t) 1237 (setq idlwave-help-assistant-available 1238 (if (file-executable-p (idlwave-help-assistant-command)) 1239 t 1240 'not-available)))) 1241 1242(defun idlwave-help-assistant-command () 1243 (expand-file-name idlwave-help-assistant-command (idlwave-sys-dir))) 1244 1245(defun idlwave-help-assistant-start (&optional full-link) 1246 "Start the IDL Assistant, loading link FULL-LINK, if passed." 1247 (when (or (not idlwave-help-assistant-socket) 1248 (not (eq (process-status idlwave-help-assistant-socket) 'open))) 1249 (let* ((help-loc (idlwave-html-help-location)) 1250 (command (idlwave-help-assistant-command)) 1251 (extra-args 1252 (nconc 1253 (if (memq system-type '(ms-dos windows-nt)) 1254 `("-profile" ,(expand-file-name "idl.adp" help-loc))) 1255 (if full-link `("-file" ,full-link)))) 1256 port) 1257 (if idlwave-help-assistant-socket 1258 (delete-process idlwave-help-assistant-socket)) 1259 1260 (setq idlwave-help-assistant-process 1261 (apply 'start-process 1262 "IDL_ASSISTANT_PROC" nil command "-server" extra-args)) 1263 1264 (set-process-filter idlwave-help-assistant-process 1265 (lambda (proc string) 1266 (setq port (string-to-number string)))) 1267 (unless (accept-process-output idlwave-help-assistant-process 15) 1268 (error "Failed binding IDL_ASSISTANT socket")) 1269 (if (not port) 1270 (error "Unable to open IDL_ASSISTANT.") 1271 (set-process-filter idlwave-help-assistant-process nil) 1272 (setq idlwave-help-assistant-socket 1273 (open-network-stream "IDL_ASSISTANT_SOCK" 1274 nil "localhost" port)) 1275 (if (eq (process-status idlwave-help-assistant-socket) 'open) 1276 (progn 1277 (process-send-string idlwave-help-assistant-socket 1278 (concat "setHelpPath " help-loc "\n")) 1279 t) 1280 (idlwave-help-assistant-close) 1281 (error "Cannot communicate with IDL_ASSISTANT")))))) 1282 1283(defun idlwave-help-assistant-raise () 1284 (idlwave-help-assistant-start) 1285 (process-send-string idlwave-help-assistant-socket "raise\n")) 1286 1287(defun idlwave-help-assistant-open-link (&optional link) 1288 ;; Open a link (file name with anchor, no leading path) in the assistant. 1289 (let ((help-loc (idlwave-html-help-location)) 1290 topic anchor file just-started exists full-link) 1291 1292 (if (string-match "\.html" link) 1293 (setq topic (substring link 0 (match-beginning 0)) 1294 anchor (substring link (match-end 0))) 1295 (error "Malformed help link.")) 1296 1297 (setq file (expand-file-name (concat topic ".html") help-loc)) 1298 (if (file-exists-p file) 1299 (setq exists t) 1300 (setq file (expand-file-name 1301 (concat (upcase topic) ".html") help-loc)) 1302 (setq exists (file-exists-p file))) 1303 1304 (setq full-link (concat file anchor) 1305 just-started (idlwave-help-assistant-start (if exists full-link))) 1306 (if exists 1307 (progn 1308 (if (not just-started) 1309 (process-send-string idlwave-help-assistant-socket 1310 (concat "openLink " full-link "\n"))) 1311 (process-send-string idlwave-help-assistant-socket 1312 (concat "searchIndexNoOpen " topic "\n"))) 1313 (process-send-string idlwave-help-assistant-socket 1314 (concat "searchIndexAndOpen " topic "\n")))) 1315 (idlwave-help-assistant-raise)) 1316 1317(defvar idlwave-help-assistant-help-with-topic-history nil 1318 "The history of help topics selected with the minibuffer.") 1319 1320(defun idlwave-help-assistant-help-with-topic (&optional topic) 1321 "Prompt for and provide help with TOPIC." 1322 (interactive) 1323 (let (list) 1324 (unless topic 1325 (idlwave-routines) 1326 (setq list (append (mapcar (lambda (x) 1327 (concat (nth 2 x) (car x))) 1328 idlwave-system-routines) 1329 (mapcar (lambda (x) 1330 (concat "." (car x))) 1331 idlwave-executive-commands-alist) 1332 idlwave-system-class-info)) 1333 (setq topic 1334 (idlwave-completing-read 1335 "Help Topic: " list 1336 nil nil nil 1337 'idlwave-help-assistant-help-with-topic-history))) 1338 (if (and topic (not (string= topic ""))) 1339 (idlwave-help-assistant-open-link (concat topic ".html"))))) 1340 1341(defun idlwave-help-assistant-close () 1342 (when (and idlwave-help-assistant-process 1343 (eq (process-status idlwave-help-assistant-process) 'run)) 1344 (when idlwave-help-assistant-socket 1345 (process-send-string idlwave-help-assistant-socket "quit\n") 1346 (delete-process idlwave-help-assistant-socket)) 1347 (stop-process idlwave-help-assistant-process) 1348 (delete-process idlwave-help-assistant-process) 1349 (setq idlwave-help-assistant-socket nil 1350 idlwave-help-assistant-process nil))) 1351 1352 1353(provide 'idlw-help) 1354(provide 'idlwave-help) 1355 1356;; arch-tag: d27b5505-59de-497f-ba3f-f199fd4fb911 1357;;; idlw-help.el ends here 1358