コード例 #1
0
 @Override
 @Deprecated
 @Nullable
 public TextRange intersectWithEditable(@NotNull TextRange rangeToEdit) {
   int startOffset = -1;
   int endOffset = -1;
   synchronized (myLock) {
     int offset = 0;
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostRange = shred.getHostRangeMarker();
       if (hostRange == null) continue;
       offset += shred.getPrefix().length();
       int length = hostRange.getEndOffset() - hostRange.getStartOffset();
       TextRange intersection =
           new ProperTextRange(offset, offset + length).intersection(rangeToEdit);
       if (intersection != null) {
         if (startOffset == -1) {
           startOffset = intersection.getStartOffset();
         }
         endOffset = intersection.getEndOffset();
       }
       offset += length;
       offset += shred.getSuffix().length();
     }
   }
   if (startOffset == -1) return null;
   return new ProperTextRange(startOffset, endOffset);
 }
コード例 #2
0
  @Nullable("null means we were unable to calculate")
  LogicalPosition hostToInjectedInVirtualSpace(@NotNull LogicalPosition hPos) {
    // beware the virtual space
    int hLineStartOffset =
        hPos.line >= myDelegate.getLineCount()
            ? myDelegate.getTextLength()
            : myDelegate.getLineStartOffset(hPos.line);
    int iLineStartOffset = hostToInjected(hLineStartOffset);
    int iLine = getLineNumber(iLineStartOffset);

    synchronized (myLock) {
      for (int i = myShreds.size() - 1; i >= 0; i--) {
        PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
        if (!shred.isValid()) continue;
        Segment hostRangeMarker = shred.getHostRangeMarker();
        if (hostRangeMarker == null) continue;
        int hShredEndOffset = hostRangeMarker.getEndOffset();
        int hShredStartOffset = hostRangeMarker.getStartOffset();

        int hShredStartLine = myDelegate.getLineNumber(hShredStartOffset);
        int hShredEndLine = myDelegate.getLineNumber(hShredEndOffset);

        if (hShredStartLine <= hPos.line && hPos.line <= hShredEndLine) {
          int hColumnOfShredEnd = hShredEndOffset - hLineStartOffset;
          int iColumnOfShredEnd = hostToInjected(hShredEndOffset) - iLineStartOffset;
          int iColumn = iColumnOfShredEnd + hPos.column - hColumnOfShredEnd;
          return new LogicalPosition(iLine, iColumn);
        }
      }
    }

    return null;
  }
コード例 #3
0
  @Override
  public int getLineStartOffset(int line) {
    LOG.assertTrue(line >= 0, line);
    if (line == 0) return 0;
    String hostText = myDelegate.getText();

    int[] pos = new int[2]; // pos[0] = curLine; pos[1] == offset;
    synchronized (myLock) {
      for (PsiLanguageInjectionHost.Shred shred : myShreds) {
        Segment hostRange = shred.getHostRangeMarker();
        if (hostRange == null) continue;

        int found = countNewLinesIn(shred.getPrefix(), pos, line);
        if (found != -1) return found;

        CharSequence text =
            hostText.subSequence(hostRange.getStartOffset(), hostRange.getEndOffset());
        found = countNewLinesIn(text, pos, line);
        if (found != -1) return found;

        found = countNewLinesIn(shred.getSuffix(), pos, line);
        if (found != -1) return found;
      }
    }

    return pos[1];
  }
コード例 #4
0
 private void initGuardedBlocks(Place shreds) {
   int origOffset = -1;
   int curOffset = 0;
   for (PsiLanguageInjectionHost.Shred shred : shreds) {
     Segment hostRangeMarker = shred.getHostRangeMarker();
     int start = shred.getRange().getStartOffset() + shred.getPrefix().length();
     int end = shred.getRange().getEndOffset() - shred.getSuffix().length();
     if (curOffset < start) {
       RangeMarker guard = myNewDocument.createGuardedBlock(curOffset, start);
       if (curOffset == 0 && shred == shreds.get(0)) guard.setGreedyToLeft(true);
       String padding =
           origOffset < 0
               ? ""
               : myOrigDocument.getText().substring(origOffset, hostRangeMarker.getStartOffset());
       guard.putUserData(REPLACEMENT_KEY, fixQuotes(padding));
     }
     curOffset = end;
     origOffset = hostRangeMarker.getEndOffset();
   }
   if (curOffset < myNewDocument.getTextLength()) {
     RangeMarker guard =
         myNewDocument.createGuardedBlock(curOffset, myNewDocument.getTextLength());
     guard.setGreedyToRight(true);
     guard.putUserData(REPLACEMENT_KEY, "");
   }
 }
