mirror of
https://github.com/leafo/moonscript.git
synced 2024-11-22 02:44:23 +00:00
add moon-tags script for generating tag file for moonscript classes
This commit is contained in:
parent
fa104985a6
commit
00397fd64b
123
bin/moon-tags
Executable file
123
bin/moon-tags
Executable file
@ -0,0 +1,123 @@
|
|||||||
|
#!/usr/bin/env moon
|
||||||
|
|
||||||
|
HEADER = [[
|
||||||
|
!_TAG_FILE_FORMAT 2 /extended format/
|
||||||
|
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||||
|
!_TAG_PROGRAM_AUTHOR leaf corcoran /leafot@gmail.com/
|
||||||
|
!_TAG_PROGRAM_NAME MoonTags //
|
||||||
|
!_TAG_PROGRAM_URL https://github.com/leafo/moonscript /GitHub repository/
|
||||||
|
!_TAG_PROGRAM_VERSION 0.0.1 //
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- see `ctags --list-kinds` for examples of kinds
|
||||||
|
-- see `ctags --list-fields`
|
||||||
|
|
||||||
|
argparse = require "argparse"
|
||||||
|
|
||||||
|
parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files"
|
||||||
|
parser\argument("files", "MoonScript files to generate tags for")\args "+"
|
||||||
|
parser\flag "--include-line", "Include line number field for each tag"
|
||||||
|
|
||||||
|
args = parser\parse [v for _, v in ipairs _G.arg]
|
||||||
|
|
||||||
|
TAGS = {} -- the final output of tags
|
||||||
|
|
||||||
|
literals = require "moonscript.parse.literals"
|
||||||
|
import Indent from require "moonscript.parse.util"
|
||||||
|
|
||||||
|
import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg"
|
||||||
|
|
||||||
|
-- consome the rest of the file
|
||||||
|
until_end = (1 - literals.Stop)^0
|
||||||
|
whitespace = S"\t " -- not including newline
|
||||||
|
ignore_line = Ct until_end -- tag it for empty line
|
||||||
|
|
||||||
|
-- we have to do this double Ct to capture both the full line and the grouped captures
|
||||||
|
Line = (p) -> Ct C Ct Cg(Indent, "indent") * p
|
||||||
|
Type = (name) -> Cg Cc(name), "type"
|
||||||
|
|
||||||
|
class_line = Line P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end * Type "class"
|
||||||
|
-- TODO: support lapis style routes
|
||||||
|
-- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property"
|
||||||
|
|
||||||
|
method = P { P"=>" + P(1 - literals.Stop) * V(1) }
|
||||||
|
class_method = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * method * until_end * Type "method"
|
||||||
|
|
||||||
|
parse_lines = Ct P {
|
||||||
|
(class_line + class_method + ignore_line) * (P(-1) + literals.Break * V(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
escape_tagaddress = (line_text) ->
|
||||||
|
replacements = P([[\]]) / [[\\]] + P([[/]]) / [[\/]] + P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]]
|
||||||
|
Cs((replacements + 1)^0)\match line_text
|
||||||
|
|
||||||
|
for fname in *args.files
|
||||||
|
file = assert io.open fname
|
||||||
|
contents = assert file\read "*a"
|
||||||
|
lines = assert parse_lines\match contents
|
||||||
|
|
||||||
|
class_stack = {}
|
||||||
|
|
||||||
|
push_class = (cls) ->
|
||||||
|
assert cls.type == "class", "not a class match"
|
||||||
|
-- remove classes that are longer in scope due to indentation
|
||||||
|
for i=#class_stack,1,-1
|
||||||
|
top = class_stack[i]
|
||||||
|
|
||||||
|
if cls.indent <= top.indent
|
||||||
|
table.remove class_stack, i
|
||||||
|
else
|
||||||
|
break
|
||||||
|
|
||||||
|
table.insert class_stack, cls
|
||||||
|
|
||||||
|
-- find the class this property is associated with based on change in indent
|
||||||
|
-- the expeted indent is written to `step` on the first proprety
|
||||||
|
find_class = (property) ->
|
||||||
|
for i=#class_stack,1,-1
|
||||||
|
top = class_stack[i]
|
||||||
|
step = property.indent - top.indent
|
||||||
|
|
||||||
|
if step > 0
|
||||||
|
if top.step == nil
|
||||||
|
top.step = step
|
||||||
|
|
||||||
|
if step == top.step
|
||||||
|
return top
|
||||||
|
|
||||||
|
for line_no, line in ipairs lines
|
||||||
|
continue unless next line
|
||||||
|
|
||||||
|
{line_text, properties} = line
|
||||||
|
|
||||||
|
fields = {"language:moon"}
|
||||||
|
if args.include_line
|
||||||
|
table.insert fields, 1, "line:#{line_no}"
|
||||||
|
|
||||||
|
switch properties.type
|
||||||
|
when "method"
|
||||||
|
if cls = find_class properties
|
||||||
|
table.insert fields, "class:#{cls.tag}"
|
||||||
|
|
||||||
|
table.insert TAGS, {
|
||||||
|
properties.tag
|
||||||
|
fname
|
||||||
|
"/^#{escape_tagaddress line_text}$/;\""
|
||||||
|
"f"
|
||||||
|
table.concat fields, " "
|
||||||
|
}
|
||||||
|
when "class"
|
||||||
|
push_class properties
|
||||||
|
|
||||||
|
table.insert TAGS, {
|
||||||
|
properties.tag
|
||||||
|
fname
|
||||||
|
"/^#{escape_tagaddress line_text}$/;\""
|
||||||
|
"c"
|
||||||
|
table.concat fields, " "
|
||||||
|
}
|
||||||
|
|
||||||
|
print HEADER
|
||||||
|
tag_lines = [table.concat(t, "\t") for t in *TAGS]
|
||||||
|
table.sort tag_lines
|
||||||
|
print table.concat tag_lines, "\n"
|
Loading…
Reference in New Issue
Block a user