All Downloads are FREE. Search and download functionalities are using the official Maven repository.

editor.GosuEditor Maven / Gradle / Ivy

There is a newer version: 1.18.1
Show newest version
package editor;

import editor.debugger.Breakpoint;
import editor.debugger.BreakpointManager;
import editor.search.SearchElement;
import editor.search.SearchLocation;
import editor.search.UsageSearcher;
import editor.search.UsageTarget;
import editor.undo.AtomicUndoManager;
import editor.util.EditorUtilities;
import editor.util.HTMLEscapeUtil;
import editor.util.IReplaceWordCallback;
import editor.util.LabToolbarButton;
import java.nio.file.Path;
import editor.util.SettleModalEventQueue;
import editor.util.TaskQueue;
import editor.util.TextComponentUtil;
import gw.lang.GosuShop;
import gw.lang.gosuc.GosuIssueContainer;
import gw.lang.parser.GosuParserFactory;
import gw.lang.parser.IExpression;
import gw.lang.parser.IGosuParser;
import gw.lang.parser.IGosuProgramParser;
import gw.lang.parser.IGosuValidator;
import gw.lang.parser.IParseIssue;
import gw.lang.parser.IParseResult;
import gw.lang.parser.IParseTree;
import gw.lang.parser.IParsedElement;
import gw.lang.parser.ISymbolTable;
import gw.lang.parser.ITypeUsesMap;
import gw.lang.parser.ParserOptions;
import gw.lang.parser.StandardSymbolTable;
import gw.lang.parser.exceptions.ParseException;
import gw.lang.parser.exceptions.ParseResultsException;
import gw.lang.parser.expressions.IBeanMethodCallExpression;
import gw.lang.parser.expressions.IImplicitTypeAsExpression;
import gw.lang.parser.expressions.IInferredNewExpression;
import gw.lang.parser.expressions.ILocalVarDeclaration;
import gw.lang.parser.expressions.IMethodCallExpression;
import gw.lang.parser.expressions.INameInDeclaration;
import gw.lang.parser.expressions.INewExpression;
import gw.lang.parser.expressions.IParameterDeclaration;
import gw.lang.parser.expressions.IVarStatement;
import gw.lang.parser.statements.IClassDeclaration;
import gw.lang.parser.statements.IClassFileStatement;
import gw.lang.parser.statements.IClassStatement;
import gw.lang.parser.statements.IFunctionStatement;
import gw.lang.parser.statements.IMethodCallStatement;
import gw.lang.parser.statements.INamespaceStatement;
import gw.lang.parser.statements.IPropertyStatement;
import gw.lang.parser.statements.IStatementList;
import gw.lang.parser.statements.IUsesStatement;
import gw.lang.parser.statements.IUsesStatementList;
import gw.lang.parser.template.ITemplateGenerator;
import gw.lang.reflect.FunctionType;
import gw.lang.reflect.IMetaType;
import gw.lang.reflect.IScriptabilityModifier;
import gw.lang.reflect.IType;
import gw.lang.reflect.ITypeLoaderListener;
import gw.lang.reflect.ITypeRef;
import gw.lang.reflect.RefreshRequest;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.gs.ClassType;
import gw.lang.reflect.gs.IGosuClass;
import gw.lang.reflect.gs.IGosuEnhancement;
import gw.lang.reflect.gs.StringSourceFileHandle;
import gw.lang.reflect.java.JavaTypes;
import gw.lang.IIssueContainer;
import gw.util.GosuStringUtil;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.undo.CompoundEdit;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static editor.util.TextComponentUtil.Direction.BACKWARD;
import static editor.util.TextComponentUtil.Direction.FORWARD;

/**
 * A component for editing Gosu source.
 */
public class GosuEditor extends EditorHost implements IScriptEditor, IGosuPanel, ITypeLoaderListener
{
  public static final int MIN_LINENUMBER_WIDTH = 16;

  private JLabel _labelCaption;
  private ParserFeedbackPanel _panelFeedback;
  private EditorHostTextPane _editor;
  private GosuDocumentHandler _docHandler;
  private IContextMenuHandler _contextMenuHandler;
  private volatile IGosuParser _parser;
  private boolean _bStatement;
  private boolean _bProgram;
  private boolean _bClass;
  private boolean _bEnhancement;
  private boolean _bEmptyTextOk;
  private ISymbolTable _symTable;
  private IReplaceWordCallback _replaceWordCallback;
  private boolean _bTemplate;
  private IScriptabilityModifier _scriptabilityModifier;
  private AtomicUndoManager _undoMgr;
  private EditorScrollPane _scroller;
  private ParseResultsException _pe;
  private boolean _bTestResource;
  private boolean _bAcceptUses;
  private IGosuClass _parsedGosuClass;
  private Map _functionStmtsByLineNumber;

  private IGosuValidator _validator;

  private SmartFixManager _smartFixManager;
  private ScopeHighlighter _ctxHighlighter;
  private DynamicSelectionManager _selectionManager;
  private CodeRefactorManager _codeManager;

  //This rectangle is used to signal that the editor is being used in test mode and that popups should therefore
  //not display
  private static final Rectangle TEST_RECTANGLE = new Rectangle( 0, 0, 0, 0 );

