add lisp packages
This commit is contained in:
331
lisp/company-web/company-web-html.el
Normal file
331
lisp/company-web/company-web-html.el
Normal file
@@ -0,0 +1,331 @@
|
||||
;;; company-web-html.el --- company for html-mode & web-mode
|
||||
|
||||
;; Copyright (C) 2015 Olexandr Sydorchuck
|
||||
|
||||
;; Author: Olexandr Sydorchuck <olexandr.syd@gmail.com>
|
||||
;; Keywords: html, company, auto-complete
|
||||
|
||||
;; This program 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Configuration:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company-web)
|
||||
|
||||
(defcustom company-web-html-emmet-enable t
|
||||
"Enable emmet specified completion when `emmet-mode' active."
|
||||
:group 'company-web
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-web-html-emmet-enable t
|
||||
"Enable emmet specified completion when `emmet-mode' active."
|
||||
:group 'company-web
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-web-html-emmet-preview-enable-advice t
|
||||
"Enable advice for `emmet-preview-accept'. This advice check for visibility of company popup
|
||||
and call `company-complete-selection' if so.
|
||||
|
||||
You may want disable it when you remap emmet-mode key map and change RET behavior."
|
||||
:group 'company-web
|
||||
:type 'boolean)
|
||||
|
||||
;; html grabs
|
||||
(defconst company-web-html-get-tag-re
|
||||
(concat "<[[:space:]]*\\(" company-web-selector "+\\)[[:space:]]")
|
||||
"Regexp of html tag")
|
||||
|
||||
(defconst company-web-html-get-attribute-re
|
||||
(concat "<[[:space:]]*\\(" company-web-selector "+\\)[^>]*"
|
||||
"[^[:alnum:]>_-]\\(" company-web-selector "+\\)=")
|
||||
"Regexp of html attribute")
|
||||
|
||||
(defun company-web-html-current-tag ()
|
||||
"Return current html tag user is typing on."
|
||||
(let ((bound (save-excursion
|
||||
(if (re-search-backward ">" (company-web-backward-min-tag-bound) t)
|
||||
(point)
|
||||
(company-web-backward-min-tag-bound)))))
|
||||
(save-excursion
|
||||
(if (re-search-backward company-web-html-get-tag-re bound t)
|
||||
(cons (match-string-no-properties 1) (point))
|
||||
(cons nil (point))))))
|
||||
|
||||
(defun company-web-html-current-attribute (bound)
|
||||
"Return current html tag's attribute user is typing on."
|
||||
(save-excursion
|
||||
(re-search-backward company-web-html-get-attribute-re bound t)
|
||||
(match-string-no-properties 2)))
|
||||
|
||||
(defconst company-web-html-tag-regexp
|
||||
(concat "<[[:space:]]*\\("
|
||||
company-web-selector
|
||||
"*\\)")
|
||||
"A regular expression matching HTML tags.")
|
||||
|
||||
(defconst company-web-html-attribute-regexp
|
||||
(concat "<[[:space:]]*" company-web-selector "[^>]*[[:space:]]+\\(.*\\)")
|
||||
"A regular expression matching HTML attribute.")
|
||||
|
||||
(defconst company-web-html-value-regexp
|
||||
(concat "\\w=[\"']\\(?:[^\"']+[ ;:]\\|\\)"
|
||||
;; catch value
|
||||
"\\([^\"']*\\)")
|
||||
"A regular expression matching HTML attribute.")
|
||||
|
||||
;; emmet grabs
|
||||
(defconst company-web-html-emmet-tag-separator
|
||||
"\\(?:^\\|[\t( +>]+\\)")
|
||||
|
||||
(defconst company-web-html-emmet-tag-regexp
|
||||
(concat company-web-html-emmet-tag-separator
|
||||
"\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching emmet's tags.")
|
||||
|
||||
(defconst company-web-html-emmet-class-regexp
|
||||
(concat company-web-html-emmet-tag-separator
|
||||
;; tag
|
||||
"\\(" company-web-selector "+\\|\\)"
|
||||
;; maybe "/" after tag
|
||||
"/?"
|
||||
;; skip #foo or .bar or .foo.bar.baz
|
||||
"[#.[:alnum:]-]*"
|
||||
;; class
|
||||
"[.]\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching emmet's class name.")
|
||||
|
||||
(defconst company-web-html-emmet-id-regexp
|
||||
(concat company-web-html-emmet-tag-separator
|
||||
;; tag
|
||||
"\\(" company-web-selector "+\\|\\)"
|
||||
;; maybe "/" after tag
|
||||
"/?"
|
||||
;; skip #foo or .bar or .foo.bar.baz
|
||||
"[#.[:alnum:]-]*"
|
||||
;; class
|
||||
"[#]\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching emmet's class name.")
|
||||
|
||||
(defconst company-web-html-emmet-attr-regexp
|
||||
(concat company-web-html-emmet-tag-separator
|
||||
;; tag name
|
||||
"\\(" company-web-selector "+\\)"
|
||||
;; maybe "/" after tag
|
||||
"/?"
|
||||
;; skip not tag separator
|
||||
"[^\t +>]*?"
|
||||
;; untill found "["
|
||||
"\\["
|
||||
;; skip any defined attributes like foo="bar"
|
||||
"\\(?:" company-web-selector "+=\"[^\"]*\"\\|\\)+"
|
||||
;; current attribute
|
||||
"\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching emmet's attribute name.")
|
||||
|
||||
(defconst company-web-html-emmet-value-regexp
|
||||
(concat company-web-html-emmet-tag-separator
|
||||
;; get tag name
|
||||
"\\(" company-web-selector "+\\)"
|
||||
;; maybe "/" after tag
|
||||
"/?"
|
||||
;; skip not tag separator
|
||||
"[^\t +>]*?"
|
||||
;; untill found "["
|
||||
"\\["
|
||||
;; skip any defined attributes like foo="bar"
|
||||
"\\(?:" company-web-selector "+=\"[^\"]*\"\\|\\)+"
|
||||
;; get current attribute
|
||||
"\\(" company-web-selector "+\\)"
|
||||
;; get current value
|
||||
"=\"\\(.*\\)")
|
||||
"A regular expression matching emmet's value name.")
|
||||
|
||||
(defun company-web-html-emmet-grab ()
|
||||
(let* ((limit (company-web-backward-min-tag-bound))
|
||||
(bound (save-excursion
|
||||
(if (re-search-backward ">" limit t)
|
||||
(point)
|
||||
limit))))
|
||||
(and company-web-html-emmet-enable
|
||||
(bound-and-true-p emmet-mode)
|
||||
(or
|
||||
(company-grab company-web-html-emmet-tag-regexp 1 bound)
|
||||
(company-grab company-web-html-emmet-class-regexp 2 bound)
|
||||
(company-grab company-web-html-emmet-id-regexp 2 bound)
|
||||
(company-grab company-web-html-emmet-attr-regexp 2 bound)
|
||||
(company-grab company-web-html-emmet-value-regexp 3 bound)))))
|
||||
|
||||
(defun company-web-html-emmet-candidates()
|
||||
(when (and company-web-html-emmet-enable
|
||||
(bound-and-true-p emmet-mode))
|
||||
(let* ((limit (company-web-backward-min-tag-bound))
|
||||
(bound (save-excursion
|
||||
(if (re-search-backward ">" limit t)
|
||||
(point)
|
||||
limit))))
|
||||
(cond
|
||||
((company-grab company-web-html-emmet-tag-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-tags)))
|
||||
;; class (default for div tag)
|
||||
((company-grab company-web-html-emmet-class-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-class-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "class" bound))))
|
||||
;; id (default for div tag)
|
||||
((company-grab company-web-html-emmet-id-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-id-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "id" bound))))
|
||||
;; attributes (default for div)
|
||||
((company-grab company-web-html-emmet-attr-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-attr-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attribute tag))))
|
||||
;; attribute values
|
||||
((company-grab company-web-html-emmet-value-regexp 3 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-value-regexp 1 bound))
|
||||
(attribute (company-grab company-web-html-emmet-value-regexp 2 bound)))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag attribute bound))))))))
|
||||
|
||||
(defadvice emmet-preview-accept (around emmet-with-company-accept)
|
||||
"First call `company-complete-selection' if visible company popup."
|
||||
(if (and company-web-html-emmet-enable
|
||||
company-web-html-emmet-preview-enable-advice
|
||||
company-pseudo-tooltip-overlay)
|
||||
(company-complete-selection)
|
||||
ad-do-it))
|
||||
|
||||
(defadvice emmet-preview-abort (around emmet-with-company-abort)
|
||||
"First call `company-abort' if visible company popup."
|
||||
(if (and company-web-html-emmet-enable
|
||||
company-web-html-emmet-preview-enable-advice
|
||||
company-pseudo-tooltip-overlay)
|
||||
(company-abort)
|
||||
ad-do-it))
|
||||
|
||||
(defun company-web-html-emmet-doc (arg)
|
||||
(let* ((limit (company-web-backward-min-tag-bound))
|
||||
(bound (save-excursion
|
||||
(if (re-search-backward ">" limit t)
|
||||
(point)
|
||||
limit))))
|
||||
(when (and company-web-html-emmet-enable
|
||||
(bound-and-true-p emmet-mode))
|
||||
(cond
|
||||
((company-grab company-web-html-emmet-tag-regexp 1 bound)
|
||||
(company-web-tag-doc arg))
|
||||
;; class (default for div tag)
|
||||
((company-grab company-web-html-emmet-class-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-class-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(company-web-attribute-doc tag arg)))
|
||||
;; id (default for div tag)
|
||||
((company-grab company-web-html-emmet-id-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-id-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(company-web-attribute-doc tag arg)))
|
||||
;; attributes (default for div)
|
||||
((company-grab company-web-html-emmet-attr-regexp 2 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-attr-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(company-web-attribute-doc tag arg)))
|
||||
((company-grab company-web-html-emmet-value-regexp 3 bound)
|
||||
(let ((tag (company-grab company-web-html-emmet-value-regexp 1 bound))
|
||||
(attribute (company-grab company-web-html-emmet-value-regexp 2 bound)))
|
||||
(company-web-attribute-doc tag arg)))))))
|
||||
|
||||
(defun company-web-html-prefix-tag ()
|
||||
(company-web-grab-not-in-string company-web-html-tag-regexp 1 (company-web-backward-min-tag-bound)))
|
||||
|
||||
(defun company-web-html-prefix-attribute (bound)
|
||||
(company-web-grab-not-in-string company-web-html-attribute-regexp 1 bound))
|
||||
|
||||
(defun company-web-html-prefix-value (bound)
|
||||
(when (looking-back company-web-html-value-regexp bound)
|
||||
(match-string-no-properties 1)))
|
||||
|
||||
;;;###autoload
|
||||
(defun company-web-html (command &optional arg &rest ignored)
|
||||
"`company-mode' completion back-end for `html-mode' and `web-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-web-html))
|
||||
(ignore-case t)
|
||||
(duplicates nil)
|
||||
|
||||
(prefix (and (or (derived-mode-p 'html-mode)
|
||||
(derived-mode-p 'web-mode))
|
||||
(let* ((tag-info (company-web-html-current-tag))
|
||||
(tag (car tag-info))
|
||||
(tag-bound (cdr tag-info)))
|
||||
(or (and tag (company-web-html-prefix-value tag-bound))
|
||||
(and tag (company-web-html-prefix-attribute tag-bound))
|
||||
(company-web-html-prefix-tag)
|
||||
(company-web-html-emmet-grab)
|
||||
))))
|
||||
|
||||
(candidates
|
||||
(let* ((tag-info (company-web-html-current-tag))
|
||||
(tag (car tag-info))
|
||||
(tag-bound (cdr tag-info)))
|
||||
(cond
|
||||
;; value
|
||||
((and tag (company-web-html-prefix-value tag-bound))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag
|
||||
(company-web-html-current-attribute tag-bound) tag-bound)))
|
||||
;; attr
|
||||
((and tag (company-web-html-prefix-attribute tag-bound))
|
||||
(all-completions arg (company-web-candidates-attribute tag)))
|
||||
;; tag
|
||||
((company-web-html-prefix-tag)
|
||||
(all-completions arg (company-web-candidates-tags)))
|
||||
;; emmet
|
||||
((company-web-html-emmet-grab)
|
||||
(company-web-html-emmet-candidates))
|
||||
)))
|
||||
|
||||
(annotation (company-web-annotation arg))
|
||||
|
||||
(doc-buffer
|
||||
;; No need grab for attribute value, attribute regexp will match enyway
|
||||
(let* ((tag-info (company-web-html-current-tag))
|
||||
(tag (car tag-info))
|
||||
(tag-bound (cdr tag-info)))
|
||||
(cond
|
||||
;; value
|
||||
((and tag (company-web-html-prefix-value tag-bound))
|
||||
(company-web-candidate-prop-doc arg))
|
||||
;; attr
|
||||
((and tag (company-web-html-prefix-attribute tag-bound))
|
||||
(company-web-attribute-doc tag arg))
|
||||
;; tag
|
||||
((company-web-html-prefix-tag)
|
||||
(company-web-tag-doc arg))
|
||||
;; emmet
|
||||
((company-web-html-emmet-grab)
|
||||
(company-web-html-emmet-doc arg))
|
||||
)))))
|
||||
|
||||
(provide 'company-web-html)
|
||||
;;; company-web-html.el ends here
|
||||
162
lisp/company-web/company-web-jade.el
Normal file
162
lisp/company-web/company-web-jade.el
Normal file
@@ -0,0 +1,162 @@
|
||||
;;; company-web-jade.el --- company for jade-mode
|
||||
|
||||
;; Copyright (C) 2015 Olexandr Sydorchuck
|
||||
|
||||
;; Author: Olexandr Sydorchuck <olexandr.syd@gmail.com>
|
||||
;; Keywords: jade, company, auto-complete, javascript
|
||||
|
||||
;; This program 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Configuration:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company-web)
|
||||
|
||||
(defconst company-web-jade-get-tag-re
|
||||
(concat "^[\t ]*\\(" company-web-selector "+\\)[.#(]")
|
||||
"Regexp of jade attribute or tag")
|
||||
|
||||
(defconst company-web-jade-get-attribute-re
|
||||
(concat "[^[:alnum:]-]\\(" company-web-selector "+\\) *=")
|
||||
"Regexp of jade attribute or tag")
|
||||
|
||||
(defun company-web-jade-current-tag ()
|
||||
"Return current jade tag user is typing on."
|
||||
(save-excursion
|
||||
(re-search-backward company-web-jade-get-tag-re nil t)
|
||||
(match-string 1)))
|
||||
|
||||
(defun company-web-jade-current-attribute ()
|
||||
"Return current jade tag's attribute user is typing on."
|
||||
(save-excursion
|
||||
(re-search-backward company-web-jade-get-attribute-re nil t)
|
||||
(match-string 1)))
|
||||
|
||||
(defconst company-web-jade-id-regexp
|
||||
(concat
|
||||
;; tag or nil(div)
|
||||
"^ *\\(" company-web-selector "+\\|\\)"
|
||||
;; classes ?
|
||||
"[.[:alnum:]-]*"
|
||||
;; id?
|
||||
"#\\(" company-web-selector "*\\|\\)")
|
||||
|
||||
"A regular expression matching Jade #idofdiv:
|
||||
|
||||
#bar -> <div id=\"bar\">
|
||||
or
|
||||
span#bar -> <span id=\"bar\">
|
||||
.")
|
||||
|
||||
(defconst company-web-jade-class-regexp
|
||||
(concat
|
||||
;; tag or nil(div)
|
||||
"^ *\\(" company-web-selector "+\\|\\)"
|
||||
"[#.[:alnum:]-]*"
|
||||
;; last class
|
||||
"[.]\\(" company-web-selector "*\\)")
|
||||
|
||||
"A regular expression matching Jade div's class:
|
||||
|
||||
.foo -> <div class=\"foo\">
|
||||
or
|
||||
span.foo
|
||||
or
|
||||
#foo.baz -> <div id=\"foo\" class=\"baz\">
|
||||
or
|
||||
span#foo.baz.bar
|
||||
.")
|
||||
|
||||
(defconst company-web-jade-tag-regexp
|
||||
(concat "^[\t ]*\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching Jade tags.")
|
||||
|
||||
(defconst company-web-jade-attribute-regexp
|
||||
(concat "\\(?:,\\|(\\)[ ]*\\(.*\\)")
|
||||
"A regular expression matching Jade attribute.")
|
||||
|
||||
(defconst company-web-jade-value-regexp
|
||||
(concat "\\w *= *[\"']\\(?:[^\"']+[ ]\\|\\)"
|
||||
;; catch value
|
||||
"\\([^\"']*\\)")
|
||||
"A regular expression matching Jade attribute.")
|
||||
|
||||
;;;###autoload
|
||||
(defun company-web-jade (command &optional arg &rest ignored)
|
||||
"`company-mode' completion back-end for `jade-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-web-jade))
|
||||
(ignore-case t)
|
||||
(duplicates nil)
|
||||
(prefix (let ((bound (company-web-backward-min-tag-bound)))
|
||||
(and (or (derived-mode-p 'jade-mode)
|
||||
(derived-mode-p 'pug-mode))
|
||||
(or (company-grab company-web-jade-value-regexp 1 bound)
|
||||
(company-grab company-web-jade-tag-regexp 1 bound)
|
||||
(company-grab company-web-jade-id-regexp 2 bound)
|
||||
(company-grab company-web-jade-class-regexp 2 bound)
|
||||
(company-grab company-web-jade-attribute-regexp 1 bound)))))
|
||||
|
||||
(candidates
|
||||
(let ((bound (company-web-backward-min-tag-bound)))
|
||||
(cond
|
||||
;; value
|
||||
((company-grab company-web-jade-value-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-attrib-values (company-web-jade-current-tag)
|
||||
(company-web-jade-current-attribute)
|
||||
bound)))
|
||||
;; class ".foo" or id "#bar"
|
||||
((and (not (company-web-is-point-in-string-face))
|
||||
(company-grab company-web-jade-id-regexp 1 bound))
|
||||
(let ((tag (company-grab company-web-jade-id-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "id" bound))))
|
||||
|
||||
((company-web-grab-not-in-string company-web-jade-class-regexp 1 bound)
|
||||
(let ((tag (company-grab company-web-jade-class-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "class" bound))))
|
||||
|
||||
;; tag
|
||||
((company-web-grab-not-in-string company-web-jade-tag-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-tags)))
|
||||
;; attr
|
||||
((company-web-grab-not-in-string company-web-jade-attribute-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-attribute (company-web-jade-current-tag)))))))
|
||||
|
||||
(annotation (company-web-annotation arg))
|
||||
|
||||
(doc-buffer
|
||||
(let ((bound (company-web-backward-min-tag-bound)))
|
||||
(cond
|
||||
((or (company-web-grab-not-in-string company-web-jade-id-regexp 1 bound)
|
||||
(company-web-grab-not-in-string company-web-jade-class-regexp 2 bound)
|
||||
(company-grab company-web-jade-value-regexp 1 bound))
|
||||
(company-web-candidate-prop-doc arg))
|
||||
;; tag
|
||||
((company-grab company-web-jade-tag-regexp 1 bound)
|
||||
(company-web-tag-doc arg))
|
||||
;; attr
|
||||
((company-grab company-web-jade-attribute-regexp 1 bound)
|
||||
(company-web-attribute-doc (company-web-jade-current-tag) arg)))))))
|
||||
|
||||
(provide 'company-web-jade)
|
||||
;;; company-web-jade.el ends here
|
||||
15
lisp/company-web/company-web-pkg.el
Normal file
15
lisp/company-web/company-web-pkg.el
Normal file
@@ -0,0 +1,15 @@
|
||||
(define-package "company-web" "20180402.1155" "Company version of ac-html, complete for web,html,emmet,jade,slim modes"
|
||||
'((company "0.8.0")
|
||||
(dash "2.8.0")
|
||||
(cl-lib "0.5.0")
|
||||
(web-completion-data "0.1.0"))
|
||||
:commit "f0cc9187c9c34f72ad71f5649a69c74f996bae9a" :keywords
|
||||
'("html" "company")
|
||||
:authors
|
||||
'(("Olexandr Sydorchuk" . "olexandr.syd@gmail.com"))
|
||||
:maintainer
|
||||
'("Olexandr Sydorchuk" . "olexandr.syd@gmail.com")
|
||||
:url "https://github.com/osv/company-web")
|
||||
;; Local Variables:
|
||||
;; no-byte-compile: t
|
||||
;; End:
|
||||
162
lisp/company-web/company-web-slim.el
Normal file
162
lisp/company-web/company-web-slim.el
Normal file
@@ -0,0 +1,162 @@
|
||||
;;; company-web-slim.el --- company for slim-mode
|
||||
|
||||
;; Copyright (C) 2015 Olexandr Sydorchuck
|
||||
|
||||
;; Author: Olexandr Sydorchuck <olexandr.syd@gmail.com>
|
||||
;; Keywords: slim, company, auto-complete, javascript
|
||||
|
||||
;; This program 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Configuration:
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'company-web)
|
||||
|
||||
(defconst company-web-slim-get-tag-re
|
||||
(concat "^[\t ]*\\(" company-web-selector "+\\)")
|
||||
"Regexp of slim attribute or tag")
|
||||
|
||||
(defconst company-web-slim-get-attribute-re
|
||||
(concat "[^[:alnum:]-]\\(" company-web-selector "+\\) *=")
|
||||
"Regexp of slim attribute or tag")
|
||||
|
||||
(defun company-web-slim-current-tag ()
|
||||
"Return current slim tag user is typing on."
|
||||
(save-excursion
|
||||
(re-search-backward company-web-slim-get-tag-re nil t)
|
||||
(match-string 1)))
|
||||
|
||||
(defun company-web-slim-current-attribute ()
|
||||
"Return current slim tag's attribute user is typing on."
|
||||
(save-excursion
|
||||
(re-search-backward company-web-slim-get-attribute-re nil t)
|
||||
(match-string 1)))
|
||||
|
||||
(defconst company-web-slim-id-regexp
|
||||
(concat
|
||||
;; tag or nil(div)
|
||||
"^ *\\(" company-web-selector "+\\|\\)"
|
||||
;; classes ?
|
||||
"[.[:alnum:]-]*"
|
||||
;; id?
|
||||
"#\\(" company-web-selector "*\\|\\)")
|
||||
|
||||
"A regular expression matching Slim #id:
|
||||
|
||||
#bar -> <div id=\"bar\">
|
||||
or
|
||||
span#bar -> <span id=\"bar\">
|
||||
.")
|
||||
|
||||
(defconst company-web-slim-class-regexp
|
||||
(concat
|
||||
;; tag or nil(div)
|
||||
"^ *\\(" company-web-selector "+\\|\\)"
|
||||
"[#.[:alnum:]-]*"
|
||||
;; last class
|
||||
"[.]\\(" company-web-selector "*\\)")
|
||||
|
||||
"A regular expression matching Slim div's class:
|
||||
|
||||
.foo -> <div class=\"foo\">
|
||||
or
|
||||
span.foo
|
||||
or
|
||||
#foo.baz -> <div id=\"foo\" class=\"baz\">
|
||||
or
|
||||
span#foo.baz.bar
|
||||
.")
|
||||
|
||||
(defconst company-web-slim-tag-regexp
|
||||
(concat "^[\t ]*\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching Slim tags.")
|
||||
|
||||
(defconst company-web-slim-attribute-regexp
|
||||
(concat "\\(?:" ; attribute may start after tag and: "[", "(", "{"
|
||||
"[[({]" ;
|
||||
"\\|" ; or
|
||||
" +\\)" ; after whitespace
|
||||
"\\(" company-web-selector "*\\)")
|
||||
"A regular expression matching Slim attribute.")
|
||||
|
||||
(defconst company-web-slim-value-regexp
|
||||
(concat "\\w *= *[\"]\\(?:[^\"]+[ ]\\|\\)"
|
||||
;; catch value
|
||||
"\\([^\"]*\\)")
|
||||
"A regular expression matching Slim attribute.")
|
||||
|
||||
;;;###autoload
|
||||
(defun company-web-slim (command &optional arg &rest ignored)
|
||||
"`company-mode' completion back-end for `slim-mode'."
|
||||
(interactive (list 'interactive))
|
||||
(cl-case command
|
||||
(interactive (company-begin-backend 'company-web-slim))
|
||||
(ignore-case t)
|
||||
(duplicates nil)
|
||||
(prefix (let ((bound (company-web-backward-min-tag-bound)))
|
||||
(and (derived-mode-p 'slim-mode)
|
||||
(or (company-grab company-web-slim-value-regexp 1 bound)
|
||||
(company-grab company-web-slim-tag-regexp 1 bound)
|
||||
(company-grab company-web-slim-id-regexp 2 bound)
|
||||
(company-grab company-web-slim-class-regexp 2 bound)
|
||||
(company-grab company-web-slim-attribute-regexp 1 bound)))))
|
||||
|
||||
(candidates
|
||||
(let ((bound (company-web-backward-min-tag-bound)))
|
||||
(cond
|
||||
;; value
|
||||
((company-grab company-web-slim-value-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-attrib-values (company-web-slim-current-tag)
|
||||
(company-web-slim-current-attribute)
|
||||
bound)))
|
||||
;; class ".foo" or id "#bar"
|
||||
((company-web-grab-not-in-string company-web-slim-id-regexp 1 bound)
|
||||
(let ((tag (company-grab company-web-slim-id-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "id" bound))))
|
||||
((company-web-grab-not-in-string company-web-slim-class-regexp 1 bound)
|
||||
(let ((tag (company-grab company-web-slim-class-regexp 1 bound)))
|
||||
(if (string= "" tag)
|
||||
(setq tag "div"))
|
||||
(all-completions arg (company-web-candidates-attrib-values tag "class" bound))))
|
||||
;; tag
|
||||
((company-web-grab-not-in-string company-web-slim-tag-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-tags)))
|
||||
;; attr
|
||||
((company-web-grab-not-in-string company-web-slim-attribute-regexp 1 bound)
|
||||
(all-completions arg (company-web-candidates-attribute (company-web-slim-current-tag)))))))
|
||||
|
||||
(annotation (company-web-annotation arg))
|
||||
|
||||
(doc-buffer
|
||||
(let ((bound (company-web-backward-min-tag-bound)))
|
||||
(cond
|
||||
((or (company-web-grab-not-in-string company-web-slim-id-regexp 1 bound)
|
||||
(company-web-grab-not-in-string company-web-slim-class-regexp 2 bound)
|
||||
(company-grab company-web-slim-value-regexp 1 bound))
|
||||
(company-web-candidate-prop-doc arg))
|
||||
;; tag
|
||||
((company-grab company-web-slim-tag-regexp 1 bound)
|
||||
(company-web-tag-doc arg))
|
||||
;; attr
|
||||
((company-grab company-web-slim-attribute-regexp 1 bound)
|
||||
(company-web-attribute-doc (company-web-slim-current-tag) arg)))))))
|
||||
|
||||
(provide 'company-web-slim)
|
||||
;;; company-web-slim.el ends here
|
||||
312
lisp/company-web/company-web.el
Normal file
312
lisp/company-web/company-web.el
Normal file
@@ -0,0 +1,312 @@
|
||||
;;; company-web.el --- Company version of ac-html, complete for web,html,emmet,jade,slim modes
|
||||
|
||||
;; Copyright (C) 2015 Olexandr Sydorchuk
|
||||
|
||||
;; Author: Olexandr Sydorchuk <olexandr.syd@gmail.com>
|
||||
;; Version: 2.1
|
||||
;; Keywords: html, company
|
||||
;; Package-Requires: ((company "0.8.0") (dash "2.8.0") (cl-lib "0.5.0") (web-completion-data "0.1.0"))
|
||||
;; URL: https://github.com/osv/company-web
|
||||
|
||||
;; This program 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Same as ac-html, but for `company' completion framework.
|
||||
|
||||
;; Configuration:
|
||||
;;
|
||||
;; (add-to-list 'company-backends 'company-web-html)
|
||||
;; (add-to-list 'company-backends 'company-web-jade)
|
||||
;; (add-to-list 'company-backends 'company-web-slim)
|
||||
;;
|
||||
;; or, for example, setup web-mode-hook:
|
||||
;;
|
||||
;; (define-key web-mode-map (kbd "C-'") 'company-web-html)
|
||||
;; (add-hook 'web-mode-hook (lambda ()
|
||||
;; (set (make-local-variable 'company-backends) '(company-web-html company-files))
|
||||
;; (company-mode t)))
|
||||
;;
|
||||
;; When you use `emmet-mode' (with `web-mode' and `html-mode')
|
||||
;; you may autocomplete as well as regular html complete.
|
||||
;;
|
||||
;; P.S: You may be interested in next packages:
|
||||
;;
|
||||
;; `ac-html-bootstrap' - Twitter:Bootstrap completion data for company-web (and ac-html as well)
|
||||
;; `ac-html-csswatcher' - Watch your project CSS/Less files for classes and ids
|
||||
;; `ac-html-angular' - Angular 1.5 completion data;
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'web-completion-data)
|
||||
(require 'company)
|
||||
(require 'company-css)
|
||||
(require 'dash)
|
||||
(require 'cl-lib)
|
||||
|
||||
(defgroup company-web nil
|
||||
"HTML Complete, Company back-end."
|
||||
:group 'company
|
||||
:prefix "company-web-")
|
||||
|
||||
(defcustom company-web-framework-name-truncate-length 10
|
||||
"Truncation length for type framework-name"
|
||||
:type 'integer
|
||||
:group 'company-web)
|
||||
|
||||
(defcustom company-web-complete-css t
|
||||
"Enable `style' attribute CSS autocomplete."
|
||||
:group 'company-web
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom company-web-backward-tag-limit 2048
|
||||
"Bound for backward searching to determinate where html tag is started. Big value may decrease perfomance"
|
||||
:group 'company-web :type 'integer)
|
||||
|
||||
(defun company-web-backward-min-tag-bound ()
|
||||
(max (- (point) company-web-backward-tag-limit)
|
||||
(point-min)))
|
||||
|
||||
(defface company-web-doc-base-face
|
||||
'((((class color) (background light))
|
||||
:foreground "navy" :inherit variable-pitch)
|
||||
(((class color) (background dark))
|
||||
:foreground "DeepSkyBlue" :inherit variable-pitch)
|
||||
(t))
|
||||
"Face for description text."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-text-1-face
|
||||
'((t :inherit company-web-doc-base-face))
|
||||
"Face for description text."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-header-1-face
|
||||
'((t :inherit company-web-doc-base-face :weight bold))
|
||||
"Face for header text."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-important-face
|
||||
'((t :inherit company-web-doc-base-face :weight bold))
|
||||
"Face in square braces, ex: [HTML5]."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-warning-face
|
||||
'((t :inherit font-lock-warning-face))
|
||||
"Face for depracated, other warnings."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-tag-face
|
||||
'((t :inherit font-lock-function-name-face))
|
||||
"Face html tag face."
|
||||
:group 'company-web)
|
||||
|
||||
(defface company-web-doc-attribute-face
|
||||
'((t :inherit font-lock-type-face))
|
||||
"Face html tag face."
|
||||
:group 'company-web)
|
||||
|
||||
(defvar company-web-string-check-faces '(font-lock-string-face web-mode-html-attr-value-face)
|
||||
"List of string faces to check.")
|
||||
|
||||
(defun company-web-load-list-from-file (filepath)
|
||||
"Return a list separated by \\n from FILEPATH."
|
||||
(with-temp-buffer
|
||||
(insert-file-contents filepath)
|
||||
(split-string (buffer-string) "\n" t)))
|
||||
|
||||
(defun company-web-is-point-in-string-face ()
|
||||
"t if text's face(s) at point is in `company-web-string-check-faces'."
|
||||
(let ((faces (get-text-property (point) 'face)))
|
||||
(if (listp faces)
|
||||
;; slim-mode define list of string-face (bug), so intersect
|
||||
(cl-intersection faces company-web-string-check-faces)
|
||||
(memq faces company-web-string-check-faces))))
|
||||
|
||||
(defun company-web-read-file (file-in-source-dir)
|
||||
"Return string content of FILE-IN-SOURCE-DIR from `web-completion-data-sources'."
|
||||
(let ((file (cdr (nth 0 (company-web-all-files-named file-in-source-dir)))))
|
||||
;; Just read from the first file.
|
||||
(when file
|
||||
(with-temp-buffer
|
||||
(insert-file-contents file)
|
||||
(buffer-string)))))
|
||||
|
||||
(defun company-web-all-files-named (file-name)
|
||||
"Get a list of file named FILE-NAME in all directory specified by
|
||||
`web-completion-data-sources'.
|
||||
|
||||
Returns an alist. car is source name, cdr is the file path."
|
||||
(let (return-files source-dir-path)
|
||||
(mapc (lambda (name-dir-cons-cell)
|
||||
(setq source-dir-path (cdr name-dir-cons-cell))
|
||||
(setq source-dir-path
|
||||
(cond ((stringp source-dir-path) source-dir-path)
|
||||
((and (symbolp source-dir-path)
|
||||
(boundp source-dir-path))
|
||||
(symbol-value source-dir-path))
|
||||
(t
|
||||
(error "[company-html] invalid element %s in\
|
||||
`web-completion-data-sources'" source-dir-path))))
|
||||
(when source-dir-path
|
||||
(setq source-dir-path (expand-file-name file-name source-dir-path))
|
||||
(when (file-exists-p source-dir-path)
|
||||
(add-to-list 'return-files (cons (car name-dir-cons-cell) source-dir-path))
|
||||
)))
|
||||
web-completion-data-sources)
|
||||
return-files))
|
||||
|
||||
(defun company-web-make-candidate (framework-name items)
|
||||
"Make popup-item for each item with FRAMEWORK-NAME.
|
||||
|
||||
FRAMEWORK-NAME will be truncated to `companu-html-framework-name-truncate-length'.
|
||||
|
||||
ITEMS is a list of string where name and documentation are
|
||||
separated by one space.
|
||||
Documentation newlines are escaped by \"\\n\".
|
||||
|
||||
If item have no inline documentation, DOCUMENTATION will be used.
|
||||
DOCUMENTATION is string or function."
|
||||
(let ((annotation
|
||||
(truncate-string-to-width framework-name company-web-framework-name-truncate-length 0 nil nil)))
|
||||
(mapcar (lambda (item)
|
||||
(if (string-match "\\(.*?\\) \\(.*\\)" item)
|
||||
(propertize (match-string 1 item)
|
||||
'annotation annotation
|
||||
'doc (replace-regexp-in-string "\\\\n" "\n"
|
||||
(match-string 2 item)))
|
||||
(propertize item
|
||||
'annotation annotation)))
|
||||
items)))
|
||||
|
||||
;; candidate getters
|
||||
(defun company-web-candidates-tags ()
|
||||
(-flatten
|
||||
(mapcar (lambda (source-name-and-file-path)
|
||||
(company-web-make-candidate
|
||||
(car source-name-and-file-path)
|
||||
(company-web-load-list-from-file (cdr source-name-and-file-path))))
|
||||
(company-web-all-files-named "html-tag-list"))))
|
||||
|
||||
(defun company-web-candidates-attribute (tag)
|
||||
"Attribute candidates of TAG."
|
||||
(unless (string= "" tag)
|
||||
(let* ((items (mapcar (lambda (plist-framwork-and-file)
|
||||
(company-web-make-candidate
|
||||
(concat (car plist-framwork-and-file) ", G")
|
||||
(company-web-load-list-from-file (cdr plist-framwork-and-file))))
|
||||
(company-web-all-files-named "html-attributes-list/global"))))
|
||||
(add-to-list 'items
|
||||
(mapcar (lambda (plist-framwork-and-file)
|
||||
(company-web-make-candidate
|
||||
(car plist-framwork-and-file)
|
||||
(company-web-load-list-from-file (cdr plist-framwork-and-file))))
|
||||
(company-web-all-files-named (concat "html-attributes-list/" tag))))
|
||||
(-flatten items))))
|
||||
|
||||
(defun company-web-candidates-attrib-values-internal (tag attribute)
|
||||
"Attribute candidates for TAG and ATTRIBUTE."
|
||||
(let* ((items (mapcar (lambda (plist-framwork-and-file)
|
||||
(company-web-make-candidate
|
||||
(car plist-framwork-and-file)
|
||||
(company-web-load-list-from-file (cdr plist-framwork-and-file))))
|
||||
(company-web-all-files-named (format "html-attributes-complete/%s-%s" tag attribute)))))
|
||||
(add-to-list 'items
|
||||
(mapcar (lambda (plist-framwork-and-file)
|
||||
(company-web-make-candidate
|
||||
(concat (car plist-framwork-and-file) ", G")
|
||||
(company-web-load-list-from-file (cdr plist-framwork-and-file))))
|
||||
(company-web-all-files-named (concat "html-attributes-complete/global-" attribute))))
|
||||
(-flatten items)))
|
||||
|
||||
(defun company-web-candidates-attrib-values (tag attribute bound)
|
||||
(if (and company-web-complete-css
|
||||
(string= attribute "style")
|
||||
(save-excursion (re-search-backward "[\"']" bound t))
|
||||
(save-excursion (re-search-backward "\\([[:alpha:]@_-]\\) *:[^;]*\\=" bound t)))
|
||||
(-flatten (company-web-make-candidate "CSS" (company-css-property-values
|
||||
(company-grab company-css-property-value-regexp 1 bound))))
|
||||
(company-web-candidates-attrib-values-internal tag attribute)))
|
||||
|
||||
(defun company-web-annotation (candidate)
|
||||
"Return type annotation for chosen CANDIDATE."
|
||||
(concat
|
||||
(unless company-tooltip-align-annotations " -> ")
|
||||
(get-text-property 0 'annotation candidate)))
|
||||
|
||||
(defvar company-web-doc-font-lock-keywords
|
||||
(list
|
||||
'("\\(\\[.*?\\]+\\)" 1 'company-web-doc-important-face t)
|
||||
'("\\b\\(deprecated\\)\\b" 1 'company-web-doc-warning-face t)
|
||||
'("<\\([[:alnum:]-]+\\)" 1 'company-web-doc-tag-face t)
|
||||
'("</\\([[:alnum:]-]+\\)>" 1 'company-web-doc-tag-face t)
|
||||
'("\\([[:alnum:]-]+\\)=" 1 'company-web-doc-attribute-face t)
|
||||
'("\\(?:^\\| \\)\\.\\([[:alnum:]-]+\\)" 1 'company-web-doc-attribute-face t)
|
||||
'("^[_ [:alnum:]-]+:" . 'company-web-doc-header-1-face)))
|
||||
|
||||
(defun company-web-doc-buffer (&optional string)
|
||||
(with-current-buffer (get-buffer-create "*html-documentation*")
|
||||
(set (make-local-variable 'font-lock-defaults)
|
||||
'(company-web-doc-font-lock-keywords))
|
||||
(font-lock-mode t)
|
||||
(erase-buffer)
|
||||
(when string
|
||||
(save-excursion
|
||||
(insert string)))
|
||||
(current-buffer)))
|
||||
|
||||
;; end
|
||||
|
||||
(defun company-web-candidate-prop-doc (candidate)
|
||||
"Return documentation for chosen CANDIDATE.
|
||||
Property of doc CANDIDATE"
|
||||
(company-web-doc-buffer (get-text-property 0 'doc candidate)))
|
||||
|
||||
(defun company-web-tag-doc (candidate)
|
||||
"Return documentation for chosen CANDIDATE.
|
||||
Property of doc CANDIDATE or load file from `html-tag-short-docs/CANDIDATE'"
|
||||
(let ((doc (get-text-property 0 'doc candidate)))
|
||||
(unless doc
|
||||
(let ((doc-file (cdr (car (company-web-all-files-named (concat "html-tag-short-docs/" candidate))))))
|
||||
(when doc-file
|
||||
(setq doc (company-web-read-file doc-file)))))
|
||||
(when doc
|
||||
(company-web-doc-buffer doc))))
|
||||
|
||||
(defun company-web-attribute-doc (tag candidate)
|
||||
"Return documentation for chosen CANDIDATE.
|
||||
Property of doc CANDIDATE or load file from `html-attributes-short-docs/global-CANDIDATE' or
|
||||
`html-attributes-short-docs/TAG-CANDIDATE'"
|
||||
(let ((doc (get-text-property 0 'doc candidate)))
|
||||
(unless doc
|
||||
(let ((doc-file (cdr (car (company-web-all-files-named (concat "html-attributes-short-docs/" tag "-" candidate))))))
|
||||
(when doc-file
|
||||
(setq doc (company-web-read-file doc-file)))))
|
||||
(unless doc
|
||||
(let ((doc-file (cdr (car (company-web-all-files-named (concat "html-attributes-short-docs/global-" candidate))))))
|
||||
(when doc-file
|
||||
(setq doc (company-web-read-file doc-file)))))
|
||||
(when doc
|
||||
(company-web-doc-buffer doc))))
|
||||
|
||||
(defun company-web-grab-not-in-string (regexp expression bound)
|
||||
"Like `company-grab' but not in string"
|
||||
(and (not (company-web-is-point-in-string-face))
|
||||
(company-grab regexp expression bound)))
|
||||
|
||||
(defconst company-web-selector "[[:alnum:]_-]"
|
||||
"Regexp of html attribute or tag")
|
||||
|
||||
(provide 'company-web)
|
||||
;;; company-web.el ends here
|
||||
Reference in New Issue
Block a user