void (final String whiteSpace, final ASTNode leafElement, final IElementType whiteSpaceToken, final @Nullable TextRange textRange) { final CharTable charTable = SharedImplUtil.findCharTableByTree(leafElement); if (textRange != null && textRange.getStartOffset() > leafElement.getTextRange().getStartOffset() && textRange.getEndOffset() < leafElement.getTextRange().getEndOffset()) { replaceInnerWhiteSpace(whiteSpace, leafElement, textRange); return; } ASTNode treePrev = findPreviousWhiteSpace(leafElement, whiteSpaceToken); if (treePrev == null) { treePrev = getWsCandidate(leafElement); } if (treePrev != null && treePrev.getText().trim().isEmpty() && treePrev.getElementType() != whiteSpaceToken && treePrev.getTextLength() > 0 && !whiteSpace.isEmpty()) { LeafElement whiteSpaceElement = Factory.createSingleLeafElement(treePrev.getElementType(), whiteSpace, charTable, SharedImplUtil.getManagerByTree(leafElement)); ASTNode treeParent = treePrev.getTreeParent(); treeParent.replaceChild(treePrev, whiteSpaceElement); } else { LeafElement whiteSpaceElement = Factory.createSingleLeafElement(whiteSpaceToken, whiteSpace, charTable, SharedImplUtil.getManagerByTree(leafElement)); if (treePrev == null) { if (!whiteSpace.isEmpty()) { addWhiteSpace(leafElement, whiteSpaceElement); } } else { if (!(treePrev.getElementType() == whiteSpaceToken)) { if (!whiteSpace.isEmpty()) { addWhiteSpace(treePrev, whiteSpaceElement); } } else { if (treePrev.getElementType() == whiteSpaceToken) { final CompositeElement treeParent = (CompositeElement)treePrev.getTreeParent(); if (!whiteSpace.isEmpty()) { // LOG.assertTrue(textRange == null || treeParent.getTextRange().equals(textRange)); treeParent.replaceChild(treePrev, whiteSpaceElement); } else { treeParent.removeChild(treePrev); } // There is a possible case that more than one PSI element is matched by the target text range. // That is the case, for example, for Python's multi-line expression. It may looks like below: // import contextlib,\ // math, decimal // Here single range contains two blocks: '\' & '\n '. So, we may want to replace that range to another text, hence, // we replace last element located there with it ('\n ') and want to remove any remaining elements ('\'). ASTNode removeCandidate = findPreviousWhiteSpace(whiteSpaceElement, whiteSpaceToken); while (textRange != null && removeCandidate != null && removeCandidate.getStartOffset() >= textRange.getStartOffset()) { treePrev = findPreviousWhiteSpace(removeCandidate, whiteSpaceToken); removeCandidate.getTreeParent().removeChild(removeCandidate); removeCandidate = treePrev; } //treeParent.subtreeChanged(); } } } } }