1
1
use core:: str;
2
2
use prettytable:: Table ;
3
- use std:: io:: Read ;
3
+ use std:: {
4
+ io:: { Read , Write } ,
5
+ process:: Stdio ,
6
+ } ;
4
7
use streaming_iterator:: StreamingIterator ;
5
8
9
+ fn clang_format ( text : & str ) -> String {
10
+ let mut cmd = std:: process:: Command :: new ( "clang-format" ) ;
11
+ cmd. stdin ( Stdio :: piped ( ) ) . stdout ( Stdio :: piped ( ) ) ;
12
+ let mut cmd = match cmd. spawn ( ) {
13
+ Ok ( cmd) => cmd,
14
+ Err ( err) if err. kind ( ) == std:: io:: ErrorKind :: NotFound => {
15
+ // clang-format not installed
16
+ return text. to_string ( ) ;
17
+ }
18
+ Err ( err) => panic ! ( "Failed to exec clang-format: {err:?}" ) ,
19
+ } ;
20
+ cmd. stdin
21
+ . take ( )
22
+ . unwrap ( )
23
+ . write_all ( text. as_bytes ( ) )
24
+ . expect ( "Failed to write to clang-format" ) ;
25
+ let output = cmd
26
+ . wait_with_output ( )
27
+ . expect ( "Failed to wait for clang-format" ) ;
28
+ if !output. status . success ( ) {
29
+ panic ! ( "clang-format exited with code: {:?}" , output. status. code( ) ) ;
30
+ }
31
+ String :: from_utf8 ( output. stdout ) . expect ( "clang-format output is not utf-8" )
32
+ }
33
+
34
+ fn find_keymaps < ' a > (
35
+ language : & ' a tree_sitter:: Language ,
36
+ tree : & ' a tree_sitter:: Tree ,
37
+ text : & str ,
38
+ ) -> Option < tree_sitter:: Node < ' a > > {
39
+ let query = tree_sitter:: Query :: new (
40
+ & language,
41
+ "(declaration (init_declarator (array_declarator (array_declarator (array_declarator (identifier) @id))))) @decl" )
42
+ . unwrap ( ) ;
43
+ let mut qc = tree_sitter:: QueryCursor :: new ( ) ;
44
+ let mut it = qc. matches ( & query, tree. root_node ( ) , text. as_bytes ( ) ) ;
45
+
46
+ while let Some ( x) = it. next ( ) {
47
+ let node = x. captures [ 1 ] . node ;
48
+ if node_to_text ( & text, & node) == "keymaps" {
49
+ return Some ( x. captures [ 0 ] . node ) ;
50
+ }
51
+ }
52
+ None
53
+ }
54
+
6
55
fn main ( ) {
7
56
let mut text = String :: new ( ) ;
8
57
std:: io:: stdin ( ) . read_to_string ( & mut text) . unwrap ( ) ;
@@ -14,6 +63,14 @@ fn main() {
14
63
. expect ( "Error loading C parser" ) ;
15
64
16
65
let tree = parser. parse ( & text, None ) . unwrap ( ) ;
66
+
67
+ // Print everything before keymaps, possibly formatting with clang-format
68
+ let keymaps = find_keymaps ( & language, & tree, & text) . expect ( "No keymaps found" ) ;
69
+ let prefix = & text. as_bytes ( ) [ 0 ..keymaps. start_byte ( ) ] ;
70
+ let prefix = str:: from_utf8 ( prefix) . expect ( "Text is not utf-8" ) ;
71
+ print ! ( "{prefix}" ) ;
72
+ let mut last_byte = keymaps. start_byte ( ) ;
73
+
17
74
let query = tree_sitter:: Query :: new (
18
75
& language,
19
76
"(call_expression (identifier) @id (argument_list) @args) @call" ,
@@ -24,40 +81,30 @@ fn main() {
24
81
let call_idx = query. capture_index_for_name ( "call" ) . unwrap ( ) ;
25
82
26
83
let lines: Vec < _ > = text. lines ( ) . collect ( ) ;
27
- let mut last_byte = 0 ;
28
84
let mut qc = tree_sitter:: QueryCursor :: new ( ) ;
29
85
let mut it = qc. matches ( & query, tree. root_node ( ) , text. as_bytes ( ) ) ;
30
86
while let Some ( m) = it. next ( ) {
31
87
let name = m. nodes_for_capture_index ( id_idx) . next ( ) . unwrap ( ) ;
32
88
let ( indent, _) = lines[ name. start_position ( ) . row ]
33
89
. split_once ( |c : char | !c. is_whitespace ( ) )
34
90
. unwrap ( ) ;
35
- let name = name
36
- . utf8_text ( text. as_bytes ( ) )
37
- . expect ( "Failed to get text from node" ) ;
38
- if !name. starts_with ( "LAYOUT" ) {
91
+ let name = node_to_text ( & text, & name) ;
92
+ if !name. starts_with ( "LAYOUT_" ) {
39
93
continue ;
40
94
}
41
95
42
96
// Print everything before the call expression
43
- let call_node = m. nodes_for_capture_index ( call_idx ) . next ( ) . unwrap ( ) ;
44
- let prefix = & text. as_bytes ( ) [ last_byte..call_node . start_byte ( ) ] ;
97
+ let args_node = m. nodes_for_capture_index ( args_idx ) . next ( ) . unwrap ( ) ;
98
+ let prefix = & text. as_bytes ( ) [ last_byte..args_node . start_byte ( ) ] ;
45
99
let prefix = str:: from_utf8 ( prefix) . expect ( "Text is not utf-8" ) ;
46
- last_byte = call_node. end_byte ( ) ;
47
100
print ! ( "{prefix}" ) ;
48
101
49
102
// Print the formatted key list inside parens
50
103
let mut table = Table :: new ( ) ;
51
104
table. set_format ( * prettytable:: format:: consts:: FORMAT_CLEAN ) ;
52
- let node = m. captures [ 1 ] . node ;
53
- let mut qc = node. walk ( ) ;
105
+ let mut qc = args_node. walk ( ) ;
54
106
55
- let keys: Vec < _ > = m
56
- . nodes_for_capture_index ( args_idx)
57
- . next ( )
58
- . unwrap ( )
59
- . named_children ( & mut qc)
60
- . collect ( ) ;
107
+ let keys: Vec < _ > = args_node. named_children ( & mut qc) . collect ( ) ;
61
108
62
109
// Group keys by row
63
110
let min_row = keys
@@ -102,29 +149,25 @@ fn main() {
102
149
. map ( |line| format ! ( "{indent}{indent}{line}" ) )
103
150
. collect :: < Vec < _ > > ( )
104
151
. join ( "\n " ) ;
105
- print ! ( "{name}(\n {table}\n {indent})" ) ;
152
+ print ! ( "(\n {table}\n {indent})" ) ;
153
+
154
+ let call_node = m. nodes_for_capture_index ( call_idx) . next ( ) . unwrap ( ) ;
155
+ last_byte = call_node. end_byte ( ) ;
106
156
}
107
157
108
- let rest = & text. as_bytes ( ) [ last_byte..] ;
158
+ let keymaps_end = keymaps. end_byte ( ) ;
159
+ let rest = & text. as_bytes ( ) [ last_byte..keymaps_end] ;
109
160
let rest = str:: from_utf8 ( rest) . expect ( "Text is not utf-8" ) ;
110
161
print ! ( "{rest}" ) ;
162
+
163
+ let rest = & text. as_bytes ( ) [ keymaps_end..] ;
164
+ let rest = str:: from_utf8 ( rest) . expect ( "Text is not utf-8" ) ;
165
+ let rest = clang_format ( rest) ;
166
+ print ! ( "{rest}" ) ;
111
167
}
112
168
113
169
fn node_to_text ( text : & str , node : & tree_sitter:: Node ) -> String {
114
170
node. utf8_text ( text. as_bytes ( ) )
115
171
. expect ( "Failed to get text from node" )
116
172
. to_string ( )
117
173
}
118
-
119
- #[ cfg( test) ]
120
- mod tests {
121
- use insta_cmd:: { assert_cmd_snapshot, get_cargo_bin} ;
122
- use std:: process:: Command ;
123
-
124
- #[ test]
125
- fn test_fmt ( ) {
126
- let mut cmd = Command :: new ( get_cargo_bin ( env ! ( "CARGO_PKG_NAME" ) ) ) ;
127
- let keymap = std:: fs:: read_to_string ( "testdata/keymap.c" ) . unwrap ( ) ;
128
- assert_cmd_snapshot ! ( cmd. pass_stdin( keymap) ) ;
129
- }
130
- }
0 commit comments