2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.psi.impl.source.codeStyle;
19 import com.intellij.formatting.FormatTextRanges;
20 import com.intellij.formatting.FormatterEx;
21 import com.intellij.formatting.FormattingModel;
22 import com.intellij.formatting.FormattingModelBuilder;
23 import com.intellij.injected.editor.DocumentWindow;
24 import com.intellij.lang.ASTNode;
25 import com.intellij.lang.LanguageFormatting;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.editor.Document;
28 import com.intellij.openapi.editor.RangeMarker;
29 import com.intellij.openapi.extensions.Extensions;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.TextRange;
32 import com.intellij.psi.PsiDocumentManager;
33 import com.intellij.psi.PsiElement;
34 import com.intellij.psi.PsiFile;
35 import com.intellij.psi.codeStyle.CodeStyleSettings;
36 import com.intellij.psi.formatter.DocumentBasedFormattingModel;
37 import com.intellij.psi.impl.source.PostprocessReformattingAspect;
38 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
39 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
40 import com.intellij.psi.util.PsiTreeUtil;
41 import com.intellij.util.IncorrectOperationException;
43 public class CodeFormatterFacade {
44 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade");
46 private final CodeStyleSettings mySettings;
48 public CodeFormatterFacade(CodeStyleSettings settings) {
49 mySettings = settings;
52 public ASTNode processElement(ASTNode element) {
53 TextRange range = element.getTextRange();
54 return processRange(element, range.getStartOffset(), range.getEndOffset());
57 public ASTNode processRange(final ASTNode element, final int startOffset, final int endOffset) {
58 final PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element);
59 final PsiFile file = psiElement.getContainingFile();
60 final Document document = file.getViewProvider().getDocument();
61 final RangeMarker rangeMarker = document != null && endOffset < document.getTextLength()? document.createRangeMarker(startOffset, endOffset):null;
63 PsiElement elementToFormat = document instanceof DocumentWindow ? InjectedLanguageUtil.getTopLevelFile(file) : psiElement;
64 final PsiFile fileToFormat = elementToFormat.getContainingFile();
66 final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(fileToFormat);
67 if (builder != null) {
68 TextRange range = preprocess(element, startOffset, endOffset);
69 if (document instanceof DocumentWindow) {
70 DocumentWindow documentWindow = (DocumentWindow)document;
71 range = documentWindow.injectedToHost(range);
74 //final SmartPsiElementPointer pointer = SmartPointerManager.getInstance(psiElement.getProject()).createSmartPsiElementPointer(psiElement);
75 final FormattingModel model = builder.createModel(elementToFormat, mySettings);
76 if (file.getTextLength() > 0) {
78 FormatterEx.getInstanceEx().format(model, mySettings,
79 mySettings.getIndentOptions(fileToFormat.getFileType()), new FormatTextRanges(range, true));
81 catch (IncorrectOperationException e) {
86 if (!psiElement.isValid()) {
87 if (rangeMarker != null) {
88 final PsiElement at = file.findElementAt(rangeMarker.getStartOffset());
89 final PsiElement result = PsiTreeUtil.getParentOfType(at, psiElement.getClass(), false);
90 assert result != null;
91 return result.getNode();
97 // return SourceTreeToPsiMap.psiElementToTree(pointer.getElement());
104 public void processText(PsiFile file, final FormatTextRanges ranges, boolean doPostponedFormatting) {
105 Project project = file.getProject();
106 Document document = PsiDocumentManager.getInstance(project).getDocument(file);
107 if (document instanceof DocumentWindow) {
108 file = InjectedLanguageUtil.getTopLevelFile(file);
109 final DocumentWindow documentWindow = (DocumentWindow)document;
110 for (FormatTextRanges.FormatTextRange range : ranges.getRanges()) {
111 range.setTextRange(documentWindow.injectedToHost(range.getTextRange()));
113 document = documentWindow.getDelegate();
117 final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file);
119 if (builder != null) {
120 if (file.getTextLength() > 0) {
122 ranges.preprocess(file.getNode());
123 if (doPostponedFormatting) {
124 RangeMarker[] markers = new RangeMarker[ranges.getRanges().size()];
126 for (FormatTextRanges.FormatTextRange range : ranges.getRanges()) {
127 TextRange textRange = range.getTextRange();
128 int start = textRange.getStartOffset();
129 int end = textRange.getEndOffset();
130 if (start >= 0 && end > start && end <= document.getTextLength()) {
131 markers[i] = document.createRangeMarker(textRange);
132 markers[i].setGreedyToLeft(true);
133 markers[i].setGreedyToRight(true);
137 final PostprocessReformattingAspect component = file.getProject().getComponent(PostprocessReformattingAspect.class);
138 component.doPostponedFormatting(file.getViewProvider());
140 for (FormatTextRanges.FormatTextRange range : ranges.getRanges()) {
141 if (markers[i] != null) {
142 range.setTextRange(new TextRange(markers[i].getStartOffset(), markers[i].getEndOffset()));
147 final FormattingModel originalModel = builder.createModel(file, mySettings);
148 final FormattingModel model = new DocumentBasedFormattingModel(originalModel.getRootBlock(),
150 project, mySettings, file.getFileType(), file);
152 FormatterEx.getInstanceEx().format(model, mySettings, mySettings.getIndentOptions(file.getFileType()), ranges);
154 catch (IncorrectOperationException e) {
161 private static TextRange preprocess(final ASTNode node, final int startOffset, final int endOffset) {
162 TextRange result = new TextRange(startOffset, endOffset);
163 for(PreFormatProcessor processor: Extensions.getExtensions(PreFormatProcessor.EP_NAME)) {
164 result = processor.process(node, result);