<commit_before>package org.rstudio.studio.client.workbench.views.source.editors.text.cpp;

import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.Rectangle;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.core.client.widget.ScrollableToolbarPopupMenu;
import org.rstudio.studio.client.workbench.views.console.shell.editor.InputEditorPosition;
import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay;
import org.rstudio.studio.client.workbench.views.source.model.CppCompletion;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;

public class CppCompletionPopupMenu extends ScrollableToolbarPopupMenu
{
   CppCompletionPopupMenu(DocDisplay docDisplay, 
                          CompletionPosition completionPosition)
   {  
      docDisplay_ = docDisplay;
      completionPosition_ = completionPosition;
      
      addToolTipHandler();
      
      addStyleName(ThemeStyles.INSTANCE.statusBarMenu());
   }
   
   public void setText(String text)
   {
      JsArray<CppCompletion> completions = JsArray.createArray().cast();
      completions.push(CppCompletion.create(text));
      setCompletions(completions, null);
   }
     
   public void setCompletions(JsArray<CppCompletion> completions, 
                              CommandWithArg<CppCompletion> onSelected)
   {
      // save completions and selectable state
      completions_ = completions;
      onSelected_ = onSelected;
      
      // clear existing items
      updatingMenu_ = true;
      menuBar_.clearItems();
      
      // add items (remember first item for programmatic selection)
      MenuItem firstItem = null;
      for (int i = 0; i<completions.length(); i++)
      {
         final CppCompletion completion = completions.get(i);
         MenuItem menuItem = new MenuItem(completion.getTypedText(), 
               new ScheduledCommand() {
            @Override
            public void execute()
            {
               docDisplay_.setFocus(true); 
               if (isSelectable())
                  onSelected_.execute(completion);
            }
         });
         
         addItem(menuItem);
         
         if (i == 0)
            firstItem = menuItem;
      }
      updatingMenu_ = false;
      
      
      // select first item
      if (isSelectable() && (firstItem != null))
         selectItem(firstItem);
      
      if (completions.length() > 0)
      {
         showMenu();
      }
      else
      {
         setVisible(false);
         if (toolTip_ != null)
            toolTip_.setVisible(false);
      }
   }
   
   public void acceptSelected()
   {
      int index = getSelectedIndex();
      if (index != -1)
      {
         if (isSelectable())
            onSelected_.execute(completions_.get(index));
      }
      hide();
   }
   
   private void showMenu()
   {
      setPopupPositionAndShow(new PositionCallback()
      {
         public void setPosition(int offsetWidth, int offsetHeight)
         {
            InputEditorPosition position = 
               docDisplay_.createInputEditorPosition(
                                    completionPosition_.getPosition());  
            Rectangle bounds = docDisplay_.getPositionBounds(position);
            
            int windowBottom = Window.getScrollTop() + 
                               Window.getClientHeight() ;
            int cursorBottom = bounds.getBottom() ;
            
            // figure out whether we should show below (do this 
            // only once so that we maintain the menu orientation
            // while filtering)
            if (showBelow_ == null)
               showBelow_ = windowBottom - cursorBottom >= offsetHeight;
            
            final int PAD = 3;
            if (showBelow_)
               setPopupPosition(bounds.getLeft(), cursorBottom + PAD) ;
            else
               setPopupPosition(bounds.getLeft(), 
                                bounds.getTop() - offsetHeight) ;
         }
      });
   }
   
   private boolean isSelectable()
   {
      return onSelected_ != null;
   }
   
