;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Major mode for editing PoVray scene Files ;; ;; NOTE: To achieve any sort of reasonable performance, YOU MUST ;; byte-compile this package. In emacs, type M-x byte-compile ;; and then enter the name of this file. ;; ;; Only tested on Emacs 19 and XEmacs 19. Let me know about ;; any compatibility problems. ;; ;; Modifief by: Jerome Berger ;; 4/19/00: ;; Added support for MegaPov 0.4 ;; 5/12/99: ;; Added support for Pov 3.1 fontification ;; Note that I didn't add support for completion ;; Modified by: Peter Boettcher ;; 5/8/97: ;; Added font-lock support for Emacs/XEmacs 19 ;; Indent under `#declare Object=' lines ;; Corrected comment syntax ;; Got rid of more remnants from postscript mode ;; General cleanup ;; Arbitrarily chose version 1.2 ;; 5/8/97: Version 1.21 ;; fontify-insanely was ignored. fixed. ;; ;; 9/24/97: Version 1.3 ;; Added indentation for Pov 3 syntax (#if #else, etc) ;; Preliminary context-sensitive keyword completion ;; ;; Original Author: Kevin O. Grover ;; Cre Date: 04 March 1994 ;; This file derived from postscript mode by Chris Maio ;; ;; ;; Please send bug reports/comments/suggestions to me at ;; pwb@andrew.cmu.edu ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The following two statements, placed in your .emacs file or site-init.el, ;; will cause this file to be autoloaded, and pov-mode invoked, when ;; visiting .pov files: ;; ;; (autoload 'pov-mode "pov-mode.el" "PoVray scene file mode" t) ;; (setq auto-mode-alist ;; (cons '("\\.pov$" . pov-mode) auto-mode-alist) ;; (cons '("\\.inc$" . pov-mode) auto-mode-alist)) ;; ;; Use this to turn on font-lock: ;; (add-hook 'pov-mode-hook 'turn-on-font-lock) ;;;;;;;;;;;;;;;;;;;; ;; These variables can be set in your .emacs (defaults given): ;; (setq pov-indent-level '2) ;; (setq pov-autoindent-endblocks t) Automatically reindents else/end/break ;; (setq pov-indent-under-declare '2) Try it! Tell me if you like it... ;; (setq pov-fontify-insanely t) When it's non-nil, we fontify *every* ;; Povray keyword. Careful! ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; TODO list: ;; Link to povray documentation ;; Vector operations (add <0, .5, 1> to every vector in region) ;; Clean up completion code ;; Do something smarter than the default for compilation mode ;; TAGS, to jump to #declared objects elsewhere in the code ;; ;; Feel free to do any of this and send me code :) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (provide 'pov-mode) (defconst pov-mode-version '1.3.1) (defvar pov-indent-level 2 "*Indentation to be used inside of PoVray blocks or arrays") (defvar pov-autoindent-endblocks t "*When non-nil, automatically reindents when you type break, end, or else") (defvar pov-indent-under-declare 2 "*Indentation under a `#declare Object=' line") (defvar pov-fontify-insanely t "*Non-nil means colorize every povray keyword. This may take a while on lare files. Maybe disable this on slow systems.") (defconst pov-tab-width 8 "*Tab stop width for PoV mode") (defun pov-make-tabs (stop) (and (< stop 132) (cons stop (pov-make-tabs (+ stop pov-tab-width))))) (defconst pov-tab-stop-list (pov-make-tabs pov-tab-width) "Tab stop list for PoV mode") (defconst pov-command "povray -" "Command used to invoke the povray program.") (defvar pov-mode-map nil "Keymap used in PoV mode buffers") (defvar pov-mode-syntax-table nil "PoV mode syntax table") (defconst pov-comment-start-regexp "//\\|/\\*" "Dual comment value for `comment-start-regexp'.") (defvar pov-comment-syntax-string ". 124b" "PoV hack to handle Emacs/XEmacs foo") (defvar pov-begin-re "\\<#\\(if\\(n?def\\)?\\|case\\|macro\\|range\\|switch\\|while\\)\\>") (defvar pov-end-re "\\<#break\\|#end\\>") (defvar pov-else-re "\\<#else\\>") (defvar pov-begin-end-re (concat pov-begin-re "\\|" pov-end-re "\\|" pov-else-re)) (defun pov-setup-syntax-table nil (if (or (string-match "Lucid" emacs-version) (string-match "XEmacs" emacs-version)) (setq pov-comment-syntax-string ". 1456")) (if pov-mode-syntax-table () (setq pov-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?_ "w" pov-mode-syntax-table) (modify-syntax-entry ?# "w" pov-mode-syntax-table) (modify-syntax-entry ?/ pov-comment-syntax-string pov-mode-syntax-table) (modify-syntax-entry ?* ". 23" pov-mode-syntax-table) (modify-syntax-entry ?\n "> b" pov-mode-syntax-table) (modify-syntax-entry ?< "." pov-mode-syntax-table) (modify-syntax-entry ?> "." pov-mode-syntax-table) (modify-syntax-entry ?= "." pov-mode-syntax-table) (modify-syntax-entry ?+ "." pov-mode-syntax-table) (modify-syntax-entry ?- "." pov-mode-syntax-table) (modify-syntax-entry ?. "w" pov-mode-syntax-table) (set-syntax-table pov-mode-syntax-table))) ; Huge regexp for pov-keyword hilighting. Organized alphabetically. Try ; to read at your own risk! (defconst pov-a-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-b-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-c-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-d-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-e-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-f-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-g-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-h-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-i-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-j-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-k-keywords-matcher nil) (defconst pov-l-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-m-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-n-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-o-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-p-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-q-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-r-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-s-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-t-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-u-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-v-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-w-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-x-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-y-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-z-keywords-matcher '("\\" . font-lock-keyword-face)) (defconst pov-all-keyword-matcher (list pov-a-keywords-matcher pov-b-keywords-matcher pov-c-keywords-matcher pov-d-keywords-matcher pov-e-keywords-matcher pov-f-keywords-matcher pov-g-keywords-matcher pov-h-keywords-matcher pov-i-keywords-matcher pov-j-keywords-matcher ;;pov-k-keywords-matcher pov-l-keywords-matcher pov-m-keywords-matcher pov-n-keywords-matcher pov-o-keywords-matcher pov-p-keywords-matcher pov-q-keywords-matcher pov-r-keywords-matcher pov-s-keywords-matcher pov-t-keywords-matcher pov-u-keywords-matcher pov-v-keywords-matcher pov-w-keywords-matcher pov-x-keywords-matcher pov-y-keywords-matcher pov-z-keywords-matcher)) (defvar pov-font-lock-keywords '( ("^[ \t]*\\(#declare\\)\\>[ \t]*\\(\\sw+\\)" 2 font-lock-variable-name-face nil t) ("\\<#\\(break\\|case\\|create\\|de\\(bug\\|clare\\|f\\(ault\\|close\\|ined\\)\\)\\|e\\(lse\\|nd\\|rror\\)\\|if\\(n?def\\)?\\|in\\(clude\\|it_\\(3d_\\)?spline\\)\\|local\\|macro\\|r\\(ange\\|ead\\|ender\\)\\|s\\(tatistics\\|witch\\)\\|undef\\|version\\|w\\(arning\\|hile\\|rite\\)\\)\\>" . font-lock-function-name-face) ("\\<\\(b\\(ezier_\\(patch\\|spline\\)\\|icubic_patch\\|lob\\|ox\\)\\|c\\(on\\(e\\|ic\\)\\|ub\\(e\\|ic\\(_\\(spline\\|wave\\)\\)?\\)\\|ylinder\\)\\|disc\\|height_field\\|iso\\(blob\\|surface\\)\\|julia_fractal\\|l\\(athe\\|inear_spline\\)\\|mesh2?\\|p\\(arametric\\|lane\\|oly\\(gon\\)?\\|rism\\)\\|qua\\(dratic\\(_spline\\)?\\|dric\\|rtic\\)\\|s\\(mooth_triangle\\|or\\|phere\\(_sweep\\)?\\|uperellipsoid\\)\\|t\\(ext\\|orus\\|riangle\\)\\|Rounded\\(Box\\|Cylinder\\)\\)\\>" . font-lock-type-face)) "Expressions to highlight in PoV mode.") (defun pov-setup-font-lock nil "Find out if we're fontifying insanely" (if pov-fontify-insanely (setq pov-font-lock-keywords (append pov-all-keyword-matcher pov-font-lock-keywords)))) (defun pov-mode nil "Major mode for editing PoV files. In this mode, TAB and \\[indent-region] attempt to indent code based on the position of {} pairs and #-type directives. The variable pov-indent-level controls the amount of indentation used inside arrays and begin/end pairs. The variable pov-indent-under-declare determines indent level when you have something like this: #declare foo = some_object { This mode also provides PoVray keyword fontification using font-lock. Set pov-fontify-insanely to nil to disable (recommended for large files!). \\[pov-complete-word] runs pov-complete-word, which attempts to complete the current word based on point location. \\{pov-mode-map} \\[pov-mode] calls the value of the variable pov-mode-hook with no args, if that value is non-nil." (interactive) (kill-all-local-variables) (use-local-map pov-mode-map) (pov-setup-syntax-table) (make-local-variable 'comment-start) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-end) (make-local-variable 'comment-multi-line) (make-local-variable 'comment-column) (make-local-variable 'indent-line-function) (make-local-variable 'tab-stop-list) (make-local-variable 'compile-command) (setq compile-command "x-povray") (set-syntax-table pov-mode-syntax-table) (setq comment-start "// " comment-start-skip "/\\*+ *\\|// *" comment-end "" comment-multi-line nil comment-column 60 indent-line-function 'pov-indent-line tab-stop-list pov-tab-stop-list) (setq mode-name "PoV") (setq major-mode 'pov-mode) (pov-setup-font-lock) (make-local-variable 'font-lock-keywords) (setq font-lock-keywords pov-font-lock-keywords) (run-hooks 'pov-mode-hook)) (defun pov-tab () "Command assigned to the TAB key in PoV mode." (interactive) (if (save-excursion (skip-chars-backward " \t") (bolp)) (pov-indent-line) (save-excursion (pov-indent-line)))) (defun pov-indent-line nil "Indents a line of PoV code." (interactive) (beginning-of-line) (delete-horizontal-space) (if (pov-top-level-p) (pov-indent-top-level) (if (not (pov-top-level-p)) (if (pov-in-star-comment-p) (indent-to '2) (if (and (< (point) (point-max)) (or (eq ?\) (char-syntax (char-after (point)))) (or (looking-at "\\<#\\(end\\|break\\)\\>") (and (looking-at "\\<#else\\>") (not (pov-in-switch-p 0)))))) (pov-indent-close) ; indent close-delimiter (pov-indent-in-block)))))) ; indent line after open delimiter (defun pov-newline nil "Terminate line and indent next line." (interactive) (newline) (pov-indent-line)) (defun pov-in-star-comment-p nil "Return true if in a star comment" (let ((state (save-excursion (parse-partial-sexp (point-min) (point))))) (nth 4 state))) (defun pov-open nil (interactive) (insert last-command-char)) (defun pov-close nil "Inserts and indents a close delimiter." (interactive) (insert last-command-char) (backward-char 1) (pov-indent-close) (forward-char 1) (blink-matching-open)) (defun pov-indent-close nil "Internal function to indent a line containing a close delimiter." (if (save-excursion (skip-chars-backward " \t") (bolp)) (let (x (oldpoint (point))) (if (looking-at "#end\\|#else\\|#break") (progn (goto-char (pov-find-begin 0)) (if (and (looking-at "#else") (pov-in-switch-p 0)) (goto-char (pov-find-begin 0)))) (forward-char) (backward-sexp)) ;XXX (if (and (eq 1 (count-lines (point) oldpoint)) (> 1 (- oldpoint (point)))) (goto-char oldpoint) (beginning-of-line) (skip-chars-forward " \t") (setq x (current-column)) (goto-char oldpoint) (delete-horizontal-space) (indent-to x))))) (defun pov-indent-in-block nil "Indent a line which does not open or close a block." (let ((goal (pov-block-start))) (setq goal (save-excursion (goto-char goal) (back-to-indentation) (if (bolp) pov-indent-level (back-to-indentation) (+ (current-column) pov-indent-level)))) (indent-to goal))) (defun pov-indent-top-level nil (if (save-excursion (forward-line -1) (looking-at "\\<#declare[ \t]+[0-9a-zA-Z_]+[ \t]*=[ \t]*$")) (indent-to pov-indent-under-declare))) ;;; returns nil if at top-level, or char pos of beginning of current block (defun pov-block-start nil "Returns the character position of the character following the nearest enclosing `{' or `begin' keyword." (save-excursion (let (open (skip 0)) (setq open (condition-case nil (save-excursion (backward-up-list 1) (1+ (point))) (error nil))) (pov-find-begin open)))) (defun pov-find-begin (start) "Search backwards from point to START for enclosing `begin' and returns the character number of the character following `begin' or START if not found." (save-excursion (let ((depth 1) match) (while (and (> depth 0) (pov-re-search-backward pov-begin-end-re start t)) (setq depth (if (looking-at pov-end-re) (if (and (looking-at "#end") (pov-in-switch-p start)) (progn (pov-re-search-backward "\\<#switch\\>" start t) depth) (+ 1 depth)) (if (looking-at "\\<#else\\>") (if (pov-in-switch-p start) (1- depth) depth) (1- depth))))) (if (not (eq 0 depth)) start (point))))) (defun pov-in-switch-p (start) "Return t if one level under a switch." (save-excursion (if (looking-at "\\<#end\\>") (pov-re-search-backward pov-begin-end-re start t)) (beginning-of-line) (pov-re-search-backward pov-begin-end-re start t) (if (looking-at "\\<#else\\>>") (forward-word -1)) (while (looking-at "\\<#break\\>") (progn (pov-re-search-backward "\\<#case\\|#range\\>" start t) (pov-re-search-backward pov-begin-end-re start t))) (pov-re-search-backward pov-begin-end-re start t) (looking-at "\\<#switch\\>"))) (defun pov-top-level-p nil "Awful test to see whether we are inside some sort of PoVray block." (and (condition-case nil (not (scan-lists (point) -1 1)) (error t)) (not (pov-find-begin nil)))) (defsubst pov-re-search-backward (REGEXP BOUND NOERROR) "Like re-search-backward, but skips over matches in comments or strings" (set-match-data '(nil nil)) (while (and (re-search-backward REGEXP BOUND NOERROR) (pov-skip-backward-comment-or-string) (not (set-match-data '(nil nil)))) ()) (match-end 0)) (defun pov-autoindent-endblock nil "Hack to automatically reindent end, break, and else." (interactive) (self-insert-command 1) (save-excursion (forward-word -1) (if (looking-at "\\<#else\\|#end\\|#break\\>") (pov-indent-line)))) ; Taken from verilog-mode.el (defun pov-skip-backward-comment-or-string () "Return true if in a string or comment" (let ((state (save-excursion (parse-partial-sexp (point-min) (point))))) (cond ((nth 3 state) ;Inside string (search-backward "\"") t) ((nth 7 state) ;Inside // comment (search-backward "//") t) ((nth 4 state) ;Inside /* */ comment (search-backward "/*") t) (t nil)))) ;;; Completions (defvar pov-completion-str nil) (defvar pov-completion-all nil) (defvar pov-completion-pred nil) ;(defvar pov-completion-buffer-to-use nil) (defvar pov-completion-flag nil) (defvar pov-top-level-keywords '("global_settings" "camera" "light_source")) (defvar pov-csg-scope-re "\\") (defvar pov-solid-primitive-keywords '("blob" "box" "cone" "cylinder" "fractal" "height_field" "lathe" "sphere" "superellipsoid" "sor" "text" "torus")) (defvar pov-blob-keywords '("threshold" "cylinder" "sphere" "component" "hierarchy" "sturm")) (defvar pov-heightfield-keywords '("hierarchy" "smooth" "water_level")) ; Julia Fractal (defvar pov-prism-keywords '("linear_sweep" "conic_sweep" "linear_spline" "quadratic_spline" "cubic_spline")) (defvar pov-patch-primitive-keywords '("bicubic_patch" "disc" "smooth_triangle" "triangle" "polygon" "mesh")) (defvar pov-bicubic-keywords '("type" "flatness" "u_steps" "v_steps")) (defvar pov-infinite-solid-keywords '("plane" "cubic" "poly" "quadric" "quartic")) (defvar pov-csg-keywords '("inverse" "union" "intersection" "difference" "merge")) (defvar pov-light-source-keywords '("color" "spotlight" "point_at" "radius" "falloff" "tightness" "area_light" "adaptive" "jitter" "looks_like" "fade_distance" "fade_power" "atmospheric_attenuation")) (defvar pov-object-modifier-keywords '("clipped_by" "bounded_by" "hollow" "no_shadow")) (defvar pov-transformation-keywords '("rotate" "scale" "translate" "matrix")) (defvar pov-camera-keywords '("perspective" "orthographic" "fisheye" "ultra_wide_angle" "omnimax" "panoramic" "cylinder" "location" "look_at" "right" "up" "direction" "sky" "angle" "blur_samples" "aperture" "focal_point" "normal" "rotate" "translate")) (defvar pov-texture-keywords '("pigment" "normal" "finish" "halo" "texture_map" "material_map")) (defvar pov-pigment-keywords '("color" "brick" "checker" "hexagon" "color_map" "gradient" "pigment_map" "pigment" "image_map" "quick_color")) (defvar pov-normal-keywords '("slope_map" "normal_map" "bump_map" "bump_size")) (defvar pov-finish-keywords '("ambient" "diffuse" "brilliance" "phong" "phong_size" "specular" "roughness" "metallic" "reflection" "refraction" "ior" "caustics" "fade_distance" "fade_power" "irid" "crand")) (defvar pov-halo-keywords '("attenuating" "emitting" "glowing" "dust" "constant" "linear" "cubic" "poly" "planar_mapping" "spherical_mapping" "cylindrical_mapping" "box_mapping" "dust_type" "eccentricity" "max_value" "exponent" "samples" "aa_level" "aa_threshold" "jitter" "turbulence" "octaves" "omega" "lambda" "colour_map" "frequency" "phase" "scale" "rotate" "translate")) (defvar pov-pattern-keywords '("agate" "average" "bozo" "granite" "leopard" "marble" "mandel" "onion" "pattern1" "pattern2" "pattern3" "bumpy1" "bumpy2" "bumpy3" "spiral1" "spiral2" "spotted" "wood" "gradient" "crackle" "colour" "checker" "brick" "hexagon" "image_map" "bump_map" "waves" "ripples" "wrinkles" "bumps" "dents" "quilted" )) (defvar pov-atmosphere-keywords '("type" "distance" "scattering" "eccentricity" "samples" "jitter" "aa_threshold" "aa_level" "colour" "color")) (defvar pov-fog-keywords '("fog_type" "distance" "color" "colour" "turbulence" "turb_depth" "omega" "lambda" "octaves" "fog_offset" "fog_alt" "up")) (defvar pov-global-settings-keywords '("adc_bailout" "ambient_light" "assumed_gamma" "hf_gray_16" "irid_wavelength" "max_intersections" "max_trace_level" "number_of_waves" "radiosity")) (defvar pov-radiosity-keywords '("brightness" "count" "distance_maximum" "error_bound" "gray_threshold" "low_error_factor" "minimum_reuse" "nearest_count" "recursion_limit")) (defvar pov-object-keywords '("texture" "pigment" "finish" "halo" "normal")) (defun pov-string-diff (str1 str2) "Return index of first letter where STR1 and STR2 differs." (catch 'done (let ((diff 0)) (while t (if (or (> (1+ diff) (length str1)) (> (1+ diff) (length str2))) (throw 'done diff)) (or (equal (aref str1 diff) (aref str2 diff)) (throw 'done diff)) (setq diff (1+ diff)))))) (defun pov-get-scope nil "Return the scope of the POV source at point" (interactive) (save-excursion (if (not (pov-top-level-p)) (progn (backward-up-list 1) (forward-word -1) (cond ((looking-at "camera") (setq pov-completion-list pov-camera-keywords)) ((looking-at "texture") (setq pov-completion-list (append pov-texture-keywords pov-pattern-keywords))) ((looking-at "pigment") (setq pov-completion-list (append pov-pigment-keywords pov-pattern-keywords))) ((looking-at "normal") (setq pov-completion-list (append pov-normal-keywords pov-pattern-keywords))) ((looking-at "finish") (setq pov-completion-list pov-finish-keywords)) ((looking-at "halo") (setq pov-completion-list pov-halo-keywords)) ((looking-at "blob") (setq pov-completion-list pov-blob-keywords)) ((looking-at "heightfield") (setq pov-completion-list pov-heightfield-keywords)) ((looking-at "prism") (setq pov-completion-list pov-prism-keywords)) ((looking-at "bicubic") (setq pov-completion-list pov-bicubic-keywords)) ((looking-at "light_source") (setq pov-completion-list pov-light-source-keywords)) ((looking-at "atmosphere") (setq pov-completion-list pov-atmosphere-keywords)) ((looking-at "fog") (setq pov-completion-list pov-fog-keywords)) ((looking-at "global_settings") (setq pov-completion-list pov-global-settings-keywords)) ((looking-at "radiosity") (setq pov-completion-list pov-radiosity-keywords)) ((looking-at pov-csg-scope-re) (setq pov-completion-list (append pov-solid-primitive-keywords pov-infinite-solid-keywords pov-object-modifier-keywords pov-csg-keywords))) (t (setq pov-completion-list (append pov-object-modifier-keywords pov-object-keywords)))) (setq pov-completion-list (append pov-completion-list pov-transformation-keywords))) (setq pov-completion-list (append pov-top-level-keywords pov-solid-primitive-keywords pov-infinite-solid-keywords pov-patch-primitive-keywords pov-csg-keywords))))) (defun pov-completion (pov-completion-str pov-completion-pred pov-completion-flag) (save-excursion (let ((pov-completion-all nil)) (pov-get-scope) (mapcar '(lambda (s) (if (string-match (concat "\\<" pov-completion-str) s) (setq pov-completion-all (cons s pov-completion-all)))) pov-completion-list) ;; Now we have built a list of all matches. Give response to caller (pov-completion-response)))) (defun pov-completion-response () (cond ((or (equal pov-completion-flag 'lambda) (null pov-completion-flag)) ;; This was not called by all-completions (if (null pov-completion-all) ;; Return nil if there was no matching label nil ;; Get longest string common in the labels (let* ((elm (cdr pov-completion-all)) (match (car pov-completion-all)) (min (length match)) tmp) (if (string= match pov-completion-str) ;; Return t if first match was an exact match (setq match t) (while (not (null elm)) ;; Find longest common string (if (< (setq tmp (pov-string-diff match (car elm))) min) (progn (setq min tmp) (setq match (substring match 0 min)))) ;; Terminate with match=t if this is an exact match (if (string= (car elm) pov-completion-str) (progn (setq match t) (setq elm nil)) (setq elm (cdr elm))))) ;; If this is a test just for exact match, return nil ot t (if (and (equal pov-completion-flag 'lambda) (not (equal match 't))) nil match)))) ;; If flag is t, this was called by all-completions. Return ;; list of all possible completions (pov-completion-flag pov-completion-all))) (defun pov-complete-word () "Complete word at current point based on POV syntax." (interactive) (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) (pov-completion-str (buffer-substring b e)) ;; The following variable is used in pov-completion ; (pov-buffer-to-use (current-buffer)) (allcomp (all-completions pov-completion-str 'pov-completion)) (match (try-completion pov-completion-str (mapcar '(lambda (elm) (cons elm 0)) allcomp)))) ;; Delete old string (delete-region b e) ;; Insert match if found, or the original string if no match (if (or (null match) (equal match 't)) (progn (insert "" pov-completion-str) (message "(No match)")) (insert "" match)) ;; Give message about current status of completion (cond ((equal match 't) (if (not (null (cdr allcomp))) (message "(Complete but not unique)") (message "(Sole completion)"))) ;; Display buffer if the current completion didn't help ;; on completing the label. ((and (not (null (cdr allcomp))) (= (length pov-completion-str) (length match))) (with-output-to-temp-buffer "*Completions*" (display-completion-list allcomp)) ;; Wait for a keypress. Then delete *Completion* window (momentary-string-display "" (point)) (delete-window (get-buffer-window (get-buffer "*Completions*"))))))) ;;; initialize the keymap if it doesn't already exist (if (null pov-mode-map) (progn (setq pov-mode-map (make-sparse-keymap)) (define-key pov-mode-map "{" 'pov-open) (define-key pov-mode-map "}" 'pov-close) (define-key pov-mode-map "\t" 'pov-tab) (define-key pov-mode-map "\r" 'pov-newline) (define-key pov-mode-map "\M-\t" 'pov-complete-word))) ;; Hack to reindent end/else/break (if pov-autoindent-endblocks (progn (define-key pov-mode-map "e" 'pov-autoindent-endblock) (define-key pov-mode-map "k" 'pov-autoindent-endblock) (define-key pov-mode-map "d" 'pov-autoindent-endblock)))