コード例 #5
0
  @Override
  public boolean areRangesEqual(@NotNull DocumentWindow otherd) {
    DocumentWindowImpl window = (DocumentWindowImpl) otherd;
    Place shreds = getShreds();
    Place otherShreds = window.getShreds();
    if (shreds.size() != otherShreds.size()) return false;
    for (int i = 0; i < shreds.size(); i++) {
      PsiLanguageInjectionHost.Shred shred = shreds.get(i);
      PsiLanguageInjectionHost.Shred otherShred = otherShreds.get(i);
      if (!shred.getPrefix().equals(otherShred.getPrefix())) return false;
      if (!shred.getSuffix().equals(otherShred.getSuffix())) return false;

      Segment hostRange = shred.getHostRangeMarker();
      Segment other = otherShred.getHostRangeMarker();
      if (hostRange == null
          || other == null
          || hostRange.getStartOffset() != other.getStartOffset()) return false;
      if (hostRange.getEndOffset() != other.getEndOffset()) return false;
    }
    return true;
  }
コード例 #6
0
 private String getRangeText(@NotNull String hostText, int hostNum) {
   synchronized (myLock) {
     PsiLanguageInjectionHost.Shred shred = myShreds.get(hostNum);
     Segment hostRangeMarker = shred.getHostRangeMarker();
     return shred.getPrefix()
         + (hostRangeMarker == null
             ? ""
             : hostText.substring(
                 hostRangeMarker.getStartOffset(), hostRangeMarker.getEndOffset()))
         + shred.getSuffix();
   }
 }
コード例 #7
0
 @Override
 public TextRange getHostRange(int hostOffset) {
   synchronized (myLock) {
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment currentRange = shred.getHostRangeMarker();
       if (currentRange == null) continue;
       TextRange textRange = ProperTextRange.create(currentRange);
       if (textRange.grown(1).contains(hostOffset)) return textRange;
     }
   }
   return null;
 }
コード例 #8
0
 @Override
 public boolean containsRange(int start, int end) {
   synchronized (myLock) {
     ProperTextRange query = new ProperTextRange(start, end);
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostRange = shred.getHostRangeMarker();
       if (hostRange == null) continue;
       TextRange textRange = ProperTextRange.create(hostRange);
       if (textRange.contains(query)) return true;
     }
     return false;
   }
 }
コード例 #9
0
 @Override
 @NotNull
 public Segment[] getHostRanges() {
   synchronized (myLock) {
     List<Segment> markers = new ArrayList<Segment>(myShreds.size());
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostMarker = shred.getHostRangeMarker();
       if (hostMarker != null) {
         markers.add(hostMarker);
       }
     }
     return markers.isEmpty() ? Segment.EMPTY_ARRAY : markers.toArray(new Segment[markers.size()]);
   }
 }
コード例 #10
0
 @Override
 public int getTextLength() {
   int length = 0;
   synchronized (myLock) {
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostRange = shred.getHostRangeMarker();
       if (hostRange == null) continue;
       length += shred.getPrefix().length();
       length += hostRange.getEndOffset() - hostRange.getStartOffset();
       length += shred.getSuffix().length();
     }
   }
   return length;
 }
コード例 #11
0
  private void doReplaceString(int startOffset, int endOffset, CharSequence s) {
    assert intersectWithEditable(new TextRange(startOffset, startOffset)) != null;
    assert intersectWithEditable(new TextRange(endOffset, endOffset)) != null;

    List<Pair<TextRange, CharSequence>> hostRangesToModify;
    synchronized (myLock) {
      hostRangesToModify = new ArrayList<Pair<TextRange, CharSequence>>(myShreds.size());

      int offset = startOffset;
      int curRangeStart = 0;
      for (int i = 0; i < myShreds.size(); i++) {
        PsiLanguageInjectionHost.Shred shred = myShreds.get(i);
        curRangeStart += shred.getPrefix().length();
        if (offset < curRangeStart) offset = curRangeStart;
        Segment hostRange = shred.getHostRangeMarker();
        if (hostRange == null) continue;
        int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset();
        TextRange range = TextRange.from(curRangeStart, hostRangeLength);
        if (range.contains(offset)
            || range.getEndOffset() == offset /* in case of inserting at the end*/) {
          TextRange rangeToModify =
              new TextRange(offset, Math.min(range.getEndOffset(), endOffset));
          TextRange hostRangeToModify =
              rangeToModify.shiftRight(hostRange.getStartOffset() - curRangeStart);
          CharSequence toReplace =
              i == myShreds.size() - 1
                      || range.getEndOffset() + shred.getSuffix().length() >= endOffset
                  ? s
                  : s.subSequence(0, Math.min(hostRangeToModify.getLength(), s.length()));
          s = toReplace == s ? "" : s.subSequence(toReplace.length(), s.length());
          hostRangesToModify.add(Pair.create(hostRangeToModify, toReplace));
          offset = rangeToModify.getEndOffset();
        }
        curRangeStart += hostRangeLength;
        curRangeStart += shred.getSuffix().length();
        if (curRangeStart > endOffset) break;
      }
    }

    int delta = 0;
    for (Pair<TextRange, CharSequence> pair : hostRangesToModify) {
      TextRange hostRange = pair.getFirst();
      CharSequence replace = pair.getSecond();

      myDelegate.replaceString(
          hostRange.getStartOffset() + delta, hostRange.getEndOffset() + delta, replace);
      delta -= hostRange.getLength() - replace.length();
    }
  }
