comparison lisp/modes/vrml-mode.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; vrml-mode.el --- major mode for editing VRML (.wrl) files
2
3 ;; Copyright (C) 1994 Free Software Foundation, Inc.
4 ;; Copyright (C) 1996 Ben Wing.
5
6 ;; Author: Ben Wing <wing@666.com>
7 ;; Keywords: languages vrml modes
8
9 ;; This file is part of XEmacs.
10
11 ;; XEmacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15
16 ;; XEmacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free
23 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24
25 ;;; Synched up with: Not in FSF.
26
27 ;;; Commentary:
28
29 ;; Mostly bastardized from tcl.el.
30
31 ;; HOW TO INSTALL:
32 ;; Put the following forms in your .emacs to enable autoloading of VRML
33 ;; mode, and auto-recognition of ".wrl" files.
34 ;;
35 ;; (autoload 'vrml-mode "vrml" "VRML mode." t)
36 ;; (setq auto-mode-alist (append '(("\\.wrl\\'" . vrml-mode))
37 ;; auto-mode-alist))
38 ;;
39
40 ;;; Code:
41
42 ;;
43 ;; User variables.
44 ;;
45
46 (defvar vrml-indent-level 3
47 "*Indentation of VRML statements with respect to containing block.")
48
49 (defvar vrml-auto-newline nil
50 "*Non-nil means automatically newline before and after braces
51 inserted in VRML code.")
52
53 (defvar vrml-tab-always-indent t
54 "*Control effect of TAB key.
55 If t (the default), always indent current line.
56 If nil and point is not in the indentation area at the beginning of
57 the line, a TAB is inserted.
58 Other values cause the first possible action from the following list
59 to take place:
60
61 1. Move from beginning of line to correct indentation.
62 2. Delete an empty comment.
63 3. Move forward to start of comment, indenting if necessary.
64 4. Move forward to end of line, indenting if necessary.
65 5. Create an empty comment.
66 6. Move backward to start of comment, indenting if necessary.")
67
68 (defvar vrml-use-hairy-comment-detector t
69 "*If not `nil', the the more complicated, but slower, comment
70 detecting function is used.")
71
72 (defvar vrml-mode-abbrev-table nil
73 "Abbrev table used while in VRML mode.")
74 (define-abbrev-table 'vrml-mode-abbrev-table ())
75
76 (defvar vrml-mode-map ()
77 "Keymap used in VRML mode.")
78 (if (null vrml-mode-map)
79 (progn
80 (setq vrml-mode-map (make-sparse-keymap))
81 (set-keymap-name vrml-mode-map 'vrml-mode-map)
82 (define-key vrml-mode-map "{" 'vrml-electric-brace)
83 (define-key vrml-mode-map "}" 'vrml-electric-brace)
84 (define-key vrml-mode-map "\e\C-q" 'indent-vrml-exp)
85 (define-key vrml-mode-map "\177" 'backward-delete-char-untabify)
86 (define-key vrml-mode-map "\t" 'vrml-indent-command)
87 (define-key vrml-mode-map "\M-;" 'vrml-indent-for-comment)
88 ))
89
90 (defvar vrml-mode-syntax-table nil
91 "Syntax table in use in vrml-mode buffers.")
92
93 (if vrml-mode-syntax-table
94 ()
95 (setq vrml-mode-syntax-table (make-syntax-table))
96 (modify-syntax-entry ?\n ">" vrml-mode-syntax-table)
97 (modify-syntax-entry ?\f ">" vrml-mode-syntax-table)
98 (modify-syntax-entry ?\# "<" vrml-mode-syntax-table)
99 (modify-syntax-entry ?\\ "\\" vrml-mode-syntax-table)
100 (modify-syntax-entry ?% "_" vrml-mode-syntax-table)
101 (modify-syntax-entry ?@ "_" vrml-mode-syntax-table)
102 (modify-syntax-entry ?& "_" vrml-mode-syntax-table)
103 (modify-syntax-entry ?* "_" vrml-mode-syntax-table)
104 (modify-syntax-entry ?- "_" vrml-mode-syntax-table)
105 (modify-syntax-entry ?: "_" vrml-mode-syntax-table)
106 (modify-syntax-entry ?! "_" vrml-mode-syntax-table)
107 (modify-syntax-entry ?$ "_" vrml-mode-syntax-table)
108 (modify-syntax-entry ?/ "_" vrml-mode-syntax-table)
109 (modify-syntax-entry ?~ "_" vrml-mode-syntax-table)
110 (modify-syntax-entry ?< "_" vrml-mode-syntax-table)
111 (modify-syntax-entry ?= "_" vrml-mode-syntax-table)
112 (modify-syntax-entry ?> "_" vrml-mode-syntax-table)
113 (modify-syntax-entry ?| "_" vrml-mode-syntax-table)
114 (modify-syntax-entry ?+ "." vrml-mode-syntax-table)
115 (modify-syntax-entry ?\' "\"" vrml-mode-syntax-table))
116
117 (defvar vrml-mode-hook nil
118 "Hook run on entry to VRML mode.")
119
120 (defvar vrml-keyword-list
121 '(
122 ; shape nodes:
123 "AsciiText" "Cone" "Cube" "Cylinder" "IndexedFaceSet" "IndexedLineSet"
124 "PointSet" "Sphere"
125 ; geometry and material nodes:
126 "Coordinate3" "FontStyle" "Info" "LOD" "Material" "MaterialBinding"
127 "Normal" "NormalBinding" "Texture2" "Texture2Transform"
128 "TextureCoordinate2" "ShapeHints"
129 ; transformation nodes:
130 "MatrixTransform" "Rotation" "Scale" "Transform" "Translation"
131 ;camera nodes:
132 "OrthographicCamera" "PerspectiveCamera"
133 ;lighting nodes:
134 "DirectionalLight" "PointLight" "SpotLight"
135 ;group nodes:
136 "Group" "Separator" "Switch" "TransformSeparator" "WWWAnchor"
137 ;other:
138 "WWWInline"
139 ;new VRML 2.0 nodes (#### not yet classified)
140 "Anchor" "Appearance" "AudioClip" "Background" "Billboard" "Box"
141 "Collision" "Color" "ColorInterpolator" "Coordinate"
142 "CoordinateInterpolator" "CylinderSensor" "DiskSensor" "ElevationGrid"
143 "Extrusion" "Fog" "FontStyle" "ImageTexture" "Inline" "MovieTexture"
144 "NavigationInfo" "NormalInterpolator" "OrientationInterpolator"
145 "PixelTexture" "PlaneSensor" "PositionInterpolator" "ProximitySensor"
146 "ScalarInterpolator" "Script" "Shape" "Sound" "SphereSensor" "Text"
147 "TextureTransform" "TextureCoordinate" "TimeSensor" "TouchSensor"
148 "Viewpoint" "VisibilitySensor" "WorldInfo"
149 ;VRML 2.0 node fields
150 "eventIn" "eventOut" "field" "exposedField"
151 ;misc. VRML 2.0 keywords (DEF, PROTO, EXTERNPROTO handled below)
152 "USE" "ROUTE" "TO" "IS" "TRUE" "FALSE" "NULL"
153 ))
154
155 (defconst vrml-font-lock-keywords
156 (list
157 ;; Names of functions (and other "defining things").
158 (list "\\(DEF\\|PROTO\\|EXTERNPROTO\\)[ \t\n]+\\([^ \t\n]+\\)"
159 2 'font-lock-function-name-face)
160
161 ;; Keywords. Only recognized if surrounded by whitespace.
162 ;; FIXME consider using "not word or symbol", not
163 ;; "whitespace".
164 (cons (concat "\\(\\s-\\|^\\)\\("
165 ;; FIXME Use regexp-quote?
166 (mapconcat 'identity vrml-keyword-list "\\|")
167 "\\)\\(\\s-\\|$\\)")
168 2)
169 )
170 "Keywords to highlight for VRML. See variable `font-lock-keywords'.")
171
172 ;;;###autoload
173 (defun vrml-mode ()
174 "Major mode for editing VRML code.
175 Expression and list commands understand all VRML brackets.
176 Tab indents for VRML code.
177 Paragraphs are separated by blank lines only.
178 Delete converts tabs to spaces as it moves back.
179
180 Variables controlling indentation style:
181 vrml-indent-level
182 Indentation of VRML statements within surrounding block.
183
184 Variables controlling user interaction with mode (see variable
185 documentation for details):
186 vrml-tab-always-indent
187 Controls action of TAB key.
188 vrml-auto-newline
189 Non-nil means automatically newline before and after braces
190 inserted in VRML code.
191
192 Turning on VRML mode calls the value of the variable `vrml-mode-hook'
193 with no args, if that value is non-nil. Read the documentation for
194 `vrml-mode-hook' to see what kinds of interesting hook functions
195 already exist.
196
197 Commands:
198 \\{vrml-mode-map}"
199 (interactive)
200 (kill-all-local-variables)
201 (use-local-map vrml-mode-map)
202 (setq major-mode 'vrml-mode)
203 (setq mode-name "VRML")
204 (setq local-abbrev-table vrml-mode-abbrev-table)
205 (set-syntax-table vrml-mode-syntax-table)
206
207 (make-local-variable 'paragraph-start)
208 (make-local-variable 'paragraph-separate)
209 (if (fboundp 'move-to-left-margin)
210 (progn
211 ;; In FSF Emacs 19.29 / XEmacs 19.14, you aren't supposed to
212 ;; start these with a ^.
213 (setq paragraph-start "$\\| ")
214 (setq paragraph-separate paragraph-start))
215 (setq paragraph-start (concat "^$\\|" page-delimiter))
216 (setq paragraph-separate paragraph-start))
217 (make-local-variable 'paragraph-ignore-fill-prefix)
218 (setq paragraph-ignore-fill-prefix t)
219 (make-local-variable 'fill-paragraph-function)
220 (setq fill-paragraph-function 'vrml-do-fill-paragraph)
221
222 (make-local-variable 'indent-line-function)
223 (setq indent-line-function 'vrml-indent-line)
224 (make-local-variable 'require-final-newline)
225 (setq require-final-newline t)
226
227 (make-local-variable 'comment-start)
228 (setq comment-start "# ")
229 (make-local-variable 'comment-start-skip)
230 (setq comment-start-skip "#+ *")
231 (make-local-variable 'comment-column)
232 (setq comment-column 40)
233 (make-local-variable 'comment-end)
234 (setq comment-end "")
235
236 (make-local-variable 'outline-regexp)
237 (setq outline-regexp "[^\n\^M]")
238 (make-local-variable 'outline-level)
239 (setq outline-level 'vrml-outline-level)
240
241 (make-local-variable 'font-lock-keywords)
242 (setq font-lock-keywords vrml-font-lock-keywords)
243
244 (make-local-variable 'parse-sexp-ignore-comments)
245 (setq parse-sexp-ignore-comments t)
246
247 (make-local-variable 'defun-prompt-regexp)
248 (setq defun-prompt-regexp "^[^ \t\n#}][^\n}]+}*[ \t]+")
249
250 ;; Settings for new dabbrev code.
251 (make-local-variable 'dabbrev-case-fold-search)
252 (setq dabbrev-case-fold-search nil)
253 (make-local-variable 'dabbrev-case-replace)
254 (setq dabbrev-case-replace nil)
255 (make-local-variable 'dabbrev-abbrev-skip-leading-regexp)
256 (setq dabbrev-abbrev-skip-leading-regexp "[$!]")
257 (make-local-variable 'dabbrev-abbrev-char-regexp)
258 (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
259
260 (run-hooks 'vrml-mode-hook))
261
262 ;; This is used for closing braces. If vrml-auto-newline is set, can
263 ;; insert a newline both before and after the brace, depending on
264 ;; context. FIXME should this be configurable? Does anyone use this?
265 (defun vrml-electric-brace (arg)
266 "Insert character and correct line's indentation."
267 (interactive "p")
268 ;; If auto-newlining and there is stuff on the same line, insert a
269 ;; newline first.
270 (if vrml-auto-newline
271 (progn
272 (if (save-excursion
273 (skip-chars-backward " \t")
274 (bolp))
275 ()
276 (vrml-indent-line)
277 (newline))
278 ;; In auto-newline case, must insert a newline after each
279 ;; brace. So an explicit loop is needed.
280 (while (> arg 0)
281 (insert last-command-char)
282 (vrml-indent-line)
283 (newline)
284 (setq arg (1- arg))))
285 (self-insert-command arg))
286 (vrml-indent-line))
287
288
289
290 (defun vrml-indent-command (&optional arg)
291 "Indent current line as VRML code, or in some cases insert a tab character.
292 If vrml-tab-always-indent is t (the default), always indent current line.
293 If vrml-tab-always-indent is nil and point is not in the indentation
294 area at the beginning of the line, a TAB is inserted.
295 Other values of vrml-tab-always-indent cause the first possible action
296 from the following list to take place:
297
298 1. Move from beginning of line to correct indentation.
299 2. Delete an empty comment.
300 3. Move forward to start of comment, indenting if necessary.
301 4. Move forward to end of line, indenting if necessary.
302 5. Create an empty comment.
303 6. Move backward to start of comment, indenting if necessary."
304 (interactive "p")
305 (cond
306 ((not vrml-tab-always-indent)
307 ;; Indent if in indentation area, otherwise insert TAB.
308 (if (<= (current-column) (current-indentation))
309 (vrml-indent-line)
310 (self-insert-command arg)))
311 ((eq vrml-tab-always-indent t)
312 ;; Always indent.
313 (vrml-indent-line))
314 (t
315 ;; "Perl-mode" style TAB command.
316 (let* ((ipoint (point))
317 (eolpoint (progn
318 (end-of-line)
319 (point)))
320 (comment-p (vrml-in-comment)))
321 (cond
322 ((= ipoint (save-excursion
323 (beginning-of-line)
324 (point)))
325 (beginning-of-line)
326 (vrml-indent-line)
327 ;; If indenting didn't leave us in column 0, go to the
328 ;; indentation. Otherwise leave point at end of line. This
329 ;; is a hack.
330 (if (= (point) (save-excursion
331 (beginning-of-line)
332 (point)))
333 (end-of-line)
334 (back-to-indentation)))
335 ((and comment-p (looking-at "[ \t]*$"))
336 ;; Empty comment, so delete it. We also delete any ";"
337 ;; characters at the end of the line. I think this is
338 ;; friendlier, but I don't know how other people will feel.
339 (backward-char)
340 (skip-chars-backward " \t;")
341 (delete-region (point) eolpoint))
342 ((and comment-p (< ipoint (point)))
343 ;; Before comment, so skip to it.
344 (vrml-indent-line)
345 (indent-for-comment))
346 ((/= ipoint eolpoint)
347 ;; Go to end of line (since we're not there yet).
348 (goto-char eolpoint)
349 (vrml-indent-line))
350 ((not comment-p)
351 (vrml-indent-line)
352 (vrml-indent-for-comment))
353 (t
354 ;; Go to start of comment. We don't leave point where it is
355 ;; because we want to skip comment-start-skip.
356 (vrml-indent-line)
357 (indent-for-comment)))))))
358
359 (defun vrml-indent-line ()
360 "Indent current line as VRML code.
361 Return the amount the indentation changed by."
362 (let ((indent (calculate-vrml-indent nil))
363 beg shift-amt
364 (case-fold-search nil)
365 (pos (- (point-max) (point))))
366 (beginning-of-line)
367 (setq beg (point))
368 (cond ((eq indent nil)
369 (setq indent (current-indentation)))
370 (t
371 (skip-chars-forward " \t")
372 (if (listp indent) (setq indent (car indent)))
373 (cond ((= (following-char) ?})
374 (setq indent (- indent vrml-indent-level)))
375 ((= (following-char) ?\])
376 (setq indent (- indent 1))))))
377 (skip-chars-forward " \t")
378 (setq shift-amt (- indent (current-column)))
379 (if (zerop shift-amt)
380 (if (> (- (point-max) pos) (point))
381 (goto-char (- (point-max) pos)))
382 (delete-region beg (point))
383 (indent-to indent)
384 ;; If initial point was within line's indentation,
385 ;; position after the indentation. Else stay at same point in text.
386 (if (> (- (point-max) pos) (point))
387 (goto-char (- (point-max) pos))))
388 shift-amt))
389
390 (defun calculate-vrml-indent (&optional parse-start)
391 "Return appropriate indentation for current line as VRML code.
392 In usual case returns an integer: the column to indent to.
393 Returns nil if line starts inside a string, t if in a comment."
394 (save-excursion
395 (beginning-of-line)
396 (let* ((indent-point (point))
397 (case-fold-search nil)
398 state
399 containing-sexp
400 found-next-line)
401 (if parse-start
402 (goto-char parse-start)
403 (beginning-of-defun))
404 (while (< (point) indent-point)
405 (setq parse-start (point))
406 (setq state (parse-partial-sexp (point) indent-point 0))
407 (setq containing-sexp (car (cdr state))))
408 (cond ((or (nth 3 state) (nth 4 state))
409 ;; Inside comment or string. Return nil or t if should
410 ;; not change this line
411 (nth 4 state))
412 ((null containing-sexp)
413 ;; Line is at top level.
414 0)
415 (t
416 (goto-char containing-sexp)
417 (let* ((expr-start (point)))
418 ;; Find the first statement in the block and indent
419 ;; like it. The first statement in the block might be
420 ;; on the same line, so what we do is skip all
421 ;; "virtually blank" lines, looking for a non-blank
422 ;; one. A line is virtually blank if it only contains
423 ;; a comment and whitespace. We do it this funky way
424 ;; because we want to know if we've found a statement
425 ;; on some line _after_ the line holding the sexp
426 ;; opener.
427 (goto-char containing-sexp)
428 (forward-char)
429 (if (and (< (point) indent-point)
430 (looking-at "[ \t]*\\(#.*\\)?$"))
431 (progn
432 (forward-line)
433 (while (and (< (point) indent-point)
434 (looking-at "[ \t]*\\(#.*\\)?$"))
435 (setq found-next-line t)
436 (forward-line))))
437 (if (not (or (= (char-after containing-sexp) ?{)
438 (and (= (char-after containing-sexp) ?\[)
439 (save-excursion
440 (goto-char containing-sexp)
441 (skip-chars-backward " \t\n")
442 (forward-char -8)
443 (looking-at "children")))))
444 (progn
445 ;; Line is continuation line, or the sexp opener
446 ;; is not a curly brace, or we are are looking at
447 ;; an `expr' expression (which must be split
448 ;; specially). So indentation is column of first
449 ;; good spot after sexp opener. If there is no
450 ;; nonempty line before the indentation point, we
451 ;; use the column of the character after the sexp
452 ;; opener.
453 (if (>= (point) indent-point)
454 (progn
455 (goto-char containing-sexp)
456 (forward-char))
457 (skip-chars-forward " \t"))
458 (current-column))
459 ;; After a curly brace, and not a continuation line.
460 ;; So take indentation from first good line after
461 ;; start of block, unless that line is on the same
462 ;; line as the opening brace. In this case use the
463 ;; indentation of the opening brace's line, plus
464 ;; another indent step. If we are in the body part
465 ;; of an "if" or "while" then the indentation is
466 ;; taken from the line holding the start of the
467 ;; statement.
468 (if (and (< (point) indent-point)
469 found-next-line)
470 (current-indentation)
471 (if t ; commands-p
472 (goto-char expr-start)
473 (goto-char containing-sexp))
474 (+ (current-indentation) vrml-indent-level)))))))))
475
476
477
478 (defun indent-vrml-exp ()
479 "Indent each line of the VRML grouping following point."
480 (interactive)
481 (let ((indent-stack (list nil))
482 (contain-stack (list (point)))
483 (case-fold-search nil)
484 outer-loop-done inner-loop-done state ostate
485 this-indent last-sexp
486 (next-depth 0)
487 last-depth)
488 (save-excursion
489 (forward-sexp 1))
490 (save-excursion
491 (setq outer-loop-done nil)
492 (while (and (not (eobp)) (not outer-loop-done))
493 (setq last-depth next-depth)
494 ;; Compute how depth changes over this line
495 ;; plus enough other lines to get to one that
496 ;; does not end inside a comment or string.
497 ;; Meanwhile, do appropriate indentation on comment lines.
498 (setq inner-loop-done nil)
499 (while (and (not inner-loop-done)
500 (not (and (eobp) (setq outer-loop-done t))))
501 (setq ostate state)
502 (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
503 nil nil state))
504 (setq next-depth (car state))
505 (if (and (car (cdr (cdr state)))
506 (>= (car (cdr (cdr state))) 0))
507 (setq last-sexp (car (cdr (cdr state)))))
508 (if (or (nth 4 ostate))
509 (vrml-indent-line))
510 (if (or (nth 3 state))
511 (forward-line 1)
512 (setq inner-loop-done t)))
513 (if (<= next-depth 0)
514 (setq outer-loop-done t))
515 (if outer-loop-done
516 nil
517 ;; If this line had ..))) (((.. in it, pop out of the levels
518 ;; that ended anywhere in this line, even if the final depth
519 ;; doesn't indicate that they ended.
520 (while (> last-depth (nth 6 state))
521 (setq indent-stack (cdr indent-stack)
522 contain-stack (cdr contain-stack)
523 last-depth (1- last-depth)))
524 (if (/= last-depth next-depth)
525 (setq last-sexp nil))
526 ;; Add levels for any parens that were started in this line.
527 (while (< last-depth next-depth)
528 (setq indent-stack (cons nil indent-stack)
529 contain-stack (cons nil contain-stack)
530 last-depth (1+ last-depth)))
531 (if (null (car contain-stack))
532 (setcar contain-stack
533 (or (car (cdr state))
534 (save-excursion
535 (forward-sexp -1)
536 (point)))))
537 (forward-line 1)
538 (skip-chars-forward " \t")
539 (if (eolp)
540 nil
541 (if (and (car indent-stack)
542 (>= (car indent-stack) 0))
543 ;; Line is on an existing nesting level.
544 (setq this-indent (car indent-stack))
545 ;; Just started a new nesting level.
546 ;; Compute the standard indent for this level.
547 (let ((val (calculate-vrml-indent
548 (if (car indent-stack)
549 (- (car indent-stack))))))
550 (setcar indent-stack
551 (setq this-indent val))
552 ))
553 (cond ((not (numberp this-indent)))
554 ((= (following-char) ?})
555 (setq this-indent (- this-indent vrml-indent-level)))
556 ((= (following-char) ?\])
557 (setq this-indent (- this-indent 1))))
558 ;; Put chosen indentation into effect.
559 (or (null this-indent)
560 (= (current-column)
561 this-indent)
562 (progn
563 (delete-region (point) (progn (beginning-of-line) (point)))
564 (indent-to
565 this-indent))))))))
566 )
567
568 ;;
569 ;; Auto-fill support.
570 ;;
571
572 (defun vrml-real-command-p ()
573 "Return nil if point is not at the beginning of a command.
574 A command is the first word on an otherwise empty line, or the
575 first word following an opening brace."
576 (save-excursion
577 (skip-chars-backward " \t")
578 (cond
579 ((bobp) t)
580 ((bolp)
581 (backward-char)
582 ;; Note -- continued comments are not supported here. I
583 ;; consider those to be a wart on the language.
584 (not (eq ?\\ (preceding-char))))
585 (t
586 (memq (preceding-char) '(?{))))))
587
588 ;; FIXME doesn't actually return t. See last case.
589 (defun vrml-real-comment-p ()
590 "Return t if point is just after the `#' beginning a real comment.
591 Does not check to see if previous char is actually `#'.
592 A real comment is either at the beginning of the buffer,
593 preceeded only by whitespace on the line, or has a preceeding
594 semicolon, opening brace, or opening bracket on the same line."
595 (save-excursion
596 (backward-char)
597 (vrml-real-command-p)))
598
599 (defun vrml-hairy-scan-for-comment (state end always-stop)
600 "Determine if point is in a comment.
601 Returns a list of the form `(FLAG . STATE)'. STATE can be used
602 as input to future invocations. FLAG is nil if not in comment,
603 t otherwise. If in comment, leaves point at beginning of comment.
604 See also `vrml-simple-scan-for-comment', a simpler version that is
605 often right."
606 (let ((bol (save-excursion
607 (goto-char end)
608 (beginning-of-line)
609 (point)))
610 real-comment
611 last-cstart)
612 (while (and (not last-cstart) (< (point) end))
613 (setq real-comment nil) ;In case we've looped around and it is
614 ;set.
615 (setq state (parse-partial-sexp (point) end nil nil state t))
616 (if (nth 4 state)
617 (progn
618 ;; If ALWAYS-STOP is set, stop even if we don't have a
619 ;; real comment, or if the comment isn't on the same line
620 ;; as the end.
621 (if always-stop (setq last-cstart (point)))
622 ;; If we have a real comment, then set the comment
623 ;; starting point if we are on the same line as the ending
624 ;; location.
625 (setq real-comment (vrml-real-comment-p))
626 (if real-comment
627 (progn
628 (and (> (point) bol) (setq last-cstart (point)))
629 ;; NOTE Emacs 19 has a misfeature whereby calling
630 ;; parse-partial-sexp with COMMENTSTOP set and with
631 ;; an initial list that says point is in a comment
632 ;; will cause an immediate return. So we must skip
633 ;; over the comment ourselves.
634 (beginning-of-line 2)))
635 ;; Frob the state to make it look like we aren't in a
636 ;; comment.
637 (setcar (nthcdr 4 state) nil))))
638 (and last-cstart
639 (goto-char last-cstart))
640 (cons real-comment state)))
641
642 (defun vrml-hairy-in-comment ()
643 "Return t if point is in a comment, and leave point at beginning
644 of comment."
645 (let ((save (point)))
646 (beginning-of-defun)
647 (car (vrml-hairy-scan-for-comment nil save nil))))
648
649 (defun vrml-simple-in-comment ()
650 "Return t if point is in comment, and leave point at beginning
651 of comment. This is faster than `vrml-hairy-in-comment', but is
652 correct less often."
653 (let ((save (point))
654 comment)
655 (beginning-of-line)
656 (while (and (< (point) save) (not comment))
657 (search-forward "#" save 'move)
658 (setq comment (vrml-real-comment-p)))
659 comment))
660
661 (defun vrml-in-comment ()
662 "Return t if point is in comment, and leave point at beginning
663 of comment."
664 (if vrml-use-hairy-comment-detector
665 (vrml-hairy-in-comment)
666 (vrml-simple-in-comment)))
667
668 (defun vrml-do-fill-paragraph (ignore)
669 "fill-paragraph function for VRML mode. Only fills in a comment."
670 (let (in-comment col where)
671 (save-excursion
672 (end-of-line)
673 (setq in-comment (vrml-in-comment))
674 (if in-comment
675 (progn
676 (setq where (1+ (point)))
677 (setq col (1- (current-column))))))
678 (and in-comment
679 (save-excursion
680 (back-to-indentation)
681 (= col (current-column)))
682 ;; In a comment. Set the fill prefix, and find the paragraph
683 ;; boundaries by searching for lines that look like
684 ;; comment-only lines.
685 (let ((fill-prefix (buffer-substring (progn
686 (beginning-of-line)
687 (point))
688 where))
689 p-start p-end)
690 ;; Search backwards.
691 (save-excursion
692 (while (looking-at "^[ \t]*#")
693 (forward-line -1))
694 (forward-line)
695 (setq p-start (point)))
696
697 ;; Search forwards.
698 (save-excursion
699 (while (looking-at "^[ \t]*#")
700 (forward-line))
701 (setq p-end (point)))
702
703 ;; Narrow and do the fill.
704 (save-restriction
705 (narrow-to-region p-start p-end)
706 (fill-paragraph ignore)))))
707 t)
708
709 (defun vrml-do-auto-fill ()
710 "Auto-fill function for VRML mode. Only auto-fills in a comment."
711 (if (> (current-column) fill-column)
712 (let ((fill-prefix "# ")
713 in-comment col)
714 (save-excursion
715 (setq in-comment (vrml-in-comment))
716 (if in-comment
717 (setq col (1- (current-column)))))
718 (if in-comment
719 (progn
720 (do-auto-fill)
721 (save-excursion
722 (back-to-indentation)
723 (delete-region (point) (save-excursion
724 (beginning-of-line)
725 (point)))
726 (indent-to-column col)))))))
727
728 (defun vrml-indent-for-comment ()
729 "Indent this line's comment to comment column, or insert an empty comment.
730 Is smart about syntax of VRML comments.
731 Parts of this were taken from indent-for-comment (simple.el)."
732 (interactive "*")
733 (end-of-line)
734 (or (vrml-in-comment)
735 (progn
736 ;; Not in a comment, so we have to insert one. Create an
737 ;; empty comment (since there isn't one on this line).
738 (skip-chars-backward " \t")
739 (let ((eolpoint (point)))
740 (beginning-of-line)
741 (if (/= (point) eolpoint)
742 (progn
743 (goto-char eolpoint)
744 (insert
745 "# ")
746 (backward-char))))))
747 ;; Point is just after the "#" starting a comment. Move it as
748 ;; appropriate.
749 (let* ((indent (funcall comment-indent-function))
750 (begpos (progn
751 (backward-char)
752 (point))))
753 (if (/= begpos indent)
754 (progn
755 (skip-chars-backward " \t" (save-excursion
756 (beginning-of-line)
757 (point)))
758 (delete-region (point) begpos)
759 (indent-to indent)))
760 (looking-at comment-start-skip) ; Always true.
761 (goto-char (match-end 0))
762 ;; I don't like the effect of the next two.
763 ;;(skip-chars-backward " \t" (match-beginning 0))
764 ;;(skip-chars-backward "^ \t" (match-beginning 0))
765 ))
766
767 ;;; vrml-mode.el ends here