Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrap closers around comment lines #58

Merged
merged 13 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 109 additions & 34 deletions lib/standard-clojure-style.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@
return arr.join(s)
}

// function rtrim (s) {
// return s.trimEnd()
// }
function rtrim (s) {
return s.trimEnd()
}

function strTrim (s) {
return s.trim()
Expand Down Expand Up @@ -886,10 +886,43 @@
return null
}

// searches forward in the nodes array for whitespace or closing nodes
// stops when it finds the first non-whitespace or non-closer
// returns an array of the closer + whitespace nodes (possibly an empty array)
function findCloserNodes (nodes, idx) {
// Are all of the nodes on the next line already slurped up or whitespace nodes?
function areForwardNodesAlreadySlurped (nodes, idx) {
const nodesSize = arraySize(nodes)
let result = true
let keepSearching = true

while (keepSearching) {
const node = nodes[idx]

if (!node) {
keepSearching = false
} else if (isNewlineNode(node)) {
keepSearching = false
} else if (!isString(node.text)) {
keepSearching = true
} else if (node._wasSlurpedUp || isWhitespaceNode(node)) {
keepSearching = true
} else {
keepSearching = false
result = false
}

idx = inc(idx)

// stop searching if we are at the end of the nodes list
if (idx >= nodesSize) {
keepSearching = false
}
}

return result
}

// Searches forward in the nodes array for closing paren nodes that could potentially
// be slurped up to the current line. Includes whitespace and comment nodes as well.
// returns an array of the nodes (possibly empty)
function findForwardClosingParens (nodes, idx) {
const closers = []
const nodesSize = arraySize(nodes)

Expand All @@ -899,17 +932,17 @@

if (!node) {
keepSearching = false
} else if (isWhitespaceNode(node) || isParenCloser(node)) {
} else if (isWhitespaceNode(node) || isParenCloser(node) || isCommentNode(node)) {
closers.push(node)
keepSearching = true // NOTE: this is a no-op, but I like being explicit
keepSearching = true
} else {
keepSearching = false
}

idx = inc(idx)

// stop searching if we are at the end of the nodes list
if (idx > nodesSize) {
if (idx >= nodesSize) {
keepSearching = false
}
}
Expand Down Expand Up @@ -2838,35 +2871,61 @@
skipPrintingThisNode = true
}

if (currentNodeIsNewline) {
// look forward to see if we can close parens on this line
// FIXME: we can skip this search ahead if the parenNestingDepth is 0
const parenTrailClosers = findCloserNodes(nodesArr, inc(idx))

// print the closers at the end of this line if applicable
let closersIdx = 0
const numClosers = arraySize(parenTrailClosers)
while (closersIdx < numClosers) {
const closerNode = parenTrailClosers[closersIdx]
// apply the closer nodes to the output string
if (isParenCloser(closerNode)) {
lineTxt = strConcat(lineTxt, closerNode.text)
parenNestingDepth = dec(parenNestingDepth)
stackPop(parenStack)
// If we are inside of a parenStack and hit a newline:
// Look forward to see if we can close the current parenTrail (ie: slurp the nodes onto this line)
const parenStackSize = arraySize(parenStack)
if (parenStackSize > 0) {
const isCommentFollowedByNewline = isCommentNode(node) && nextTextNode && isNewlineNode(nextTextNode)
const isNewline = isNewlineNode(node)
if (isCommentFollowedByNewline || isNewline) {
// look forward and grab any nodes that may be slurped up
const parenTrailClosers = findForwardClosingParens(nodesArr, inc(idx))

// If we have printed a whitespace node just before this, we may need to remove it and then re-print
const lastNodeWePrinted = arrayLast(nodesWeHavePrintedOnThisLine)
let lineTxtHasBeenRightTrimmed = false
if (lastNodeWePrinted && isWhitespaceNode(lastNodeWePrinted)) {
lineTxt = rtrim(lineTxt)
lineTxtHasBeenRightTrimmed = true
}
closersIdx = inc(closersIdx)

// increase the outer loop index as well (ie: skipping forward nodes)
idx = inc(idx)
let parenTrailCloserIdx = 0
const numParenTrailClosers = arraySize(parenTrailClosers)

while (parenTrailCloserIdx < numParenTrailClosers) {
const parenTrailCloserNode = parenTrailClosers[parenTrailCloserIdx]

if (isParenCloser(parenTrailCloserNode)) {
// NOTE: we are adjusting the current line here, but we do not update the nodesWeHavePrintedOnThisLine
// because we cannot have a Rule 3 alignment to a closer node
lineTxt = strConcat(lineTxt, parenTrailCloserNode.text)

parenTrailCloserNode.text = ''
parenTrailCloserNode._wasSlurpedUp = true

parenNestingDepth = dec(parenNestingDepth)
stackPop(parenStack)
}

parenTrailCloserIdx = inc(parenTrailCloserIdx)
}

// re-print the whitespace node if necessary
if (lineTxtHasBeenRightTrimmed) {
lineTxt = strConcat(lineTxt, lastNodeWePrinted.text)
}
}
}

if (currentNodeIsNewline) {
// record the original column indexes for the next line
nodesArr = recordOriginalColIndexes(nodesArr, idx)

// FIXME: I am not sure this is working correctly after we print the closers above?
// need to confirm
const numSpacesOnNextLine = numSpacesAfterNewline(node)

// Have we already slurped up everything on the next line?
const allNextLineNodesWereSlurpedUp = areForwardNodesAlreadySlurped(nodesArr, inc(idx))

const nextLineContainsOnlyOneComment = isNextLineACommentLine(nodesArr, inc(idx))
let nextLineCommentColIdx = -1
if (nextLineContainsOnlyOneComment) {
Expand Down Expand Up @@ -2975,11 +3034,20 @@
numSpaces = numSpacesForIndentation(topOfTheParenStack)
}

const indentationStr = repeatString(' ', numSpaces)
let indentationStr = repeatString(' ', numSpaces)

// If we have slurped up all of the nodes on this line, we can remove it.
if (allNextLineNodesWereSlurpedUp) {
newlineStr = ''
indentationStr = ''
}

// add this line to the outTxt and reset lineTxt
outTxt = strConcat(outTxt, lineTxt)
if (strTrim(lineTxt) !== '') {
outTxt = strConcat(outTxt, lineTxt)
}
outTxt = strConcat(outTxt, newlineStr)

lineTxt = indentationStr
nodesWeHavePrintedOnThisLine = []

Expand All @@ -2992,7 +3060,12 @@
lineIdx = inc(lineIdx)
}
}
} else if (nodeContainsText(node)) {

// we have taken care of printing this node, skip the "normal" printing step
skipPrintingThisNode = true
}

if (nodeContainsText(node) && !skipPrintingThisNode) {
const isTokenFollowedByOpener = isTokenNode(node) && nextTextNode && isParenOpener(nextTextNode)
const isParenCloserFollowedByText = isParenCloser(node) && nextTextNode && (isTokenNode(nextTextNode) || isParenOpener(nextTextNode))
const addSpaceAfterThisNode = isTokenFollowedByOpener || isParenCloserFollowedByText
Expand All @@ -3007,6 +3080,8 @@
skipPrintingThisNode = true
} else if (currentNodeIsWhitespace && lineIdx === lineIdxOfClosingNsForm) {
skipPrintingThisNode = true
} else if (node._skipPrintingThisNode === true) {
skipPrintingThisNode = true
}

// add the text of this node to the current line
Expand Down Expand Up @@ -3034,7 +3109,7 @@
}

idx = inc(idx)
}
} // end looping through the nodes

// add the last line to outTxt if necesary
if (lineTxt !== '') {
Expand Down
2 changes: 0 additions & 2 deletions test/format.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ test('All test_format/ cases should have unique names', () => {
const onlyRunSpecificTests = false
const specificTests = new Set()
// specificTests.add('your test case here')
// specificTests.add('nested rule 3 with comments - example 2')
specificTests.add('whitespace before comment lines 2')

const ignoreSomeTests = true
const ignoreTests = new Set()
Expand Down
Loading