1;; 2;; Copyright (c) 2002 by The XFree86 Project, Inc. 3;; 4;; Permission is hereby granted, free of charge, to any person obtaining a 5;; copy of this software and associated documentation files (the "Software"), 6;; to deal in the Software without restriction, including without limitation 7;; the rights to use, copy, modify, merge, publish, distribute, sublicense, 8;; and/or sell copies of the Software, and to permit persons to whom the 9;; Software is furnished to do so, subject to the following conditions: 10;; 11;; The above copyright notice and this permission notice shall be included in 12;; all copies or substantial portions of the Software. 13;; 14;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17;; THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19;; OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20;; SOFTWARE. 21;; 22;; Except as contained in this notice, the name of the XFree86 Project shall 23;; not be used in advertising or otherwise to promote the sale, use or other 24;; dealings in this Software without prior written authorization from the 25;; XFree86 Project. 26;; 27;; Author: Paulo César Pereira de Andrade 28;; 29;; 30;; $XFree86: xc/programs/xedit/lisp/modules/progmodes/sgml.lsp,v 1.2 2002/10/06 17:11:48 paulo Exp $ 31;; 32 33(require "syntax") 34(in-package "XEDIT") 35 36;; Default property the text is shown. 37(defsynprop *prop-sgml-default* 38 "default" 39 :font "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-1" 40 :foreground "Gray10" 41) 42 43(defsynprop *prop-sgml-default-short* 44 "default-short" 45 :font "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-1" 46 :foreground "Gray10" 47 :underline t 48) 49 50;; Large font. 51(defsynprop *prop-sgml-sect* 52 "sect" 53 :font "-*-helvetica-bold-r-*-*-17-*-*-*-*-*-*-1" 54 :foreground "Gray20" 55) 56 57;; Monospaced property. 58(defsynprop *prop-sgml-tt* 59 "tt" 60 :font "-*-courier-medium-r-*-*-12-*-*-*-*-*-*-1" 61 :foreground "Black" 62) 63 64;; Italic property. 65(defsynprop *prop-sgml-it* 66 "it" 67 :font "-*-helvetica-medium-o-*-*-12-*-*-*-*-*-*-1" 68 :foreground "Black" 69) 70 71;; Bold font property. 72(defsynprop *prop-sgml-bf* 73 "bf" 74 :font "-*-helvetica-bold-r-*-*-12-*-*-*-*-*-*-1" 75 :foreground "Gray10" 76) 77 78;; Looks like a link... 79(defsynprop *prop-sgml-link* 80 "link" 81 :font "-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-1" 82 :foreground "blue" 83 :underline t 84) 85 86;; Monospaced, also looks like a link... 87(defsynprop *prop-sgml-email* 88 "email" 89 :font "-*-courier-medium-r-*-*-12-*-*-*-*-*-*-1" 90 :foreground "blue" 91 :underline t 92) 93 94;; Another monospaced property, 95(defsynprop *prop-sgml-screen* 96 "screen" 97 :font "-*-fixed-*-*-*-*-*-*-*-*-*-*-*-1" 98 :foreground "Gray10" 99) 100 101(defsynprop *prop-sgml-maybe-entity* 102 "maybe-entity" 103 :font "*lucidatypewriter-medium-r*-12-*" 104 :foreground "VioletRed4" 105 :background "LightYellow" 106) 107 108;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 109;; The macros sgml-syntoken and sgml-syntable allows creating rules for 110;; matching text inside tags in the format: 111;; <tag> or <tag arg=value> or <tag arg1=value ... argn=value> 112;; any-text 113;; </tag> 114;; The generated rules don't allow things like: < tag> or </tag > 115;; 116;; This could also be done as a normal definition, with a starting rule like: 117;; "<(tag1|tag2|tag3)\\>" 118;; and an ending rule like: 119;; "</(tag1|tag2|tag3)>" 120;; But is implemented in way that will fail on purpose for things like: 121;; <tag1>any text</tag3></tag1> 122;; 123;; NOTE: These definitions aren't cheap in the time required to process the 124;; file, and are just adaptations/tests with the syntax-highlight code, 125;; probably it is better to avoid using it in other syntax definitions. 126;; NOTE2: It cannot be defined as a single macro because it is required to 127;; generate 2 entries in the main SGML syntax highlight definition, 128;; or, should generate the entire definition from a macro; you will 129;; need to type the tag name twice, but shouldn't be a problem if 130;; you are using sgml :-) 131;; XXX: Maybe the syntax-highlight code could save the starting match and 132;; apply a regex generated at run-time to check for the ending tag, 133;; but this probably would make the parser too slow, better to have 134;; a specialized parser if that is required... 135;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 136(defmacro sgml-syntoken (name) 137 `(syntoken (string-concat "<" ,name "\\>") 138 :icase t 139 :contained t 140 :begin (intern (string-concat ,name "$") 'keyword)) 141) 142(defmacro sgml-syntable (name property) 143 `(let 144 ( 145 (label (intern (string-concat ,name "$") 'keyword)) 146 (nested-label (intern (string (gensym)) 'keyword)) 147 ) 148 (syntable label *prop-preprocessor* nil 149 ;; tag is still open, process any options 150 (synaugment :generic-tag) 151 (syntoken ">" 152 :nospec t 153 :property *prop-preprocessor* 154 :begin nested-label) 155 ;; Generate a nested table that includes everything, and only 156 ;; returns when the closing tag is found. 157 (syntable nested-label ,property nil 158 (syntoken (string-concat "</" ,name ">") 159 :icase t 160 :nospec t 161 :property *prop-preprocessor* 162 :switch -2) 163 (synaugment :main) 164 ) 165 ) 166 ) 167) 168;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 169;; Generate tokens for tags that don't require and ending tag. 170;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 171(defmacro sgml-syntable-simple (name property) 172 `(let 173 ( 174 (label (intern (string-concat ,name "$") 'keyword)) 175 (nested-label (intern (string (gensym)) 'keyword)) 176 ) 177 (syntable label *prop-preprocessor* nil 178 ;; tag is still open, process any options 179 (synaugment :generic-tag) 180 (syntoken ">" 181 :nospec t 182 :property *prop-preprocessor* 183 :begin nested-label) 184 ;; Generate a nested table that finishes whenever an unmatched 185 ;; start or end tag is found. 186 (syntable nested-label ,property nil 187 (syntoken "</" 188 :icase t 189 :nospec t 190 :contained t 191 :begin :simple-nested-tag) 192 ;; These will take precedence over other rules 193 (syntoken "<" 194 :icase t 195 :nospec t 196 :contained t 197 :begin :simple-nested-tag) 198 (syntoken "<p>" 199 :icase t 200 :nospec t 201 :property *prop-preprocessor* 202 :switch :main) 203 (synaugment :main) 204 ) 205 ) 206 ) 207) 208;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 209;; Define some macros to generate tokens for tags in the format: 210;; <tag/ ... / 211;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 212(defmacro sgml-syntoken-short (name) 213 `(syntoken (string-concat "<" ,name "/") 214 :icase t 215 :property *prop-preprocessor* 216 :begin (intern (string-concat ,name "/") 'keyword)) 217) 218(defmacro sgml-syntable-short (name property) 219 `(syntable (intern (string-concat ,name "/") 'keyword) ,property nil 220 (syntoken "/" 221 :nospec t 222 :property *prop-preprocessor* 223 :switch -1) 224 (syntoken "</?\\w+>" 225 :property *prop-control* 226 :switch :main) 227 ) 228) 229 230 231;; The main SGML syntax table 232(defsyntax *sgml-mode* :main *prop-sgml-default* nil nil 233 ;; Comments 234 (syntoken "<!--" 235 :nospec t 236 :contained t 237 :begin :comment) 238 (syntable :comment *prop-comment* nil 239 ;; Only one rule, to finish the comment. 240 (syntoken "-->" 241 :nospec t 242 :switch -1) 243 ) 244 245 ;; Entities 246 (syntoken "&[a-zA-Z0-9_.-]+;" 247 :property *prop-constant*) 248 ;; Probably an entity, missing ending `;' 249 (syntoken "&[a-zA-Z0-9_.-]+" 250 :property *prop-sgml-maybe-entity*) 251 252 ;; Strings 253 (syntable :string *prop-string* nil 254 ;; Ignore escaped characters. 255 (syntoken "\\\\.") 256 ;; Rule to finish the string. 257 (syntoken "\"" 258 :nospec t 259 :switch -1) 260 ) 261 262 ;; Links 263 (syntable :link *prop-preprocessor* nil 264 ;; No link string following "url=" 265 (syntoken ">" 266 :nospec t 267 :property *prop-control* 268 :switch -1) 269 (syntoken "\"" 270 :nospec t 271 :contained t 272 :begin :link-string) 273 (syntable :link-string *prop-sgml-link* nil 274 ;; Ignore escaped characters. 275 (syntoken "\\\\.") 276 ;; Rule to finish the link, note that returns two levels. 277 (syntoken "\"" 278 :nospec t 279 :switch -2) 280 ) 281 ) 282 283 ;; "Special" tag 284 (syntoken "<!" 285 :nospec t 286 :contained t 287 :begin :special-tag) 288 ;; Rules for "special" tags 289 (syntable :special-tag *prop-preprocessor* nil 290 (syntoken "[" 291 :nospec t 292 :property *prop-preprocessor* 293 :begin :brackets) 294 ;; Finish the "special" tag 295 (syntoken ">" 296 :nospec t 297 :switch -1) 298 (syntable :brackets *prop-sgml-default* nil 299 (syntoken "]" 300 :nospec t 301 :property *prop-preprocessor* 302 :switch -1) 303 ;; Allow nesting. 304 (syntoken "[" 305 :nospec t 306 :property *prop-preprocessor* 307 :begin :brackets) 308 ;; Entities. 309 (syntoken "%[a-zA-Z0-9_.-]+;?" 310 :property *prop-annotation*) 311 ;; Allow everything inside the brackets 312 (synaugment :main) 313 ) 314 ;; Don't use generic tag tokens, only create a rule for strings 315 (syntoken "\"" 316 :nospec t 317 :begin :string 318 :contained t) 319 ;; Allow everything inside the "special" tag 320 (synaugment :main) 321 ) 322 323 ;; Some "short" tags 324 (sgml-syntoken-short "tt") 325 (sgml-syntable-short "tt" *prop-sgml-tt*) 326 (sgml-syntoken-short "it") 327 (sgml-syntable-short "it" *prop-sgml-it*) 328 (sgml-syntoken-short "bf") 329 (sgml-syntable-short "bf" *prop-sgml-bf*) 330 (sgml-syntoken-short "em") 331 (sgml-syntable-short "em" *prop-sgml-bf*) 332 333 ;; Short tag 334 (syntoken "<\\w+/" 335 :property *prop-preprocessor* 336 :begin :short-tag) 337 (syntable :short-tag *prop-sgml-default-short* nil 338 (syntoken "/" 339 :nospec t 340 :property *prop-preprocessor* 341 :switch -1) 342 (syntoken "</?\\w+>" 343 :property *prop-control* 344 :switch -1) 345 ) 346 347 ;; Don't allow spaces, this may and may not be the start of a tag, 348 ;; but the syntax-highlight definition is not specialized... 349 (syntoken "<([^/a-zA-Z]|$)" 350 :property *prop-control*) 351 352 ;; Some tags that require an end tag 353 (sgml-syntoken "tt") 354 (sgml-syntable "tt" *prop-sgml-tt*) 355 (sgml-syntoken "code") 356 (sgml-syntable "code" *prop-sgml-tt*) 357 (sgml-syntoken "tag") 358 (sgml-syntable "tag" *prop-sgml-tt*) 359 (sgml-syntoken "verb") 360 (sgml-syntable "verb" *prop-sgml-tt*) 361 (sgml-syntoken "programlisting") 362 (sgml-syntable "programlisting" *prop-sgml-tt*) 363 (sgml-syntoken "it") 364 (sgml-syntable "it" *prop-sgml-it*) 365 (sgml-syntoken "bf") 366 (sgml-syntable "bf" *prop-sgml-bf*) 367 (sgml-syntoken "em") 368 (sgml-syntable "em" *prop-sgml-bf*) 369 (sgml-syntoken "mail") 370 (sgml-syntable "mail" *prop-sgml-email*) 371 (sgml-syntoken "email") 372 (sgml-syntable "email" *prop-sgml-email*) 373 (sgml-syntoken "screen") 374 (sgml-syntable "screen" *prop-sgml-screen*) 375 (sgml-syntoken "tscreen") 376 (sgml-syntable "tscreen" *prop-sgml-screen*) 377 378 379 ;; Helper for tags that don't need an ending one. 380 ;; NOTE: Since the parser is not specialized, if the tag is 381 ;; folowed by one that has a special property defined here, 382 ;; it may not be detected, i.e. put a <p> after the <sect> 383 ;; and it will work. 384 (syntable :simple-nested-tag *prop-preprocessor* nil 385 ;; tag is still open, process any options 386 (synaugment :generic-tag) 387 (syntoken ">" 388 :nospec t 389 :property *prop-preprocessor* 390 :switch -3) 391 ) 392 (sgml-syntoken "sect") 393 (sgml-syntable-simple "sect" *prop-sgml-sect*) 394 (sgml-syntoken "sect1") 395 (sgml-syntable-simple "sect1" *prop-sgml-sect*) 396 (sgml-syntoken "sect2") 397 (sgml-syntable-simple "sect2" *prop-sgml-sect*) 398 399 ;; Generic tags 400 (syntoken "<" 401 :nospec t 402 :contained t 403 :begin :tag) 404 ;; Table :generic-tag is defined to be augmented, no rule to finish it. 405 (syntable :generic-tag *prop-preprocessor* nil 406 ;; Start string 407 (syntoken "\"" 408 :nospec t 409 :begin :string 410 :contained t) 411 ;; Start url link 412 (syntoken "url=" 413 :nospec t 414 :begin :link) 415 ;; Cannot nest 416 (syntoken "<" 417 :nospec t 418 :property *prop-control*) 419 ) 420 (syntable :tag *prop-preprocessor* nil 421 ;; Finish the tag 422 (syntoken ">" 423 :nospec t 424 :switch -1) 425 ;; Import generic definitions 426 (synaugment :generic-tag) 427 ) 428) 429