;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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 XEmacs 20. Let me know about any ;; compatibility problems (or even better fix them and send a patch). ;; ;; 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 ;; ;; Modified by: Peter Toneby ;; 22/3/99: Version 1.99beata1 ;; Added support for Pov3.1s new keywords. (not all, I think...) ;; Removed atmosphere (and atmosphere_*) (stupid me...) ;; ;; 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/b reak ;; (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 *eve ry* ;; 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) (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 el se") (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 o n 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\\|range\\|switch\\|whi le\\)\\>") (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-tab le) (modify-syntax-entry ?* ". 23" pov-mode-syntax-table) (modify-syntax-entry ?\n "> b" 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-all-keyword-matcher '("\\<\\(a\\(a_\\(level\\|threshold\\)\\|bs\\|cosh?\\|d\\(aptive\\|c_ba ilout\\)\\|gate\\(_turb\\)?\\|ll\\|lpha\\|mbient\\(_light\\)?\\|ngle\\|pe rture\\|r\\(c_angle\\|ea_light\\|ray\\)\\|sc\\|sinh?\\|ssumed_gamma\\|tan [2h]?\\|verage\\)\\|b\\(ackground\\|l\\(ack_hole\\|ue\\|ur_samples\\)\\|o \\(unded_by\\|x\\(ed\\|_mapping\\)\\|zo\\)\\|r\\(eak\\|ick\\(_size\\)?\\| ightness\\|illiance\\)\\|ump\\(s\\|y[123]?\\|_map\\|_size\\)\\)\\|c\\(a\\ (mera\\|se\\|ustics\\)\\|eil\\|h\\(ecker\\|r\\)\\|l\\(ipped_by\\|ock\\(_d elta\\)?\\)\\|o\\(lou?r\\(_map\\)?\\|mpo\\(nent\\|site\\)\\|n\\(cat\\|fid ence\\|ic_sweep\\|stant\\|trol[01]\\)\\|sh?\\|unt\\)\\|ra\\(ckle\\|nd\\)\ \|ubic_wave\\|ylindrical_mapping\\)\\|d\\(e\\(grees\\|nts\\)\\|i\\(ff\\(e rence\\|use\\)\\|mension\\(_size\\)?\\|rection\\|s\\(c\\|tance\\(_maximum \\)?\\)\\|v\\)\\|ust\\(_type\\)?\\)\\|e\\(ccentricity\\|lse\\|mitting\\|n d\\|rror_bound\\|xp\\(onent\\)?\\)\\|f\\(a\\(de_\\(distance\\|power\\)\\| l\\(loff\\(_angle\\)?\\|se\\)\\)\\|i\\(l\\(e_exists\\|ter\\)\\|nish\\|she ye\\)\\|l\\(atness\\|ip\\|oor\\)\\|o\\(cal_point\\|g\\(_alt\\|_offset\\|_ type\\)?\\)\\|requency\\)\\|g\\(if\\|lo\\(bal_settings\\|wing\\)\\|r\\(ad ient\\|anite\\|ay_threshold\\|een\\)\\)\\|h\\(alo\\|exagon\\|f_gray_16\\| ierarchy\\|ollow\\|ypercomplex\\)\\|i\\(ff\\|mage_map\\|n\\(cidence\\|t\\ (er\\(ior\\|polate\\|section\\)\\)?\\|verse\\)\\|or\\|rid\\(_wavelength\\ )?\\)\\|jitter\\|l\\(ambda\\|eopard\\|i\\(ght_source\\|near\\(_spline\\|_ sweep\\)?\\)\\|o\\(cation\\|g\\|oks_like\\|ok_at\\|w_error_factor\\)\\)\\ |m\\(a\\(ndel\\|p_type\\|rble\\|terial_map\\|trix\\|x\\(_intersections\\| _iteration\\|_trace_level\\|_value\\)?\\)\\|e\\(dia\\(_attenuation\\|_int eraction\\)?\\|rge\\|tallic\\)\\|in\\(imum_reuse\\)?\\|od\\|ortar\\)\\|n\ \(earest_count\\|o\\(rmal\\(_map\\)?\\|_shadow\\)?\\|umber_of_waves\\)\\| o\\(bject\\|ctaves\\|ff\\(set\\)?\\|mega\\|mnimax\\|n\\(ce\\|ion\\)?\\|pe n\\|rthographic\\)\\|p\\(a\\(noramic\\|ttern[123]\\)\\|erspective\\|gm\\| h\\(ase\\|ong\\(_size\\)?\\)\\|i\\(gment\\(_map\\)?\\)?\\|lanar\\(_mappin g\\)?\\|ng\\|o\\(int_at\\|[tw]\\|ly_wave\\)\\|pm\\|recision\\|wr\\)\\|qu\ \(adratic_spline\\|aternion\\|ick_colou?r\\|ilted\\)\\|r\\(a\\(di\\(al\\| ans\\|osity\\|us\\)\\|inbow\\|mp_wave\\|nd\\|nge\\)\\|e\\(ciprocal\\|curs ion_limit\\|d\\|flection\\(_exponent\\)?\\|fraction\\|peat\\)\\|gbf?t?\\| ight\\|ipples\\|otate\\|oughness\\)\\|s\\(amples\\|ca\\(le\\|llop_wave\\| ttering\\)\\|eed\\|hadowless\\|in\\(e_wave\\|h\\)?\\|ky\\(_sphere\\)?\\|l ice\\|lope_map\\|mooth\\|or\\|p\\(ecular\\|herical\\(_mapping\\)?\\|iral[ 12]?\\|otlight\\|otted\\)\\|qrt?\\|t\\(atistics\\|r\\(cmp\\|ength\\|len\\ |lwr\\|upr\\)?\\|urm\\)\\|ubstr\\|witch\\|ys\\)\\|t\\(anh?\\|est_camera_[ 1234]\\|exture\\(_map\\)?\\|ga\\|hickness\\|hreshold\\|ightness\\|ile[2s] \\|r\\(ack\\|ans\\(form\\|late\\|mit\\)\\|iangle_wave\\|ue\\)\\|tf\\|urb\ \(ulence\\|_depth\\)\\|ype\\)?\\|u\\(ltra_wide_angle\\|nion\\|p\\|se_\\(c olou?r\\|index\\)\\|_steps\\)?\\|v\\(a\\(l\\|riance\\|xis_rotate\\)\\|cro ss\\|dot\\|ersion\\|length\\|normalize\\|olume_\\(object\\|rendered\\)\\| ol_with_light\\|rotate\\|_steps\\)?\\|w\\(a\\(rp\\|ter_level\\|ves\\)\\|h ile\\|idth\\|ood\\|rinkles\\)\\|x\\|y\\(es\\)?\\|z\\)\\>" . font-lock-key word-face)) (defvar pov-font-lock-keywords '( ("^[ \t]*\\(#declare\\)\\>[ \t]*\\(\\sw+\\)" 2 font-lock-variable-na me-face nil t) ("\\<#\\(break\\|case\\|de\\(bug\\|clare\\|fault\\)\\|e\\(lse\\|nd\\| rror\\)\\|f\\(open\\|close\\)\\|if\\(n?def\\)?\\|include\\|macro\\|r\\(an ge\\|ender\\|ead\\)\\|s\\(tatistics\\|witch\\)\\|version\\|w\\(arning\\|h ile\\|rite\\)\\)\\>" . font-lock-function-name-face) ("\\<\\(b\\(icubic_patch\\|lob\\|ox\\)\\|c\\(one\\|ub\\(e\\|ic\\(_spl ine\\)?\\)\\|ylinder\\)\\|disc\\|height_field\\|julia_fractal\\|lathe\\|m esh\\|p\\(lane\\|oly\\(gon\\)?\\|rism\\)\\|qua\\(rt\\|dr\\)ic\\|s\\(mooth _triangle\\|sor\\|phere\\|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 (list 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 "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 bloc k (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" "sphe re" "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" "cubi c_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_l ight" "adaptive" "jitter" "looks_like" "shadowless" "cylinder" "fade_dist ance" "fade_power" "media_attenuation" "media_interaction")) (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" "trans late")) (defvar pov-texture-keywords '("pigment" "normal" "finish" "halo" "texture_map" "material_map" "boxe d" "planar" "cylindrical" "spherical")) (defvar pov-pigment-keywords '("color" "boxed" "brick" "checker" "cylindrical" "hexagon" "color_map" "gradient" "pigment_map" "pigment" "planar" "spherical" "image_map" "qui ck_color")) (defvar pov-normal-keywords '("slope_map" "normal_map" "bump_map" "bump_size" "boxed" "cylindrical" "planar" "spherical")) (defvar pov-finish-keywords '("ambient" "diffuse" "brilliance" "phong" "phong_size" "specular" "rou ghness" "metallic" "reflection" "reflection_exponent" "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_m apping" "dust_type" "eccentricity" "max_value" "exponent" "samples" "aa_l evel" "aa_threshold" "jitter" "turbulence" "octaves" "omega" "lambda" "co lour_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" "d ents" "quilted" )) ;;(defvar pov-atmosphere-keywords ;; '("type" "distance" "scattering" "eccentricity" "samples" "jitter" "a a_threshold" "aa_level" "colour" "color")) (defvar pov-media-keyword '("intervals" "samples" "confidence" "variance" "ratio" "absorption" "e mission" "scattering" "density" "color_map" "colour_map" "density_map")) (defvar pov-interior-keyword '("ior" "caustics" "fade_distance" "fade_power")) (defvar pov-density-keyword '("color_map" "colour_map" "density_map" "boxed" "planar" "cylindrical" "spherical")) (defvar pov-fog-keywords '("fog_type" "distance" "color" "colour" "turbulence" "turb_depth" "omeg a" "lambda" "octaves" "fog_offset" "fog_alt" "up")) (defvar pov-global-settings-keywords '("adc_bailout" "ambient_light" "assumed_gamma" "hf_gray_16" "irid_wave length" "max_intersections" "max_trace_level" "number_of_waves" "radiosit y")) (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-k eywords))) ((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 "interior") (setq pov-completion-list pov-interior-keywords)) ((looking-at "media") (setq pov-completion-list pov-media-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-transforma tion-keywords))) (setq pov-completion-list (append pov-top-level-keywords pov-solid- primitive-keywords pov-infinite-solid-keywords pov-patch-primitive-keywor ds 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-fla g)) ;; 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 redindent 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)))