Skip to content

Commit 378a113

Browse files
author
Fischstaebchen
committed
Changed as per recommendations by danthe1st.
1 parent f3a9cc8 commit 378a113

File tree

4 files changed

+641
-632
lines changed

4 files changed

+641
-632
lines changed

src/main/java/net/javadiscord/javabot/util/IndentationHelper.java

Lines changed: 177 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -4,176 +4,188 @@
44
* Utility class to help indent strings that contain code.
55
*/
66
public class IndentationHelper {
7-
/**
8-
* Enum which denotes the different types of indentation possible.
9-
* When {@link #NULL} is passed to any method in this class, the output of said method should match the input.
10-
*/
11-
public enum IndentationType {
12-
/**
13-
* A tab character (\t) should be used for indentation.
14-
*/
15-
TABS("\t"),
16-
/**
17-
* Four spaces should be used for indentation.
18-
*/
19-
FOUR_SPACES(" "),
20-
/**
21-
* Two spaces should be used for indentation
22-
*/
23-
TWO_SPACES(" "),
24-
/**
25-
* Doesn't define an indentation type but
26-
* Is used as a substitute to null to indicate that a String given to any method in {@link IndentationHelper} should not be changed.
27-
*/
28-
NULL("");
7+
/**
8+
* Enum which denotes the different types of indentation possible.
9+
* When {@link #NULL} is passed to any method in this class, the output of said method should match the input.
10+
*/
11+
public enum IndentationType {
12+
/**
13+
* A tab character (\t) should be used for indentation.
14+
*/
15+
TABS("\t"),
16+
/**
17+
* Four spaces should be used for indentation.
18+
*/
19+
FOUR_SPACES(" "),
20+
/**
21+
* Two spaces should be used for indentation.
22+
*/
23+
TWO_SPACES(" "),
24+
/**
25+
* Doesn't define an indentation type but
26+
* Is used as a substitute to null to indicate that a String given to any method in {@link IndentationHelper} should not be changed.
27+
*/
28+
NULL("");
2929

30-
/**
31-
* Holds the characters used for indentation of the type.
32-
*/
33-
private final String pattern;
30+
/**
31+
* Holds the characters used for indentation of the type.
32+
*/
33+
private final String pattern;
3434

35-
/**
36-
* Constructs the indentation type
37-
* @param pattern The pattern to be used as indentation
38-
*/
39-
IndentationType(String pattern) {
40-
this.pattern = pattern;
41-
}
35+
/**
36+
* Constructs the indentation type.
37+
*
38+
* @param pattern The pattern to be used as indentation
39+
*/
40+
IndentationType(String pattern) {
41+
this.pattern = pattern;
42+
}
4243

43-
/**
44-
* Get the pattern for a given Indentation type.
45-
* @return the pattern to be used for indenting.
46-
*/
47-
public String getPattern() {
48-
return pattern;
49-
}
44+
/**
45+
* Get the pattern for a given Indentation type.
46+
*
47+
* @return the pattern to be used for indenting.
48+
*/
49+
public String getPattern() {
50+
return pattern;
51+
}
5052

51-
/**
52-
* Returns the number of characters a pattern is using.
53-
* @return the number of characters the pattern of this type consists of.
54-
*/
55-
private int getNumberOfChars() {
56-
return pattern.length();
57-
}
53+
/**
54+
* Returns the number of characters a pattern is using.
55+
*
56+
* @return the number of characters the pattern of this type consists of.
57+
*/
58+
private int getNumberOfChars() {
59+
return pattern.length();
60+
}
61+
}
5862

59-
}
63+
/**
64+
* Private enum to denote the current State of the Indentation Process.
65+
*/
66+
private enum IndentationState {
67+
/**
68+
* Denotes that the Process is currently in a codeblock and should indent the code accordingly.
69+
*/
70+
CODE,
71+
/**
72+
* Denotes that the Process is currently in a String literal.
73+
*/
74+
STRING,
75+
/**
76+
* Denotes that the Indentation Process is currently in a character literal.
77+
*/
78+
CHARACTER,
79+
/**
80+
* Denotes that the Process is currently in a single line comment.
81+
*/
82+
SINGLE_LINE_COMMENT,
83+
/**
84+
* Denotes that the process is inside a multi line comment or a javadoc.
85+
*/
86+
MULTI_LINE_COMMENT
87+
}
6088

61-
/**
62-
* Aims to indent the given String using the pattern provided. Will return the String unchanged if {@link IndentationHelper.IndentationType#NULL} is passed as the IndentationType parameter.
63-
* @param text The text that should be indented.
64-
* @param type The type of indentation to be used.
65-
* @return The indented String with the format specified.
66-
*/
67-
public static String formatIndentation(String text, IndentationType type) {
68-
if(type == IndentationType.NULL) {
69-
return text;
70-
}
71-
int numberOfBrackets = 0;
72-
StringBuilder builder = new StringBuilder((int) (text.length()*1.25f));
73-
boolean startOfLine = true;
74-
boolean inString = false;
75-
boolean inChar = false;
76-
boolean singleLineComment = false;
77-
boolean multiLineComment = false;
78-
for(int i = 0; i< text.length(); i++) {
79-
char current = text.charAt(i);
80-
switch (current) {
81-
case '{' -> {
82-
if(!inString && !singleLineComment && !multiLineComment && !inChar) {
83-
numberOfBrackets++;
84-
}
85-
startOfLine = false;
86-
builder.append(current);
87-
}
88-
case '}' -> {
89-
if(!inString && !singleLineComment && !multiLineComment && !inChar) {
90-
numberOfBrackets--;
91-
}
92-
if(startOfLine && builder.length()-type.getNumberOfChars() > 0 && !multiLineComment) {
93-
startOfLine = false;
94-
builder.replace(builder.length()-type.getNumberOfChars(),builder.length(),"}");
95-
} else {
96-
startOfLine = false;
97-
builder.append(current);
98-
}
99-
}
100-
case '"'-> {
101-
if(builder.length() > 0) {
102-
if (isEscaped(builder,builder.length()) || inChar || singleLineComment ||multiLineComment) {
103-
builder.append(current);
104-
break;
105-
}
106-
}
107-
inString = !inString;
108-
builder.append(current);
109-
}
110-
case '\'' -> {
111-
if(builder.length() > 0) {
112-
if (isEscaped(builder,builder.length()) || inString || singleLineComment ||multiLineComment) {
113-
builder.append(current);
114-
break;
115-
}
116-
}
117-
inChar = !inChar;
118-
builder.append(current);
119-
}
120-
case '/' -> {
121-
builder.append(current);
122-
startOfLine = false;
123-
if(i+1 < text.length() && !inString && !inChar) {
124-
char nextChar = text.charAt(i+1);
125-
if(nextChar == '/'){
126-
singleLineComment = true;
127-
}
128-
if(nextChar == '*') {
129-
multiLineComment = true;
130-
}
131-
}
132-
}
133-
case '\n' -> {
134-
startOfLine = true;
135-
singleLineComment = false;
136-
builder.append("\n").append(type.getPattern().repeat(Math.max(numberOfBrackets,0)));
137-
}
138-
case '*' -> {
139-
builder.append(current);
140-
startOfLine = false;
141-
if(i+1 < text.length() && !inString && !inChar) {
142-
char nextChar = text.charAt(i+1);
143-
if(nextChar == '/'){
144-
multiLineComment = false;
145-
}
146-
}
147-
}
148-
default -> {
149-
if(startOfLine && !Character.isWhitespace(current)) {
150-
builder.append(current);
151-
startOfLine = false;
152-
} else if(!startOfLine) {
153-
builder.append(current);
154-
}
155-
}
156-
}
157-
}
158-
return builder.toString();
159-
}
16089

161-
/**
162-
* Determines if the character in the StringBuilder at the specified position is escaped.
163-
* @param builder the StringBuilder which holds the current String
164-
* @param index The index at which the character to be checked is located.
165-
* @return True, if the escape character is referring to the character at the index, false otherwise.
166-
*/
167-
private static boolean isEscaped(StringBuilder builder,int index) {
168-
int numberOfCharacters = 0;
169-
index--;
170-
if(index >= builder.length()) {
171-
return false;
172-
}
173-
while(index > 0 && builder.charAt(index) == '\\') {
174-
numberOfCharacters++;
175-
index--;
176-
}
177-
return numberOfCharacters % 2 == 1;
178-
}
90+
/**
91+
* Aims to indent the given String using the pattern provided. Will return the String unchanged if {@link IndentationHelper.IndentationType#NULL} is passed as the IndentationType parameter.
92+
*
93+
* @param text The text that should be indented.
94+
* @param type The type of indentation to be used.
95+
* @return The indented String with the format specified.
96+
*/
97+
public static String formatIndentation(String text, IndentationType type) {
98+
if (type == IndentationType.NULL) {
99+
return text;
100+
}
101+
int numberOfBrackets = 0;
102+
StringBuilder builder = new StringBuilder((int) (text.length() * 1.25f));
103+
IndentationState currentState = IndentationState.CODE;
104+
boolean startOfLine = true;
105+
for (int i = 0; i < text.length(); i++) {
106+
char current = text.charAt(i);
107+
builder.append(current);
108+
if (current == '\n') {
109+
builder.append(type.getPattern().repeat(Math.max(numberOfBrackets, 0)));
110+
startOfLine = true;
111+
}
112+
if (startOfLine && current == ' ') {
113+
builder.deleteCharAt(builder.length() - 1);
114+
}
115+
switch (currentState) {
116+
case CODE -> {
117+
switch (current) {
118+
case '{' -> numberOfBrackets++;
119+
case '}' -> {
120+
numberOfBrackets--;
121+
if (startOfLine && builder.length() - type.getNumberOfChars() - 1 >= 0) {
122+
builder.replace(builder.length() - type.getNumberOfChars() - 1, builder.length(), "}");
123+
}
124+
}
125+
case '\'' -> currentState = IndentationState.CHARACTER;
126+
case '\"' -> currentState = IndentationState.STRING;
127+
case '/' -> {
128+
if (i + 1 < text.length()) {
129+
if (text.charAt(i + 1) == '/') {
130+
currentState = IndentationState.SINGLE_LINE_COMMENT;
131+
} else if (text.charAt(i + 1) == '*') {
132+
currentState = IndentationState.MULTI_LINE_COMMENT;
133+
}
134+
}
135+
}
136+
}
137+
}
138+
case STRING -> {
139+
if (current == '\"') {
140+
if (!isEscaped(builder, builder.length() - 1)) {
141+
currentState = IndentationState.CODE;
142+
}
143+
}
144+
}
145+
case CHARACTER -> {
146+
if (current == '\'') {
147+
if (!isEscaped(builder, builder.length() - 1)) {
148+
currentState = IndentationState.CODE;
149+
}
150+
}
151+
}
152+
case SINGLE_LINE_COMMENT -> {
153+
if (current == '\n') {
154+
currentState = IndentationState.CODE;
155+
}
156+
}
157+
case MULTI_LINE_COMMENT -> {
158+
if (current == '*' && i + 1 < text.length()) {
159+
if (text.charAt(i + 1) == '/') {
160+
currentState = IndentationState.CODE;
161+
}
162+
}
163+
}
164+
}
165+
if (!Character.isWhitespace(current) && startOfLine) {
166+
startOfLine = false;
167+
}
168+
}
169+
return builder.toString();
170+
}
171+
172+
/**
173+
* Determines if the character in the StringBuilder at the specified position is escaped.
174+
*
175+
* @param builder the StringBuilder which holds the current String
176+
* @param index The index at which the character to be checked is located.
177+
* @return True, if the escape character is referring to the character at the index, false otherwise.
178+
*/
179+
private static boolean isEscaped(StringBuilder builder, int index) {
180+
int numberOfCharacters = 0;
181+
index--;
182+
if (index >= builder.length()) {
183+
return false;
184+
}
185+
while (index > 0 && builder.charAt(index) == '\\') {
186+
numberOfCharacters++;
187+
index--;
188+
}
189+
return numberOfCharacters % 2 == 1;
190+
}
179191
}

0 commit comments

Comments
 (0)