[CodeCompletion] Add rudimentary support for configuring allowable completions

On a per-request basis. Allows hiding/showing at multiple granularities
* everything
* module
* API by name
* keywords (by uid or all of them)
* literals (by uid or all of them)

With more specific rules overriding less specific ones (so you can hide
everything and then selectively show certain API for example).

rdar://24170060
This commit is contained in:
Ben Langmuir
2016-01-23 14:18:46 -08:00
parent 7fad03d822
commit d16e4b0467
19 changed files with 531 additions and 46 deletions

View File

@@ -534,6 +534,45 @@ bool SwiftToSourceKitCompletionAdapter::handleResult(
return Consumer.handleResult(Info);
}
static CodeCompletionLiteralKind
getCodeCompletionLiteralKindForUID(UIdent uid) {
if (uid == KindLiteralArray) {
return CodeCompletionLiteralKind::ArrayLiteral;
} else if (uid == KindLiteralBoolean) {
return CodeCompletionLiteralKind::BooleanLiteral;
} else if (uid == KindLiteralColor) {
return CodeCompletionLiteralKind::ColorLiteral;
} else if (uid == KindLiteralDictionary) {
return CodeCompletionLiteralKind::DictionaryLiteral;
} else if (uid == KindLiteralFloat) {
return CodeCompletionLiteralKind::FloatLiteral;
} else if (uid == KindLiteralInteger) {
return CodeCompletionLiteralKind::IntegerLiteral;
} else if (uid == KindLiteralNil) {
return CodeCompletionLiteralKind::NilLiteral;
} else if (uid == KindLiteralString) {
return CodeCompletionLiteralKind::StringLiteral;
} else if (uid == KindLiteralTuple) {
return CodeCompletionLiteralKind::Tuple;
} else {
llvm_unreachable("unexpected literal kind");
}
}
static CodeCompletionKeywordKind
getCodeCompletionKeywordKindForUID(UIdent uid) {
#define SIL_KEYWORD(kw)
#define KEYWORD(kw) \
static UIdent Keyword##kw##UID("source.lang.swift.keyword." #kw); \
if (uid == Keyword##kw##UID) { \
return CodeCompletionKeywordKind::kw_##kw; \
}
#include "swift/Parse/Tokens.def"
// FIXME: should warn about unexpected keyword kind.
return CodeCompletionKeywordKind::None;
}
using ChunkKind = CodeCompletionString::Chunk::ChunkKind;
/// Provide the text for the call parameter, including constructing a typed
@@ -658,6 +697,11 @@ CompletionKind CodeCompletion::SessionCache::getCompletionKind() {
llvm::sys::ScopedLock L(mtx);
return completionKind;
}
const CodeCompletion::FilterRules &
CodeCompletion::SessionCache::getFilterRules() {
llvm::sys::ScopedLock L(mtx);
return filterRules;
}
//===----------------------------------------------------------------------===//
// CodeCompletion::SessionCacheMap
@@ -760,6 +804,48 @@ static void translateCodeCompletionOptions(OptionsDictionary &from,
from.valueForOption(KeyHideByName, to.hideByNameStyle);
}
static void translateFilterRules(ArrayRef<FilterRule> rawFilterRules,
CodeCompletion::FilterRules &filterRules) {
for (auto &rule : rawFilterRules) {
switch (rule.kind) {
case FilterRule::Everything:
filterRules.hideAll = rule.hide;
break;
case FilterRule::Identifier:
for (auto name : rule.names) {
filterRules.hideByName[name] = rule.hide;
}
break;
case FilterRule::Module:
for (auto name : rule.names) {
filterRules.hideModule[name] = rule.hide;
}
break;
case FilterRule::Keyword:
if (rule.uids.empty())
filterRules.hideAllKeywords = rule.hide;
for (auto uid : rule.uids) {
auto kind = getCodeCompletionKeywordKindForUID(uid);
filterRules.hideKeyword[kind] = rule.hide;
}
break;
case FilterRule::Literal:
if (rule.uids.empty())
filterRules.hideAllValueLiterals = rule.hide;
for (auto uid : rule.uids) {
auto kind = getCodeCompletionLiteralKindForUID(uid);
filterRules.hideValueLiteral[kind] = rule.hide;
}
break;
case FilterRule::CustomCompletion:
if (rule.uids.empty())
filterRules.hideCustomCompletions = rule.hide;
// FIXME: hide individual custom completions
break;
}
}
}
static bool checkInnerResult(CodeCompletionResult *result, bool &hasDot,
bool &hasQDot, bool &hasInit) {
auto chunks = result->getCompletionString()->getChunks();
@@ -849,7 +935,8 @@ static void transformAndForwardResults(
if (!hasEarlyInnerResults) {
organizer.addCompletionsWithFilter(session->getSortedCompletions(),
filterText, exactMatch);
filterText, session->getFilterRules(),
exactMatch);
}
if (hasEarlyInnerResults &&
@@ -870,7 +957,8 @@ static void transformAndForwardResults(
innerResults.insert(innerResults.begin(), buildQDot());
}
organizer.addCompletionsWithFilter(innerResults, filterText, exactMatch);
organizer.addCompletionsWithFilter(innerResults, filterText,
session->getFilterRules(), exactMatch);
}
organizer.groupAndSort(options);
@@ -925,7 +1013,8 @@ static void transformAndForwardResults(
// Add the inner results (and don't filter them).
exactMatch = nullptr; // No longer needed.
organizer.addCompletionsWithFilter(innerResults, filterText, exactMatch);
organizer.addCompletionsWithFilter(innerResults, filterText,
session->getFilterRules(), exactMatch);
CodeCompletion::Options noGroupOpts = options;
noGroupOpts.groupStems = false;
@@ -944,12 +1033,10 @@ static void transformAndForwardResults(
consumer.setNextRequestStart(limitedResults.getNextOffset());
}
void SwiftLangSupport::codeCompleteOpen(StringRef name,
llvm::MemoryBuffer *inputBuf,
unsigned offset,
OptionsDictionary *options,
GroupedCodeCompletionConsumer &consumer,
ArrayRef<const char *> args) {
void SwiftLangSupport::codeCompleteOpen(
StringRef name, llvm::MemoryBuffer *inputBuf, unsigned offset,
OptionsDictionary *options, ArrayRef<FilterRule> rawFilterRules,
GroupedCodeCompletionConsumer &consumer, ArrayRef<const char *> args) {
StringRef filterText;
unsigned resultOffset = 0;
unsigned maxResults = 0;
@@ -958,6 +1045,9 @@ void SwiftLangSupport::codeCompleteOpen(StringRef name,
translateCodeCompletionOptions(*options, CCOpts, filterText, resultOffset,
maxResults);
CodeCompletion::FilterRules filterRules;
translateFilterRules(rawFilterRules, filterRules);
// Set up the code completion consumer to pass results to organizer.
CodeCompletion::CompletionSink sink;
std::vector<Completion *> completions;
@@ -1005,9 +1095,9 @@ void SwiftLangSupport::codeCompleteOpen(StringRef name,
auto bufferCopy = llvm::MemoryBuffer::getMemBufferCopy(
inputBuf->getBuffer(), inputBuf->getBufferIdentifier());
std::vector<std::string> argsCopy(extendedArgs.begin(), extendedArgs.end());
SessionCacheRef session{
new SessionCache(std::move(sink), std::move(bufferCopy),
std::move(argsCopy), completionKind)};
SessionCacheRef session{new SessionCache(
std::move(sink), std::move(bufferCopy), std::move(argsCopy),
completionKind, std::move(filterRules))};
session->setSortedCompletions(std::move(completions));
if (!CCSessions.set(name, offset, session)) {