// Copyright 2012 Google Inc. All Rights Reserved. // // 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 com.google.collide.client.code.autocomplete; import com.google.collide.client.code.autocomplete.AutocompleteProposals.ProposalWithContext; import com.google.collide.client.documentparser.DocumentParser; import com.google.collide.client.editor.selection.SelectionModel; import com.google.collide.client.util.PathUtil; import com.google.collide.codemirror2.SyntaxType; import com.google.common.base.Preconditions; import javax.annotation.Nonnull; /** * Base class for language-specific autocompleters. * * <p>State transitions:<ol> * <li> {@link #LanguageSpecificAutocompleter} -> (2) * <li> {@link #attach} -> (3) or (8) * <li> {@link #getExplicitAction} -> (4) or (7) or (8) * <li> {@link #start} -> (5) or (8) * <li> {@link #findAutocompletions} -> (5) or (6) or (7) or (8) * <li> {@link #computeAutocompletionResult} -> (5) or (6) or (7) or (8) * <li> {@link #pause} -> (3) or (8) * <li> {@link #detach()} * </ol> */ public abstract class LanguageSpecificAutocompleter { /** * Enumeration of types of actions preformed on keypress. */ public enum ExplicitActionType { /** * Default behaviour (just append char). */ DEFAULT, /** * Append char and open autocompletion box. */ DEFERRED_COMPLETE, /** * Do not append char, use explicit autocompletion. */ EXPLICIT_COMPLETE, /** * Append char and close autocompletion box. */ CLOSE_POPUP } /** * Bean that holds explicit action type, and optional explicit autocompletion. */ public static class ExplicitAction { public static final ExplicitAction DEFAULT = new ExplicitAction( ExplicitActionType.DEFAULT, null); public static final ExplicitAction DEFERRED_COMPLETE = new ExplicitAction( ExplicitActionType.DEFERRED_COMPLETE, null); public static final ExplicitAction CLOSE_POPUP = new ExplicitAction( ExplicitActionType.CLOSE_POPUP, null); private final ExplicitActionType type; private final AutocompleteResult explicitAutocompletion; public ExplicitAction(AutocompleteResult explicitAutocompletion) { this(ExplicitActionType.EXPLICIT_COMPLETE, explicitAutocompletion); } public ExplicitAction(ExplicitActionType type, AutocompleteResult explicitAutocompletion) { this.type = type; this.explicitAutocompletion = explicitAutocompletion; } public ExplicitActionType getType() { return type; } public AutocompleteResult getExplicitAutocompletion() { return explicitAutocompletion; } } private AutocompleteController controller; private boolean isPaused; private final SyntaxType mode; private DocumentParser documentParser; protected LanguageSpecificAutocompleter(SyntaxType mode) { Preconditions.checkNotNull(mode); this.mode = mode; } /** * Computes the full autocompletion for a selected proposal. * * <p>A full autocompletion may include such things as closing tags or braces. * In complex substitution case the number of indexes the caret should jump * after the autocompletion is complete is also computed. * * @param proposal proposal selected by user * @return value object with information for applying changes */ public abstract AutocompleteResult computeAutocompletionResult(ProposalWithContext proposal); /** * Finds autocompletions for a given completion query. * * @param selection used to obtain current cursor position and selection * @param trigger used to request different lists of proposals * @return POJO holding array of autocompletion proposals. */ public abstract AutocompleteProposals findAutocompletions( SelectionModel selection, SignalEventEssence trigger); /** * Cleanup before instance is dismissed. */ public abstract void cleanup(); /** * Prepare instance for the new autocompletion life cycle. * * <p>No completions are requested yet, but the completer can prepare * itself (e.g. pre-fetch data). */ protected void attach( DocumentParser parser, AutocompleteController controller, PathUtil filePath) { Preconditions.checkNotNull(parser); documentParser = parser; this.controller = controller; isPaused = true; } /** * Specifies the behavior of this controller on signal events (not text * changes). * * <p>Ctrl-space event is processed directly and not passed to this * method. * * <p>Key press in not applied to document yet, so be careful when analyse * text around cursor. */ protected ExplicitAction getExplicitAction(SelectionModel selectionModel, SignalEventEssence signal, boolean popupIsShown) { return ExplicitAction.DEFAULT; } protected void start() { isPaused = false; } protected void pause() { isPaused = true; } /** * Indicates the end of this autocompleter lifecycle. * * <p>User switched to other file and is not willing to see any proposals * from this completer. */ protected void detach() { pause(); this.controller = null; } /** * Invoked by implementations to provide asynchronously obtained proposals. */ protected final void scheduleRequestForUpdatedProposals() { if (!isPaused) { controller.scheduleRequestForUpdatedProposals(); } } protected SyntaxType getMode() { return mode; } @Nonnull protected DocumentParser getParser() { return Preconditions.checkNotNull(documentParser); } }