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

editor.SymbolCompletionHandler Maven / Gradle / Ivy

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

import editor.util.EditorUtilities;
import editor.util.TextComponentUtil;
import gw.lang.GosuShop;
import gw.lang.parser.IDynamicFunctionSymbol;
import gw.lang.parser.IParseTree;
import gw.lang.parser.ISymbol;
import gw.lang.parser.ISymbolTable;
import gw.lang.parser.Keyword;
import gw.lang.reflect.IEnumType;
import gw.lang.reflect.IType;
import gw.lang.reflect.java.GosuTypes;
import gw.util.GosuObjectUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 */
public class SymbolCompletionHandler extends AbstractPathCompletionHandler
{
  @Override
  public boolean handleCompletePath( ISymbolTable transientSymTable )
  {
    final GosuEditor gsEditor = getGosuEditor();
    boolean bDotAtCaret = GosuObjectUtil.equals( TextComponentUtil.getWordAtCaret( gsEditor.getEditor() ), "." ) ||
                          GosuObjectUtil.equals( TextComponentUtil.getPartialWordBeforeCaret( gsEditor.getEditor() ), "." ) ||
                          GosuObjectUtil.equals( TextComponentUtil.getWordAtCaret( gsEditor.getEditor() ), ":" ) ||
                          GosuObjectUtil.equals( TextComponentUtil.getPartialWordBeforeCaret( gsEditor.getEditor() ), ":" );
    if( bDotAtCaret )
    {
      return false;
    }
    IParseTree locationAtCaret = gsEditor.getDeepestLocationAtCaret();
    if( locationAtCaret != null &&
        InitializerCompletionHandler.isInitializerStart( locationAtCaret.getParsedElement() ) )
    {
      return false;
    }

    String strMemberPath = getSingleNameAtCaret();
    strMemberPath = strMemberPath != null ? strMemberPath.trim() : null;

    String wordBeforeCaret = TextComponentUtil.getPartialWordBeforeCaret( getGosuEditor().getEditor() );
    boolean isAtAsPosition = wordBeforeCaret != null && wordBeforeCaret.trim().equals( Keyword.KW_as.toString() );
    if( gsEditor.isAltDown() || isAtAsPosition )
    {
      return displayTypesPopup( strMemberPath );
    }

    //noinspection unchecked
    List listSymbols = new ArrayList( transientSymTable.getSymbols().values() );
    filterUnwantedSymbols( listSymbols );
    IType expectedType = addValuesForType( listSymbols );

    ISymbol[] symbols = listSymbols.toArray( new ISymbol[listSymbols.size()] );
    SymbolPopup valuePopup = new SymbolPopup( symbols, strMemberPath, gsEditor, expectedType );
    valuePopup.addNodeChangeListener(
      e -> {
        String word = (String)e.getSource();
        if( word.endsWith( "()" ) )
        {
          TextComponentUtil.replaceWordAtCaretDynamicAndRemoveEmptyParens( gsEditor.getEditor(),
                                                                           word,
                                                                           gsEditor.getReplaceWordCallback(),
                                                                           true,
                                                                           valuePopup.isReplaceWholeWord() );
        }
        else
        {
          TextComponentUtil.replaceWordAtCaretDynamic( gsEditor.getEditor(),
                                                       word,
                                                       gsEditor.getReplaceWordCallback(),
                                                       true,
                                                       valuePopup.isReplaceWholeWord() );
        }
        gsEditor.getEditor().requestFocus();
        EditorUtilities.fixSwingFocusBugWhenPopupCloses( gsEditor );
        gsEditor.getEditor().repaint();
      } );
    gsEditor.setCompletionPopup( valuePopup );
    gsEditor.displayCompletionPopup( gsEditor.getEditor().getCaretPosition() );
    if( !valuePopup.isShowing() && !valuePopup.wasAutoDismissed() )
    {
      return displayTypesPopup( strMemberPath );
    }

    return false;
  }

  private IType addValuesForType( List listSymbols )
  {
    IType expectedType = getGosuEditor().findExpectedTypeErrorAtCaret();
    if( expectedType != null && expectedType.isEnum() )
    {
      int[] i = {0};
      ((IEnumType)expectedType).getEnumConstants().forEach( e -> listSymbols.add( i[0]++, GosuShop.createSymbol( e, expectedType, null ) ) );
    }
    return expectedType;
  }

  private void filterUnwantedSymbols( Collection listSymbols )
  {
    List deleteSyms = new ArrayList<>();
    for( ISymbol s : listSymbols )
    {
      if( s.getType() == GosuTypes.DEF_CTOR_TYPE() || (s instanceof IDynamicFunctionSymbol && ((IDynamicFunctionSymbol)s).isConstructor()) )
      {
        // Filter constructor symbols (only applicable when editing a gs class)
        deleteSyms.add( s );
      }
      else if( s instanceof IDynamicFunctionSymbol && s.getName().startsWith( "@" ) )
      {
        // This is the getter or setter for a property, and the DPS will be in the list already
        deleteSyms.add( s );
      }
    }
    listSymbols.removeAll( deleteSyms );
  }

  boolean displayTypesPopup( String strPrefix )
  {
    TypePopup popup = new TypePopup( strPrefix, getGosuEditor(), isAnnotationsOnly() );
    getGosuEditor().setCompletionPopup( popup );
    final boolean addUsesAutomatically = getGosuEditor().acceptsUses();
    popup.addNodeChangeListener(
      e -> {
        String strQualifedType = (String)e.getSource();
        String strRelativeType = TypePopup.getRelativeTypeName( strQualifedType );
        String strPartialType = strQualifedType;
        if( strPartialType.contains( TextComponentUtil.getWordAtCaret( getGosuEditor().getEditor() ) ) )
        {
          strPartialType = strPartialType.substring( strPartialType.indexOf( TextComponentUtil.getWordAtCaret( getGosuEditor().getEditor() ) ) );
        }

        if( addUsesAutomatically )
        {
          // Need to do this before we replace word because replace word causes
          // reparse, which would leave usesStmts in incomplete state.
          getGosuEditor().addToUses( strQualifedType );
        }

        //noinspection StatementWithEmptyBody
        if( addUsesAutomatically &&
            GosuObjectUtil.equals( TextComponentUtil.getPartialWordBeforeCaret( getGosuEditor().getEditor() ), strRelativeType ) )
        {
          //no need to replace the text, since it is already there
        }
        else
        {
          TextComponentUtil.replaceWordAtCaretDynamic(
            getGosuEditor().getEditor(),
            addUsesAutomatically ? strRelativeType : strPartialType,
            getGosuEditor().getReplaceWordCallback(), false, popup.isReplaceWholeWord() );
        }


        getGosuEditor().getEditor().requestFocus();
        EditorUtilities.fixSwingFocusBugWhenPopupCloses( getGosuEditor() );
        getGosuEditor().getEditor().repaint();
      } );
    getGosuEditor().displayCompletionPopup( getGosuEditor().getEditor().getCaretPosition() );
    return true;
  }

  protected boolean isAnnotationsOnly()
  {
    return false;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy