TemplateImpl (@NotNull CustomTemplateCallback callback, @Nullable ZenCodingGenerator generator, @NotNull Collection<ZenCodingFilter> filters, boolean insertSurroundedText, int segmentsLimit) { myContainsSurroundedTextMarker = !(insertSurroundedText && myInsertSurroundedTextAtTheEnd); GenerationNode generationNode = this; boolean shouldNotReformatTemplate = false; boolean oneLineTemplateExpanding = false; for (ZenCodingFilter filter : filters) { generationNode = filter.filterNode(generationNode); if (filter instanceof SingleLineEmmetFilter) { shouldNotReformatTemplate = true; oneLineTemplateExpanding = true; } } CodeStyleSettings settings = CodeStyle.getSettings(callback.getFile()); String indentStr; if (callback.isInInjectedFragment()) { Editor editor = callback.getEditor(); Document document = editor.getDocument(); if (document instanceof DocumentWindow && ((DocumentWindow)document).isOneLine()) { /* * If document is one-line that in the moment of inserting text, * new line chars will be filtered (see DocumentWindowImpl#insertString). * So in this case we should filter text by SingleLineAvoid in order to avoid * inconsistency of template segments. */ oneLineTemplateExpanding = true; filters.add(new SingleLineEmmetFilter()); } indentStr = ""; } else if (settings.useTabCharacter(callback.getFileType())) { indentStr = "\t"; } else { int tabSize = settings.getTabSize(callback.getFileType()); indentStr = StringUtil.repeatSymbol(' ', tabSize); } LiveTemplateBuilder builder = new LiveTemplateBuilder(EmmetOptions.getInstance().isAddEditPointAtTheEndOfTemplate(), segmentsLimit); int end = -1; boolean hasChildren = myChildren.size() > 0; TemplateImpl parentTemplate; Map<String, String> predefinedValues; if (generator instanceof XmlZenCodingGenerator) { TemplateToken xmlTemplateToken = myTemplateToken; parentTemplate = invokeXmlTemplate(xmlTemplateToken, callback, generator, hasChildren); predefinedValues = buildPredefinedValues(xmlTemplateToken.getAttributes(), (XmlZenCodingGenerator)generator, hasChildren); } else { parentTemplate = invokeTemplate(myTemplateToken, hasChildren, callback, generator); predefinedValues = null; } String s = parentTemplate.getString(); for (ZenCodingFilter filter : filters) { s = filter.filterText(s, myTemplateToken); } parentTemplate = parentTemplate.copy(); parentTemplate.setString(s); final String txt = hasChildren || myContainsSurroundedTextMarker ? null : mySurroundedText; parentTemplate = expandTemplate(parentTemplate, predefinedValues, txt, segmentsLimit); int offset = builder.insertTemplate(0, parentTemplate, null); int newOffset = gotoChild(callback.getProject(), builder.getText(), offset, 0, builder.length()); if (offset < builder.length() && newOffset != offset) { end = offset; } offset = newOffset; if (end == -1 && offset < builder.length() && myChildren.size() == 0) { end = offset; } LiveTemplateBuilder.Marker marker = offset < builder.length() ? builder.createMarker(offset) : null; for (int i = 0, myChildrenSize = myChildren.size(); i < myChildrenSize; i++) { GenerationNode child = myChildren.get(i); TemplateImpl childTemplate = child.generate(callback, generator, filters, !myContainsSurroundedTextMarker, segmentsLimit); boolean blockTag = child.isBlockTag(); if (!oneLineTemplateExpanding && blockTag && !isNewLineBefore(builder.getText(), offset)) { builder.insertText(offset, "\n" + indentStr, false); offset += indentStr.length() + 1; } int e = builder.insertTemplate(offset, childTemplate, null); offset = marker != null ? marker.getEndOffset() : builder.length(); if (!oneLineTemplateExpanding && ((blockTag && !isNewLineAfter(builder.getText(), offset)) || myInsertNewLineBetweenNodes)) { builder.insertText(offset, "\n" + indentStr, false); offset += indentStr.length() + 1; } if (end == -1 && e < offset) { end = e; } } if (shouldNotReformatTemplate) { builder.setIsToReformat(false); } return builder.buildTemplate(); }