コード例 #12
0
 @NotNull
 private String calcText() {
   StringBuilder text = new StringBuilder();
   CharSequence hostText = myDelegate.getCharsSequence();
   synchronized (myLock) {
     for (PsiLanguageInjectionHost.Shred shred : myShreds) {
       Segment hostRange = shred.getHostRangeMarker();
       if (hostRange != null) {
         text.append(shred.getPrefix());
         text.append(hostText, hostRange.getStartOffset(), hostRange.getEndOffset());
         text.append(shred.getSuffix());
       }
     }
   }
   return text.toString();
 }
コード例 #13
0
  @NotNull
  @Override
  public List<TextRange> getNonEditableFragments(@NotNull DocumentWindow window) {
    List<TextRange> result = ContainerUtil.newArrayList();
    int offset = 0;
    for (PsiLanguageInjectionHost.Shred shred : ((DocumentWindowImpl) window).getShreds()) {
      Segment hostRange = shred.getHostRangeMarker();
      if (hostRange == null) continue;

      offset = appendRange(result, offset, shred.getPrefix().length());
      offset += hostRange.getEndOffset() - hostRange.getStartOffset();
      offset = appendRange(result, offset, shred.getSuffix().length());
    }

    return result;
  }
コード例 #14
0
  @Override
  public int getLineNumber(int offset) {
    int lineNumber = 0;
    String hostText = myDelegate.getText();
    synchronized (myLock) {
      for (PsiLanguageInjectionHost.Shred shred : myShreds) {
        String prefix = shred.getPrefix();
        String suffix = shred.getSuffix();
        lineNumber +=
            StringUtil.getLineBreakCount(prefix.substring(0, Math.min(offset, prefix.length())));
        if (offset < prefix.length()) {
          return lineNumber;
        }
        offset -= prefix.length();

        Segment currentRange = shred.getHostRangeMarker();
        if (currentRange == null) continue;
        int rangeLength = currentRange.getEndOffset() - currentRange.getStartOffset();
        CharSequence rangeText =
            hostText.subSequence(currentRange.getStartOffset(), currentRange.getEndOffset());

        lineNumber +=
            StringUtil.getLineBreakCount(rangeText.subSequence(0, Math.min(offset, rangeLength)));
        if (offset < rangeLength) {
          return lineNumber;
        }
        offset -= rangeLength;

        lineNumber +=
            StringUtil.getLineBreakCount(suffix.substring(0, Math.min(offset, suffix.length())));
        if (offset < suffix.length()) {
          return lineNumber;
        }

        offset -= suffix.length();
      }
    }
    lineNumber = getLineCount() - 1;
    return lineNumber < 0 ? 0 : lineNumber;
  }
コード例 #15
0
  @Override
  public void deleteString(final int startOffset, final int endOffset) {
    assert intersectWithEditable(new TextRange(startOffset, startOffset)) != null;
    assert intersectWithEditable(new TextRange(endOffset, endOffset)) != null;

    List<TextRange> hostRangesToDelete;
    synchronized (myLock) {
      hostRangesToDelete = new ArrayList<TextRange>(myShreds.size());

      int offset = startOffset;
      int curRangeStart = 0;
      for (PsiLanguageInjectionHost.Shred shred : myShreds) {
        curRangeStart += shred.getPrefix().length();
        if (offset < curRangeStart) offset = curRangeStart;
        if (offset >= endOffset) break;
        Segment hostRange = shred.getHostRangeMarker();
        if (hostRange == null) continue;
        int hostRangeLength = hostRange.getEndOffset() - hostRange.getStartOffset();
        TextRange range = TextRange.from(curRangeStart, hostRangeLength);
        if (range.contains(offset)) {
          TextRange rangeToDelete =
              new TextRange(offset, Math.min(range.getEndOffset(), endOffset));
          hostRangesToDelete.add(
              rangeToDelete.shiftRight(hostRange.getStartOffset() - curRangeStart));
          offset = rangeToDelete.getEndOffset();
        }
        curRangeStart += hostRangeLength;
        curRangeStart += shred.getSuffix().length();
      }
    }

    int delta = 0;
    for (TextRange hostRangeToDelete : hostRangesToDelete) {
      myDelegate.deleteString(
          hostRangeToDelete.getStartOffset() + delta, hostRangeToDelete.getEndOffset() + delta);
      delta -= hostRangeToDelete.getLength();
    }
  }
