From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Simen =?iso-8859-1?q?Heggest=F8yl?= Newsgroups: gmane.emacs.devel Subject: Re: [Emacs-diffs] master 269d563: Support completion of attribute values in CSS mode Date: Sat, 25 Jun 2016 15:19:07 +0200 Message-ID: <1466860747.1138.1@smtp.gmail.com> References: <20160323180952.31942.96525@vcs.savannah.gnu.org> <1458828752.7618.0@smtp.gmail.com> <4360929d-b0eb-bdb7-9a29-686aba681995@yandex.ru> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-gz7PmmAhZgPvWiPaZmhp" X-Trace: ger.gmane.org 1466860816 4383 80.91.229.3 (25 Jun 2016 13:20:16 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 25 Jun 2016 13:20:16 +0000 (UTC) Cc: emacs-devel@gnu.org, Dmitry Gutov To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Jun 25 15:20:11 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1bGnVL-0005yb-1I for ged-emacs-devel@m.gmane.org; Sat, 25 Jun 2016 15:20:11 +0200 Original-Received: from localhost ([::1]:49927 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGnVK-00044Y-BZ for ged-emacs-devel@m.gmane.org; Sat, 25 Jun 2016 09:20:10 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:55624) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGnUW-00042G-UB for emacs-devel@gnu.org; Sat, 25 Jun 2016 09:19:22 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bGnUR-0002a1-0e for emacs-devel@gnu.org; Sat, 25 Jun 2016 09:19:19 -0400 Original-Received: from mail-lf0-x22f.google.com ([2a00:1450:4010:c07::22f]:36839) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bGnUQ-0002Zp-Jp for emacs-devel@gnu.org; Sat, 25 Jun 2016 09:19:14 -0400 Original-Received: by mail-lf0-x22f.google.com with SMTP id q132so131308229lfe.3 for ; Sat, 25 Jun 2016 06:19:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=date:from:subject:to:cc:message-id:in-reply-to:references :mime-version; bh=LStL/kjrVBCEst3q1HMpYueVsWPMZUQ8uaA+cr8PWBI=; b=YMFJvlxnEb/wtn5On5i6Vxj/r/Jcav1KrYOutnNZYlKpzo579L1FkJBQCCm83ranT1 Tdx4SNo3nyD1ZTf2tLqF2V6ZDDQdihsWULui6Zt9PdfMHwIoKfz+d3KRzJYr1sp3tm1d BGR6ebKp3TsRDBRA55STrj7MHaillz6ssUVP8lbNL521tLnC+gmd3nkHF+YrZy8G1a91 XPF+mBMgngat3jv3jZukdy4goP0tBKKqEGAyGYjk2cRtXIFjl2lAXgydX4fdiXoR8nSK Y5dycxUf6P4fW/4JQOtgukzE8kHC3FItMi3XCUgMjhXV1tsFkfzg3fRpfeXzKgb/cFW+ t2ww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:subject:to:cc:message-id:in-reply-to :references:mime-version; bh=LStL/kjrVBCEst3q1HMpYueVsWPMZUQ8uaA+cr8PWBI=; b=llSu1TeZZgfHMSuwKxBgsN0WPjwPDqW4TB+GlOQ+jSZ/mPSQ1DJu0byFuY54U1Gsaw +xBIAU1TXzR8ro8b9LDiX5B6q+kDGe+Lx6Bw2W0XMSKWTOIrLUNOhQXkKzcYFJhlAQwa 9dXDlIW3vGVOsRdymMzeVqsPCta55D7n5Y7sXdV53nKS33urAvh+ONmRyiDT8FtEYHhk AKOhHteNDny6lZbL+DOiKkniJL7MFSn573HDWPjqqjrWvihuh68iXy+0IlpKstMVwG5T vQ70ZNoy/IRKhbajU+z5DRgqOmIM4T2d6nvC/bSX7peuqNe4GOqdW2Q89FNS7jzMSMVd PgNg== X-Gm-Message-State: ALyK8tJUDVY8j1DhCuH6sAY6iTxN3k32VREvKNTnkIjTeYWIgRORE8xV/UmgLKPH6RSzQQ== X-Received: by 10.46.33.199 with SMTP id h68mr2488448lji.47.1466860753690; Sat, 25 Jun 2016 06:19:13 -0700 (PDT) Original-Received: from [192.168.1.10] (155-172-11.connect.netcom.no. [176.11.172.155]) by smtp.gmail.com with ESMTPSA id 193sm1725402ljj.49.2016.06.25.06.19.11 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sat, 25 Jun 2016 06:19:12 -0700 (PDT) In-Reply-To: X-Mailer: geary/0.11.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::22f X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:204755 Archived-At: --=-gz7PmmAhZgPvWiPaZmhp Content-Type: text/plain; charset=utf-8; format=flowed > When we don't have any html-mode buffer at hand, that's obviously the > better choice, yes. When we do have html-mode buffers around, both > choices make sense, depending on the situation. Maybe it's better not > to try to be clever about it, I don't know. I think it's better not to be clever about it; I think having tags disappear from the completion list because you have few HTML buffers open will hurt more than presenting a too long completion list. However maybe it would make sense to extend the completion list when tags that aren't in `html-tag-alist' are used in a HTML buffer? > Completion of user-chosen classes is a different matter, it would be > great, and I've seen people asking for it a few times. I've played around with this a bit and have got a basic version working, see the attached patch. If it looks like something I can chisel it onto a proper patch. -- Simen --=-gz7PmmAhZgPvWiPaZmhp Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-WIP-Support-completion-of-classes-and-IDs-in-CSS-mod.patch Content-Transfer-Encoding: quoted-printable >From 1ca24c576e10477bdf360dc1433bf7d7eb166d4e Mon Sep 17 00:00:00 2001 From: =3D?UTF-8?q?Simen=3D20Heggest=3DC3=3DB8yl?=3D Date: Sat, 25 Jun 2016 15:12:09 +0200 Subject: [PATCH] WIP: Support completion of classes and IDs in CSS mode --- lisp/textmodes/css-mode.el | 55 +++++++++++++++++++++++++++++++++++++++--= ---- lisp/textmodes/sgml-mode.el | 29 ++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el index 060af33..a77c8ba 100644 --- a/lisp/textmodes/css-mode.el +++ b/lisp/textmodes/css-mode.el @@ -30,7 +30,6 @@ ;; - electric ; and } ;; - filling code with auto-fill-mode ;; - fix font-lock errors with multi-line selectors -;; - support completion of user-defined classes names and IDs =20 ;;; Code: =20 @@ -863,16 +862,58 @@ css--nested-selectors-allowed "Non-nil if nested selectors are allowed in the current mode.") (make-variable-buffer-local 'css--nested-selectors-allowed) =20 -;; TODO: Currently only supports completion of HTML tags. By looking -;; at open HTML mode buffers we should be able to provide completion -;; of user-defined classes and IDs too. +(defun css--complete-html-tag () + (save-excursion + (let ((end (point))) + (skip-chars-backward "-[:alnum:]") + (list (point) end css--html-tags)))) + +(defvar css--foreign-completion-cache + (list 'html-class-extractor-function (make-hash-table :test 'equal) + 'html-id-extractor-function (make-hash-table :test 'equal)) + "Cache of completions provided by other buffers. +This is a property list where each property is the name of an +extractor function and the associated value is a hash table +serving as a cache for that function.") + +(defun css--foreign-completions (extractor) + "Return a list of completions provided by other buffers. +EXTRACTOR should be the name of a function that may be defined in +one or more buffers. In each of the buffers where EXTRACTOR is +defined, EXTRACTOR is called and the results are accumulated into +a list." + (seq-uniq + (seq-mapcat + (lambda (buf) + (with-current-buffer buf + (when (boundp extractor) + (let ((cache + (plist-get css--foreign-completion-cache extractor))) + (if cache + (let ((hash (buffer-hash buf))) + (or (gethash hash cache) + (puthash hash (funcall (symbol-value extractor)) + cache))) + (funcall (symbol-value extractor))))))) + (buffer-list)))) + (defun css--complete-selector () "Complete part of a CSS selector at point." (when (or (=3D (nth 0 (syntax-ppss)) 0) css--nested-selectors-allowed) - (save-excursion - (let ((end (point))) + (let ((end (point))) + (save-excursion (skip-chars-backward "-[:alnum:]") - (list (point) end css--html-tags))))) + (let ((start-char (char-before))) + (list + (point) end + (completion-table-dynamic + (lambda (_) + (cond + ((eq start-char ?.) (css--foreign-completions + 'html-class-extractor-function)) + ((eq start-char ?#) (css--foreign-completions + 'html-id-extractor-function)) + (t css--html-tags)))))))))) =20 (defun css-completion-at-point () "Complete current symbol at point. diff --git a/lisp/textmodes/sgml-mode.el b/lisp/textmodes/sgml-mode.el index 990c09b..5e943de 100644 --- a/lisp/textmodes/sgml-mode.el +++ b/lisp/textmodes/sgml-mode.el @@ -32,6 +32,9 @@ =20 ;;; Code: =20 +(require 'dom) +(require 'seq) +(require 'subr-x) (eval-when-compile (require 'skeleton) (require 'cl-lib)) @@ -2168,6 +2171,27 @@ html-current-defun-name nil t) (match-string-no-properties 1)))) =20 +(defun html-current-buffer-classes () + "Return a list of class names used in the current buffer." + (let ((dom (libxml-parse-html-region (point-min) (point-max)))) + (seq-mapcat + (lambda (el) + (when-let (class-list (cdr (assq 'class (dom-attributes el)))) + (split-string class-list))) + (dom-by-class dom "")))) + +(defun html-current-buffer-ids () + "Return a list of IDs used in the current buffer." + (let ((dom (libxml-parse-html-region (point-min) (point-max)))) + (seq-mapcat + (lambda (el) + (when-let (id-list (cdr (assq 'id (dom-attributes el)))) + (split-string id-list))) + (dom-by-id dom "")))) + +(defvar html-class-extractor-function) +(defvar html-id-extractor-function) + =0C ;;;###autoload (define-derived-mode html-mode sgml-mode '(sgml-xml-mode "XHTML" "HTML") @@ -2218,6 +2242,11 @@ html-mode (setq-local add-log-current-defun-function #'html-current-defun-name) (setq-local sentence-end-base "[.?!][]\"'=E2=80=9D)}]*\\(<[^>]*>\\)*") =20 + (when (fboundp 'libxml-parse-html-region) + (setq-local html-class-extractor-function + #'html-current-buffer-classes) + (setq-local html-id-extractor-function #'html-current-buffer-ids)) + (setq imenu-create-index-function 'html-imenu-index) =20 (setq-local sgml-empty-tags --=20 2.8.1 = --=-gz7PmmAhZgPvWiPaZmhp--