Package org.intellij.grammar.livePreview

Source Code of org.intellij.grammar.livePreview.LivePreviewHelper

/*
* Copyright 2011-2014 Gregory Shrago
*
* 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 org.intellij.grammar.livePreview;

import com.intellij.lang.*;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.TokenType;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.file.impl.FileManager;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.FileContentUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PairProcessor;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.intellij.grammar.BnfFileType;
import org.intellij.grammar.parser.GeneratedParserUtilBase;
import org.intellij.grammar.psi.BnfExpression;
import org.intellij.grammar.psi.BnfFile;
import org.intellij.grammar.psi.BnfRule;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.Collections;
import java.util.Map;

/**
* @author gregsh
*/
public class LivePreviewHelper {

  public static void showFor(BnfFile bnfFile) {
    PsiFile psiFile = parseFile(bnfFile, "");
    VirtualFile virtualFile = psiFile == null? null : psiFile.getVirtualFile();
    if (virtualFile == null) return;
    Project project = bnfFile.getProject();
    installUpdateListener(project);

    FileEditorManagerEx fileEditorManager = FileEditorManagerEx.getInstanceEx(project);
    EditorWindow curWindow = fileEditorManager.getCurrentWindow();
    curWindow.split(SwingConstants.HORIZONTAL, false, virtualFile, true);
    fileEditorManager.openFile(virtualFile, true);
  }

  @Nullable
  public static PsiFile parseFile(BnfFile bnfFile, String text) {
    Language language = getLanguageFor(bnfFile);
    if (language == null) return null;

    String fileName = bnfFile.getName() + ".preview";
    LightVirtualFile virtualFile = new LightVirtualFile(fileName, language, text);
    final Project project = bnfFile.getProject();
    return PsiManager.getInstance(project).findFile(virtualFile);
  }

  @Nullable
  public static Language getLanguageFor(BnfFile psiFile) {
    VirtualFile vFile = psiFile.getVirtualFile();
    if (vFile == null) return null;
    for (Language language : Language.getRegisteredLanguages()) {
      if (language instanceof LivePreviewLanguage &&
          vFile == ((LivePreviewLanguage)language).getGrammarFile()) {
        return language;
      }
    }
    // create new one
    LivePreviewLanguage language = LivePreviewLanguage.newInstance(psiFile);
    registerLanguageExtensions(language);
    return language;
  }

  public static void registerLanguageExtensions(LivePreviewLanguage language) {
    LanguageStructureViewBuilder.INSTANCE.addExplicitExtension(language, new LivePreviewStructureViewFactory());
    LanguageParserDefinitions.INSTANCE.addExplicitExtension(language, new LivePreviewParserDefinition(language));
    //SyntaxHighlighterFactory.LANGUAGE_FACTORY.addExplicitExtension(language, new LivePreviewSyntaxHighlighterFactory(language));
  }

  public static void unregisterLanguageExtensions(LivePreviewLanguage language) {
    LanguageStructureViewBuilder.INSTANCE.removeExplicitExtension(language, LanguageStructureViewBuilder.INSTANCE.forLanguage(language));
    LanguageParserDefinitions.INSTANCE.removeExplicitExtension(language, LanguageParserDefinitions.INSTANCE.forLanguage(language));
  }

  public static MergingUpdateQueue getUpdateQueue(Project project) {
    return project.getUserData(LIVE_PREVIEW_QUEUE);
  }

