/* * Copyright 2013-2017 consulo.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.codeInsight.completion; import com.intellij.injected.editor.DocumentWindow; import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import org.jetbrains.annotations.NotNull; import java.util.function.Function; /** * @author VISTALL * @since 02-May-17 * <p> * from kotlin platform\lang-impl\src\com\intellij\codeInsight\completion\OffsetsInFile.kt */ public class OffsetsInFile { private PsiFile file; private OffsetMap offsets; public OffsetsInFile(PsiFile file) { this(file, new OffsetMap(file.getViewProvider().getDocument())); } public OffsetsInFile(PsiFile file, OffsetMap offsets) { this.file = file; this.offsets = offsets; } public OffsetMap getOffsets() { return offsets; } public PsiFile getFile() { return file; } @NotNull public OffsetsInFile toFileCopy(PsiFile copyFile) { CompletionAssertions.assertCorrectOriginalFile("Given ", file, copyFile); assert copyFile.getViewProvider().getDocument().getTextLength() == file.getViewProvider().getDocument().getTextLength(); return mapOffsets(copyFile, it -> it); } @NotNull public OffsetsInFile toInjectedIfAny(int offset) { PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(file, offset); if (injected == null) { return this; } DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injected); assert documentWindow != null; return mapOffsets(injected, documentWindow::hostToInjected); } @NotNull public OffsetsInFile toTopLevelFile() { InjectedLanguageManager manager = InjectedLanguageManager.getInstance(file.getProject()); PsiFile hostFile = manager.getTopLevelFile(file); if (hostFile == file) { return this; } else { return mapOffsets(hostFile, it -> manager.injectedToHost(file, it)); } } @NotNull public OffsetsInFile copyWithReplacement(int startOffset, int endOffset, String replacement) { PsiFile fileCopy = (PsiFile)file.copy(); Document document = fileCopy.getViewProvider().getDocument(); document.setText(file.getViewProvider().getDocument().getImmutableCharSequence()); // original file might be uncommitted OffsetsInFile result = toFileCopy(fileCopy); document.replaceString(startOffset, endOffset, replacement); PsiDocumentManager.getInstance(file.getProject()).commitDocument(document); return result; } @NotNull private OffsetsInFile mapOffsets(PsiFile newFile, Function<Integer, Integer> offsetFun) { OffsetMap map = new OffsetMap(newFile.getViewProvider().getDocument()); for (OffsetKey key : offsets.getAllOffsets()) { map.addOffset(key, offsetFun.apply(offsets.getOffset(key))); } return new OffsetsInFile(newFile, map); } }