  private ITypeUsesMap _typeUsesMap;
  private ITypeUsesMap _typeUsesMapFromMostRecentParse;

  private JavadocPopup _javadocPopup;

  private IType _programSuperType;
  private boolean _bAccessPrivateMembers;
  private IType _expectedType;

  public GosuEditor( ILineInfoManager lineInfoRenderer,
                     AtomicUndoManager undoMgr,
                     IScriptabilityModifier scriptabilityConstraint,
                     IContextMenuHandler contextMenuHandler,
                     boolean bStatement, boolean bEmptyTextOk )
  {
    this( null, lineInfoRenderer, undoMgr, scriptabilityConstraint, contextMenuHandler, bStatement, bEmptyTextOk );
  }

  public GosuEditor( ISymbolTable symTable,
                     ILineInfoManager lineInfoRenderer,
                     AtomicUndoManager undoMgr,
                     IScriptabilityModifier scriptabilityConstraint,
                     IContextMenuHandler contextMenuHandler,
                     boolean bStatement, boolean bEmptyTextOk )
  {
    super( undoMgr );
    if( lineInfoRenderer != null )
    {
      lineInfoRenderer.setEditor( this );
    }
    _symTable = symTable;
    _undoMgr = undoMgr;
    _contextMenuHandler = contextMenuHandler == null
                          ? new DefaultContextMenuHandler()
                          : contextMenuHandler;
    _bStatement = bStatement;
    _bEmptyTextOk = bEmptyTextOk;
    _bAcceptUses = true;
    _docHandler = new GosuDocumentHandler();
    _parser = null;
    _scriptabilityModifier = scriptabilityConstraint;

    _replaceWordCallback = new ReplaceWordCallback();
    _ctxHighlighter = new ScopeHighlighter( this );

    configureLayout( lineInfoRenderer );
    _smartFixManager = new SmartFixManager( this );
    _selectionManager = new DynamicSelectionManager( this );
    _codeManager = new CodeRefactorManager( this );
  }

  void configureLayout( ILineInfoManager lineInfoRenderer )
  {
    setBorder( UIManager.getBorder( "TextField.border" ) );
    setLayout( new BorderLayout() );

    _editor = createEditorPane();
    ToolTipManager.sharedInstance().registerComponent( _editor );
    ToolTipManager.sharedInstance().setDismissDelay( 60000 );
    ScrollableEditorRootPane editorRootPane = new ScrollableEditorRootPane( _editor );
    editorRootPane.setContentPane( _editor );
    editorRootPane.setBorder( null );

    GosuEditorKit kit = new GosuEditorKit();
    _editor.setEditorKitForContentType( "text/gosu", kit );
    _editor.setContentType( "text/gosu" );
    _editor.setMargin( new Insets( 3, 3, 3, 3 ) ); // set margin directly, otherwise some other platforms (cough, mac, cough) don't have a margin at all
    _editor.setFont( new Font( GosuEditorKit.getStylePreferences().getFontFamily(), Font.PLAIN,
                               GosuEditorKit.getStylePreferences().getFontSize() ) );
    _editor.setBackground( Scheme.active().getWindow() );
    _editor.setForeground( Scheme.active().getWindowText() );
    _editor.putClientProperty( "caretWidth", 2 );
    _editor.setCaretColor( Scheme.active().getWindowText() );
    _editor.setEditable( true );
    _editor.addKeyListener( new EditorKeyHandler() );
    _editor.addMouseListener( new ScriptEditorPopupHandler( this, _contextMenuHandler ) );
    _editor.addMouseWheelListener( new ScriptEditorMouseWheelHandler( this ) );
    _editor.addCaretListener( new ErrorAtCaretHandler() );
    _editor.addCaretListener( _ctxHighlighter );
    _editor.addFocusListener( _ctxHighlighter );
    _editor.addFocusListener( new FocusAdapter()
    {
      @Override
      public void focusGained( FocusEvent e )
      {
        _smartFixManager.updateState();
      }
    } );
    TypeSystem.addTypeLoaderListenerAsWeakRef( this );
    MouseInEditorHandler mouseInEditorHandler = new MouseInEditorHandler( this );
    _editor.addMouseListener( mouseInEditorHandler );
    _editor.addMouseMotionListener( mouseInEditorHandler );
    _editor.addMouseListener( new MouseAdapter()
    {
      @Override
      public void mouseClicked( MouseEvent e )
      {
        setCompleteCode( false );
      }

      @Override
      public void mousePressed( MouseEvent e )
      {
        setCompleteCode( false );
      }

      @Override
      public void mouseReleased( MouseEvent e )
      {
        setCompleteCode( false );
      }
    } );

    addDocumentListener();

    addKeyHandlers();

    // Sets the editor's width such that lines won't word wrap
    EventQueue.invokeLater( () -> _editor.setSize( 1000, _editor.getHeight() ) );

    _scroller = new EditorScrollPane( lineInfoRenderer, _editor, editorRootPane );
    _scroller.setBorder( null );
    JViewport vp = _scroller.getViewport();
    vp.setScrollMode( JViewport.BLIT_SCROLL_MODE );

    add( BorderLayout.CENTER, _scroller );

    _labelCaption = new JLabel( "