Mercurial > emacs
view lisp/textmodes/sgml-mode.el @ 1717:aa7d6d57504b
* frame.h (struct frame): New fields `can_have_scrollbars' and
`has_vertical_scrollbars'.
(FRAME_CAN_HAVE_SCROLLBARS, FRAME_HAS_VERTICAL_SCROLLBARS): New
accessors, for both the MULTI_FRAME and non-MULTI_FRAME.
(VERTICAL_SCROLLBAR_WIDTH, WINDOW_VERTICAL_SCROLLBAR,
WINDOW_VERTICAL_SCROLLBAR_COLUMN,
WINDOW_VERTICAL_SCROLLBAR_HEIGHT): New macros.
* window.h (struct window): New field `vertical_scrollbar'.
* xterm.h (struct x_display): vertical_scrollbars,
judge_timestamp, vertical_scrollbar_extra: New fields.
(struct scrollbar): New struct.
(VERTICAL_SCROLLBAR_PIXEL_WIDTH, VERTICAL_SCROLLBAR_PIXEL_HEIGHT,
VERTICAL_SCROLLBAR_LEFT_BORDER, VERTICAL_SCROLLBAR_RIGHT_BORDER,
VERTICAL_SCROLLBAR_TOP_BORDER, VERTICAL_SCROLLBAR_BOTTOM_BORDER,
CHAR_TO_PIXEL_WIDTH, CHAR_TO_PIXEL_HEIGHT, PIXEL_TO_CHAR_WIDTH,
PIXEL_TO_CHAR_HEIGHT): New accessors and macros.
* frame.c (make_frame): Initialize the `can_have_scrollbars' and
`has_vertical_scrollbars' fields of the frame.
* term.c (term_init): Note that TERMCAP terminals don't support
scrollbars.
(mouse_position_hook): Document new args.
(set_vertical_scrollbar_hook, condemn_scrollbars_hook,
redeem_scrollbar_hook, judge_scrollbars_hook): New hooks.
* termhooks.h: Declare and document them.
(enum scrollbar_part): New type.
(struct input_event): Describe the new form of the scrollbar_click
event type. Change `part' from a Lisp_Object to an enum
scrollbar_part. Add a new field `scrollbar'.
* keyboard.c (kbd_buffer_get_event): Pass appropriate new
parameters to *mouse_position_hook, and make_lispy_movement.
* xfns.c (x_set_vertical_scrollbar): New function.
(x_figure_window_size): Use new macros to calculate frame size.
(Fx_create_frame): Note that X Windows frames do support scroll
bars. Default to "yes".
* xterm.c: #include <X11/cursorfont.h> and "window.h".
(x_vertical_scrollbar_cursor): New variable.
(x_term_init): Initialize it.
(last_mouse_bar, last_mouse_bar_frame, last_mouse_part,
last_mouse_scroll_range_start, last_mouse_scroll_range_end): New
variables.
(XTmouse_position): Use them to return scrollbar movement events.
Take new arguments, for that purpose.
(x_window_to_scrollbar, x_scrollbar_create,
x_scrollbar_set_handle, x_scrollbar_remove, x_scrollbar_move,
XTset_scrollbar, XTcondemn_scrollbars, XTredeem_scrollbar,
XTjudge_scrollbars, x_scrollbar_expose,
x_scrollbar_background_expose, x_scrollbar_handle_click,
x_scrollbar_handle_motion): New functions to implement scrollbars.
(x_term_init): Set the termhooks.h hooks to point to them.
(x_set_window_size): Use new macros to calculate frame size. Set
vertical_scrollbar_extra field.
(x_make_frame_visible): Use the frame accessor
FRAME_HAS_VERTICAL_SCROLLBARS to decide if we need to map the
frame's subwindows as well.
(XTread_socket): Use new size-calculation macros from xterm.h when
processing ConfigureNotify events.
(x_wm_set_size_hint): Use PIXEL_TO_CHAR_WIDTH and
PIXEL_TO_CHAR_HEIGHT macros.
* ymakefile (xdisp.o): This now depends on termhooks.h.
(xterm.o): This now depends on window.h.
| author | Jim Blandy <jimb@redhat.com> |
|---|---|
| date | Thu, 24 Dec 1992 06:17:18 +0000 |
| parents | 7861f8756850 |
| children | 10e417efb12a |
line wrap: on
line source
;;; sgml-mode.el --- SGML-editing mode ;; Copyright (C) 1992 Free Software Foundation, Inc. ;; Author: James Clark <jjc@clark.com> ;; Adapted-By: ESR ;; Keywords: wp ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 1, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;;; Commentary: ;; Some suggestions for your .emacs file: ;; ;; (autoload 'sgml-mode "sgml-mode" "SGML mode" t) ;; ;; (setq auto-mode-alist ;; (append (list (cons "\\.sgm$" 'sgml-mode) ;; (cons "\\.sgml$" 'sgml-mode) ;; (cons "\\.dtd$" 'sgml-mode)) ;; auto-mode-alist)) ;;; Code: (provide 'sgml-mode) (require 'compile) ;;; sgmls is a free SGML parser available from ;;; ftp.uu.net:pub/text-processing/sgml ;;; Its error messages can be parsed by next-error. ;;; The -s option suppresses output. (defconst sgml-validate-command "sgmls -s" "*The command to validate an SGML document. The file name of current buffer file name will be appended to this, separated by a space.") (defvar sgml-saved-validate-command nil "The command last used to validate in this buffer.") (defvar sgml-mode-map nil "Keymap for SGML mode") (if sgml-mode-map () (setq sgml-mode-map (make-sparse-keymap)) (define-key sgml-mode-map ">" 'sgml-close-angle) (define-key sgml-mode-map "/" 'sgml-slash) (define-key sgml-mode-map "\C-c\C-v" 'sgml-validate)) (defun sgml-mode () "Major mode for editing SGML. Makes > display the matching <. Makes / display matching /. Use \\[sgml-validate] to validate your document with an SGML parser." (interactive) (kill-all-local-variables) (setq local-abbrev-table text-mode-abbrev-table) (use-local-map sgml-mode-map) (setq mode-name "SGML") (setq major-mode 'sgml-mode) (make-local-variable 'paragraph-start) ;; A start or end tag by itself on a line separates a paragraph. ;; This is desirable because SGML discards a newline that appears ;; immediately after a start tag or immediately before an end tag. (setq paragraph-start "^[ \t\n]\\|\ \\(</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$\\)") (make-local-variable 'paragraph-separate) (setq paragraph-separate "^[ \t\n]*$\\|\ ^</?\\([A-Za-z]\\([-.A-Za-z0-9= \t\n]\\|\"[^\"]*\"\\|'[^']*'\\)*\\)?>$") (make-local-variable 'sgml-saved-validate-command) (set-syntax-table text-mode-syntax-table) (make-local-variable 'comment-start) (setq comment-start "<!-- ") (make-local-variable 'comment-end) (setq comment-end " -->") (make-local-variable 'comment-indent-hook) (setq comment-indent-hook 'sgml-comment-indent) (make-local-variable 'comment-start-skip) ;; This will allow existing comments within declarations to be ;; recognized. (setq comment-start-skip "--[ \t]*") (run-hooks 'text-mode-hook 'sgml-mode-hook)) (defun sgml-comment-indent () (if (and (looking-at "--") (not (and (eq (char-after (1- (point))) ?!) (eq (char-after (- (point) 2)) ?<)))) (progn (skip-chars-backward " \t") (max comment-column (1+ (current-column)))) 0)) (defconst sgml-start-tag-regex "<[A-Za-z]\\([-.A-Za-z0-9= \n\t]\\|\"[^\"]*\"\\|'[^']*'\\)*" "Regular expression that matches a non-empty start tag. Any terminating > or / is not matched.") (defvar sgml-mode-markup-syntax-table nil "Syntax table used for scanning SGML markup.") (if sgml-mode-markup-syntax-table () (setq sgml-mode-markup-syntax-table (make-syntax-table)) (modify-syntax-entry ?< "(>" sgml-mode-markup-syntax-table) (modify-syntax-entry ?> ")<" sgml-mode-markup-syntax-table) (modify-syntax-entry ?- "_ 1234" sgml-mode-markup-syntax-table) (modify-syntax-entry ?\' "\"" sgml-mode-markup-syntax-table)) (defconst sgml-angle-distance 4000 "*If non-nil, is the maximum distance to search for matching < when > is inserted.") (defun sgml-close-angle (arg) "Insert > and display matching <." (interactive "p") (insert-char ?> arg) (if (> arg 0) (let ((oldpos (point)) (blinkpos)) (save-excursion (save-restriction (if sgml-angle-distance (narrow-to-region (max (point-min) (- (point) sgml-angle-distance)) oldpos)) ;; See if it's the end of a marked section. (and (> (- (point) (point-min)) 3) (eq (char-after (- (point) 2)) ?\]) (eq (char-after (- (point) 3)) ?\]) (re-search-backward "<!\\[\\(-?[A-Za-z0-9. \t\n&;]\\|\ --\\([^-]\\|-[^-]\\)*--\\)*\\[" (point-min) t) (let ((msspos (point))) (if (and (search-forward "]]>" oldpos t) (eq (point) oldpos)) (setq blinkpos msspos)))) ;; This handles cases where the > ends one of the following: ;; markup declaration starting with <! (possibly including a ;; declaration subset); start tag; end tag; SGML declaration. (if blinkpos () (goto-char oldpos) (condition-case () (let ((oldtable (syntax-table)) (parse-sexp-ignore-comments t)) (unwind-protect (progn (set-syntax-table sgml-mode-markup-syntax-table) (setq blinkpos (scan-sexps oldpos -1))) (set-syntax-table oldtable))) (error nil)) (and blinkpos (goto-char blinkpos) (or ;; Check that it's a valid delimiter in context. (not (looking-at "<\\(\\?\\|/?[A-Za-z>]\\|!\\([[A-Za-z]\\|--\\)\\)")) ;; Check that it's not a net-enabling start tag ;; nor an unclosed start-tag. (looking-at (concat sgml-start-tag-regex "[/<]")) ;; Nor an unclosed end-tag. (looking-at "</[A-Za-z][-.A-Za-z0-9]*[ \t]*<")) (setq blinkpos nil))) (if blinkpos () ;; See if it's the end of a processing instruction. (goto-char oldpos) (if (search-backward "<?" (point-min) t) (let ((pipos (point))) (if (and (search-forward ">" oldpos t) (eq (point) oldpos)) (setq blinkpos pipos)))))) (if blinkpos (progn (goto-char blinkpos) (if (pos-visible-in-window-p) (sit-for 1) (message "Matches %s" (buffer-substring blinkpos (progn (end-of-line) (point))))))))))) ;;; I doubt that null end tags are used much for large elements, ;;; so use a small distance here. (defconst sgml-slash-distance 1000 "*If non-nil, is the maximum distance to search for matching / when / is inserted.") (defun sgml-slash (arg) "Insert / and display any previous matching /. Two /s are treated as matching if the first / ends a net-enabling start tag, and the second / is the corresponding null end tag." (interactive "p") (insert-char ?/ arg) (if (> arg 0) (let ((oldpos (point)) (blinkpos) (level 0)) (save-excursion (save-restriction (if sgml-slash-distance (narrow-to-region (max (point-min) (- (point) sgml-slash-distance)) oldpos)) (if (and (re-search-backward sgml-start-tag-regex (point-min) t) (eq (match-end 0) (1- oldpos))) () (goto-char (1- oldpos)) (while (and (not blinkpos) (search-backward "/" (point-min) t)) (let ((tagend (save-excursion (if (re-search-backward sgml-start-tag-regex (point-min) t) (match-end 0) nil)))) (if (eq tagend (point)) (if (eq level 0) (setq blinkpos (point)) (setq level (1- level))) (setq level (1+ level))))))) (if blinkpos (progn (goto-char blinkpos) (if (pos-visible-in-window-p) (sit-for 1) (message "Matches %s" (buffer-substring (progn (beginning-of-line) (point)) (1+ blinkpos)))))))))) (defun sgml-validate (command) "Validate an SGML document. Runs COMMAND, a shell command, in a separate process asynchronously with output going to the buffer *compilation*. You can then use the command \\[next-error] to find the next error message and move to the line in the SGML document that caused it." (interactive (list (read-string "Validate command: " (or sgml-saved-validate-command (concat sgml-validate-command " " (let ((name (buffer-file-name))) (and name (file-name-nondirectory name)))))))) (setq sgml-saved-validate-command command) (compile1 command "No more errors")) ;;; sgml-mode.el ends here
