-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtsi-css.el
146 lines (128 loc) · 3.96 KB
/
tsi-css.el
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
;;; tsi-css.el --- tree-sitter indentation for CSS and friends -*- lexical-binding: t; -*-
;;; Version: 1.0.2
;;; Author: Dan Orzechowski
;;; URL: https://github.com/orzechowskid/tsi.el
;;; Package-Requires: ((tsi "1.0.0"))
;;; SPDX-License-Identifier: GPLv3
;;; Commentary:
;; a file containing indentation rules for CSS. Enable
;; it via `M-x tsi-css-mode`, or configure as part of your major-mode hook:
;;
;; (add-hook 'css-mode-hook (lambda () (tsi-css-mode t)))
;;
;; Enabling `tsi-css-mode` will set the current buffer's `indent-line-function`,
;; as well as register an outdent function (<S-iso-lefttab>, aka <backtab>). I should
;; make that configurable at some point.
;;
;; Indentation amount is controlled by the value of `tsi-css-indent-offset`.
;;; Code:
(require 'tsi)
(defgroup tsi-css nil
"Minor mode for indenting CSS using the tree-sitter CST."
:group 'programming
:prefix "tsi-css-")
(defcustom tsi-css-indent-offset 2
"Default indent level."
:type 'number
:group 'tsi-css)
(defun tsi-css--get-indent-for (current-node parent-node)
"Returns an indentation operation for the given CURRENT-NODE and PARENT-NODE."
(let* ((current-type
(tsc-node-type current-node))
(parent-type
(tsc-node-type parent-node))
(parent-indentation
(cond
((eq
parent-type
'stylesheet)
nil)
((eq
parent-type
'declaration)
(if (eq
current-type
'plain_value)
tsi-css-indent-offset
nil))
((eq
parent-type
'block)
(if (tsc-node-named-p current-node)
tsi-css-indent-offset
nil))
((eq
parent-type
'arguments)
(if (tsc-node-named-p current-node)
tsi-css-indent-offset
nil))))
(child-indentation
nil)
(comment-indentation
(if (and
(or
(eq
current-type
'comment)
(eq
(tsc-node-type
(tsi--highest-node-at current-node))
'stylesheet))
(save-excursion
(beginning-of-line)
(back-to-indentation)
(looking-at-p "\\*")))
1
nil)))
(tsi--debug "child indentation: %s parent indentation: %s" child-indentation parent-indentation)
(+
(or parent-indentation 0)
(or child-indentation 0)
(or comment-indentation 0))))
;; exposed for testing purposes
;;;###autoload
(defun tsi-css--indent-line ()
"Internal function.
Calculate indentation for the current line."
(tsi-indent-line #'tsi-css--get-indent-for))
(defun tsi-css--outdent-line ()
"Outdents by `tsi-css-indent-offset`."
(interactive)
(let* ((current-indentation
(save-excursion
(back-to-indentation)
(current-column)))
(new-indentation
(max
0
(- current-indentation tsi-css-indent-offset))))
(delete-region
(progn (beginning-of-line) (point))
(progn (back-to-indentation) (point)))
(indent-to-column new-indentation)
(back-to-indentation)))
;;;###autoload
(define-minor-mode tsi-css-mode
"Use tree-sitter to calculate indentation for CSS buffers."
:group 'tsi-css
:keymap (make-sparse-keymap)
(cond
(tsi-css-mode
;; enabling mode
;; ensure tree-sitter is loaded
(unless tree-sitter-mode
(tree-sitter-mode))
;; update indent-line-function
(setq-local
indent-line-function
#'tsi-css--indent-line)
;; add an outdent function
(define-key tsi-css-mode-map (kbd "<S-iso-lefttab>") #'tsi-css--outdent-line)
t)
(t
;; disabling mode
(setq-local
indent-line-function
(default-value 'indent-line-function)))))
(provide 'tsi-css)