   private void addToolTipHandler()
   {
      toolTip_ = new CppCompletionToolTip();
      
      addSelectionHandler(new SelectionHandler<MenuItem>()
      {
         public void onSelection(SelectionEvent<MenuItem> event)
         { 
            // bail if we are updating the menu
            if (updatingMenu_)
               return;
            
            // bail if we have no more tooltip
            if (toolTip_ == null)
               return;
            
            // screen unselectable
            if (!isSelectable())
            {
               toolTip_.setVisible(false);
               return;
            }
               
            // screen unable to find menu
            final MenuItem selectedItem = event.getSelectedItem();
            int index = menuBar_.getItemIndex(selectedItem);
            if (index == -1)
            {
               toolTip_.setVisible(false);
               return;
            }
            
            // screen no completion text
            CppCompletion completion = completions_.get(index);
            if (completion.getText() == null)
            {
               toolTip_.setVisible(false);
               return;
            }
            String text = completion.getText().get(0);
            
            // only do tooltips for functions and variables
            if (!completion.isFunction() && !completion.isVariable())
            {
               toolTip_.setVisible(false);
               return;
            }
            <commit_msg>check for null selected item<commit_after>package org.rstudio.studio.client.workbench.views.source.editors.text.cpp;

import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.Rectangle;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.core.client.widget.ScrollableToolbarPopupMenu;
import org.rstudio.studio.client.workbench.views.console.shell.editor.InputEditorPosition;
import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay;
import org.rstudio.studio.client.workbench.views.source.model.CppCompletion;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;

public class CppCompletionPopupMenu extends ScrollableToolbarPopupMenu
{
   CppCompletionPopupMenu(DocDisplay docDisplay, 
                          CompletionPosition completionPosition)
   {  
      docDisplay_ = docDisplay;
      completionPosition_ = completionPosition;
      
      addToolTipHandler();
      
      addStyleName(ThemeStyles.INSTANCE.statusBarMenu());
   }
   
   public void setText(String text)
   {
      JsArray<CppCompletion> completions = JsArray.createArray().cast();
      completions.push(CppCompletion.create(text));
      setCompletions(completions, null);
   }
     
   public void setCompletions(JsArray<CppCompletion> completions, 
                              CommandWithArg<CppCompletion> onSelected)
   {
      // save completions and selectable state
      completions_ = completions;
      onSelected_ = onSelected;
      
      // clear existing items
      updatingMenu_ = true;
      menuBar_.clearItems();
      
      // add items (remember first item for programmatic selection)
      MenuItem firstItem = null;
      for (int i = 0; i<completions.length(); i++)
      {
         final CppCompletion completion = completions.get(i);
         MenuItem menuItem = new MenuItem(completion.getTypedText(), 
               new ScheduledCommand() {
            @Override
            public void execute()
            {
               docDisplay_.setFocus(true); 
               if (isSelectable())
                  onSelected_.execute(completion);
            }
         });
         
         addItem(menuItem);
         
         if (i == 0)
            firstItem = menuItem;
      }
      updatingMenu_ = false;
      
      
      // select first item
      if (isSelectable() && (firstItem != null))
         selectItem(firstItem);
      
      if (completions.length() > 0)
      {
         showMenu();
      }
      else
      {
         setVisible(false);
         if (toolTip_ != null)
            toolTip_.setVisible(false);
      }
   }
   
   public void acceptSelected()
   {
      int index = getSelectedIndex();
      if (index != -1)
      {
         if (isSelectable())
            onSelected_.execute(completions_.get(index));
      }
      hide();
   }
   
   private void showMenu()
   {
      setPopupPositionAndShow(new PositionCallback()
      {
         public void setPosition(int offsetWidth, int offsetHeight)
         {
            InputEditorPosition position = 
               docDisplay_.createInputEditorPosition(
                                    completionPosition_.getPosition());  
            Rectangle bounds = docDisplay_.getPositionBounds(position);
            
            int windowBottom = Window.getScrollTop() + 
                               Window.getClientHeight() ;
            int cursorBottom = bounds.getBottom() ;
            
            // figure out whether we should show below (do this 
            // only once so that we maintain the menu orientation
            // while filtering)
            if (showBelow_ == null)
               showBelow_ = windowBottom - cursorBottom >= offsetHeight;
            
            final int PAD = 3;
            if (showBelow_)
               setPopupPosition(bounds.getLeft(), cursorBottom + PAD) ;
            else
               setPopupPosition(bounds.getLeft(), 
                                bounds.getTop() - offsetHeight) ;
         }
      });
   }
   
   private boolean isSelectable()
   {
      return onSelected_ != null;
   }
   
   private void addToolTipHandler()
   {
      toolTip_ = new CppCompletionToolTip();
      
      addSelectionHandler(new SelectionHandler<MenuItem>()
      {
         public void onSelection(SelectionEvent<MenuItem> event)
         { 
            // bail if we are updating the menu
            if (updatingMenu_)
               return;
            
            // bail if we have no more tooltip
            if (toolTip_ == null)
               return;
            
            // screen unselectable
            if (!isSelectable())
            {
               toolTip_.setVisible(false);
               return;
            }
               
            // screen unable to find menu or selected item
            final MenuItem selectedItem = event.getSelectedItem();
            if (selectedItem == null)
            {
               toolTip_.setVisible(false);
               return;
            }
            
            int index = menuBar_.getItemIndex(selectedItem);
            if (index == -1)
            {
               toolTip_.setVisible(false);
               return;
            }
            
            // screen no completion text
            CppCompletion completion = completions_.get(index);
            if (completion.getText() == null)
            {
               toolTip_.setVisible(false);
               return;
            }
            String text = completion.getText().get(0);
            
            // only do tooltips for functions and variables
            if (!completion.isFunction() && !completion.isVariable())
            {
               toolTip_.setVisible(false);
               return;
            }
            
{'fraction_non_alphanumeric': 0.08851926977687627, 'fraction_numerical': 0.0011359026369168357, 'mean_word_length': 1.761200716845878, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4561081', 'n_tokens_mistral': 3209, 'n_tokens_neox': 3180, 'n_words': 632}