Mercurial > hg > xemacs-beta
diff lisp/syntax.el @ 209:41ff10fd062f r20-4b3
Import from CVS: tag r20-4b3
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:04:58 +0200 |
parents | |
children | 8626e4521993 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/syntax.el Mon Aug 13 10:04:58 2007 +0200 @@ -0,0 +1,418 @@ +;; syntax.el --- Syntax-table hacking stuff, moved from syntax.c + +;; Copyright (C) 1993, 1997 Free Software Foundation, Inc. +;; Copyright (C) 1995 Sun Microsystems. + +;; This file is part of XEmacs. + +;; XEmacs 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 2, or (at your option) +;; any later version. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the +;; Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Synched up with: FSF 19.28. + +;;; Commentary: + +;; This file is dumped with XEmacs. + +;; Note: FSF does not have a file syntax.el. This stuff is +;; in syntax.c. See comments there about not merging past 19.28. + +;; Significantly hacked upon by Ben Wing. + +;;; Code: + +(defun make-syntax-table (&optional oldtable) + "Return a new syntax table. +It inherits all characters from the standard syntax table." + (make-char-table 'syntax)) + +(defun simple-set-syntax-entry (char spec table) + (put-char-table char spec table)) + +(defun char-syntax-from-code (code) + "Extract the syntax designator from the internal syntax code CODE. +CODE is the value actually contained in the syntax table." + (if (consp code) + (setq code (car code))) + (aref (syntax-designator-chars) (logand code 127))) + +(defun set-char-syntax-in-code (code desig) + "Return a new internal syntax code whose syntax designator is DESIG. +Other characteristics are the same as in CODE." + (let ((newcode (if (consp code) (car code) code))) + (setq newcode (logior (string-match + (regexp-quote (char-to-string desig)) + (syntax-designator-chars)) + (logand newcode (lognot 127)))) + (if (consp code) (cons newcode (cdr code)) + newcode))) + +(defun syntax-code-to-string (code) + "Return a string equivalent to internal syntax code CODE. +The string can be passed to `modify-syntax-entry'. +If CODE is invalid, return nil." + (let ((match (and (consp code) (cdr code))) + (codes (syntax-designator-chars))) + (if (consp code) + (setq code (car code))) + (if (or (not (integerp code)) + (> (logand code 127) (length codes))) + nil + (with-output-to-string + (let* ((spec (elt codes (logand code 127))) + (b3 (lsh code -16)) + (start1 (/= 0 (logand b3 128))) ;logtest! + (start1b (/= 0 (logand b3 64))) + (start2 (/= 0 (logand b3 32))) + (start2b (/= 0 (logand b3 16))) + (end1 (/= 0 (logand b3 8))) + (end1b (/= 0 (logand b3 4))) + (end2 (/= 0 (logand b3 2))) + (end2b (/= 0 (logand b3 1))) + (prefix (/= 0 (logand code 128))) + (single-char-p (or (= spec ?<) (= spec ?>))) + ) + (write-char spec) + (write-char (if match match 32)) +;;; (if start1 (if single-char-p (write-char ?a) (write-char ?1))) + (if start1 (if single-char-p (write-char ? ) (write-char ?1))) + (if start2 (write-char ?2)) +;;; (if end1 (if single-char-p (write-char ?a) (write-char ?3))) + (if end1 (if single-char-p (write-char ? ) (write-char ?3))) + (if end2 (write-char ?4)) + (if start1b (if single-char-p (write-char ?b) (write-char ?5))) + (if start2b (write-char ?6)) + (if end1b (if single-char-p (write-char ?b) (write-char ?7))) + (if end2b (write-char ?8)) + (if prefix (write-char ?p))))))) + +(defun syntax-string-to-code (string) + "Return the internal syntax code equivalent to STRING. +STRING should be something acceptable as the second argument to +`modify-syntax-entry'. +If STRING is invalid, signal an error." + (let* ((bflag nil) + (b3 0) + (ch0 (aref string 0)) + (len (length string)) + (code (string-match (regexp-quote (char-to-string ch0)) + (syntax-designator-chars))) + (i 2) + ch) + (or code + (error "Invalid syntax designator: %S" string)) + (while (< i len) + (setq ch (aref string i)) + (incf i) + (case ch + (?1 (setq b3 (logior b3 128))) + (?2 (setq b3 (logior b3 32))) + (?3 (setq b3 (logior b3 8))) + (?4 (setq b3 (logior b3 2))) + (?5 (setq b3 (logior b3 64))) + (?6 (setq b3 (logior b3 16))) + (?7 (setq b3 (logior b3 4))) + (?8 (setq b3 (logior b3 1))) + (?a (case ch0 + (?< (setq b3 (logior b3 128))) + (?> (setq b3 (logior b3 8))))) + (?b (case ch0 + (?< (setq b3 (logior b3 64) bflag t)) + (?> (setq b3 (logior b3 4) bflag t)))) + (?p (setq code (logior code (lsh 1 7)))) + (?\ nil) ;; ignore for compatibility + (otherwise + (error "Invalid syntax description flag: %S" string)))) + ;; default single char style if `b' has not been seen + (if (not bflag) + (case ch0 + (?< (setq b3 (logior b3 128))) + (?> (setq b3 (logior b3 8))))) + (setq code (logior code (lsh b3 16))) + (if (and (> len 1) + ;; tough luck if you want to make space a paren! + (/= (aref string 1) ?\ )) + (setq code (cons code (aref string 1)))) + code)) + +(defun modify-syntax-entry (char-range spec &optional table) + "Set syntax for the characters CHAR-RANGE according to string SPEC. +CHAR-RANGE is a single character or a range of characters, + as per `put-char-table'. +The syntax is changed only for table TABLE, which defaults to + the current buffer's syntax table. +The first character of SPEC should be one of the following: + Space whitespace syntax. w word constituent. + _ symbol constituent. . punctuation. + \( open-parenthesis. \) close-parenthesis. + \" string quote. \\ character-quote. + $ paired delimiter. ' expression quote or prefix operator. + < comment starter. > comment ender. + / character-quote. @ inherit from `standard-syntax-table'. + +Only single-character comment start and end sequences are represented thus. +Two-character sequences are represented as described below. +The second character of SPEC is the matching parenthesis, + used only if the first character is `(' or `)'. +Any additional characters are flags. +Defined flags are the characters 1, 2, 3, 4, 5, 6, 7, 8, p, a, and b. + 1 means C is the first of a two-char comment start sequence of style a. + 2 means C is the second character of such a sequence. + 3 means C is the first of a two-char comment end sequence of style a. + 4 means C is the second character of such a sequence. + 5 means C is the first of a two-char comment start sequence of style b. + 6 means C is the second character of such a sequence. + 7 means C is the first of a two-char comment end sequence of style b. + 8 means C is the second character of such a sequence. + p means C is a prefix character for `backward-prefix-chars'; + such characters are treated as whitespace when they occur + between expressions. + a means C is comment starter or comment ender for comment style a (default) + b means C is comment starter or comment ender for comment style b." + (interactive + ;; I really don't know why this is interactive + ;; help-form should at least be made useful whilst reading the second arg + "cSet syntax for character: \nsSet syntax for %c to: ") + (cond ((syntax-table-p table)) + ((not table) + (setq table (syntax-table))) + (t + (setq table + (wrong-type-argument 'syntax-table-p table)))) + (let ((code (syntax-string-to-code spec))) + (simple-set-syntax-entry char-range code table)) + nil) + +(defun map-syntax-table (__function __table &optional __range) + "Map FUNCTION over entries in syntax table TABLE, collapsing inheritance. +This is similar to `map-char-table', but works only on syntax tables, and + collapses any entries that call for inheritance by invisibly substituting + the inherited values from the standard syntax table." + (check-argument-type 'syntax-table-p __table) + (map-char-table #'(lambda (__key __value) + (if (eq ?@ (char-syntax-from-code __value)) + (map-char-table #'(lambda (__key __value) + (funcall __function + __key __value)) + (standard-syntax-table) + __key) + (funcall __function __key __value))) + __table __range)) + +;(defun test-xm () +; (let ((o (copy-syntax-table)) +; (n (copy-syntax-table)) +; (codes (syntax-designator-chars)) +; (flags "12345678abp")) +; (while t +; (let ((spec (concat (char-to-string (elt codes +; (random (length codes)))))) +; (if (= (random 4) 0) +; "b" +; " ") +; (let* ((n (random 4)) +; (s (make-string n 0))) +; (while (> n 0) +; (setq n (1- n)) +; (aset s n (aref flags (random (length flags))))) +; s)))) +; (message "%S..." spec) +; (modify-syntax-entry ?a spec o) +; (xmodify-syntax-entry ?a spec n) +; (or (= (aref o ?a) (aref n ?a)) +; (error "%s" +; (format "fucked with %S: %x %x" +; spec (aref o ?a) (aref n ?a)))))))) + + +(defun describe-syntax-table (table stream) + (let (first-char + last-char + prev-val + (describe-one + (if (featurep 'mule) + #'(lambda (first last value stream) + (if (equal first last) + (cond ((vectorp first) + (princ (format "%s, row %d\t" + (charset-name + (aref first 0)) + (aref first 1)) + stream)) + ((symbolp first) + (princ first stream) + (princ "\t" stream)) + (t + (princ (text-char-description first) stream) + (princ "\t" stream))) + (cond ((vectorp first) + (princ (format "%s, rows %d .. %d\t" + (charset-name + (aref first 0)) + (aref first 1) + (aref last 1)) + stream)) + ((symbolp first) + (princ (format "%s .. %s\t" first last) stream)) + (t + (princ (format "%s .. %s\t" + (text-char-description first) + (text-char-description last)) + stream)))) + (describe-syntax-code value stream)) + #'(lambda (first last value stream) + (let* ((tem (text-char-description first)) + (pos (length tem)) + ;;(limit (cond ((numberp ctl-arrow) ctl-arrow) + ;; ((memq ctl-arrow '(t nil)) 256) + ;; (t 160))) + ) + (princ tem stream) + (if (> last first) + (progn + (princ " .. " stream) + (setq tem (text-char-description last)) + (princ tem stream) + (setq pos (+ pos (length tem) 4)))) + (while (progn (write-char ?\ stream) + (setq pos (1+ pos)) + (< pos 16)))) + (describe-syntax-code value stream))))) + (map-syntax-table + #'(lambda (range value) + (cond + ((not first-char) + (setq first-char range + last-char range + prev-val value)) + ((and (equal value prev-val) + (or + (and (characterp range) + (characterp first-char) + (or (not (featurep 'mule)) + (eq (char-charset range) + (char-charset first-char))) + (= (char-int last-char) (1- (char-int range)))) + (and (vectorp range) + (vectorp first-char) + (eq (aref range 0) (aref first-char 0)) + (= (aref last-char 1) (1- (aref range 1)))))) + (setq last-char range)) + (t + (funcall describe-one first-char last-char prev-val stream) + (setq first-char range + last-char range + prev-val value))) + nil) + table) + (if first-char + (funcall describe-one first-char last-char prev-val stream)))) + +(defun describe-syntax-code (code stream) + (let ((match (and (consp code) (cdr code))) + (invalid (gettext "**invalid**")) ;(empty "") ;constants + (standard-output (or stream standard-output)) + ;; #### I18N3 should temporarily set buffer to output-translatable + (in #'(lambda (string) + (princ ",\n\t\t\t\t ") + (princ string))) + (syntax-string (syntax-code-to-string code))) + (if (consp code) + (setq code (car code))) + (if (null syntax-string) + (princ invalid) + (princ syntax-string) + (princ "\tmeaning: ") + (princ (aref ["whitespace" "punctuation" "word-constituent" + "symbol-constituent" "open-paren" "close-paren" + "expression-prefix" "string-quote" "paired-delimiter" + "escape" "character-quote" "comment-begin" "comment-end" + "inherit" "extended-word-constituent"] + (logand code 127))) + + (if match + (progn + (princ ", matches ") + (princ (text-char-description match)))) + (let* ((spec (elt syntax-string 0)) + (b3 (lsh code -16)) + (start1 (/= 0 (logand b3 128))) ;logtest! + (start1b (/= 0 (logand b3 64))) + (start2 (/= 0 (logand b3 32))) + (start2b (/= 0 (logand b3 16))) + (end1 (/= 0 (logand b3 8))) + (end1b (/= 0 (logand b3 4))) + (end2 (/= 0 (logand b3 2))) + (end2b (/= 0 (logand b3 1))) + (prefix (/= 0 (logand code 128))) + (single-char-p (or (= spec ?<) (= spec ?>)))) + (if start1 + (if single-char-p + (princ ", style A") + (funcall in + (gettext "first character of comment-start sequence A")))) + (if start2 + (funcall in + (gettext "second character of comment-start sequence A"))) + (if end1 + (if single-char-p + (princ ", style A") + (funcall in + (gettext "first character of comment-end sequence A")))) + (if end2 + (funcall in + (gettext "second character of comment-end sequence A"))) + (if start1b + (if single-char-p + (princ ", style B") + (funcall in + (gettext "first character of comment-start sequence B")))) + (if start2b + (funcall in + (gettext "second character of comment-start sequence B"))) + (if end1b + (if single-char-p + (princ ", style B") + (funcall in + (gettext "first character of comment-end sequence B")))) + (if end2b + (funcall in + (gettext "second character of comment-end sequence B"))) + (if prefix + (funcall in + (gettext "prefix character for `backward-prefix-chars'")))) + (terpri stream)))) + +(defun symbol-near-point () + "Return the first textual item to the nearest point." + (interactive) + ;alg stolen from etag.el + (save-excursion + (if (or (bobp) (not (memq (char-syntax (char-before)) '(?w ?_)))) + (while (not (looking-at "\\sw\\|\\s_\\|\\'")) + (forward-char 1))) + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (re-search-backward "\\sw\\|\\s_" nil t) + (regexp-quote + (progn (forward-char 1) + (buffer-substring (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point))))) + nil))) + +;;; syntax.el ends here