From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Edward Welbourne Newsgroups: gmane.emacs.bugs Subject: Re: C-comments in sgml-mode's html-mode Date: Tue, 24 Jul 2007 22:05:13 +0200 Message-ID: References: <46A1DEB4.8080501@gmx.at> <46A49E9F.1090806@gmx.at> <46A4F65C.2070403@gmx.at> <46A5F814.2000701@gmx.at> <46A611DE.8080501@gmail.com> <46A62D1A.3070306@gmx.at> Reply-To: eddy@opera.com NNTP-Posting-Host: lo.gmane.org X-Trace: sea.gmane.org 1185307562 30495 80.91.229.12 (24 Jul 2007 20:06:02 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Tue, 24 Jul 2007 20:06:02 +0000 (UTC) Cc: bug-gnu-emacs@gnu.org To: martin rudalics Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Tue Jul 24 22:05:51 2007 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1IDQdg-0000db-AN for geb-bug-gnu-emacs@m.gmane.org; Tue, 24 Jul 2007 22:05:48 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IDQdf-0003NH-V6 for geb-bug-gnu-emacs@m.gmane.org; Tue, 24 Jul 2007 16:05:47 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1IDQde-0003NB-RV for bug-gnu-emacs@gnu.org; Tue, 24 Jul 2007 16:05:46 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1IDQdd-0003Mz-W1 for bug-gnu-emacs@gnu.org; Tue, 24 Jul 2007 16:05:46 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1IDQdd-0003Mw-T7 for bug-gnu-emacs@gnu.org; Tue, 24 Jul 2007 16:05:45 -0400 Original-Received: from sam.opera.com ([213.236.208.81]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1IDQdd-0003O3-2k for bug-gnu-emacs@gnu.org; Tue, 24 Jul 2007 16:05:45 -0400 Original-Received: from whorl (pat-tdc.opera.com [213.236.208.22]) by sam.opera.com (8.13.4/8.13.4/Debian-3sarge3) with ESMTP id l6OK5ZPv004331 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT); Tue, 24 Jul 2007 20:05:36 GMT Original-Received: from eddy by whorl with local (Exim 4.67) (envelope-from ) id 1IDQd7-0004rd-Fs; Tue, 24 Jul 2007 22:05:13 +0200 In-reply-to: <46A62D1A.3070306@gmx.at> (message from martin rudalics on Tue, 24 Jul 2007 18:47:22 +0200) X-Virus-Scanned: ClamAV 0.90.1/3754/Tue Jul 24 13:41:21 2007 on sam.opera.com X-Virus-Status: Clean X-detected-kernel: Linux 2.4-2.6 X-BeenThere: bug-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:16227 > In any case this should be reported to the Debian bug tracking > system since probably more people might be affected by this. Debian bug submitted. I'll follow up with bug number and URL once the robots answer. > Apparently, Zaitseff's modifications are too persistent but I can't tell > anything because I don't have the sources. Source follows, Eddy. -- ;;;; A major mode for editing CSS. ;;; Adds font locking, some rather primitive indentation handling and ;;; some typing help. ;;; (defvar cssm-version "0.11.zap1" "The current version number of css-mode.") ;;; copyright (c) 1998 Lars Marius Garshol, larsga@ifi.uio.no ;;; $Id: css-mode.el,v 1.9 2000/01/05 21:21:56 larsga Exp $ ;;; Modified by John Zaitseff, 3rd November 2004. ;;; css-mode 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. ;;; ;;; css-mode 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. ; Send me an email if you want new features (or if you add them yourself). ; I will do my best to preserve the API to functions not explicitly marked ; as internal and variables shown as customizable. I make no promises about ; the rest. ; Bug reports are very welcome. New versions of the package will appear at ; http://www.stud.ifi.uio.no/~larsga/download/css-mode.html ; You can register at the same address if you want to be notified when a ; new version appears. ; Thanks to Philippe Le Hegaret, Kjetil Kjernsmo, Alf-Ivar Holm and ; Alfred Correira for much useful feedback. Alf-Ivar Holm also contributed ; patches. ; To install, put this in your .emacs: ; ; (autoload 'css-mode "css-mode") ; (setq auto-mode-alist ; (cons '("\\.css\\'" . css-mode) auto-mode-alist)) ;; Todo: ; - must not color URL file name extensions as class selectors (*.css) ; - color [] and url() constructs correctly, even if quoted strings present ; - disregard anything inside strings ;; Possible later additions: ; ; - forward/backward style/@media rule commands ; - more complete syntax table ;; Required modules (require 'apropos) (require 'font-lock) (require 'cl) ;;; The code itself ; Customizable variables: (defvar cssm-indent-level 2 "The indentation level inside rules.") (defvar cssm-mirror-mode t "Whether brackets, quotes etc should be mirrored automatically on insertion.") (defvar cssm-newline-before-closing-bracket nil "In mirror-mode, controls whether a newline should be inserted before the closing bracket or not.") (defvar cssm-indent-function #'cssm-old-style-indenter "Which function to use when deciding which column to indent to. To get C-style indentation, use cssm-c-style-indenter. To get old-style indentation, use cssm-old-style-indenter.") ; The rest of the code: (defvar cssm-properties '("font-family" "font-style" "font-variant" "font-weight" "font-size" "font" "background-color" "background-image" "background-repeat" "background-attachment" "background-position" "background" "color" "word-spacing" "letter-spacing" "text-decoration" "vertical-align" "text-transform" "text-align" "text-indent" "line-height" "margin-top" "margin-right" "margin-bottom" "margin-left" "margin" "padding-top" "padding-right" "padding-bottom" "padding-left" "padding" "border-top-width" "border-right-width" "border-left-width" "border-bottom-width" "border-width" "border-color" "border-style" "border-top" "border-right" "border-bottom" "border-left" "border" "width" "height" "float" "clear" "display" "white-space" "list-style-type" "list-style-image" "list-style-position" "list-style" ; CSS level 2.1: "border-bottom-color" "border-bottom-style" "border-collapse" "border-left-color" "border-left-style" "border-right-color" "border-right-style" "border-spacing" "border-top-color" "border-top-style" "bottom" "caption-side" "clip" "content" "counter-increment" "counter-reset" "cursor" "direction" "empty-cells" "left" "max-height" "max-width" "min-height" "min-width" "orphans" "outline" "outline-color" "outline-style" "outline-width" "overflow" "page-break-after" "page-break-before" "page-break-inside" "position" "quotes" "right" "table-layout" "top" "unicode-bidi" "visibility" "widows" "z-index" ; CSS level 2 (dropped from 2.1): "azimuth" "cue" "cue-after" "cue-before" "elevation" "font-size-adjust" "font-stretch" "marker-offset" "marks" "page" "pause" "pause-after" "pause-before" "pitch" "pitch-range" "play-during" "richness" "size" "speak" "speak-header" "speak-numeral" "speak-punctuation" "speech-rate" "stress" "text-shadow" "voice-family" "volume" ; Non-standard properties "cell-spacing" "column-span" "row-span" "speak-date" "speak-time") "A list of all CSS properties.") (defvar cssm-properties-alist (mapcar (lambda(prop) (cons (concat prop ":") nil)) cssm-properties) "An association list of the CSS properties for completion use.") (defvar cssm-keywords (append '("!\\s-*important" ; CSS level 2: "@media" "@import" "@page" "@font-face") (mapcar (lambda(property) (concat property "\\s-*:")) cssm-properties)) "A list of all CSS keywords.") (defvar cssm-pseudos '("link" "visited" "active" "first-line" "first-letter" ; CSS level 2 "first-child" "before" "after" "hover" "focus" "lang") "A list of all CSS pseudo-classes.") ; internal (defun cssm-list-2-regexp(altlist) "Takes a list and returns the regexp \\(elem1\\|elem2\\|...\\)" (let ((regexp "\\(")) (mapcar (lambda(elem) (setq regexp (concat regexp elem "\\|"))) altlist) (concat (substring regexp 0 -2) ; cutting the last "\\|" "\\)") )) (defvar cssm-font-lock-keywords (list (cons (cssm-list-2-regexp cssm-keywords) font-lock-keyword-face) (cons "\\.[a-zA-Z][-a-zA-Z0-9.]+" font-lock-variable-name-face) (cons (concat ":" (cssm-list-2-regexp cssm-pseudos)) font-lock-variable-name-face) (cons "#[a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]\\)?" font-lock-reference-face) (cons "\\[.*\\]" font-lock-variable-name-face) (cons "#[-a-zA-Z0-9]*" font-lock-function-name-face) (cons "rgb(\\s-*[0-9]+\\(\\.[0-9]+\\s-*%\\s-*\\)?\\s-*,\\s-*[0-9]+\\(\\.[0-9]+\\s-*%\\s-*\\)?\\s-*,\\s-*[0-9]+\\(\\.[0-9]+\\s-*%\\s-*\\)?\\s-*)" font-lock-reference-face) ) "Rules for highlighting CSS style sheets.") (defvar cssm-mode-map () "Keymap used in CSS mode.") (when (not cssm-mode-map) (setq cssm-mode-map (make-sparse-keymap)) (define-key cssm-mode-map (read-kbd-macro "C-c C-c") 'cssm-insert-comment) (define-key cssm-mode-map (read-kbd-macro "C-c C-u") 'cssm-insert-url) (define-key cssm-mode-map (read-kbd-macro "}") 'cssm-insert-right-brace-and-indent) (define-key cssm-mode-map (read-kbd-macro "M-TAB") 'cssm-complete-property)) ;;; Cross-version compatibility layer (when (not (or (apropos-macrop 'kbd) (fboundp 'kbd))) (defmacro kbd (keys) "Convert KEYS to the internal Emacs key representation. KEYS should be a string constant in the format used for saving keyboard macros (see `insert-kbd-macro')." (read-kbd-macro keys))) ;;; Auto-indentation support ; internal (defun cssm-insert-right-brace-and-indent() (interactive) (insert "}") (cssm-indent-line)) ; internal (defun cssm-inside-atmedia-rule() "Decides if point is currently inside an @media rule." (let ((orig-pos (point)) (atmedia (re-search-backward "@media" 0 t)) (balance 1) ; used to keep the {} balance, 1 because we start on a { ) ; Going to the accompanying { (re-search-forward "{" (point-max) t) (if (null atmedia) nil ; no @media before this point => not inside (while (and (< (point) orig-pos) (< 0 balance)) (if (null (re-search-forward "[{}]" (point-max) 0)) (goto-char (point-max)) ; break (setq balance (if (string= (match-string 0) "{") (+ balance 1) (- balance 1))))) (= balance 1)) )) ; internal (defun cssm-rule-is-atmedia() "Decides if point is currently on the { of an @media or ordinary style rule." (let ((result (re-search-backward "[@}{]" 0 t))) (if (null result) nil (string= (match-string 0) "@")))) ; internal (defun cssm-find-column(first-char) "Find which column to indent to." ; Find out where to indent to by looking at previous lines ; spinning backwards over comments (let (pos) (while (and (setq pos (re-search-backward (cssm-list-2-regexp '("/\\*" "\\*/" "{" "}")) (point-min) t)) (string= (match-string 0) "*/")) (search-backward "/*" (point-min) t)) ; did the last search find anything? (if pos (save-excursion (let ((construct (match-string 0)) (column (current-column))) (apply cssm-indent-function (list (cond ((string= construct "{") (cond ((cssm-rule-is-atmedia) 'inside-atmedia) ((cssm-inside-atmedia-rule) 'inside-rule-and-atmedia) (t 'inside-rule))) ((string= construct "/*") 'inside-comment) ((string= construct "}") (if (cssm-inside-atmedia-rule) 'inside-atmedia 'outside)) (t 'outside)) column first-char)))) (apply cssm-indent-function (list 'outside (current-column) first-char))))) (defun cssm-indent-line() "Indents the current line." (interactive) (beginning-of-line) (let* ((beg-of-line (point)) (pos (re-search-forward "[]@#a-zA-Z0-9;,.\"{}/*\n:[]" (point-max) t)) (first (match-string 0)) (start (match-beginning 0))) (goto-char beg-of-line) (let ((indent-column (cssm-find-column first))) (goto-char beg-of-line) ; Remove all leading whitespace on this line ( (if (not (or (null pos) (= beg-of-line start))) (kill-region beg-of-line start)) (goto-char beg-of-line) ; Indent (while (< 0 indent-column) (insert " ") (setq indent-column (- indent-column 1)))))) ;;; Indent-style functions (defun cssm-old-style-indenter(position column first-char-on-line) (cond ((eq position 'inside-atmedia) (if (string= "}" first-char-on-line) 0 cssm-indent-level)) ((eq position 'inside-rule) (+ column 2)) ((eq position 'inside-rule-and-atmedia) (+ column 2)) ((eq position 'inside-comment) (+ column 3)) ((eq position 'outside) 0))) (defun cssm-c-style-indenter(position column first-char-on-line) (cond ((or (eq position 'inside-atmedia) (eq position 'inside-rule)) (if (string= "}" first-char-on-line) 0 cssm-indent-level)) ((eq position 'inside-rule-and-atmedia) (if (string= "}" first-char-on-line) cssm-indent-level (* 2 cssm-indent-level))) ((eq position 'inside-comment) (+ column 3)) ((eq position 'outside) 0))) ;;; Typing shortcuts (define-skeleton cssm-insert-curlies "Inserts a pair of matching curly parenthesises." nil "{" (if cssm-newline-before-closing-bracket "\n" " ") (if cssm-newline-before-closing-bracket '>) _ (if cssm-newline-before-closing-bracket "\n" " ") "}" (if cssm-newline-before-closing-bracket '>)) (define-skeleton cssm-insert-quotes "Inserts a pair of matching quotes." nil "\"" _ "\"") (define-skeleton cssm-insert-parenthesises "Inserts a pair of matching parenthesises." nil "(" _ ")") (define-skeleton cssm-insert-comment "Inserts a full comment." nil "/* " _ " */") (define-skeleton cssm-insert-url "Inserts a URL." nil "url(" _ ")") (define-skeleton cssm-insert-brackets "Inserts a pair of matching brackets." nil "[" _ "]") (defun cssm-enter-mirror-mode() "Turns on mirror mode, where quotes, brackets etc are mirrored automatically on insertion." (interactive) (define-key cssm-mode-map (read-kbd-macro "{") 'cssm-insert-curlies) (define-key cssm-mode-map (read-kbd-macro "\"") 'cssm-insert-quotes) (define-key cssm-mode-map (read-kbd-macro "(") 'cssm-insert-parenthesises) (define-key cssm-mode-map (read-kbd-macro "[") 'cssm-insert-brackets)) (defun cssm-leave-mirror-mode() "Turns off mirror mode." (interactive) (define-key cssm-mode-map (read-kbd-macro "{") 'self-insert-command) (define-key cssm-mode-map (read-kbd-macro "\"") 'self-insert-command) (define-key cssm-mode-map (read-kbd-macro "(") 'self-insert-command) (define-key cssm-mode-map (read-kbd-macro "[") 'self-insert-command)) ;;; Property completion (defun cssm-property-at-point() "If point is at the end of a property name: returns it." (let ((end (point)) (start (+ (re-search-backward "[^-A-Za-z]") 1))) (goto-char end) (buffer-substring start end))) ; internal (defun cssm-maximum-common(alt1 alt2) "Returns the maximum common starting substring of alt1 and alt2." (let* ((maxlen (min (length alt1) (length alt2))) (alt1 (substring alt1 0 maxlen)) (alt2 (substring alt2 0 maxlen))) (while (not (string= (substring alt1 0 maxlen) (substring alt2 0 maxlen))) (setq maxlen (- maxlen 1))) (substring alt1 0 maxlen))) ; internal (defun cssm-common-beginning(alts) "Returns the maximum common starting substring of all alts elements." (let ((common (car alts))) (dolist (alt (cdr alts) common) (setq common (cssm-maximum-common alt common))))) (defun cssm-complete-property-frame(completions) ; This code stolen from message.el. Kudos to larsi. (let ((cur (current-buffer))) (pop-to-buffer "*Completions*") (buffer-disable-undo (current-buffer)) (let ((buffer-read-only nil)) (erase-buffer) (let ((standard-output (current-buffer))) (display-completion-list (sort completions 'string<))) (goto-char (point-min)) (pop-to-buffer cur)))) (defun cssm-complete-property() "Completes the CSS property being typed at point." (interactive) (let* ((prop (cssm-property-at-point)) (alts (all-completions prop cssm-properties-alist)) (proplen (length prop))) (if (= (length alts) 1) (insert (substring (car alts) proplen)) (let ((beg (cssm-common-beginning alts))) (if (not (string= beg prop)) (insert (substring beg proplen)) (insert (substring (completing-read "Property: " cssm-properties-alist nil nil prop) proplen))))))) (defun css-mode() "Major mode for editing CSS style sheets. \\{cssm-mode-map}" (interactive) ; Initializing (kill-all-local-variables) ; Setting up indentation handling (make-local-variable 'indent-line-function) (setq indent-line-function 'cssm-indent-line) ; Setting up font-locking (make-local-variable 'font-lock-defaults) (setq font-lock-defaults '(cssm-font-lock-keywords nil t nil nil)) ; Setting up typing shortcuts (make-local-variable 'skeleton-end-hook) (setq skeleton-end-hook nil) (when cssm-mirror-mode (cssm-enter-mirror-mode)) (use-local-map cssm-mode-map) ; Setting up syntax recognition (make-local-variable 'comment-start) (make-local-variable 'comment-end) (make-local-variable 'comment-start-skip) (setq comment-start "/* " comment-end " */" comment-start-skip "/\\*[ \n\t]+") ; Setting up syntax table (modify-syntax-entry ?* ". 23") (modify-syntax-entry ?/ ". 14") ; Final stuff, then we're done (setq mode-name "CSS" major-mode 'css-mode) (run-hooks 'css-mode-hook)) (provide 'css-mode) ;; CSS-mode ends here