コード例 #16
0
  QuickEditHandler(
      Project project,
      @NotNull PsiFile injectedFile,
      final PsiFile origFile,
      Editor editor,
      QuickEditAction action) {
    myProject = project;
    myEditor = editor;
    myAction = action;
    myOrigDocument = editor.getDocument();
    Place shreds = InjectedLanguageUtil.getShreds(injectedFile);
    FileType fileType = injectedFile.getFileType();
    Language language = injectedFile.getLanguage();
    PsiLanguageInjectionHost.Shred firstShred = ContainerUtil.getFirstItem(shreds);

    PsiFileFactory factory = PsiFileFactory.getInstance(project);
    String text = InjectedLanguageManager.getInstance(project).getUnescapedText(injectedFile);
    String newFileName =
        StringUtil.notNullize(language.getDisplayName(), "Injected")
            + " Fragment "
            + "("
            + origFile.getName()
            + ":"
            + firstShred.getHost().getTextRange().getStartOffset()
            + ")"
            + "."
            + fileType.getDefaultExtension();

    // preserve \r\n as it is done in MultiHostRegistrarImpl
    myNewFile = factory.createFileFromText(newFileName, language, text, true, false);
    myNewVirtualFile = ObjectUtils.assertNotNull((LightVirtualFile) myNewFile.getVirtualFile());
    myNewVirtualFile.setOriginalFile(origFile.getVirtualFile());

    assert myNewFile != null : "PSI file is null";
    assert myNewFile.getTextLength() == myNewVirtualFile.getContent().length()
        : "PSI / Virtual file text mismatch";

    myNewVirtualFile.setOriginalFile(origFile.getVirtualFile());
    // suppress possible errors as in injected mode
    myNewFile.putUserData(
        InjectedLanguageUtil.FRANKENSTEIN_INJECTION,
        injectedFile.getUserData(InjectedLanguageUtil.FRANKENSTEIN_INJECTION));
    myNewFile.putUserData(FileContextUtil.INJECTED_IN_ELEMENT, shreds.getHostPointer());
    myNewDocument = PsiDocumentManager.getInstance(project).getDocument(myNewFile);
    assert myNewDocument != null;
    EditorActionManager.getInstance()
        .setReadonlyFragmentModificationHandler(myNewDocument, new MyQuietHandler());
    myOrigCreationStamp =
        myOrigDocument.getModificationStamp(); // store creation stamp for UNDO tracking
    myOrigDocument.addDocumentListener(this, this);
    myNewDocument.addDocumentListener(this, this);
    EditorFactory editorFactory = ObjectUtils.assertNotNull(EditorFactory.getInstance());
    // not FileEditorManager listener because of RegExp checker and alike
    editorFactory.addEditorFactoryListener(
        new EditorFactoryAdapter() {
          int useCount;

          @Override
          public void editorCreated(@NotNull EditorFactoryEvent event) {
            if (event.getEditor().getDocument() != myNewDocument) return;
            useCount++;
          }

          @Override
          public void editorReleased(@NotNull EditorFactoryEvent event) {
            if (event.getEditor().getDocument() != myNewDocument) return;
            if (--useCount > 0) return;
            if (Boolean.TRUE.equals(
                myNewVirtualFile.getUserData(FileEditorManagerImpl.CLOSING_TO_REOPEN))) return;

            Disposer.dispose(QuickEditHandler.this);
          }
        },
        this);

    if ("JAVA".equals(firstShred.getHost().getLanguage().getID())) {
      PsiLanguageInjectionHost.Shred lastShred = ContainerUtil.getLastItem(shreds);
      myAltFullRange =
          myOrigDocument.createRangeMarker(
              firstShred.getHostRangeMarker().getStartOffset(),
              lastShred.getHostRangeMarker().getEndOffset());
      myAltFullRange.setGreedyToLeft(true);
      myAltFullRange.setGreedyToRight(true);

      initGuardedBlocks(shreds);
      myInjectedFile = null;
    } else {
      initMarkers(shreds);
      myAltFullRange = null;
      myInjectedFile = injectedFile;
    }
  }