The task is (supposedly) simple! Take an input (\t
indented with \n
newlines):
one
two
three
four
five
six
seven
eight
nine
Then convert it to the following (using ├
, │
, and └
):
one
├ two
│ ├ three
│ │ └ four
│ │ └ five
│ └ six
└ seven
└ eight
└ nine
Turns out this is not simple and I completely underestimated it…
I did eventually figure this one out and my tool is viewable here.
Some of the main issues I faced were:
- When to render
│
. - Are we at the end of the list and should
└
render?
My approach to this was to split each line out and attach some metadata.
- What line number are you on
- How many tabs are at the start of your line
- What is the content of your line
We then loop through each line and focus on rendering the ├
, and └
.
- Are there any lines with the same tab count?
- If so, does the line after with the same tab count come before any unindented lines?
const blockingLine = linesAfterThisLine.find(lineAfter =>
.lineNumber > line.lineNumber &&
lineAfter.tabCount === line.tabCount
lineAfter
)
// Check if any line after is unindented & before blockingLine
if (
.find(lineAfter =>
linesAfterThisLine.tabCount < blockingLine.tabCount &&
lineAfter.lineNumber < blockingLine.lineNumber
lineAfter
)
) {// Render └
else {
} // Render ├
}
We then loop through this output and focus on rendering the │
. It’s likely possible to avoid the second loop however I had spent too much time trying to “optimise” I just wanted something that worked.
- For each of the tab characters on the line
- Get the last line before itself where it’s indented to the same level as the tab depth we’re checking
- Depending on the content of the line, render a
│
for (let indentLevelToCheck = line.tabCount - 1; indentLevelToCheck > 0; indentLevelToCheck--) {
const relatedPreviousLines = linesBeforeThisLine.filter(previousLine => previousLine.tabCount === indentLevelToCheck)
const lastRelatedLine = relatedPreviousLines[relatedPreviousLines.length - 1]
if (lastRelatedLine) {
if (lastRelatedLine.content.includes("├")) {
// Render │
else {
} = " " + lineContent
lineContent // Render spacing
}
} }
This loop here is the first thing I’d tackle if I went at this project again since it feels wrong. However, it’s much faster than iterating over every line again for some directory structures, since it only loops based on tabCount - 1
. If you knew you were only working with shallow directory depths it would be fine, but for generic use-cases it can use some work.
I recommend giving this a shot yourself in your language of choice, it’s a surprisingly difficult but fun challenge. Again, you can view my solution here!