  private static final Key<MergingUpdateQueue> LIVE_PREVIEW_QUEUE = Key.create("LIVE_PREVIEW_QUEUE");
  private static void installUpdateListener(final Project project) {
    MergingUpdateQueue queue = project.getUserData(LIVE_PREVIEW_QUEUE);
    if (queue == null) {
      JComponent activationComponent = WindowManager.getInstance().getFrame(project).getRootPane();
      project.putUserData(LIVE_PREVIEW_QUEUE, queue = new MergingUpdateQueue("LIVE_PREVIEW_QUEUE", 1000, true, null, project, activationComponent));
    }
    final FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
    final MergingUpdateQueue finalQueue = queue;
    EditorFactory.getInstance().getEventMulticaster().addDocumentListener(new DocumentAdapter() {
      @Override
      public void documentChanged(DocumentEvent e) {
        Document document = e.getDocument();
        final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
        VirtualFile file = fileDocumentManager.getFile(document);
        if (file == null || file.getFileType() != BnfFileType.INSTANCE) return;
        finalQueue.cancelAllUpdates();
        finalQueue.queue(new Update(Boolean.TRUE, true) {
          @Override
          public void run() {
            FileManager fileManager = ((PsiManagerEx)PsiManager.getInstance(project)).getFileManager();
            for (FileEditor fileEditor : fileEditorManager.getAllEditors()) {
              if (!(fileEditor instanceof TextEditor)) continue;
              EditorEx editor = (EditorEx)((TextEditor)fileEditor).getEditor();
              Document document = editor.getDocument();
              VirtualFile virtualFile = editor.getVirtualFile();
              Language language = virtualFile instanceof LightVirtualFile ? ((LightVirtualFile)virtualFile).getLanguage() : null;
              if (!(language instanceof LivePreviewLanguage)) continue;

              FileContentUtil.reparseFiles(project, Collections.singletonList(virtualFile), false);
              fileManager.setViewProvider(virtualFile, fileManager.createFileViewProvider(virtualFile, true));
              PsiDocumentManagerImpl.cachePsi(document, ObjectUtils.assertNotNull(PsiManager.getInstance(project).findFile(virtualFile)));
              editor.setHighlighter(EditorHighlighterFactory.getInstance().createEditorHighlighter(project, virtualFile));
            }
          }
        });
      }
    }, project);

    //project.getMessageBus().connect(project).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
    //  @Override
    //  public void fileOpened(FileEditorManager source, VirtualFile file) {
    //
    //
    //    // add structure component
    //
    //    FileEditor fileEditor = source.getSelectedEditor(file);
    //    if (!(fileEditor instanceof TextEditor)) return;
    //    StructureViewBuilder builder =
    //      StructureViewBuilder.PROVIDER.getStructureViewBuilder(file.getFileType(), file, project);
    //    if (builder == null) return;
    //    StructureView structureView = builder.createStructureView(fileEditor, project);
    //
    //    Editor editor = ((TextEditor)fileEditor).getEditor();
    //    editor.getComponent().getParent().getParent().add(structureView.getComponent(), BorderLayout.EAST);
    //    Disposer.register(fileEditor, structureView);
    //  }
    //});
  }

  public static boolean collectExpressionsAtOffset(Project project, Editor previewEditor, LivePreviewLanguage language, final PairProcessor<BnfExpression, Boolean> processor) {
    Lexer lexer = new LivePreviewLexer(project, language);
    final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
    final PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(parserDefinition, lexer, previewEditor.getDocument().getText());
    final int caretOffset = previewEditor.getCaretModel().getOffset();
    final PsiParser parser = new LivePreviewParser(project, language) {
      @Override
      protected boolean generateNodeCall(PsiBuilder builder,
                                         int level,
                                         BnfRule rule,
                                         @Nullable BnfExpression node,
                                         String nextName,
                                         Map<String, GeneratedParserUtilBase.Parser> externalArguments) {
        int tokenStartOffset = builder.getCurrentOffset();
        int initialOffset = builder.rawLookup(-1) == TokenType.WHITE_SPACE ? builder.rawTokenTypeStart(-1) : builder.getCurrentOffset();
        String tokenText = builder.getTokenText();
        int tokenEndOffset = tokenText == null? tokenStartOffset : tokenStartOffset + tokenText.length();
        boolean result = super.generateNodeCall(builder, level, rule, node, nextName, externalArguments);
        builder.getCurrentOffset(); // advance to the next token first
        int finalOffset = builder.rawLookup(-1) == TokenType.WHITE_SPACE ? builder.rawTokenTypeStart(-1) : builder.getCurrentOffset();
        if (node != null) {
          if (result && initialOffset <= caretOffset && finalOffset > caretOffset ||
              !result && initialOffset <= caretOffset && tokenEndOffset > caretOffset) {
            boolean inWhitespace = isTokenExpression(node) &&
                                   initialOffset <= caretOffset && tokenStartOffset > caretOffset;
            if (!processor.process(node, result && !inWhitespace)) {
              throw new ProcessCanceledException();
            }
          }
        }
        return result;
      }

    };
    try {
      parser.parse(parserDefinition.getFileNodeType(), builder);
      return true;
    }
    catch (ProcessCanceledException e) {
      return false;
    }
  }
}
TOP

Related Classes of org.intellij.grammar.livePreview.LivePreviewHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.