Skip to content

Commit 00397fd

Browse files
committed
add moon-tags script for generating tag file for moonscript classes
1 parent fa10498 commit 00397fd

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

bin/moon-tags

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#!/usr/bin/env moon
2+
3+
HEADER = [[
4+
!_TAG_FILE_FORMAT 2 /extended format/
5+
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
6+
!_TAG_PROGRAM_AUTHOR leaf corcoran /[email protected]/
7+
!_TAG_PROGRAM_NAME MoonTags //
8+
!_TAG_PROGRAM_URL https://github.com/leafo/moonscript /GitHub repository/
9+
!_TAG_PROGRAM_VERSION 0.0.1 //
10+
]]
11+
12+
-- see `ctags --list-kinds` for examples of kinds
13+
-- see `ctags --list-fields`
14+
15+
argparse = require "argparse"
16+
17+
parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files"
18+
parser\argument("files", "MoonScript files to generate tags for")\args "+"
19+
parser\flag "--include-line", "Include line number field for each tag"
20+
21+
args = parser\parse [v for _, v in ipairs _G.arg]
22+
23+
TAGS = {} -- the final output of tags
24+
25+
literals = require "moonscript.parse.literals"
26+
import Indent from require "moonscript.parse.util"
27+
28+
import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg"
29+
30+
-- consome the rest of the file
31+
until_end = (1 - literals.Stop)^0
32+
whitespace = S"\t " -- not including newline
33+
ignore_line = Ct until_end -- tag it for empty line
34+
35+
-- we have to do this double Ct to capture both the full line and the grouped captures
36+
Line = (p) -> Ct C Ct Cg(Indent, "indent") * p
37+
Type = (name) -> Cg Cc(name), "type"
38+
39+
class_line = Line P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end * Type "class"
40+
-- TODO: support lapis style routes
41+
-- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property"
42+
43+
method = P { P"=>" + P(1 - literals.Stop) * V(1) }
44+
class_method = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * method * until_end * Type "method"
45+
46+
parse_lines = Ct P {
47+
(class_line + class_method + ignore_line) * (P(-1) + literals.Break * V(1))
48+
}
49+
50+
escape_tagaddress = (line_text) ->
51+
replacements = P([[\]]) / [[\\]] + P([[/]]) / [[\/]] + P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]]
52+
Cs((replacements + 1)^0)\match line_text
53+
54+
for fname in *args.files
55+
file = assert io.open fname
56+
contents = assert file\read "*a"
57+
lines = assert parse_lines\match contents
58+
59+
class_stack = {}
60+
61+
push_class = (cls) ->
62+
assert cls.type == "class", "not a class match"
63+
-- remove classes that are longer in scope due to indentation
64+
for i=#class_stack,1,-1
65+
top = class_stack[i]
66+
67+
if cls.indent <= top.indent
68+
table.remove class_stack, i
69+
else
70+
break
71+
72+
table.insert class_stack, cls
73+
74+
-- find the class this property is associated with based on change in indent
75+
-- the expeted indent is written to `step` on the first proprety
76+
find_class = (property) ->
77+
for i=#class_stack,1,-1
78+
top = class_stack[i]
79+
step = property.indent - top.indent
80+
81+
if step > 0
82+
if top.step == nil
83+
top.step = step
84+
85+
if step == top.step
86+
return top
87+
88+
for line_no, line in ipairs lines
89+
continue unless next line
90+
91+
{line_text, properties} = line
92+
93+
fields = {"language:moon"}
94+
if args.include_line
95+
table.insert fields, 1, "line:#{line_no}"
96+
97+
switch properties.type
98+
when "method"
99+
if cls = find_class properties
100+
table.insert fields, "class:#{cls.tag}"
101+
102+
table.insert TAGS, {
103+
properties.tag
104+
fname
105+
"/^#{escape_tagaddress line_text}$/;\""
106+
"f"
107+
table.concat fields, " "
108+
}
109+
when "class"
110+
push_class properties
111+
112+
table.insert TAGS, {
113+
properties.tag
114+
fname
115+
"/^#{escape_tagaddress line_text}$/;\""
116+
"c"
117+
table.concat fields, " "
118+
}
119+
120+
print HEADER
121+
tag_lines = [table.concat(t, "\t") for t in *TAGS]
122+
table.sort tag_lines
123+
print table.concat tag_lines, "\n"

0 commit comments

Comments
 (0)