aboutsummaryrefslogtreecommitdiff
path: root/apheleia-utils.el
blob: 5e8b3649151ea2caa6ad860b7706dccd9df58b8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
;;; apheleia-utils.el --- Formatter helpers. -*- lexical-binding: t -*-

;; SPDX-License-Identifier: MIT

;;; Commentary:

;; Helper functions for defining apheleia formatters.

;;; Code:

(require 'cl-lib)
(require 'subr-x)

(defcustom apheleia-formatters-respect-indent-level t
  "Whether formatters should respect Emacs' indent configuration."
  :type 'boolean
  :group 'apheleia)

(defun apheleia-formatters-indent (tab-flag indent-flag &optional indent-var)
  "Set flag for indentation.
Helper function for `apheleia-formatters' which allows you to supply
alternating flags based on the current buffers indent configuration. If the
buffer is indented with tabs then returns TAB-FLAG. Otherwise if INDENT-VAR
is set in the buffer return INDENT-FLAG and the value of INDENT-VAR. Use this
to easily configure the indentation level of a formatter. If INDENT-VAR is
unset then intelligently try to determine the indentation variable based on
the current mode.

If `apheleia-formatters-respect-indent-level' is nil then this
always returns nil to defer to the formatter."
  (cond
   ((not apheleia-formatters-respect-indent-level) nil)
   (indent-tabs-mode tab-flag)
   (indent-var
    (unless indent-var
      (setq indent-var
            (cl-case major-mode
              (cperl-mode 'cperl-indent-level)
              (css-mode 'css-indent-offset)
              (css-ts-mode 'css-indent-offset)
              (js-jsx-mode 'js-indent-level)
              (js-ts-mode 'js-indent-level)
              (js-mode 'js-indent-level)
              (js2-jsx-mode 'js2-basic-offset)
              (js2-mode 'js2-basic-offset)
              (js3-mode 'js3-indent-level)
              (json-mode 'js-indent-level)
              (json-ts-mode 'json-ts-mode-indent-offset)
              (nxml-mode 'nxml-child-indent)
              (robot-mode 'robot-mode-basic-offset)
              (perl-mode 'perl-indent-level)
              (scss-mode 'css-indent-offset)
              (web-mode 'web-mode-indent-style)
              (tsx-ts-mode 'typescript-ts-mode-indent-offset)
              (typescript-mode 'typescript-indent-level)
              (typescript-ts-mode 'typescript-ts-mode-indent-offset))))

    (when-let ((indent (and indent-var
                            (boundp indent-var)
                            (symbol-value indent-var))))
      (list indent-flag (number-to-string indent))))))

(define-obsolete-function-alias 'apheleia-formatters-js-indent
  'apheleia-formatters-indent "4.1")

(defcustom apheleia-formatters-respect-fill-column nil
  "Whether formatters should set `fill-column' related flags."
  :type 'boolean
  :group 'apheleia)

(defun apheleia-formatters-fill-column (fill-flag)
  "Set flag for wrap column.
Helper function to set a flag based on `fill-column'. When `fill-column' is set
and `apheleia-formatters-respect-fill-column' return a list of FILL-FLAG and
`fill-column'."
  (when (and apheleia-formatters-respect-fill-column
             (bound-and-true-p fill-column))
    (list fill-flag (number-to-string fill-column))))

(defun apheleia-formatters-locate-file (file-flag file-name)
  "Set a flag based on a dominating-file.
Look for a file up recursively from the current directory until FILE-NAME is
found. If found return a list of FILE-FLAG and the absolute path to the located
FILE-NAME."
  (when-let ((file (locate-dominating-file default-directory file-name)))
    (list file-flag (concat (expand-file-name file) file-name))))

(defun apheleia-formatters-extension-p (&rest exts)
  "Assert whether current buffer has an extension in EXTS."
  (when-let ((name buffer-file-name)
             (ext (file-name-extension name)))
    (cl-find-if (apply-partially #'string-equal ext)
                exts)))

(defcustom apheleia-formatters-mode-extension-assoc
  '((c-mode . ".c")
    (c-ts-mode . ".c")
    (c++-mode . ".cpp")
    (c++-ts-mode . ".cpp")
    (glsl-mode . ".glsl")
    (java-mode . ".java")
    (java-ts-mode . ".java"))
  "Association list between major-modes and common file extensions for them."
  :type 'alist
  :group 'apheleia)

(defun apheleia-formatters-mode-extension (&optional flag)
  "Get a file-extension based on the current `major-mode'.
If FLAG is set this function returns a list of FLAG and then the extension.
Otherwise return the extension only."
  (when-let ((ext
              (alist-get major-mode apheleia-formatters-mode-extension-assoc)))
    (if flag
        (list flag ext)
      ext)))

(defun apheleia-formatters-local-buffer-file-name (&optional file-name)
  "Get FILE-NAME without any remote components.
FILE-NAME defaults to variable `buffer-file-name'."
  (when-let ((file-name (or file-name buffer-file-name)))
    (if-let ((remote (file-remote-p file-name)))
        (substring file-name (length remote))
      file-name)))

(provide 'apheleia-utils)

;;; apheleia-utils.el ends here