blob: 37cb79ed3fb74ccfb7a1d3c0a6dabc1dfd3b6293 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2013 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* QNX Software Systems - Initial API and implementation
* Andrew Gvozdev
*******************************************************************************/
package org.eclipse.cdt.make.internal.ui.text.makefile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.cdt.make.core.makefile.IAutomaticVariable;
import org.eclipse.cdt.make.core.makefile.IBuiltinFunction;
import org.eclipse.cdt.make.core.makefile.IDirective;
import org.eclipse.cdt.make.core.makefile.IMacroDefinition;
import org.eclipse.cdt.make.core.makefile.IMakefile;
import org.eclipse.cdt.make.core.makefile.ITargetRule;
import org.eclipse.cdt.make.internal.ui.MakeUIImages;
import org.eclipse.cdt.make.internal.ui.MakeUIPlugin;
import org.eclipse.cdt.make.internal.ui.text.WordPartDetector;
import org.eclipse.cdt.make.ui.IWorkingCopyManager;
import org.eclipse.cdt.ui.CDTSharedImages;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ContextInformation;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.IEditorPart;
/**
* MakefileCompletionProcessor
*/
public class MakefileCompletionProcessor implements IContentAssistProcessor {
/**
* Simple content assist tip closer. The tip is valid in a range
* of 5 characters around its pop-up location.
*/
protected static class Validator implements IContextInformationValidator, IContextInformationPresenter {
protected int fInstallOffset;
@Override
public boolean isContextInformationValid(int offset) {
return Math.abs(fInstallOffset - offset) < 5;
}
@Override
public void install(IContextInformation info, ITextViewer viewer, int offset) {
fInstallOffset = offset;
}
@Override
public boolean updatePresentation(int documentPosition, TextPresentation presentation) {
return false;
}
}
protected IContextInformationValidator fValidator = new Validator();
protected Image imageFunction = MakeUIImages.getImage(MakeUIImages.IMG_OBJS_FUNCTION);
protected Image imageVariable = CDTSharedImages.getImage(CDTSharedImages.IMG_OBJS_VARIABLE);
protected Image imageAutomaticVariable = MakeUIImages.getImage(MakeUIImages.IMG_OBJS_AUTO_VARIABLE);
protected Image imageTarget = MakeUIImages.getImage(MakeUIImages.IMG_OBJS_TARGET);
protected IEditorPart fEditor;
protected IWorkingCopyManager fManager;
private Comparator<IDirective> directivesComparator = new Comparator<>() {
@Override
public int compare(IDirective o1, IDirective o2) {
return o1.toString().compareToIgnoreCase(o2.toString());
}
};
private class BracketHandler {
private char open;
private char closed;
private boolean found;
private String followingText;
public BracketHandler(String input) {
char firstChar = input.length() > 0 ? input.charAt(0) : 0;
open = firstChar == '{' ? '{' : '(';
closed = firstChar == '{' ? '}' : ')';
found = firstChar == open;
followingText = found ? input.substring(1) : input;
}
}
public MakefileCompletionProcessor(IEditorPart editor) {
fEditor = editor;
fManager = MakeUIPlugin.getDefault().getWorkingCopyManager();
}
@Override
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) {
List<ICompletionProposal> proposalList = new ArrayList<>();
IMakefile makefile = fManager.getWorkingCopy(fEditor.getEditorInput());
WordPartDetector wordPart = new WordPartDetector(viewer.getDocument(), documentOffset);
if (wordPart.isMacro()) {
IAutomaticVariable[] automaticVariables = makefile.getAutomaticVariables();
proposalList.addAll(createCompletionProposals(wordPart, automaticVariables));
IMacroDefinition[] macroDefinitions = makefile.getMacroDefinitions();
Arrays.sort(macroDefinitions, directivesComparator);
proposalList.addAll(createCompletionProposals(wordPart, macroDefinitions));
IBuiltinFunction[] builtinFunctions = makefile.getBuiltinFunctions();
Arrays.sort(builtinFunctions, directivesComparator);
proposalList.addAll(createCompletionProposals(wordPart, builtinFunctions));
} else {
ITargetRule[] targetRules = makefile.getTargetRules();
Arrays.sort(targetRules, directivesComparator);
proposalList.addAll(createCompletionProposals(wordPart, targetRules));
}
return proposalList.toArray(new ICompletionProposal[proposalList.size()]);
}
private String macro(String name, BracketHandler bracket) {
if (bracket.found) {
name = bracket.open + name + bracket.closed;
}
return '$' + name;
}
private ArrayList<ICompletionProposal> createCompletionProposals(WordPartDetector wordPart,
IAutomaticVariable[] autoVars) {
ArrayList<ICompletionProposal> proposalList = new ArrayList<>(autoVars.length);
String wordPartName = wordPart.getName();
BracketHandler bracket = new BracketHandler(wordPartName);
String partialName = bracket.followingText;
for (IMacroDefinition autoVar : autoVars) {
String name = autoVar.getName();
if (name.startsWith(partialName)) {
String replacement;
if (bracket.found) {
replacement = name + bracket.closed;
} else {
replacement = name;
}
CompletionProposal proposal = new CompletionProposal(replacement, wordPart.getOffset(),
partialName.length(), replacement.length(), imageAutomaticVariable,
macro(name, bracket) + " - " + autoVar.getValue().toString(), //$NON-NLS-1$
null, autoVar.getValue().toString());
proposalList.add(proposal);
}
}
return proposalList;
}
private ArrayList<ICompletionProposal> createCompletionProposals(WordPartDetector wordPart,
IMacroDefinition[] macros) {
ArrayList<ICompletionProposal> proposalList = new ArrayList<>(macros.length);
String wordPartName = wordPart.getName();
BracketHandler bracket = new BracketHandler(wordPartName);
String partialName = bracket.followingText;
for (IMacroDefinition macro : macros) {
String name = macro.getName();
if (name.startsWith(partialName)) {
String replacement;
if (bracket.found) {
replacement = name + bracket.closed;
} else {
replacement = bracket.open + name + bracket.closed;
}
String displayString = name;
ICompletionProposal proposal = new CompletionProposal(replacement, wordPart.getOffset(),
partialName.length(), replacement.length(), imageVariable, displayString, null,
macro.getValue().toString());
proposalList.add(proposal);
}
}
return proposalList;
}
private ArrayList<ICompletionProposal> createCompletionProposals(WordPartDetector wordPart,
IBuiltinFunction[] builtinFuns) {
ArrayList<ICompletionProposal> proposalList = new ArrayList<>(builtinFuns.length);
String wordPartName = wordPart.getName();
BracketHandler bracket = new BracketHandler(wordPartName);
String partialName = bracket.followingText;
for (IBuiltinFunction builtinFun : builtinFuns) {
String name = builtinFun.getName();
String replacement;
if (bracket.found) {
replacement = name + bracket.closed;
} else {
replacement = bracket.open + name + bracket.closed;
}
int indexComma = replacement.indexOf(',');
int cursorPosition = indexComma >= 0 ? indexComma : replacement.length() - 1;
if (name.startsWith(partialName)) {
ICompletionProposal proposal = new CompletionProposal(replacement, wordPart.getOffset(),
partialName.length(), cursorPosition, imageFunction, "$" + bracket.open + name + bracket.closed, //$NON-NLS-1$
null, builtinFun.getValue().toString());
proposalList.add(proposal);
}
}
return proposalList;
}
private ArrayList<ICompletionProposal> createCompletionProposals(WordPartDetector wordPart, ITargetRule[] targets) {
ArrayList<ICompletionProposal> proposalList = new ArrayList<>(targets.length);
String partialName = wordPart.getName();
for (ITargetRule target : targets) {
String name = target.getTarget().toString();
if (name.startsWith(partialName)) {
String replacement = name;
ICompletionProposal proposal = new CompletionProposal(replacement, wordPart.getOffset(),
partialName.length(), replacement.length(), imageTarget, name, null, null);
proposalList.add(proposal);
}
}
return proposalList;
}
@Override
public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) {
WordPartDetector wordPart = new WordPartDetector(viewer.getDocument(), documentOffset);
IMakefile makefile = fManager.getWorkingCopy(fEditor.getEditorInput());
ArrayList<String> contextList = new ArrayList<>();
ArrayList<IContextInformation> contextInformationList = new ArrayList<>();
if (wordPart.isMacro()) {
IDirective[] statements = makefile.getMacroDefinitions();
for (IDirective statement : statements) {
if (statement instanceof IMacroDefinition) {
String name = ((IMacroDefinition) statement).getName();
if (name != null && name.equals(wordPart.getName())) {
String value = ((IMacroDefinition) statement).getValue().toString();
if (value != null && value.length() > 0) {
contextList.add(value);
contextInformationList
.add(new ContextInformation(imageVariable, wordPart.getName(), value));
}
}
}
}
statements = makefile.getBuiltinMacroDefinitions();
for (IDirective statement : statements) {
if (statement instanceof IMacroDefinition) {
String name = ((IMacroDefinition) statement).getName();
if (name != null && name.equals(wordPart.getName())) {
String value = ((IMacroDefinition) statement).getValue().toString();
if (value != null && value.length() > 0) {
contextList.add(value);
contextInformationList
.add(new ContextInformation(imageAutomaticVariable, wordPart.getName(), value));
}
}
}
}
}
IContextInformation[] result = contextInformationList
.toArray(new IContextInformation[contextInformationList.size()]);
return result;
}
@Override
public char[] getCompletionProposalAutoActivationCharacters() {
return null;
}
@Override
public char[] getContextInformationAutoActivationCharacters() {
return null;
}
@Override
public String getErrorMessage() {
return null;
}
@Override
public IContextInformationValidator getContextInformationValidator() {
return fValidator;
}
}