@Override
 public boolean isFileModified(@NotNull VirtualFile file) {
   final Document doc = getCachedDocument(file);
   return doc != null
       && isDocumentUnsaved(doc)
       && doc.getModificationStamp() != file.getModificationStamp();
 }
  @Override
  @Nullable
  public Document getDocument(@NotNull final VirtualFile file) {
    DocumentEx document = (DocumentEx) getCachedDocument(file);
    if (document == null) {
      if (file.isDirectory()
          || isBinaryWithoutDecompiler(file)
          || SingleRootFileViewProvider.isTooLargeForContentLoading(file)) {
        return null;
      }
      final CharSequence text = LoadTextUtil.loadText(file);

      synchronized (lock) {
        document = (DocumentEx) getCachedDocument(file);
        if (document != null) return document; // Double checking

        document = (DocumentEx) createDocument(text);
        document.setModificationStamp(file.getModificationStamp());
        final FileType fileType = file.getFileType();
        document.setReadOnly(!file.isWritable() || fileType.isBinary());
        file.putUserData(DOCUMENT_KEY, new WeakReference<Document>(document));
        document.putUserData(FILE_KEY, file);

        if (!(file instanceof LightVirtualFile
            || file.getFileSystem() instanceof DummyFileSystem)) {
          document.addDocumentListener(
              new DocumentAdapter() {
                @Override
                public void documentChanged(DocumentEvent e) {
                  final Document document = e.getDocument();
                  myUnsavedDocuments.add(document);
                  final Runnable currentCommand =
                      CommandProcessor.getInstance().getCurrentCommand();
                  Project project =
                      currentCommand == null
                          ? null
                          : CommandProcessor.getInstance().getCurrentCommandProject();
                  String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
                  document.putUserData(LINE_SEPARATOR_KEY, lineSeparator);

                  // avoid documents piling up during batch processing
                  if (areTooManyDocumentsInTheQueue(myUnsavedDocuments)) {
                    saveAllDocumentsLater();
                  }
                }
              });
        }
      }

      myMultiCaster.fileContentLoaded(file, document);
    }

    return document;
  }
  private void doSaveDocumentInWriteAction(@NotNull Document document, @NotNull VirtualFile file)
      throws IOException {
    if (!file.isValid()) {
      removeFromUnsaved(document);
      return;
    }

    if (!file.equals(getFile(document))) {
      registerDocument(document, file);
    }

    if (!isSaveNeeded(document, file)) {
      if (document instanceof DocumentEx) {
        ((DocumentEx) document).setModificationStamp(file.getModificationStamp());
      }
      removeFromUnsaved(document);
      updateModifiedProperty(file);
      return;
    }

    myMultiCaster.beforeDocumentSaving(document);

    LOG.assertTrue(file.isValid());

    String text = document.getText();
    String lineSeparator = getLineSeparator(document, file);
    if (!lineSeparator.equals("\n")) {
      text = StringUtil.convertLineSeparators(text, lineSeparator);
    }

    Project project = ProjectLocator.getInstance().guessProjectForFile(file);
    LoadTextUtil.write(project, file, this, text, document.getModificationStamp());

    myUnsavedDocuments.remove(document);
    LOG.assertTrue(!myUnsavedDocuments.contains(document));
    myTrailingSpacesStripper.clearLineModificationFlags(document);
  }