aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock573
-rw-r--r--Cargo.toml25
-rw-r--r--readme.txt10
-rw-r--r--src/app.rs259
-rw-r--r--src/config.rs26
-rw-r--r--src/main.rs102
7 files changed, 996 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..a3ecfa2
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,573 @@
1# This file is automatically @generated by Cargo.
2# It is not intended for manual editing.
3version = 3
4
5[[package]]
6name = "aho-corasick"
7version = "1.1.3"
8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
10dependencies = [
11 "memchr",
12]
13
14[[package]]
15name = "bitflags"
16version = "1.3.2"
17source = "registry+https://github.com/rust-lang/crates.io-index"
18checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
19
20[[package]]
21name = "cc"
22version = "1.0.106"
23source = "registry+https://github.com/rust-lang/crates.io-index"
24checksum = "066fce287b1d4eafef758e89e09d724a24808a9196fe9756b8ca90e86d0719a2"
25
26[[package]]
27name = "cfg-if"
28version = "1.0.0"
29source = "registry+https://github.com/rust-lang/crates.io-index"
30checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
31
32[[package]]
33name = "console"
34version = "0.15.8"
35source = "registry+https://github.com/rust-lang/crates.io-index"
36checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
37dependencies = [
38 "encode_unicode",
39 "lazy_static",
40 "libc",
41 "unicode-width",
42 "windows-sys 0.52.0",
43]
44
45[[package]]
46name = "encode_unicode"
47version = "0.3.6"
48source = "registry+https://github.com/rust-lang/crates.io-index"
49checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
50
51[[package]]
52name = "filetime"
53version = "0.2.23"
54source = "registry+https://github.com/rust-lang/crates.io-index"
55checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
56dependencies = [
57 "cfg-if",
58 "libc",
59 "redox_syscall",
60 "windows-sys 0.52.0",
61]
62
63[[package]]
64name = "inotify"
65version = "0.9.6"
66source = "registry+https://github.com/rust-lang/crates.io-index"
67checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
68dependencies = [
69 "bitflags",
70 "inotify-sys",
71 "libc",
72]
73
74[[package]]
75name = "inotify-sys"
76version = "0.1.5"
77source = "registry+https://github.com/rust-lang/crates.io-index"
78checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
79dependencies = [
80 "libc",
81]
82
83[[package]]
84name = "kqueue"
85version = "1.0.8"
86source = "registry+https://github.com/rust-lang/crates.io-index"
87checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
88dependencies = [
89 "kqueue-sys",
90 "libc",
91]
92
93[[package]]
94name = "kqueue-sys"
95version = "1.0.4"
96source = "registry+https://github.com/rust-lang/crates.io-index"
97checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
98dependencies = [
99 "bitflags",
100 "libc",
101]
102
103[[package]]
104name = "lazy_static"
105version = "1.5.0"
106source = "registry+https://github.com/rust-lang/crates.io-index"
107checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
108
109[[package]]
110name = "libc"
111version = "0.2.155"
112source = "registry+https://github.com/rust-lang/crates.io-index"
113checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
114
115[[package]]
116name = "log"
117version = "0.4.22"
118source = "registry+https://github.com/rust-lang/crates.io-index"
119checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
120
121[[package]]
122name = "memchr"
123version = "2.7.4"
124source = "registry+https://github.com/rust-lang/crates.io-index"
125checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
126
127[[package]]
128name = "mio"
129version = "0.8.11"
130source = "registry+https://github.com/rust-lang/crates.io-index"
131checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
132dependencies = [
133 "libc",
134 "log",
135 "wasi",
136 "windows-sys 0.48.0",
137]
138
139[[package]]
140name = "notify"
141version = "5.2.0"
142source = "registry+https://github.com/rust-lang/crates.io-index"
143checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486"
144dependencies = [
145 "bitflags",
146 "filetime",
147 "inotify",
148 "kqueue",
149 "libc",
150 "mio",
151 "walkdir",
152 "windows-sys 0.45.0",
153]
154
155[[package]]
156name = "redox_syscall"
157version = "0.4.1"
158source = "registry+https://github.com/rust-lang/crates.io-index"
159checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
160dependencies = [
161 "bitflags",
162]
163
164[[package]]
165name = "regex"
166version = "1.10.5"
167source = "registry+https://github.com/rust-lang/crates.io-index"
168checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
169dependencies = [
170 "aho-corasick",
171 "memchr",
172 "regex-automata",
173 "regex-syntax",
174]
175
176[[package]]
177name = "regex-automata"
178version = "0.4.7"
179source = "registry+https://github.com/rust-lang/crates.io-index"
180checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
181dependencies = [
182 "aho-corasick",
183 "memchr",
184 "regex-syntax",
185]
186
187[[package]]
188name = "regex-syntax"
189version = "0.8.4"
190source = "registry+https://github.com/rust-lang/crates.io-index"
191checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
192
193[[package]]
194name = "same-file"
195version = "1.0.6"
196source = "registry+https://github.com/rust-lang/crates.io-index"
197checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
198dependencies = [
199 "winapi-util",
200]
201
202[[package]]
203name = "tree-sitter"
204version = "0.20.10"
205source = "registry+https://github.com/rust-lang/crates.io-index"
206checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d"
207dependencies = [
208 "cc",
209 "regex",
210]
211
212[[package]]
213name = "tree-sitter"
214version = "0.21.0"
215source = "registry+https://github.com/rust-lang/crates.io-index"
216checksum = "705bf7c0958d0171dd7d3a6542f2f4f21d87ed5f1dc8db52919d3a6bed9a359a"
217dependencies = [
218 "cc",
219 "regex",
220]
221
222[[package]]
223name = "tree-sitter-elm"
224version = "5.7.0"
225source = "registry+https://github.com/rust-lang/crates.io-index"
226checksum = "1ee736eec2208cd9ea7f2bf1af505c27df03edaed8c7bac38c29f2b147c6035d"
227dependencies = [
228 "cc",
229 "tree-sitter 0.20.10",
230]
231
232[[package]]
233name = "tree-sitter-go"
234version = "0.19.1"
235source = "registry+https://github.com/rust-lang/crates.io-index"
236checksum = "71967701c8214be4aa77e0260e98361e6fd71ceec1d9d03abb37a22c9f60d0ff"
237dependencies = [
238 "cc",
239 "tree-sitter 0.20.10",
240]
241
242[[package]]
243name = "tree-sitter-javascript"
244version = "0.21.4"
245source = "registry+https://github.com/rust-lang/crates.io-index"
246checksum = "8710a71bc6779e33811a8067bdda3ed08bed1733296ff915e44faf60f8c533d7"
247dependencies = [
248 "cc",
249 "tree-sitter 0.21.0",
250]
251
252[[package]]
253name = "tree-sitter-json"
254version = "0.21.0"
255source = "git+https://github.com/tree-sitter/tree-sitter-json#94f5c527b2965465956c2000ed6134dd24daf2a7"
256dependencies = [
257 "cc",
258 "tree-sitter 0.21.0",
259]
260
261[[package]]
262name = "tree-sitter-md"
263version = "0.2.3"
264source = "registry+https://github.com/rust-lang/crates.io-index"
265checksum = "d9c3cfd068f2527250bbd8ff407431164e12b17863e7eafb76e311dd3f96965a"
266dependencies = [
267 "cc",
268 "tree-sitter 0.21.0",
269]
270
271[[package]]
272name = "tree-sitter-mdx"
273version = "0.0.1"
274source = "git+https://github.com/jlopezcur/tree-sitter-mdx#df43681bff333228fa60b69c09a1e7a6f9ed1610"
275dependencies = [
276 "cc",
277 "tree-sitter 0.20.10",
278]
279
280[[package]]
281name = "tree-sitter-python"
282version = "0.21.0"
283source = "registry+https://github.com/rust-lang/crates.io-index"
284checksum = "b4066c6cf678f962f8c2c4561f205945c84834cce73d981e71392624fdc390a9"
285dependencies = [
286 "cc",
287 "tree-sitter 0.21.0",
288]
289
290[[package]]
291name = "tree-sitter-ruby"
292version = "0.21.0"
293source = "registry+https://github.com/rust-lang/crates.io-index"
294checksum = "c0031f687c0772f2dad7b77104c43428611099a1804c81244ada21560f41f0b1"
295dependencies = [
296 "cc",
297 "tree-sitter 0.21.0",
298]
299
300[[package]]
301name = "tree-sitter-rust"
302version = "0.21.2"
303source = "registry+https://github.com/rust-lang/crates.io-index"
304checksum = "277690f420bf90741dea984f3da038ace46c4fe6047cba57a66822226cde1c93"
305dependencies = [
306 "cc",
307 "tree-sitter 0.21.0",
308]
309
310[[package]]
311name = "tree-sitter-typescript"
312version = "0.21.2"
313source = "registry+https://github.com/rust-lang/crates.io-index"
314checksum = "ecb35d98a688378e56c18c9c159824fd16f730ccbea19aacf4f206e5d5438ed9"
315dependencies = [
316 "cc",
317 "tree-sitter 0.21.0",
318]
319
320[[package]]
321name = "tree-viz"
322version = "0.1.0"
323dependencies = [
324 "console",
325 "notify",
326 "tree-sitter 0.21.0",
327 "tree-sitter-elm",
328 "tree-sitter-go",
329 "tree-sitter-javascript",
330 "tree-sitter-json",
331 "tree-sitter-md",
332 "tree-sitter-mdx",
333 "tree-sitter-python",
334 "tree-sitter-ruby",
335 "tree-sitter-rust",
336 "tree-sitter-typescript",
337]
338
339[[package]]
340name = "unicode-width"
341version = "0.1.13"
342source = "registry+https://github.com/rust-lang/crates.io-index"
343checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
344
345[[package]]
346name = "walkdir"
347version = "2.5.0"
348source = "registry+https://github.com/rust-lang/crates.io-index"
349checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
350dependencies = [
351 "same-file",
352 "winapi-util",
353]
354
355[[package]]
356name = "wasi"
357version = "0.11.0+wasi-snapshot-preview1"
358source = "registry+https://github.com/rust-lang/crates.io-index"
359checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
360
361[[package]]
362name = "winapi-util"
363version = "0.1.8"
364source = "registry+https://github.com/rust-lang/crates.io-index"
365checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
366dependencies = [
367 "windows-sys 0.52.0",
368]
369
370[[package]]
371name = "windows-sys"
372version = "0.45.0"
373source = "registry+https://github.com/rust-lang/crates.io-index"
374checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
375dependencies = [
376 "windows-targets 0.42.2",
377]
378
379[[package]]
380name = "windows-sys"
381version = "0.48.0"
382source = "registry+https://github.com/rust-lang/crates.io-index"
383checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
384dependencies = [
385 "windows-targets 0.48.5",
386]
387
388[[package]]
389name = "windows-sys"
390version = "0.52.0"
391source = "registry+https://github.com/rust-lang/crates.io-index"
392checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
393dependencies = [
394 "windows-targets 0.52.6",
395]
396
397[[package]]
398name = "windows-targets"
399version = "0.42.2"
400source = "registry+https://github.com/rust-lang/crates.io-index"
401checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
402dependencies = [
403 "windows_aarch64_gnullvm 0.42.2",
404 "windows_aarch64_msvc 0.42.2",
405 "windows_i686_gnu 0.42.2",
406 "windows_i686_msvc 0.42.2",
407 "windows_x86_64_gnu 0.42.2",
408 "windows_x86_64_gnullvm 0.42.2",
409 "windows_x86_64_msvc 0.42.2",
410]
411
412[[package]]
413name = "windows-targets"
414version = "0.48.5"
415source = "registry+https://github.com/rust-lang/crates.io-index"
416checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
417dependencies = [
418 "windows_aarch64_gnullvm 0.48.5",
419 "windows_aarch64_msvc 0.48.5",
420 "windows_i686_gnu 0.48.5",
421 "windows_i686_msvc 0.48.5",
422 "windows_x86_64_gnu 0.48.5",
423 "windows_x86_64_gnullvm 0.48.5",
424 "windows_x86_64_msvc 0.48.5",
425]
426
427[[package]]
428name = "windows-targets"
429version = "0.52.6"
430source = "registry+https://github.com/rust-lang/crates.io-index"
431checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
432dependencies = [
433 "windows_aarch64_gnullvm 0.52.6",
434 "windows_aarch64_msvc 0.52.6",
435 "windows_i686_gnu 0.52.6",
436 "windows_i686_gnullvm",
437 "windows_i686_msvc 0.52.6",
438 "windows_x86_64_gnu 0.52.6",
439 "windows_x86_64_gnullvm 0.52.6",
440 "windows_x86_64_msvc 0.52.6",
441]
442
443[[package]]
444name = "windows_aarch64_gnullvm"
445version = "0.42.2"
446source = "registry+https://github.com/rust-lang/crates.io-index"
447checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
448
449[[package]]
450name = "windows_aarch64_gnullvm"
451version = "0.48.5"
452source = "registry+https://github.com/rust-lang/crates.io-index"
453checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
454
455[[package]]
456name = "windows_aarch64_gnullvm"
457version = "0.52.6"
458source = "registry+https://github.com/rust-lang/crates.io-index"
459checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
460
461[[package]]
462name = "windows_aarch64_msvc"
463version = "0.42.2"
464source = "registry+https://github.com/rust-lang/crates.io-index"
465checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
466
467[[package]]
468name = "windows_aarch64_msvc"
469version = "0.48.5"
470source = "registry+https://github.com/rust-lang/crates.io-index"
471checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
472
473[[package]]
474name = "windows_aarch64_msvc"
475version = "0.52.6"
476source = "registry+https://github.com/rust-lang/crates.io-index"
477checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
478
479[[package]]
480name = "windows_i686_gnu"
481version = "0.42.2"
482source = "registry+https://github.com/rust-lang/crates.io-index"
483checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
484
485[[package]]
486name = "windows_i686_gnu"
487version = "0.48.5"
488source = "registry+https://github.com/rust-lang/crates.io-index"
489checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
490
491[[package]]
492name = "windows_i686_gnu"
493version = "0.52.6"
494source = "registry+https://github.com/rust-lang/crates.io-index"
495checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
496
497[[package]]
498name = "windows_i686_gnullvm"
499version = "0.52.6"
500source = "registry+https://github.com/rust-lang/crates.io-index"
501checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
502
503[[package]]
504name = "windows_i686_msvc"
505version = "0.42.2"
506source = "registry+https://github.com/rust-lang/crates.io-index"
507checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
508
509[[package]]
510name = "windows_i686_msvc"
511version = "0.48.5"
512source = "registry+https://github.com/rust-lang/crates.io-index"
513checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
514
515[[package]]
516name = "windows_i686_msvc"
517version = "0.52.6"
518source = "registry+https://github.com/rust-lang/crates.io-index"
519checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
520
521[[package]]
522name = "windows_x86_64_gnu"
523version = "0.42.2"
524source = "registry+https://github.com/rust-lang/crates.io-index"
525checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
526
527[[package]]
528name = "windows_x86_64_gnu"
529version = "0.48.5"
530source = "registry+https://github.com/rust-lang/crates.io-index"
531checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
532
533[[package]]
534name = "windows_x86_64_gnu"
535version = "0.52.6"
536source = "registry+https://github.com/rust-lang/crates.io-index"
537checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
538
539[[package]]
540name = "windows_x86_64_gnullvm"
541version = "0.42.2"
542source = "registry+https://github.com/rust-lang/crates.io-index"
543checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
544
545[[package]]
546name = "windows_x86_64_gnullvm"
547version = "0.48.5"
548source = "registry+https://github.com/rust-lang/crates.io-index"
549checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
550
551[[package]]
552name = "windows_x86_64_gnullvm"
553version = "0.52.6"
554source = "registry+https://github.com/rust-lang/crates.io-index"
555checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
556
557[[package]]
558name = "windows_x86_64_msvc"
559version = "0.42.2"
560source = "registry+https://github.com/rust-lang/crates.io-index"
561checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
562
563[[package]]
564name = "windows_x86_64_msvc"
565version = "0.48.5"
566source = "registry+https://github.com/rust-lang/crates.io-index"
567checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
568
569[[package]]
570name = "windows_x86_64_msvc"
571version = "0.52.6"
572source = "registry+https://github.com/rust-lang/crates.io-index"
573checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..73ec928
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,25 @@
1[package]
2name = "tree-viz"
3version = "0.1.0"
4edition = "2021"
5
6# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
8[dependencies]
9tree-sitter-elm = "5.6.3"
10tree-sitter-ruby = "0.21"
11tree-sitter-rust = "0.21"
12tree-sitter = "0.21"
13console = "^0.15"
14tree-sitter-go = "0.19.1"
15tree-sitter-typescript = "0.21"
16tree-sitter-javascript = "0.21"
17tree-sitter-mdx = { git = "https://github.com/jlopezcur/tree-sitter-mdx" }
18tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json" }
19tree-sitter-python = "0.21"
20tree-sitter-md = "0.2.3"
21# tree-sitter-cobol = { path = "../../tree-sitter-cobol/" }
22
23[dependencies.notify]
24version = "5.0.0"
25default-features = false
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..008008b
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,10 @@
1tree-viz -- <language> <file> [scope_query]
2
3language is one of:
4
5- typescript
6- javascript
7- python
8- rust
9- markdown
10- ruby
diff --git a/src/app.rs b/src/app.rs
new file mode 100644
index 0000000..285034b
--- /dev/null
+++ b/src/app.rs
@@ -0,0 +1,259 @@
1use crate::config::Config;
2
3use std::{
4 collections::HashMap,
5 fmt::Write,
6 path::{Path, PathBuf},
7};
8
9use console::{style, Style, Term};
10use tree_sitter::{Node, Parser, Query, QueryCursor, Range, Tree};
11
12pub struct App {
13 config: Config,
14 language: tree_sitter::Language,
15 path: PathBuf,
16 query: Option<Query>,
17 query_path: Option<PathBuf>,
18 src: Vec<u8>,
19 tree: Tree,
20}
21
22impl App {
23 pub fn new<'a, P: AsRef<Path>>(
24 src: &'a [u8],
25 path: P,
26 query_path: Option<P>,
27 language: tree_sitter::Language,
28 ) -> Self {
29 let path = path.as_ref().to_owned();
30
31 let mut parser = Parser::new();
32 parser.set_language(&language).unwrap();
33
34 let tree = parser.parse(&src, None).unwrap();
35 let query_path = query_path.map(|q| q.as_ref().to_owned());
36 let query = query_path.as_ref().map(|p| {
37 let query_src = std::fs::read_to_string(&p).expect("unable to read query");
38 Query::new(&language, &query_src).expect("query parse error")
39 });
40
41 Self {
42 config: Default::default(),
43 path,
44 query,
45 query_path,
46 src: src.to_owned(),
47 tree,
48 language,
49 }
50 }
51
52 pub fn draw(&self) {
53 let term = Term::stdout();
54 term.clear_screen().unwrap();
55 let mut done = false;
56 let mut depth = 0;
57 let mut in_capture: Option<Range> = None;
58 let mut cursor = self.tree.walk();
59
60 let capture_names = self
61 .query
62 .as_ref()
63 .map(|q| q.capture_names())
64 .unwrap_or_default();
65 let capture_map = self
66 .query
67 .as_ref()
68 .map(|query| {
69 QueryCursor::new()
70 .matches(&query, self.tree.root_node(), self.src.as_slice())
71 .flat_map(|match_| match_.captures)
72 .fold(
73 HashMap::new(),
74 |mut map: HashMap<Node, Vec<u32>>, capture| {
75 map.entry(capture.node)
76 .and_modify(|idxs| idxs.push(capture.index))
77 .or_insert_with(|| vec![capture.index]);
78 map
79 },
80 )
81 })
82 .unwrap_or_default();
83
84 while !done {
85 let node = cursor.node();
86 let mut tree_string = String::new();
87 in_capture = match in_capture {
88 Some(range)
89 if !contains(&range, &node.range()) && capture_map.contains_key(&node) =>
90 {
91 Some(node.range())
92 }
93 Some(range) if !contains(&range, &node.range()) => None,
94 None if capture_map.contains_key(&node) => Some(node.range()),
95 i => i,
96 };
97
98 write!(
99 tree_string,
100 "{}",
101 (if in_capture.is_some() {
102 Style::new().on_yellow().on_bright()
103 } else {
104 Style::new()
105 })
106 .bright()
107 .black()
108 .apply_to(
109 format!("{}{}", "|", " ".repeat(self.config.indent_level))
110 .repeat(depth as usize)
111 )
112 )
113 .unwrap();
114
115 if self.config.show_field_name {
116 if let Some(f) = cursor.field_name() {
117 write!(
118 tree_string,
119 "{} ",
120 if in_capture.is_some() {
121 Style::new().on_yellow().on_bright()
122 } else {
123 Style::new()
124 }
125 .yellow()
126 .apply_to(f)
127 )
128 .unwrap()
129 }
130 }
131
132 write!(
133 tree_string,
134 "{} ",
135 if node.is_error() {
136 Style::new().red()
137 } else if in_capture.is_some() {
138 Style::new().on_yellow().on_bright()
139 } else {
140 Style::new()
141 }
142 .apply_to(node.kind()),
143 )
144 .unwrap();
145
146 if let Some(idxs) = capture_map.get(&node) {
147 for index in idxs {
148 write!(
149 tree_string,
150 "@{} ",
151 style(capture_names[*index as usize]).magenta()
152 )
153 .unwrap();
154 }
155 }
156
157 if self.config.show_ranges {
158 let range = node.range();
159 write!(
160 tree_string,
161 " {}",
162 style(format!("{:?}..{:?}", range.start_byte, range.end_byte,))
163 .bright()
164 .black()
165 )
166 .unwrap();
167 }
168
169 if self.config.show_src {
170 write!(
171 tree_string,
172 " {:.?}",
173 style(node.utf8_text(&self.src).unwrap()).cyan()
174 )
175 .unwrap();
176 }
177
178 term.write_line(&tree_string).unwrap();
179 term.clear_to_end_of_screen().unwrap();
180
181 if cursor.goto_first_child() {
182 depth += 1;
183 continue;
184 }
185 if cursor.goto_next_sibling() {
186 continue;
187 }
188
189 loop {
190 if !cursor.goto_parent() {
191 done = true;
192 break;
193 } else {
194 depth -= 1;
195 }
196
197 if cursor.goto_next_sibling() {
198 break;
199 }
200 }
201 }
202
203 // see https://github.com/console-rs/console/issues/36#issuecomment-624731432
204 // for the reasoning behing this hackjob
205
206 term.write_line("\n(>) increase indent").unwrap();
207 term.clear_to_end_of_screen().unwrap();
208
209 term.write_line("(<) decrease indent ").unwrap();
210 term.clear_to_end_of_screen().unwrap();
211
212 term.write_line("(n) toggle ranges").unwrap();
213 term.clear_to_end_of_screen().unwrap();
214
215 term.write_line("(s) toggle source text").unwrap();
216 term.clear_to_end_of_screen().unwrap();
217
218 term.write_line("(r) reload from disk").unwrap();
219 term.clear_to_end_of_screen().unwrap();
220
221 term.write_line("(C-c) quit").unwrap();
222 term.clear_to_end_of_screen().unwrap();
223 }
224
225 pub fn increase_indent(&mut self) {
226 self.config.indent_level = self.config.indent_level.saturating_add(1);
227 }
228
229 pub fn decrease_indent(&mut self) {
230 self.config.indent_level = self.config.indent_level.saturating_sub(1);
231 }
232
233 pub fn toggle_ranges(&mut self) {
234 self.config.show_ranges = !self.config.show_ranges;
235 }
236
237 pub fn toggle_source(&mut self) {
238 self.config.show_src = !self.config.show_src;
239 }
240
241 pub fn reload(&mut self) {
242 let src = std::fs::read_to_string(&self.path).unwrap();
243 let new = Self::new(
244 src.as_bytes(),
245 &self.path,
246 self.query_path.as_ref(),
247 self.language.clone(),
248 );
249 *self = Self {
250 config: self.config,
251 ..new
252 };
253 }
254}
255
256// does a encompass b
257fn contains(a: &Range, b: &Range) -> bool {
258 a.start_byte <= b.start_byte && a.end_byte >= b.end_byte
259}
diff --git a/src/config.rs b/src/config.rs
new file mode 100644
index 0000000..18ed5cc
--- /dev/null
+++ b/src/config.rs
@@ -0,0 +1,26 @@
1use std::default::Default;
2
3#[derive(Clone, Copy)]
4pub struct Config {
5 pub indent_level: usize,
6 pub show_ranges: bool,
7 pub show_src: bool,
8 pub show_field_name: bool,
9}
10
11impl Default for Config {
12 fn default() -> Self {
13 Config::new()
14 }
15}
16
17impl Config {
18 fn new() -> Self {
19 Self {
20 indent_level: 2,
21 show_ranges: true,
22 show_src: true,
23 show_field_name: true,
24 }
25 }
26}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..ce7c84c
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,102 @@
1mod app;
2mod config;
3
4use std::{
5 env, fs,
6 path::Path,
7 sync::{mpsc, Arc, RwLock},
8 thread,
9 time::Duration,
10};
11
12use app::App;
13use console::{Key, Term};
14use notify::{Event as WatchEvent, EventKind as WatchEventKind, RecursiveMode, Watcher};
15
16fn main() {
17 let mut args = env::args();
18 let _ = args.next();
19
20 let language = match args.next().as_ref().map(|s| s.as_str()) {
21 Some("rust") => tree_sitter_rust::language(),
22 Some("tsx") | Some("typescript") => tree_sitter_typescript::language_tsx(),
23 Some("javascript") => tree_sitter_javascript::language(),
24 Some("python") => tree_sitter_python::language(),
25 Some("ruby") => tree_sitter_ruby::language(),
26 Some("markdown") => tree_sitter_md::language(),
27 Some(s) => panic!("invalid language passed: {s}"),
28 None => panic!("no language passed"),
29 };
30 let path = args.next().expect("no arg passed");
31 let query_path = args.next();
32 let src = fs::read_to_string(&path).expect("unable to read file");
33
34 let app = Arc::new(RwLock::new(App::new(
35 src.as_bytes(),
36 &path,
37 query_path.as_ref(),
38 language,
39 )));
40
41 let watch_fn = |watcher_app: Arc<RwLock<App>>| {
42 move |ev| {
43 if let Ok(WatchEvent {
44 kind: WatchEventKind::Modify(..),
45 ..
46 }) = ev
47 {
48 if let Ok(mut locked) = watcher_app.try_write() {
49 locked.reload();
50 locked.draw();
51 };
52 }
53 }
54 };
55
56 let mut watcher1 = notify::recommended_watcher(watch_fn(Arc::clone(&app))).unwrap();
57 watcher1
58 .watch(Path::new(&path), RecursiveMode::NonRecursive)
59 .unwrap();
60
61 let mut watcher2 = notify::recommended_watcher(watch_fn(Arc::clone(&app))).unwrap();
62 if let Some(query_path) = query_path {
63 watcher2
64 .watch(Path::new(&query_path), RecursiveMode::NonRecursive)
65 .unwrap();
66 }
67
68 let (tx, rx) = mpsc::channel();
69 let tx0 = tx.clone();
70 thread::spawn(move || {
71 let term = Term::stdout();
72 loop {
73 if let Ok(Key::Char(ev)) = term.read_key() {
74 tx0.send(ev).unwrap();
75 }
76 }
77 });
78
79 if let Ok(locked) = app.try_read() {
80 locked.draw();
81 }
82
83 loop {
84 match rx.try_recv() {
85 Ok(ev) => {
86 if let Ok(mut locked) = app.try_write() {
87 match ev {
88 '>' => locked.increase_indent(),
89 '<' => locked.decrease_indent(),
90 'n' => locked.toggle_ranges(),
91 's' => locked.toggle_source(),
92 'r' => locked.reload(),
93 _ => (),
94 }
95 locked.draw();
96 }
97 }
98 _ => (),
99 }
100 thread::sleep(Duration::from_millis(10));
101 }
102}