<commit_before>/*
 * StanCompletionManager.java
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
package org.rstudio.studio.client.workbench.views.console.shell.assist;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.Debug;
import org.rstudio.core.client.StringUtil;
import org.rstudio.studio.client.common.codetools.CodeToolsServerOperations;
import org.rstudio.studio.client.common.codetools.RCompletionType;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.views.console.shell.assist.CompletionRequester.QualifiedName;
import org.rstudio.studio.client.workbench.views.output.lint.model.AceAnnotation;
import org.rstudio.studio.client.workbench.views.output.lint.model.LintItem;
import org.rstudio.studio.client.workbench.views.source.editors.text.CompletionContext;
import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Position;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Token;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.TokenIterator;
import org.rstudio.studio.client.workbench.views.source.editors.text.r.SignatureToolTipManager;
import org.rstudio.studio.client.workbench.views.source.events.SaveFileEvent;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.shared.HandlerRegistration;

public class StanCompletionManager extends CompletionManagerBase
                                   implements CompletionManager
{
   public StanCompletionManager(DocDisplay docDisplay,
                                CompletionPopupDisplay popup,
                                CodeToolsServerOperations server,
                                CompletionContext context)
   {
      super(popup, docDisplay, context);
      
      docDisplay_ = docDisplay;
      server_ = server;
      context_ = context;
      
      sigTips_ = new SignatureToolTipManager(docDisplay)
      {
         @Override
         protected void getFunctionArguments(final String name,
                                             final String source,
                                             final String helpHandler,
                                             final CommandWithArg<String> onReady)
         {
            server_.stanGetArguments(name, new ServerRequestCallback<String>()
            {
               @Override
               public void onResponseReceived(String response)
               {
                  onReady.execute(response);
               }

               @Override
               public void onError(ServerError error)
               {
                  Debug.logError(error);
               }
            });
         }
      };
      
      docDisplay_.addAttachHandler((AttachEvent event) -> {
         if (event.isAttached())
            attachHandlers();
         else
            detachHandlers();
      });
   }
   
   @Override
   public void getCompletions(String line, CompletionRequestContext context)
   {
      server_.stanGetCompletions(line, context);
   }
   
   @Override
   protected void addExtraCompletions(String token,
                                      List<QualifiedName> completions)
   {
      Set<String> discoveredIdentifiers = new HashSet<String>();
      
      Token cursorToken = docDisplay_.getTokenAt(docDisplay_.getCursorPosition());
      TokenIterator it = docDisplay_.createTokenIterator();
      for (Token t = it.getCurrentToken();
           t != null && t != cursorToken;
           t = it.stepForward())
      {
         if (!t.hasType("identifier"))
            continue;
         
         String value = t.getValue();
         if (discoveredIdentifiers.contains(value))
            continue;
         
         if (!StringUtil.isSubsequence(value, token))
            continue;
         
         QualifiedName name = new QualifiedName(
               t.getValue(),
               "[identifier]",
               false,
               RCompletionType.CONTEXT,
               "",
               null,
               "Stan");
         
         discoveredIdentifiers.add(value);
         completions.add(name);
      }
   }
   
   @Override
   protected void onCompletionInserted(QualifiedName completion)
   {
      int type = completion.type;
      if (!RCompletionType.isFunctionType(type))
         return;
      
      boolean insertParensAfterCompletion =
            RCompletionType.isFunctionType(type) &&
            uiPrefs_.insertParensAfterFunctionCompletion().getValue();
      
      if (insertParensAfterCompletion)
      {
         String meta = completion.meta;
         
         boolean isZeroArityFunction = meta.equals("()");
         if (!isZeroArityFunction)
         {
            docDisplay_.moveCursorBackward();
            sigTips_.displayToolTip(completion.name, completion.source, completion.helpHandler);
         }
      }
   }
   
   @Override
   public void goToHelp()
   {
      // TODO Auto-generated method stub
   }

   @Override
   public void goToDefinition()
   {
      // TODO Auto-generated method stub
   }

   @Override
   public void codeCompletion()
   {
      beginSuggest(true, false, true);
   }
   
   private void runDiagnostics(final boolean useSourceDatabase)
   {
      server_.stanRunDiagnostics(
            context_.getPath(),
            useSourceDatabase,
            new ServerRequestCallback<JsArray<AceAnnotation>>()
            {
               @Override
               public void onResponseReceived(JsArray<AceAnnotation> response)
               {
                  JsArray<LintItem> lintItems = JavaScriptObject.createArray(response.length()).cast();
                  for (int i = 0; i < response.length(); i++)
                  {
                     LintItem item = createLintItem(response.get(i), useSourceDatabase);
                     if (item != null)
                        lintItems.set(i, item);
                  }
                  docDisplay_.showLint(lintItems);
               }

               @Override
               public void onError(ServerError error)
               {
                  Debug.logError(error);
               }
            });
   }
   
   private LintItem createLintItem(AceAnnotation annotation,
                                   boolean didUseSourceDatabase)
   {
      TokenIterator it = docDisplay_.createTokenIterator();<commit_msg>Stan diagnostics only in .stan for now<commit_after>/*
 * StanCompletionManager.java
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
package org.rstudio.studio.client.workbench.views.console.shell.assist;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.rstudio.core.client.CommandWithArg;
import org.rstudio.core.client.Debug;
import org.rstudio.core.client.StringUtil;
import org.rstudio.studio.client.common.codetools.CodeToolsServerOperations;
import org.rstudio.studio.client.common.codetools.RCompletionType;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.views.console.shell.assist.CompletionRequester.QualifiedName;
import org.rstudio.studio.client.workbench.views.output.lint.model.AceAnnotation;
import org.rstudio.studio.client.workbench.views.output.lint.model.LintItem;
import org.rstudio.studio.client.workbench.views.source.editors.text.CompletionContext;
import org.rstudio.studio.client.workbench.views.source.editors.text.DocDisplay;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Position;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.Token;
import org.rstudio.studio.client.workbench.views.source.editors.text.ace.TokenIterator;
import org.rstudio.studio.client.workbench.views.source.editors.text.r.SignatureToolTipManager;
import org.rstudio.studio.client.workbench.views.source.events.SaveFileEvent;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.shared.HandlerRegistration;

public class StanCompletionManager extends CompletionManagerBase
                                   implements CompletionManager
{
   public StanCompletionManager(DocDisplay docDisplay,
                                CompletionPopupDisplay popup,
                                CodeToolsServerOperations server,
                                CompletionContext context)
   {
      super(popup, docDisplay, context);
      
      docDisplay_ = docDisplay;
      server_ = server;
      context_ = context;
      
      sigTips_ = new SignatureToolTipManager(docDisplay)
      {
         @Override
         protected void getFunctionArguments(final String name,
                                             final String source,
                                             final String helpHandler,
                                             final CommandWithArg<String> onReady)
         {
            server_.stanGetArguments(name, new ServerRequestCallback<String>()
            {
               @Override
               public void onResponseReceived(String response)
               {
                  onReady.execute(response);
               }

               @Override
               public void onError(ServerError error)
               {
                  Debug.logError(error);
               }
            });
         }
      };
      
      docDisplay_.addAttachHandler((AttachEvent event) -> {
         if (event.isAttached())
            attachHandlers();
         else
            detachHandlers();
      });
   }
   
   @Override
   public void getCompletions(String line, CompletionRequestContext context)
   {
      server_.stanGetCompletions(line, context);
   }
   
   @Override
   protected void addExtraCompletions(String token,
                                      List<QualifiedName> completions)
   {
      Set<String> discoveredIdentifiers = new HashSet<String>();
      
      Token cursorToken = docDisplay_.getTokenAt(docDisplay_.getCursorPosition());
      TokenIterator it = docDisplay_.createTokenIterator();
      for (Token t = it.getCurrentToken();
           t != null && t != cursorToken;
           t = it.stepForward())
      {
         if (!t.hasType("identifier"))
            continue;
         
         String value = t.getValue();
         if (discoveredIdentifiers.contains(value))
            continue;
         
         if (!StringUtil.isSubsequence(value, token))
            continue;
         
         QualifiedName name = new QualifiedName(
               t.getValue(),
               "[identifier]",
               false,
               RCompletionType.CONTEXT,
               "",
               null,
               "Stan");
         
         discoveredIdentifiers.add(value);
         completions.add(name);
      }
   }
   
   @Override
   protected void onCompletionInserted(QualifiedName completion)
   {
      int type = completion.type;
      if (!RCompletionType.isFunctionType(type))
         return;
      
      boolean insertParensAfterCompletion =
            RCompletionType.isFunctionType(type) &&
            uiPrefs_.insertParensAfterFunctionCompletion().getValue();
      
      if (insertParensAfterCompletion)
      {
         String meta = completion.meta;
         
         boolean isZeroArityFunction = meta.equals("()");
         if (!isZeroArityFunction)
         {
            docDisplay_.moveCursorBackward();
            sigTips_.displayToolTip(completion.name, completion.source, completion.helpHandler);
         }
      }
   }
   
   @Override
   public void goToHelp()
   {
      // TODO Auto-generated method stub
   }

   @Override
   public void goToDefinition()
   {
      // TODO Auto-generated method stub
   }

   @Override
   public void codeCompletion()
   {
      beginSuggest(true, false, true);
   }
   
   private void runDiagnostics(final boolean useSourceDatabase)
   {
      // TODO: can we enable this in R Markdown documents using Stan?
      if (!docDisplay_.getFileType().isStan())
         return;
      
      server_.stanRunDiagnostics(
            context_.getPath(),
            useSourceDatabase,
            new ServerRequestCallback<JsArray<AceAnnotation>>()
            {
               @Override
               public void onResponseReceived(JsArray<AceAnnotation> response)
               {
                  JsArray<LintItem> lintItems = JavaScriptObject.createArray(response.length()).cast();
                  for (int i = 0; i < response.length(); i++)
                  {
                     LintItem item = createLintItem(response.get(i), useSourceDatabase);
                     if (item != null)
                        lintItems.set(i, item);
                  }
                  docDisplay_.showLint(lintItems);
               }

               @Override
               public void onError(ServerError error)
               {
                  Debug.logError(error);
               }
            });
   }
   
   private LintItem createLintItem(AceAnnotation annotation,
                                   boolean didUseSourceDatabase)
   {
      TokenIterator it = docDisplay_.createTokenIterator();
{'fraction_non_alphanumeric': 0.08579398557626888, 'fraction_numerical': 0.0013607293509320995, 'mean_word_length': 2.071891327063741, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2376482', 'n_tokens_mistral': 3852, 'n_tokens_neox': 3775, 'n_words': 735}