diff --git a/src/main/java/xyz/naofal/jtags/Jtags.java b/src/main/java/xyz/naofal/jtags/Jtags.java index ca2eac9..805202b 100644 --- a/src/main/java/xyz/naofal/jtags/Jtags.java +++ b/src/main/java/xyz/naofal/jtags/Jtags.java @@ -1,5 +1,9 @@ package xyz.naofal.jtags; +import static xyz.naofal.jtags.JtagsLogger.logger; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.util.ArrayDeque; import java.util.Arrays; @@ -23,7 +27,16 @@ public class Jtags { } static boolean run(Options options) { - return TagCollector.run(options); + var tags = TagCollector.collectTags(options); + + try { + TagsWriter.writeTagsFile(tags, new FileOutputStream("tags")); + } catch (FileNotFoundException ex) { + logger.severe(ex.toString()); + return false; + } + + return true; } static void printUsage() { diff --git a/src/main/java/xyz/naofal/jtags/Tag.java b/src/main/java/xyz/naofal/jtags/Tag.java index 9256ee2..2a15e8f 100644 --- a/src/main/java/xyz/naofal/jtags/Tag.java +++ b/src/main/java/xyz/naofal/jtags/Tag.java @@ -1,8 +1,12 @@ package xyz.naofal.jtags; -public record Tag(TagKind kind, String name, String location, String line) +public record Tag(TagKind kind, String name, String location, String line, boolean isStatic) implements Comparable { + public Tag(TagKind kind, String name, String location, String line) { + this(kind, name, location, line, false); + } + @Override public int compareTo(Tag o) { return String.CASE_INSENSITIVE_ORDER.compare(name, o.name()); diff --git a/src/main/java/xyz/naofal/jtags/TagCollector.java b/src/main/java/xyz/naofal/jtags/TagCollector.java index aef11d5..a671bf7 100644 --- a/src/main/java/xyz/naofal/jtags/TagCollector.java +++ b/src/main/java/xyz/naofal/jtags/TagCollector.java @@ -6,6 +6,7 @@ import com.sun.source.tree.CompilationUnitTree; import com.sun.source.util.JavacTask; import com.sun.source.util.Trees; import java.io.IOException; +import java.util.PriorityQueue; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; @@ -16,7 +17,7 @@ public class TagCollector { static JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - public static boolean run(Options options) { + public static PriorityQueue collectTags(Options options) { try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null)) { Iterable compilationUnits = @@ -30,11 +31,12 @@ public class TagCollector { for (CompilationUnitTree compilationUnitTree : trees) { treeVisitor.scan(compilationUnitTree, context); } + return treeVisitor.tags; } catch (IOException ex) { logger.severe(ex.toString()); + System.exit(1); + return null; } - - return true; } } diff --git a/src/main/java/xyz/naofal/jtags/TagsWriter.java b/src/main/java/xyz/naofal/jtags/TagsWriter.java new file mode 100644 index 0000000..f5a80ce --- /dev/null +++ b/src/main/java/xyz/naofal/jtags/TagsWriter.java @@ -0,0 +1,59 @@ +package xyz.naofal.jtags; + +import static xyz.naofal.jtags.JtagsLogger.logger; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.PriorityQueue; + +public class TagsWriter { + private static final int MAX_PATTERN_LENGTH = 96; + + public static void writeTagsFile(PriorityQueue tags, OutputStream outputStream) { + var writer = new OutputStreamWriter(outputStream); + try { + writer.write( + """ + !_TAG_FILE_ENCODING\tutf-8\t + !_TAG_FILE_SORTED\t2\t/0=unsorted, 1=sorted, 2=foldcase/ + """); + + Tag tag; + while ((tag = tags.poll()) != null) { + writeTag(writer, tag); + } + + writer.flush(); + } catch (IOException ex) { + logger.severe(ex.toString()); + } + } + + private static void writeTag(Writer writer, Tag tag) throws IOException { + writer.write(tag.name()); + writer.write('\t'); + writer.write(tag.location()); + writer.write("\t/^"); + writer.write(tag.line().substring(0, Math.min(tag.line().length(), MAX_PATTERN_LENGTH))); + writer.write("$/;\"\t"); + writer.write( + switch (tag.kind()) { + case PACKAGE -> 'P'; + case CLASS -> 'C'; + case RECORD -> 'R'; + case INTERFACE -> 'I'; + case ANNOTATION -> 'A'; + case ENUM -> 'E'; + case FIELD -> 'f'; + case ENUM_CONSTANT -> 'e'; + case METHOD -> 'm'; + }); + if (tag.isStatic()) { + writer.write("\tfile:"); + } + + writer.write('\n'); + } +} diff --git a/src/main/java/xyz/naofal/jtags/TreeVisitor.java b/src/main/java/xyz/naofal/jtags/TreeVisitor.java index 2e9e8dd..7341649 100644 --- a/src/main/java/xyz/naofal/jtags/TreeVisitor.java +++ b/src/main/java/xyz/naofal/jtags/TreeVisitor.java @@ -14,7 +14,7 @@ import java.util.PriorityQueue; import javax.lang.model.element.Modifier; public class TreeVisitor extends TreePathScanner { - public PriorityQueue tags = new PriorityQueue<>(); + public final PriorityQueue tags = new PriorityQueue<>(); @Override public Void visitCompilationUnit(CompilationUnitTree node, TreeVisitorContext p) { @@ -55,7 +55,8 @@ public class TreeVisitor extends TreePathScanner { }, node.getSimpleName().toString(), p.getLocation(), - p.getLine(node)); + p.getLine(node), + node.getModifiers().getFlags().contains(Modifier.STATIC)); logger.finer(() -> "Type: " + tag); @@ -66,7 +67,19 @@ public class TreeVisitor extends TreePathScanner { @Override public Void visitMethod(MethodTree node, TreeVisitorContext p) { - Tag tag = new Tag(TagKind.METHOD, node.getName().toString(), p.getLocation(), p.getLine(node)); + Tag tag = + new Tag( + switch (node.getKind()) { + case METHOD -> TagKind.METHOD; + default -> { + logger.warning("Unknown method kind " + node.getKind()); + yield TagKind.METHOD; + } + }, + node.getName().toString(), + p.getLocation(), + p.getLine(node), + node.getModifiers().getFlags().contains(Modifier.STATIC)); logger.finer(() -> "Method: " + tag); tags.add(tag); @@ -91,7 +104,8 @@ public class TreeVisitor extends TreePathScanner { : TagKind.FIELD, node.getName().toString(), p.getLocation(), - p.getLine(node)); + p.getLine(node), + node.getModifiers().getFlags().contains(Modifier.STATIC)); logger.finer(() -> "Variable: " + tag); tags.add(tag); diff --git a/ttt b/ttt new file mode 100644 index 0000000..c9644a5 --- /dev/null +++ b/ttt @@ -0,0 +1,93 @@ +!_TAG_EXTRA_DESCRIPTION anonymous /Include tags for non-named objects like lambda/ +!_TAG_EXTRA_DESCRIPTION fileScope /Include tags of file scope/ +!_TAG_EXTRA_DESCRIPTION pseudo /Include pseudo tags/ +!_TAG_EXTRA_DESCRIPTION subparser /Include tags generated by subparsers/ +!_TAG_FIELD_DESCRIPTION epoch /the last modified time of the input file (only for F\/file kind tag)/ +!_TAG_FIELD_DESCRIPTION file /File-restricted scoping/ +!_TAG_FIELD_DESCRIPTION input /input file/ +!_TAG_FIELD_DESCRIPTION name /tag name/ +!_TAG_FIELD_DESCRIPTION pattern /pattern/ +!_TAG_FIELD_DESCRIPTION typeref /Type and name of a variable or typedef/ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_KIND_DESCRIPTION!Java a,annotation /annotation declarations/ +!_TAG_KIND_DESCRIPTION!Java c,class /classes/ +!_TAG_KIND_DESCRIPTION!Java e,enumConstant /enum constants/ +!_TAG_KIND_DESCRIPTION!Java f,field /fields/ +!_TAG_KIND_DESCRIPTION!Java g,enum /enum types/ +!_TAG_KIND_DESCRIPTION!Java i,interface /interfaces/ +!_TAG_KIND_DESCRIPTION!Java m,method /methods/ +!_TAG_KIND_DESCRIPTION!Java p,package /packages/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_OUTPUT_VERSION 0.0 /current.age/ +!_TAG_PARSER_VERSION!Java 0.0 /current.age/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/noon/code/java/jtags/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 6.1.0 /v6.1.0/ +!_TAG_ROLE_DESCRIPTION!Java!package imported /imported package/ +A src/main/java/xyz/naofal/jtags/example/Example.java /^ A;$/;" e enum:Example.T file: +ANNOTATION src/main/java/xyz/naofal/jtags/TagKind.java /^ ANNOTATION,$/;" e enum:TagKind file: +CLASS src/main/java/xyz/naofal/jtags/TagKind.java /^ CLASS,$/;" e enum:TagKind file: +ENUM src/main/java/xyz/naofal/jtags/TagKind.java /^ ENUM,$/;" e enum:TagKind file: +ENUM_CONSTANT src/main/java/xyz/naofal/jtags/TagKind.java /^ ENUM_CONSTANT,$/;" e enum:TagKind file: +Example src/main/java/xyz/naofal/jtags/example/Example.java /^public class Example {$/;" c +FIELD src/main/java/xyz/naofal/jtags/TagKind.java /^ FIELD,$/;" e enum:TagKind file: +INTERFACE src/main/java/xyz/naofal/jtags/TagKind.java /^ INTERFACE,$/;" e enum:TagKind file: +Jtags src/main/java/xyz/naofal/jtags/Jtags.java /^public class Jtags {$/;" c +JtagsLogger src/main/java/xyz/naofal/jtags/JtagsLogger.java /^public class JtagsLogger {$/;" c +LogHandler src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public static class LogHandler extends Handler {$/;" c class:JtagsLogger +METHOD src/main/java/xyz/naofal/jtags/TagKind.java /^ METHOD;$/;" e enum:TagKind file: +Options src/main/java/xyz/naofal/jtags/Jtags.java /^ static class Options {$/;" c class:Jtags +PACKAGE src/main/java/xyz/naofal/jtags/TagKind.java /^ PACKAGE,$/;" e enum:TagKind file: +RECORD src/main/java/xyz/naofal/jtags/TagKind.java /^ RECORD,$/;" e enum:TagKind file: +T src/main/java/xyz/naofal/jtags/example/Example.java /^ enum T {$/;" g class:Example +T src/main/java/xyz/naofal/jtags/example/Example.java /^@interface T {$/;" a +TagCollector src/main/java/xyz/naofal/jtags/TagCollector.java /^public class TagCollector {$/;" c +TagKind src/main/java/xyz/naofal/jtags/TagKind.java /^public enum TagKind {$/;" g +TagsWriter src/main/java/xyz/naofal/jtags/TagsWriter.java /^public class TagsWriter {$/;" c +TreeVisitor src/main/java/xyz/naofal/jtags/TreeVisitor.java /^public class TreeVisitor extends TreePathScanner {$/;" c +TreeVisitorContext src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ public TreeVisitorContext(Trees trees) {$/;" m class:TreeVisitorContext +TreeVisitorContext src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^public class TreeVisitorContext {$/;" c +a src/main/java/xyz/naofal/jtags/example/Example.java /^ int a;$/;" f class:Example.T +close src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public void close() {$/;" m class:JtagsLogger.LogHandler +collectTags src/main/java/xyz/naofal/jtags/TagCollector.java /^ public static PriorityQueue collectTags(Options options) {$/;" m class:TagCollector +colors src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public static Map colors =$/;" f class:JtagsLogger.LogHandler +compilationUnitTree src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ public CompilationUnitTree compilationUnitTree;$/;" f class:TreeVisitorContext +compiler src/main/java/xyz/naofal/jtags/TagCollector.java /^ static JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();$/;" f class:TagCollector +flush src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public void flush() {$/;" m class:JtagsLogger.LogHandler +getLine src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ public String getLine(Tree node) {$/;" m class:TreeVisitorContext +getLocation src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ public String getLocation() {$/;" m class:TreeVisitorContext +getOffsetInSource src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ private long getOffsetInSource(CompilationUnitTree compilationUnitTree, Tree node) {$/;" m class:TreeVisitorContext file: +logger src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public static Logger logger = Logger.getLogger("logger");$/;" f class:JtagsLogger +loggingHandler src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public static Handler loggingHandler = new LogHandler();$/;" f class:JtagsLogger +lorem src/main/java/xyz/naofal/jtags/example/Example.java /^ public static void lorem($/;" m class:Example +main src/main/java/xyz/naofal/jtags/Jtags.java /^ public static void main(String[] args) {$/;" m class:Jtags +printUsage src/main/java/xyz/naofal/jtags/Jtags.java /^ static void printUsage() {$/;" m class:Jtags +publish src/main/java/xyz/naofal/jtags/JtagsLogger.java /^ public void publish(LogRecord record) {$/;" m class:JtagsLogger.LogHandler +run src/main/java/xyz/naofal/jtags/Jtags.java /^ static boolean run(Options options) {$/;" m class:Jtags +sourcePositions src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ final SourcePositions sourcePositions;$/;" f class:TreeVisitorContext +sources src/main/java/xyz/naofal/jtags/Jtags.java /^ String[] sources;$/;" f class:Jtags.Options +t src/main/java/xyz/naofal/jtags/example/Example.java /^ static int t = 1;$/;" f annotation:T +tags src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public final PriorityQueue tags = new PriorityQueue<>();$/;" f class:TreeVisitor +trees src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^ final Trees trees;$/;" f class:TreeVisitorContext +visitClass src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public Void visitClass(ClassTree node, TreeVisitorContext p) {$/;" m class:TreeVisitor +visitCompilationUnit src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public Void visitCompilationUnit(CompilationUnitTree node, TreeVisitorContext p) {$/;" m class:TreeVisitor +visitMethod src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public Void visitMethod(MethodTree node, TreeVisitorContext p) {$/;" m class:TreeVisitor +visitPackage src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public Void visitPackage(PackageTree node, TreeVisitorContext p) {$/;" m class:TreeVisitor +visitVariable src/main/java/xyz/naofal/jtags/TreeVisitor.java /^ public Void visitVariable(VariableTree node, TreeVisitorContext p) {$/;" m class:TreeVisitor +writeTag src/main/java/xyz/naofal/jtags/TagsWriter.java /^ private static void writeTag(Writer writer, Tag tag) throws IOException {$/;" m class:TagsWriter file: +writeTagsFile src/main/java/xyz/naofal/jtags/TagsWriter.java /^ public static void writeTagsFile(PriorityQueue tags, OutputStream outputStream) {$/;" m class:TagsWriter +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/Jtags.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/JtagsLogger.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/Tag.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/TagCollector.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/TagKind.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/TagsWriter.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/TreeVisitor.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags src/main/java/xyz/naofal/jtags/TreeVisitorContext.java /^package xyz.naofal.jtags;$/;" p +xyz.naofal.jtags.example src/main/java/xyz/naofal/jtags/example/Example.java /^package xyz.naofal.jtags.example;$/;" p