dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

editorconfig-core.el (7645B)


      1 ;;; editorconfig-core.el --- EditorConfig Core library in Emacs Lisp  -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2011-2021 EditorConfig Team
      4 
      5 ;; Author: EditorConfig Team <editorconfig@googlegroups.com>
      6 
      7 ;; See
      8 ;; https://github.com/editorconfig/editorconfig-emacs/graphs/contributors
      9 ;; or the CONTRIBUTORS file for the list of contributors.
     10 
     11 ;; This file is part of EditorConfig Emacs Plugin.
     12 
     13 ;; EditorConfig Emacs Plugin is free software: you can redistribute it and/or
     14 ;; modify it under the terms of the GNU General Public License as published by
     15 ;; the Free Software Foundation, either version 3 of the License, or (at your
     16 ;; option) any later version.
     17 
     18 ;; EditorConfig Emacs Plugin is distributed in the hope that it will be useful,
     19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
     21 ;; Public License for more details.
     22 
     23 ;; You should have received a copy of the GNU General Public License along with
     24 ;; EditorConfig Emacs Plugin. If not, see <https://www.gnu.org/licenses/>.
     25 
     26 ;;; Commentary:
     27 
     28 ;; This library is one implementation of EditorConfig Core, which parses
     29 ;; .editorconfig files and returns properties for given files.
     30 ;; This can be used in place of, for example, editorconfig-core-c.
     31 
     32 
     33 ;; Use from EditorConfig Emacs Plugin
     34 
     35 ;; Emacs plugin (v0.5 or later) can utilize this implementation.
     36 ;; By default, the plugin first search for any EditorConfig executable,
     37 ;; and fallback to this library if not found.
     38 ;; If you always want to use this library, add following lines to your init.el:
     39 
     40 ;;     (setq editorconfig-get-properties-function
     41 ;;           'editorconfig-core-get-properties-hash)
     42 
     43 
     44 ;; Functions
     45 
     46 ;; editorconfig-core-get-properties (&optional file confname confversion)
     47 
     48 ;; Get EditorConfig properties for FILE.
     49 
     50 ;; If FILE is not given, use currently visiting file.
     51 ;; Give CONFNAME for basename of config file other than .editorconfig.
     52 ;; If need to specify config format version, give CONFVERSION.
     53 
     54 ;; This functions returns alist of properties.  Each element will look like
     55 ;; (KEY . VALUE) .
     56 
     57 
     58 ;; editorconfig-core-get-properties-hash (&optional file confname confversion)
     59 
     60 ;; Get EditorConfig properties for FILE.
     61 
     62 ;; This function is almost same as `editorconfig-core-get-properties', but
     63 ;; returns hash object instead.
     64 
     65 ;;; Code:
     66 
     67 (require 'cl-lib)
     68 
     69 (require 'editorconfig-core-handle)
     70 
     71 
     72 (defun editorconfig-core--get-handles (dir confname &optional result)
     73   "Get list of EditorConfig handlers for DIR from CONFNAME.
     74 
     75 In the resulting list, the handle for root config file comes first, and the
     76 nearest comes last.
     77 The list may contains nil when no file was found for directories.
     78 RESULT is used internally and normally should not be used."
     79   (setq dir (expand-file-name dir))
     80   (let ((handle (editorconfig-core-handle (concat (file-name-as-directory dir)
     81                                                   confname)))
     82         (parent (file-name-directory (directory-file-name dir))))
     83     (if (or (string= parent
     84                      dir)
     85             (and handle
     86                  (editorconfig-core-handle-root-p handle)))
     87         (cl-remove-if-not 'identity
     88                           (cons handle result))
     89       (editorconfig-core--get-handles parent
     90                                       confname
     91                                       (cons handle
     92                                             result)))))
     93 
     94 ;;;###autoload
     95 (defun editorconfig-core-get-nearest-editorconfig (directory)
     96   "Return path to .editorconfig file that is closest to DIRECTORY."
     97   (let ((handle (car (last (editorconfig-core--get-handles directory
     98                                                            ".editorconfig")))))
     99     (when handle
    100       (editorconfig-core-handle-path handle))))
    101 
    102 ;;;###autoload
    103 (defun editorconfig-core-get-properties (&optional file confname confversion)
    104   "Get EditorConfig properties for FILE.
    105 If FILE is not given, use currently visiting file.
    106 Give CONFNAME for basename of config file other than .editorconfig.
    107 If need to specify config format version, give CONFVERSION.
    108 
    109 This functions returns alist of properties.  Each element will look like
    110 '(KEY . VALUE) ."
    111   (let ((hash (editorconfig-core-get-properties-hash file confname confversion))
    112         (result nil))
    113     (maphash (lambda (key value)
    114                (add-to-list 'result
    115                             (cons (symbol-name key)
    116                                   value)))
    117              hash)
    118     result))
    119 
    120 (defun editorconfig-core--hash-merge (into update)
    121   "Merge two hashes INTO and UPDATE.
    122 
    123 This is a destructive function, hash INTO will be modified.
    124 When the same key exists in both two hashes, values of UPDATE takes precedence."
    125   (maphash (lambda (key value)
    126              (puthash key
    127                       value
    128                       into))
    129            update)
    130   into)
    131 
    132 ;;;###autoload
    133 (defun editorconfig-core-get-properties-hash (&optional file confname confversion)
    134   "Get EditorConfig properties for FILE.
    135 If FILE is not given, use currently visiting file.
    136 Give CONFNAME for basename of config file other than .editorconfig.
    137 If need to specify config format version, give CONFVERSION.
    138 
    139 This function is almost same as `editorconfig-core-get-properties', but returns
    140 hash object instead."
    141   (setq file
    142         (expand-file-name (or file
    143                               buffer-file-name
    144                               (error "FILE is not given and `buffer-file-name' is nil"))))
    145   (setq confname (or confname
    146                      ".editorconfig"))
    147   (setq confversion (or confversion
    148                         "0.12.0"))
    149   (let ((result (make-hash-table)))
    150     (dolist (handle (editorconfig-core--get-handles (file-name-directory file)
    151                                                     confname))
    152       (editorconfig-core--hash-merge result
    153                                      (editorconfig-core-handle-get-properties-hash handle
    154                                                                                    file)))
    155 
    156     ;; Downcase known boolean values
    157     (dolist (key '(
    158                    end_of_line indent_style indent_size insert_final_newline
    159                    trim_trailing_whitespace charset
    160                    ))
    161       (let ((val (gethash key
    162                           result)))
    163         (when val
    164           (puthash key
    165                    (downcase val)
    166                    result))))
    167 
    168     ;; Add indent_size property
    169     (let ((v-indent-size (gethash 'indent_size result))
    170           (v-indent-style (gethash 'indent_style result)))
    171       (when (and (not v-indent-size)
    172                  (string= v-indent-style "tab")
    173                  ;; If VERSION < 0.9.0, indent_size should have no default value
    174                  (version<= "0.9.0"
    175                             confversion))
    176         (puthash 'indent_size
    177                  "tab"
    178                  result)))
    179     ;; Add tab_width property
    180     (let ((v-indent-size (gethash 'indent_size result))
    181           (v-tab-width (gethash 'tab_width result)))
    182       (when (and v-indent-size
    183                  (not v-tab-width)
    184                  (not (string= v-indent-size "tab")))
    185         (puthash 'tab_width
    186                  v-indent-size
    187                  result)))
    188     ;; Update indent-size property
    189     (let ((v-indent-size (gethash 'indent_size result))
    190           (v-tab-width (gethash 'tab_width result)))
    191       (when (and v-indent-size
    192                  v-tab-width
    193                  (string= v-indent-size "tab"))
    194         (puthash 'indent_size
    195                  v-tab-width
    196                  result)))
    197 
    198     result))
    199 
    200 (provide 'editorconfig-core)
    201 
    202 ;;; editorconfig-core.el ends here