branch: scratch/editorconfig-cc commit d7a42c819cf8f36e63a756fc1e10636491d4b0a4 Author: 10sr <8slashes+...@gmail.com> Commit: Stefan Monnier <monn...@iro.umontreal.ca>
Add editorconfig-core el files --- bin/editorconfig-el | 102 +++++++++++++++ editorconfig-core-handle.el | 198 ++++++++++++++++++++++++++++ editorconfig-core.el | 208 ++++++++++++++++++++++++++++++ editorconfig-fnmatch.el | 307 ++++++++++++++++++++++++++++++++++++++++++++ editorconfig.el | 1 + 5 files changed, 816 insertions(+) diff --git a/bin/editorconfig-el b/bin/editorconfig-el new file mode 100755 index 0000000000..fbba8ea971 --- /dev/null +++ b/bin/editorconfig-el @@ -0,0 +1,102 @@ +#!/bin/sh +:;#-*-Emacs-Lisp-*- +:;test -n "$EMACS_BIN" || EMACS_BIN=emacs +:;exec "$EMACS_BIN" -batch -Q --eval '(setq debug-on-error t)' -l "$0" -- "$@" + +;; editorconfig-el --- EditorConfig Core executable in Emacs Lisp + +;;; Commentary: + +;; This executable is mainly for testing core feature, and not intended to be +;; used by users. + +;;; Code: + +(when (getenv "EDITORCONFIG_CORE_LIBRARY_PATH") + (setq load-path + (append (split-string (getenv "EDITORCONFIG_CORE_LIBRARY_PATH") + ":") + load-path))) + +(require 'cl-lib) +(require 'editorconfig-core) + +(defconst editorconfig-bin-help-message + "Usage: editorconfig [-f <configname>] [-b <configversion>] [-h|--help] + [-v|--version] [<filepath> ...] + +Options: + -f <configname> Specify config filename other than \".editorconfig\" + -b <configversion> Specify config format version + -h|--help Print this help message + -v|--version Display version information + <filepath> ... File paths to get EditorConfig properties" + "Help message of EditorConfig executable.") + +(defun editorconfig-bin-parse-args + (argv &optional confname version) + "Parse arguments and return list. + +List returned will be looked like (FILES CONFNAME VERSION). +If either -v, --version, -h or --help option apprears, exit emacs immediately +with required output." + (unless argv + (message editorconfig-bin-help-message) + (kill-emacs 0)) + (cl-case (intern (car argv)) + (-f + (editorconfig-bin-parse-args (cddr argv) + (cadr argv) + version)) + (-b + (editorconfig-bin-parse-args (cddr argv) + confname + (cadr argv))) + ((-h --help) + (message editorconfig-bin-help-message) + (kill-emacs 0)) + ((-v --version) + (message "EditorConfig-Core-EmacsLisp Version %s" + editorconfig-core-version) + (kill-emacs 0)) + + (otherwise + (when (and argv + (string-match-p "^-" + (car argv))) + (error "Invalid option: %s" + (car argv))) + (list argv + confname + version)) + )) + +(defun main (argv) + ;; TODO: Read file list from stdin if - is given as FILENAME + (let ((parsed (editorconfig-bin-parse-args argv))) + (cl-case (length (car parsed)) + (0 + nil) + (1 + (dolist (p (editorconfig-core-get-properties (caar parsed) + (nth 1 parsed) + (nth 2 parsed))) + (message "%s=%s" + (car p) + (cdr p)))) + (otherwise + (dolist (file (car parsed)) + (message "[%s]" + file) + (dolist (p (editorconfig-core-get-properties file + (nth 1 parsed) + (nth 2 parsed))) + (message "%s=%s" + (car p) + (cdr p))))))) + 0) + +;; car of command-line-args-left is "--" +(kill-emacs (main (cdr command-line-args-left))) + +;;; editorconfig-el ends here diff --git a/editorconfig-core-handle.el b/editorconfig-core-handle.el new file mode 100644 index 0000000000..ac9fa2e2a6 --- /dev/null +++ b/editorconfig-core-handle.el @@ -0,0 +1,198 @@ +;;; editorconfig-core-handle.el --- Handle Class for EditorConfig File + +;; Copyright (C) 2011-2015 EditorConfig Team + +;; Author: EditorConfig Team <editorcon...@googlegroups.com> +;; Version: 0.5 +;; URL: https://github.com/editorconfig/editorconfig-emacs#readme + +;; See +;; https://github.com/editorconfig/editorconfig-emacs/graphs/contributors +;; or the CONTRIBUTORS file for the list of contributors. + +;; This file is part of EditorConfig Emacs Plugin. + +;; EditorConfig Emacs Plugin 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. + +;; EditorConfig Emacs Plugin 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 +;; EditorConfig Emacs Plugin. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Handle class for EditorConfig config file. This library is used internally +;; from editorconfig-core.el . + +;;; Code: + +(require 'editorconfig-fnmatch) + +;; For cl-defstruct +(require 'cl-lib) + +(defvar editorconfig-core-handle--cache-hash + (make-hash-table :test 'equal) + "Hash of EditorConfig filename and its `editorconfig-core-handle' instance.") + +(cl-defstruct editorconfig-core-handle + (top-prop nil) + (prop nil) + (mtime nil) + (path nil)) + + + +(defun editorconfig-core-handle (conf) + "Return EditorConfig handle for CONF, which should be a file path. + +If CONF does not exist return nil." + (when (file-readable-p conf) + (let ((cached (gethash conf + editorconfig-core-handle--cache-hash)) + (mtime (nth 5 + (file-attributes conf)))) + (if (and cached + (equal (editorconfig-core-handle-mtime cached) + mtime)) + cached + (let ((parsed (editorconfig-core-handle--parse-file conf))) + (puthash conf + (make-editorconfig-core-handle :top-prop (car parsed) + :prop (cdr parsed) + :mtime mtime + :path conf) + editorconfig-core-handle--cache-hash)))))) + +(defun editorconfig-core-handle-root-p (handle) + "Return non-nil if HANDLE represent root EditorConfig file. + +If HANDLE is nil return nil." + (when handle + (string-equal "true" + (downcase (or (cdr (assoc "root" + (editorconfig-core-handle-top-prop handle))) + ""))))) + +(defun editorconfig-core-handle-get-properties (handle file) + "Return list of alist of properties from HANDLE for FILE. +The list returned will be ordered by the lines they appear. + +If HANDLE is nil return nil." + (when handle + (mapcar 'cdr + (cl-remove-if-not (lambda (prop) + (editorconfig-core-handle--fnmatch-p file + (car prop) + (file-name-directory (editorconfig-core-handle-path handle)))) + (editorconfig-core-handle-prop handle))))) + +(defun editorconfig-core-handle--fnmatch-p (name pattern dir) + "Return non-nil if NAME match PATTERN. +If pattern has slash, pattern should be relative to DIR. + +This function is a fnmatch with a few modification for EditorConfig usage." + (if (string-match-p "/" pattern) + (let ((pattern (replace-regexp-in-string "^/" + "" + pattern)) + (dir (file-name-as-directory dir))) + (editorconfig-fnmatch-p name + (concat dir + pattern))) + (editorconfig-fnmatch-p name + (concat "**/" + pattern)))) + +(defsubst editorconfig-core-handle--string-trim (str) + "Remove leading and trailing whitespace from STR." + (replace-regexp-in-string "[ \t\n\r]+\\'" + "" + (replace-regexp-in-string "\\`[ \t\n\r]+" + "" + str))) + +(defun editorconfig-core-handle--parse-file (conf) + "Parse EditorConfig file CONF. + +This function returns cons of its top properties alist and +alist of patterns and its properties alist. +The list returned will be ordered by the lines they appear. + +If CONF is not found return nil." + (when (file-readable-p conf) + (with-temp-buffer + ;; NOTE: Use this instead of insert-file-contents-literally to enable + ;; code conversion + (insert-file-contents conf) + (goto-char (point-min)) + (let ((point-max (point-max)) + (all-props ()) + (top-props nil) + + ;; String of current line + (line "") + ;; nil when pattern not appeared yet, "" when pattern is empty ("[]") + (pattern nil) + ;; Alist of properties for current PATTERN + (props ()) + + ) + (while (not (eq (point) point-max)) + (setq line + (buffer-substring-no-properties (point-at-bol) + (point-at-eol))) + (setq line + (replace-regexp-in-string "\\(^\\| \\)\\(#\\|;\\).*$" + "" + (editorconfig-core-handle--string-trim line))) + + (cond + ((string-equal "" line) + nil) + + ((string-match "^\\[\\(.*\\)\\]$" + line) + (when pattern + (setq all-props + `(,@all-props (,pattern . ,props))) + (setq props nil)) + (setq pattern (match-string 1 line))) + + ((string-match-p "=\\|:" + line) + ;; NOTE: Using match-string does not work as expected + (let* ( + (idx (string-match "=\\|:" + line)) + (key (downcase (editorconfig-core-handle--string-trim (substring line + 0 + idx)))) + (value (editorconfig-core-handle--string-trim (substring line + (1+ idx)))) + ) + (when (and (< (length key) 51) + (< (length value) 256)) + (if pattern + (when (< (length pattern) 4097) + (setq props + `(,@props (,key . ,value)))) + (setq top-props + `(,@top-props (,key . ,value))))))) + ) + (forward-line 1)) + (when pattern + (setq all-props + `(,@all-props (,pattern . ,props)))) + (cons top-props + all-props))))) + +(provide 'editorconfig-core-handle) + +;;; editorconfig-core-handle.el ends here diff --git a/editorconfig-core.el b/editorconfig-core.el new file mode 100644 index 0000000000..5dee261f4a --- /dev/null +++ b/editorconfig-core.el @@ -0,0 +1,208 @@ +;;; editorconfig-core.el --- EditorConfig Core library in Emacs Lisp + +;; Copyright (C) 2011-2015 EditorConfig Team + +;; Author: EditorConfig Team <editorcon...@googlegroups.com> +;; Version: 0.5 +;; URL: https://github.com/editorconfig/editorconfig-emacs#readme +;; Package-Requires: ((editorconfig-fnmatch "20151023.1021") (cl-lib "0.5")) + +;; See +;; https://github.com/editorconfig/editorconfig-emacs/graphs/contributors +;; or the CONTRIBUTORS file for the list of contributors. + +;; This file is part of EditorConfig Emacs Plugin. + +;; EditorConfig Emacs Plugin 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. + +;; EditorConfig Emacs Plugin 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 +;; EditorConfig Emacs Plugin. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This library is one implementation of EditorConfig Core, which parses +;; .editorconfig files and returns properties for given files. +;; This can be used in place of, for example, editorconfig-core-c. + +;; This library is not an editor plugin and does not configure Emacs for editing +;; the files: this should be done with editorconfig-emacs. + + +;; Use from EditorConfig Emacs Plugin + +;; editorconfig-emacs (v0.5 or later) can utilize this library. +;; Add following lines to your init.el: + +;; (setq editorconfig-get-properties-function +;; 'editorconfig-core-get-properties-hash) + +;; This sexp configures editorconfig-emacs to call this library when getting +;; EditorConfig properties instead of the default function +;; editorconfig-get-properties-from-exec, which invokes external program +;; like editorconfig-core-c. + + +;; Functions + +;; editorconfig-core-get-properties (&optional file confname confversion) + +;; Get EditorConfig properties for FILE. + +;; If FILE is not given, use currently visiting file. +;; Give CONFNAME for basename of config file other than .editorconfig. +;; If need to specify config format version, give CONFVERSION. + +;; This functions returns alist of properties. Each element will look like +;; (KEY . VALUE) . + + +;; editorconfig-core-get-properties-hash (&optional file confname confversion) + +;; Get EditorConfig properties for FILE. + +;; This function is almost same as `editorconfig-core-get-properties', but +;; returns hash object instead. + +;;; Code: + +(require 'editorconfig-core-handle) + + +(defconst editorconfig-core-version + "0.1.5" + "EditorConfig core version.") + +(defun editorconfig-core--remove-duplicate (alist) + "Remove duplicated keys in ALIST. + +If same keys are found in ALIST multiple times, the latter ones take precedence. +For example, when ALIST is + + '((a 1) (b 2) (c 3) (b 4)) + +then the result will be + + '((a 1) (b 4) (c 3)) ." + (let ((result ())) + (dolist (e alist) + (let ((pair (assoc (car e) + result))) + (if pair + (setcdr pair + (cdr e)) + (setq result + `(,@result ,e))))) + result)) + +(defun editorconfig-core--get-handles (dir confname &optional result) + "Get list of EditorConfig handlers for DIR from CONFNAME. + +In the resulting list, the handle for root config file comes first, and the +nearest comes last. +The list may contains nil when no file was found for directories. +RESULT is used internally and normally should not be used." + (setq dir (expand-file-name dir)) + (let ((handle (editorconfig-core-handle (concat (file-name-as-directory dir) + confname))) + (parent (file-name-directory (directory-file-name dir)))) + (if (or (string= parent + dir) + (and handle + (editorconfig-core-handle-root-p handle))) + (cons handle result) + (editorconfig-core--get-handles parent + confname + (cons handle + result))))) + + +;;;###autoload +(defun editorconfig-core-get-properties (&optional file confname confversion) + "Get EditorConfig properties for FILE. +If FILE is not given, use currently visiting file. +Give CONFNAME for basename of config file other than .editorconfig. +If need to specify config format version, give CONFVERSION. + +This functions returns alist of properties. Each element will look like +'(KEY . VALUE) ." + (setq file (expand-file-name (or file + buffer-file-name + (error "FILE is not given and `buffer-file-name' is nil")))) + (setq confname (or confname + ".editorconfig")) + (setq confversion (or confversion + "0.12.0")) + (let ((result (editorconfig-core--remove-duplicate + (apply 'append + (mapcar (lambda (handle) + (apply 'append + (editorconfig-core-handle-get-properties handle + file))) + (editorconfig-core--get-handles (file-name-directory file) + confname)))))) + (dolist (key '("end_of_line" "indent_style" "indent_size" + "insert_final_newline" "trim_trailing_whitespace" "charset")) + (let ((pair (assoc key + result))) + (when pair + (setcdr pair + (downcase (cdr pair)))))) + + ;; Add indent_size property + (let ((p-indent-size (assoc "indent_size" result)) + (p-indent-style (assoc "indent_style" result))) + (when (and (not p-indent-size) + (string= (cdr p-indent-style) "tab") + ;; If VERSION < 0.9.0, indent_size should have no default value + (version<= "0.9.0" + confversion)) + (setq result + `(,@result ("indent_size" . "tab"))))) + ;; Add tab_width property + (let ((p-indent-size (assoc "indent_size" result)) + (p-tab-width (assoc "tab_width" result))) + (when (and p-indent-size + (not p-tab-width) + (not (string= (cdr p-indent-size) "tab"))) + (setq result + `(,@result ("tab_width" . ,(cdr p-indent-size)))))) + ;; Update indent-size property + (let ((p-indent-size (assoc "indent_size" result)) + (p-tab-width (assoc "tab_width" result))) + (when (and p-indent-size + p-tab-width + (string= (cdr p-indent-size) "tab")) + (setcdr p-indent-size (cdr p-tab-width)))) + + result)) + +;;;###autoload +(defun editorconfig-core-get-properties-hash (&optional file confname confversion) + "Get EditorConfig properties for FILE. +If FILE is not given, use currently visiting file. +Give CONFNAME for basename of config file other than .editorconfig. +If need to specify config format version, give CONFVERSION. + +This function is almost same as `editorconfig-core-get-properties', but returns +hash object instead." + (let ((result (editorconfig-core-get-properties file + confname + confversion)) + (hash (make-hash-table :test 'equal))) + (dolist (prop result) + (puthash (intern (car prop)) + (cdr prop) + hash)) + hash)) + +(provide 'editorconfig-core) + +;;; editorconfig-core.el ends here diff --git a/editorconfig-fnmatch.el b/editorconfig-fnmatch.el new file mode 100644 index 0000000000..4096eaf158 --- /dev/null +++ b/editorconfig-fnmatch.el @@ -0,0 +1,307 @@ +;;; editorconfig-fnmatch.el --- Glob pattern matching in Emacs lisp + +;; Copyright (C) 2011-2015 EditorConfig Team + +;; Author: EditorConfig Team <editorcon...@googlegroups.com> +;; Version: 0.5 +;; Package-Requires: ((cl-lib "0.5")) +;; URL: https://github.com/editorconfig/editorconfig-emacs#readme + +;; See +;; https://github.com/editorconfig/editorconfig-emacs/graphs/contributors +;; or the CONTRIBUTORS file for the list of contributors. + +;; This file is part of EditorConfig Emacs Plugin. + +;; EditorConfig Emacs Plugin 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. + +;; EditorConfig Emacs Plugin 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 +;; EditorConfig Emacs Plugin. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; editorconfig-fnmatch.el provides a fnmatch implementation with a few +;; extensions. +;; The main usage of this library is glob pattern matching for EditorConfig, but +;; it can also act solely. + +;; editorconfig-fnmatch-p (name pattern) + +;; Test whether NAME match PATTERN. + +;; PATTERN should be a shell glob pattern, and some zsh-like wildcard matchings +;; can be used: + +;; * Matches any string of characters, except path separators (/) +;; ** Matches any string of characters +;; ? Matches any single character +;; [name] Matches any single character in name +;; [^name] Matches any single character not in name +;; {s1,s2,s3} Matches any of the strings given (separated by commas) +;; {min..max} Matches any number between min and max + + +;; This library is a port from editorconfig-core-py library. +;; https://github.com/editorconfig/editorconfig-core-py/blob/master/editorconfig/fnmatch.py + +;;; Code: + +(require 'cl-lib) + +(defvar editorconfig-fnmatch--cache-hash + (make-hash-table :test 'equal) + "Cache of shell pattern and its translation.") + + +(defconst editorconfig-fnmatch--left-brace-regexp + "\\(^\\|[^\\]\\){" + "Regular expression for left brace ({).") + +(defconst editorconfig-fnmatch--right-brace-regexp + "\\(^\\|[^\\]\\)}" + "Regular expression for right brace (}).") + + +(defconst editorconfig-fnmatch--numeric-range-regexp + "\\([+-]?[0-9]+\\)\\.\\.\\([+-]?[0-9]+\\)" + "Regular expression for numaric range (like {-3..+3}).") + +(defun editorconfig-fnmatch--match-num (regexp string) + "Return how many times REGEXP is found in STRING." + (let ((num 0)) + ;; START arg does not work as expected in this case + (while (string-match regexp string) + (setq num (1+ num) + string (substring string (match-end 0)))) + num)) + +;;;###autoload +(defun editorconfig-fnmatch-p (name pattern) + "Test whether NAME match PATTERN. + +Matching ignores case if `case-fold-search' is non-nil. + +PATTERN should be a shell glob pattern, and some zsh-like wildcard matchings can +be used: + +* Matches any string of characters, except path separators (/) +** Matches any string of characters +? Matches any single character +[name] Matches any single character in name +[^name] Matches any single character not in name +{s1,s2,s3} Matches any of the strings given (separated by commas) +{min..max} Matches any number between min and max" + (let* ((translated (editorconfig-fnmatch-translate pattern)) + (re (car translated)) + (num-groups (nth 1 translated)) + (match (string-match re name)) + (num-groups-len (length num-groups)) + (pattern-matched t)) + (when match + (let (num-group matched-num-str matched-num min-num max-num) + (dotimes (index num-groups-len) + (setq num-group (nth index num-groups)) + (setq matched-num-str (match-string (1+ index) + name) + min-num (car num-group) + max-num (nth 1 num-group)) + (setq matched-num (string-to-number matched-num-str)) + (when (or (= (aref matched-num-str 0) + ?0) + (< matched-num min-num) + (< max-num matched-num)) + (setq pattern-matched nil)))) + pattern-matched))) + +;;(editorconfig-fnmatch-translate "{a,{-3..3}}.js") +;;(editorconfig-fnmatch-p "1.js" "{a,{-3..3}}.js") + +(defun editorconfig-fnmatch-translate (pattern) + "Translate a shell PATTERN to a regular expression. + +Translation result will be cached, so same translation will not be done twice." + (let ((cached (gethash pattern + editorconfig-fnmatch--cache-hash))) + (or cached + (puthash pattern + (editorconfig-fnmatch--do-translate pattern) + editorconfig-fnmatch--cache-hash)))) + + +(defun editorconfig-fnmatch--do-translate (pattern &optional nested) + "Translate a shell PATTERN to a regular expression. + +Set NESTED to t when this function is called from itself. + +This function is called from `editorconfig-fnmatch-translate', when no cached +translation is found for PATTERN." + (let ((index 0) + (length (length pattern)) + (brace-level 0) + (in-brackets nil) + ;; List of strings of resulting regexp + (result ()) + (is-escaped nil) + (matching-braces (= (editorconfig-fnmatch--match-num + editorconfig-fnmatch--left-brace-regexp + pattern) + (editorconfig-fnmatch--match-num + editorconfig-fnmatch--right-brace-regexp + pattern))) + (numeric-groups ()) + + current-char + pos + has-slash + has-comma + num-range) + + (while (< index length) + (if (and (not is-escaped) + (string-match "[^]\\*?[{},/\\-]+" + ;;(string-match "[^]\\*?[{},/\\-]+" "?.a") + pattern + index) + (eq index (match-beginning 0))) + (setq result `(,@result ,(regexp-quote (match-string 0 pattern))) + index (match-end 0) + is-escaped nil) + + (setq current-char (aref pattern index) + index (1+ index)) + + (cl-case current-char + (?* + (setq pos index) + (if (and (< pos length) + (= (aref pattern pos) ?*)) + (setq result `(,@result ".*")) + (setq result `(,@result "[^/]*")))) + + (?? + (setq result `(,@result "."))) + + (?\[ + (if in-brackets + (setq result `(,@result "\\[")) + (setq pos index + has-slash nil) + (while (and (< pos length) + (not (= (aref pattern pos) ?\])) + (not has-slash)) + (if (and (= (aref pattern pos) ?/) + (not (= (aref pattern (- pos 1)) ?\\))) + (setq has-slash t) + (setq pos (1+ pos)))) + (if has-slash + (setq result `(,@result ,(concat "\\[" + (substring pattern + index + (1+ pos)) + "\\]")) + index (+ pos 2)) + (if (and (< index length) + (memq (aref pattern index) + '(?! ?^))) + (setq index (1+ index) + result `(,@result "[^")) + (setq result `(,@result "["))) + (setq in-brackets t)))) + + (?- + (if in-brackets + (setq result `(,@result "-")) + (setq result `(,@result "\\-")))) + + (?\] + (setq result `(,@result "]") + in-brackets nil)) + + (?{ + (setq pos index + has-comma nil) + (while (and (or (and (< pos length) + (not (= (aref pattern pos) + ?}))) + is-escaped) + (not has-comma)) + (if (and (eq (aref pattern pos) + ?,) + (not is-escaped)) + (setq has-comma t) + (setq is-escaped (and (eq (aref pattern pos) + ?\\) + (not is-escaped)) + pos (1+ pos)))) + (if (and (not has-comma) + (< pos length)) + (let ((pattern-sub (substring pattern index pos))) + (setq num-range (string-match editorconfig-fnmatch--numeric-range-regexp + pattern-sub)) + (if num-range + (setq numeric-groups `(,@numeric-groups ,(mapcar 'string-to-number + (list (match-string 1 + pattern-sub) + (match-string 2 + pattern-sub)))) + result `(,@result "\\([+-]?[0-9]+\\)")) + (let ((inner (editorconfig-fnmatch--do-translate pattern-sub t))) + (setq result `(,@result ,(format "{%s}" + (car inner))) + numeric-groups `(,@numeric-groups ,@(nth 1 inner))))) + (setq index (1+ pos))) + (if matching-braces + (setq result `(,@result "\\(?:") + brace-level (1+ brace-level)) + (setq result `(,@result "{"))))) + + (?, + (if (and (> brace-level 0) + (not is-escaped)) + (setq result `(,@result "\\|")) + (setq result `(,@result "\\,")))) + + (?} + (if (and (> brace-level 0) + (not is-escaped)) + (setq result `(,@result "\\)") + brace-level (- brace-level 1)) + (setq result `(,@result "}")))) + + (?/ + (if (and (<= (+ index 3) + (length pattern)) + (string= (substring pattern index (+ index 3)) + "**/")) + (setq result `(,@result "\\(?:/\\|/.*/\\)") + index (+ index 3)) + (setq result `(,@result "/")))) + + (t + (unless (= current-char + ?\\) + (setq result `(,@result ,(regexp-quote (char-to-string current-char))))))) + + (if (= current-char ?\\) + (progn (when is-escaped + (setq result `(,@result "\\\\"))) + (setq is-escaped (not is-escaped))) + (setq is-escaped nil)))) + (unless nested + (setq result `("^" ,@result "\\'"))) + (list (mapconcat 'identity + result + "") + numeric-groups))) + +(provide 'editorconfig-fnmatch) + +;;; editorconfig-fnmatch.el ends here diff --git a/editorconfig.el b/editorconfig.el index 2ec930e9e6..174ad8f679 100644 --- a/editorconfig.el +++ b/editorconfig.el @@ -5,6 +5,7 @@ ;; Author: EditorConfig Team <editorcon...@googlegroups.com> ;; Version: 0.5 ;; URL: https://github.com/editorconfig/editorconfig-emacs#readme +;; Package-Requires: ((editorconfig-core "20151107.831")) ;; See ;; http://github.com/editorconfig/editorconfig-emacs/graphs/contributors