-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathCodeStat.java
More file actions
201 lines (185 loc) · 7.03 KB
/
CodeStat.java
File metadata and controls
201 lines (185 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package roj.plugins;
import roj.collect.ArrayList;
import roj.collect.HashMap;
import roj.collect.ToIntMap;
import roj.gui.GuiUtil;
import roj.gui.TextAreaPrintStream;
import roj.io.IOUtil;
import roj.plugin.Plugin;
import roj.plugin.SimplePlugin;
import roj.text.CharList;
import roj.text.TextReader;
import roj.text.TextUtil;
import roj.ui.Argument;
import roj.ui.CommandNode;
import roj.ui.Tty;
import roj.util.function.Flow;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* @author Roj234
* @since 2022/10/7 22:32
*/
@SimplePlugin(id = "codeStat", desc = "让你可以直观的看到自己写了多少代码\n指令: codestat [文件夹]", version = "2.1")
public class CodeStat extends Plugin {
private static final Function<String, ToIntMap<String>> compute = (x) -> new ToIntMap<>();
private final HashMap<String, ToIntMap<String>> lines = new HashMap<>(), chars = new HashMap<>();
private final ToIntMap<String> totalLines = new ToIntMap<>(), totalChars = new ToIntMap<>();
private static boolean hasUI;
@Override
protected void onEnable() throws Exception {
registerCommand(CommandNode.literal("codestat").executes(ctx -> {
main(new String[0]);
}).then(CommandNode.argument("path", Argument.path()).executes(ctx -> {
main(new String[] {ctx.argument("path", String.class)});
})));
}
public static void main(String[] args) throws IOException {
if (!Tty.IS_RICH) {
if (!hasUI) {
hasUI = true;
GuiUtil.systemLaf();
JFrame frame = new JFrame() {
{
JScrollPane scrollPane1 = new JScrollPane();
JTextArea textArea1 = new JTextArea();
System.setOut(new TextAreaPrintStream(textArea1, 99999));
JButton button1 = new JButton();
//======== this ========
setTitle("New JFrame Layout");
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
//======== scrollPane1 ========
scrollPane1.setViewportView(textArea1);
contentPane.add(scrollPane1, BorderLayout.CENTER);
//---- button1 ----
button1.setText("open");
contentPane.add(button1, BorderLayout.NORTH);
button1.addActionListener(e -> {
try {
main(new String[0]);
} catch (IOException ex) {
ex.printStackTrace();
}
});
pack();
setLocationRelativeTo(getOwner());
setSize(500, 700);
}
};
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
return;
}
}
List<File> files;
File f = new File(args.length == 0 ? "projects/rojlib/java" : args[0]);
if (!f.isDirectory()) {
File[] f1 = GuiUtil.filesLoadFrom("选择文件夹以统计所有子目录(可多选)", null, JFileChooser.DIRECTORIES_ONLY);
if (f1 == null) return;
files = Arrays.asList(f1);
} else {
files = Collections.singletonList(f);
}
System.out.println("正在计算...");
CodeStat inst = new CodeStat();
for (File file : files) {
Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
if (dir.endsWith("node_modules") || dir.endsWith("site-packages")) return FileVisitResult.SKIP_SUBTREE;
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
String name = file.getFileName().toString();
String ext = IOUtil.getExtension(name);
switch (ext) {
case "java", "go", "c", "cpp", "h", "hpp", "js", "jsx", "ts", "py":
case "php", "asp", "jsp", "html", "aspx", "xhtml", "htm", "css":
case "less", "scss", "sass", "vue", "lua", "kt", "rs", "mjs":
inst.accept(name, ext, file);
break;
}
return FileVisitResult.CONTINUE;
}
});
}
boolean noLimit = Boolean.getBoolean("noLimit");
int TOP = noLimit ? Integer.MAX_VALUE : 10;
long totalLinesX = 0;
for (ToIntMap.Entry<String> entry : inst.totalLines.selfEntrySet()) {
totalLinesX += entry.value;
}
long totalCharsX = 0;
for (ToIntMap.Entry<String> entry : inst.totalChars.selfEntrySet()) {
totalCharsX += entry.value;
}
int fileCount = 0;
for (ToIntMap<String> value : inst.lines.values()) {
fileCount += value.size();
}
System.out.println("你已经写了 "+totalLinesX+" 行 (合 " +totalCharsX+" 字符, "+fileCount+" 文件) 的代码呢~");
if (inst.totalLines.size() > 1) {
printStatistic(inst, "语言按行数", new ArrayList<>(inst.totalLines.selfEntrySet()), 99);
printStatistic(inst, "语言按字符数", new ArrayList<>(inst.totalChars.selfEntrySet()), 99);
printStatistic(inst, "语言按文件数", Flow.of(inst.lines.entrySet()).map(entry -> new ToIntMap.Entry<>(entry.getKey(), entry.getValue().size())).toList(), 99);
for (Map.Entry<String, ToIntMap<String>> entry : inst.lines.entrySet()) {
printStatistic(inst, "行数Top"+TOP+" - "+entry.getKey(), new ArrayList<>(entry.getValue().selfEntrySet()), TOP);
}
for (Map.Entry<String, ToIntMap<String>> entry : inst.chars.entrySet()) {
printStatistic(inst, "字符Top"+TOP+" - "+entry.getKey(), new ArrayList<>(entry.getValue().selfEntrySet()), TOP);
}
}
ArrayList<ToIntMap.Entry<String>> all = new ArrayList<>();
for (Map.Entry<String, ToIntMap<String>> entry : inst.lines.entrySet())
all.addAll(entry.getValue().selfEntrySet());
printStatistic(inst, "行数Top"+TOP, all, TOP);
all.clear();
for (Map.Entry<String, ToIntMap<String>> entry : inst.chars.entrySet())
all.addAll(entry.getValue().selfEntrySet());
printStatistic(inst, "字符Top"+TOP, all, TOP);
}
private static void printStatistic(CodeStat inst, String title, List<ToIntMap.Entry<String>> list, int limit) {
System.out.println("========= "+title+" ============");
list.sort((o1, o2) -> Integer.compare(o2.value, o1.value));
double sum = 0;
for (int i = 0; i < list.size(); i++) sum += list.get(i).value;
sum /= 100;
for (int i = 0; i < Math.min(list.size(), limit); i++) {
System.out.println((i + 1) + ". " + list.get(i).getKey() + ": " + list.get(i).value + " (" + TextUtil.toFixed(list.get(i).value / sum, 2) + "%)");
}
System.out.println("========= "+title+" 结束 ============");
}
private void accept(String name, String ext, Path file) {
int lines = 0, chars = 0;
try (TextReader in = TextReader.auto(file)) {
CharList sb = IOUtil.getSharedCharBuf();
while (in.readLine(sb)) {
if (sb.length() > 0) {
lines++;
chars += sb.length();
}
}
} catch (IOException e) {
System.out.println(file);
e.printStackTrace();
}
this.lines.computeIfAbsent(ext, compute).put(name, lines);
this.chars.computeIfAbsent(ext, compute).put(name, chars);
totalLines.increment(ext, lines);
totalChars.increment(ext, chars);
}
}