Skip to content

Commit

Permalink
devtools: make closure libraries participate in code completions
Browse files Browse the repository at this point in the history
close #24
  • Loading branch information
darwin committed Jun 18, 2016
1 parent 4f8a160 commit 829d5c7
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 84 deletions.
142 changes: 103 additions & 39 deletions resources/unpacked/devtools/front_end/console/DiracPrompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,11 @@ WebInspector.DiracPromptWithHistory.prototype = {
if (javascriptCompletion) {
this._prefixRange = new WebInspector.TextRange(cursor.line, token.start + javascriptCompletion.offset, cursor.line, cursor.ch);
const completionsForJavascriptReady = this._completionsForJavascriptReady.bind(this, this._lastAutocompleteRequest, !!reverse, !!force);
this._loadJavascriptCompletions(this._lastAutocompleteRequest, javascriptCompletion.prefix, force || false, completionsForJavascriptReady);
this._loadJavascriptCompletions(this._lastAutocompleteRequest, javascriptCompletion.prefix, !!force, completionsForJavascriptReady);
} else {
this._prefixRange = new WebInspector.TextRange(cursor.line, token.start, cursor.line, cursor.ch);
const completionsForClojureScriptReady = this._completionsForClojureScriptReady.bind(this, this._lastAutocompleteRequest, !!reverse, !!force);
this._loadClojureScriptCompletions(this._lastAutocompleteRequest, prefix, force || false, completionsForClojureScriptReady);
this._loadClojureScriptCompletions(this._lastAutocompleteRequest, prefix, !!force, completionsForClojureScriptReady);
}
},

Expand Down Expand Up @@ -400,7 +400,7 @@ WebInspector.DiracPromptWithHistory.prototype = {
return;
}

const suggestStyle = (style = "") => `suggest-cljs ${style}`;
const makeSuggestStyle = (style = "") => `suggest-cljs ${style}`;

const namespaceSelector = name => {
return function(namespaceDescriptors) {
Expand Down Expand Up @@ -431,13 +431,13 @@ WebInspector.DiracPromptWithHistory.prototype = {
const annotateQualifiedSymbols = (style, symbols) => {
return symbols.filter(symbol => symbol.startsWith(prefix)).map(symbol => ({
title: symbol || "?",
className: suggestStyle(style)
className: makeSuggestStyle(style)
}));
};

const currentNamespaceDescriptorPromise = dirac.extractNamespacesAsync().then(selectCurrentNamespace);

const resolvedNamespacePromise = currentNamespaceDescriptorPromise.then(currentNamespaceDescriptor => {
const resolvedNamespaceNamePromise = currentNamespaceDescriptorPromise.then(currentNamespaceDescriptor => {
if (!currentNamespaceDescriptor) {
return namespace;
}
Expand All @@ -447,16 +447,65 @@ WebInspector.DiracPromptWithHistory.prototype = {
return allAliases[namespace] || namespace; // resolve alias or assume namespace name is a full namespace name
});

const namespaceSymbolsPromise = resolvedNamespacePromise.then(dirac.extractNamespaceSymbolsAsync).then(annotateQualifiedSymbols.bind(this, "suggest-cljs-qualified"));
const macroNamespaceSymbolsPromise = resolvedNamespacePromise.then(dirac.extractMacroNamespaceSymbolsAsync).then(annotateQualifiedSymbols.bind(this, "suggest-cljs-qualified suggest-cljs-macro"));
const prepareAnnotatedJavascriptCompletionsForPseudoNamespaceAsync = (namespaceName, callback) => {
return new Promise(resolve => {
const resultHandler = (expression, prefix, completions) => {
const annotatedCompletions = annotateQualifiedSymbols("suggest-cljs-qualified suggest-cljs-pseudo", completions);
if (dirac._DEBUG_COMPLETIONS) {
console.log("resultHandler got", expression, prefix, completions, annotatedCompletions);
}
resolve(annotatedCompletions);
};

// order matters here, see _markAliasedCompletions below
const jobs = [
namespaceSymbolsPromise,
macroNamespaceSymbolsPromise
];
this._loadJavascriptCompletions(requestId, namespaceName + ".", force, resultHandler);
});
};

const readyCallback = completionsReadyCallback.bind(this, expression, prefix);

const provideCompletionsForNamespace = ([namespaces, namespaceName]) => {
const namespace = namespaces[namespaceName];
if (!namespace) {
const macroNamespaceNames = dirac.getMacroNamespaceNames(namespaces);
if (!macroNamespaceNames.includes(namespaceName)) {
if (dirac._DEBUG_COMPLETIONS) {
console.log("no known namespace for ", namespaceName);
}
readyCallback([]);
return;
} else {
if (dirac._DEBUG_COMPLETIONS) {
console.log("namespace is a macro namespace", namespaceName);
}
}
}

if (namespace && namespace.pseudo) {
if (dirac._DEBUG_COMPLETIONS) {
console.log("pseudo namespace => falling back to JS completions", namespaceName);
}
prepareAnnotatedJavascriptCompletionsForPseudoNamespaceAsync(namespaceName).then(readyCallback);
return;
}

if (dirac._DEBUG_COMPLETIONS) {
console.log("cljs namespace => retrieving symbols and macros from caches", namespaceName);
}
const namespaceSymbolsPromise = dirac.extractNamespaceSymbolsAsync(namespaceName)
.then(annotateQualifiedSymbols.bind(this, "suggest-cljs-qualified"));
const macroNamespaceSymbolsPromise = dirac.extractMacroNamespaceSymbolsAsync(namespaceName)
.then(annotateQualifiedSymbols.bind(this, "suggest-cljs-qualified suggest-cljs-macro"));

// order matters here, see _markAliasedCompletions below
const jobs = [
namespaceSymbolsPromise,
macroNamespaceSymbolsPromise
];

Promise.all(jobs).then(concatAnnotatedResults).then(readyCallback);
};

Promise.all(jobs).then(concatAnnotatedResults).then(completionsReadyCallback.bind(this, expression, prefix));
Promise.all([dirac.extractNamespacesAsync(), resolvedNamespaceNamePromise]).then(provideCompletionsForNamespace);
} else {
// general completion (without slashes)
// combine: locals (if paused in debugger), current ns symbols, namespace names and cljs.core symbols
Expand All @@ -465,7 +514,7 @@ WebInspector.DiracPromptWithHistory.prototype = {
const annotateSymbols = (style, symbols) => {
return symbols.filter(symbol => symbol.startsWith(input)).map(symbol => ({
title: symbol || "?",
className: suggestStyle(style)
className: makeSuggestStyle(style)
}));
};

Expand Down Expand Up @@ -506,60 +555,75 @@ WebInspector.DiracPromptWithHistory.prototype = {
const annotatedCompletions = filteredLocals.map(item => ({
title: item.name || "?",
epilogue: item.identifier ? "js/" + item.identifier : undefined,
className: suggestStyle("suggest-cljs-scope")
className: makeSuggestStyle("suggest-cljs-scope")
}));
annotatedCompletions.reverse(); // we want to display inner scopes first
return annotatedCompletions;
};

const annotateNamespaceNames = (style, namespaces) => {
const annotateNamespaceName = namespace => {
let extraStyle = "";
if (namespace.pseudo) {
extraStyle += " suggest-cljs-pseudo";
}
return {
title: namespace.name || "?",
className: makeSuggestStyle("suggest-cljs-ns" + extraStyle)
}
};

const annotateNamespaceNames = namespaces => {
return Object.keys(namespaces)
.filter(name => name.startsWith(input))
.map(name => annotateNamespaceName(namespaces[name]));
};

const annotateMacroNamespaceNames = (namespaces) => {
return namespaces.filter(name => name.startsWith(input)).map(name => ({
title: name || "?",
className: suggestStyle(style)
className: makeSuggestStyle("suggest-cljs-ns suggest-cljs-macro")
}));
};

const extractNamespaceNames = namespaceDescriptors => {
return Object.keys(namespaceDescriptors);
};

const extractMacroNamespaceNames = namespaceDescriptors => {
let names = [];
for (let descriptor of Object.values(namespaceDescriptors)) {
if (!descriptor.detectedMacroNamespaces) {
continue;
}
names = names.concat(descriptor.detectedMacroNamespaces);
}
return dirac.deduplicate(names);
};

const annotateAliasesOrRefers = (kind, prefix, style, namespaceDescriptor) => {
if (!namespaceDescriptor) {
return [];
}
const mapping = namespaceDescriptor[kind] || {};
return Object.keys(mapping).filter(name => name.startsWith(input)).map(name => {
const targetName = mapping[name];
return {
title: name,
epilogue: targetName ? prefix + targetName : null, // full target name
className: suggestStyle(style)
}

return dirac.extractNamespacesAsync().then(namespaces => {
const mapping = namespaceDescriptor[kind] || {};
return Object.keys(mapping).filter(name => name.startsWith(input)).map(name => {
const targetName = mapping[name];
const targetNamespace = namespaces[targetName] || {};
let extraStyle = "";
if (targetNamespace.pseudo) {
extraStyle += " suggest-cljs-pseudo";
}
return {
title: name,
epilogue: targetName ? prefix + targetName : null, // full target name
className: makeSuggestStyle(style + extraStyle)
}
});

});
};

const annotateReplSpecials = symbols => {
return symbols.filter(symbol => symbol.startsWith(input)).map(symbol => ({
title: symbol || "?",
className: suggestStyle("suggest-cljs-repl suggest-cljs-special")
className: makeSuggestStyle("suggest-cljs-repl suggest-cljs-special")
}));
};

const localsPromise = dirac.extractScopeInfoFromScopeChainAsync(debuggerModel.selectedCallFrame()).then(extractAndAnnotateLocals);
const currentNamespaceSymbolsPromise = dirac.extractNamespaceSymbolsAsync(this._currentClojureScriptNamespace).then(annotateSymbols.bind(this, "suggest-cljs-in-ns"));
const namespaceNamesPromise = dirac.extractNamespacesAsync().then(extractNamespaceNames).then(annotateNamespaceNames.bind(this, "suggest-cljs-ns"));
const macroNamespaceNamesPromise = dirac.extractNamespacesAsync().then(extractMacroNamespaceNames).then(annotateNamespaceNames.bind(this, "suggest-cljs-ns suggest-cljs-macro"));
const namespaceNamesPromise = dirac.extractNamespacesAsync().then(annotateNamespaceNames);
const macroNamespaceNamesPromise = dirac.extractNamespacesAsync().then(dirac.getMacroNamespaceNames).then(annotateMacroNamespaceNames);
const coreNamespaceSymbolsPromise = dirac.extractNamespaceSymbolsAsync("cljs.core").then(annotateSymbols.bind(this, "suggest-cljs-core"));
const currentNamespaceDescriptor = dirac.extractNamespacesAsync().then(selectCurrentNamespace);
const namespaceAliasesPromise = currentNamespaceDescriptor.then(annotateAliasesOrRefers.bind(this, "namespaceAliases", "is ", "suggest-ns-alias"));
Expand Down
7 changes: 6 additions & 1 deletion resources/unpacked/devtools/front_end/dirac/dirac.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ Object.assign(window.dirac, (function() {
return loadLazyDirac().then(() => window.dirac.invalidateNamespacesCache(...args));
}

function getMacroNamespaceNames(...args) {
return loadLazyDirac().then(() => window.dirac.getMacroNamespaceNames(...args));
}

// --- exported interface ---------------------------------------------------------------------------------------------------

// don't forget to update externs.js too
Expand Down Expand Up @@ -254,7 +258,8 @@ Object.assign(window.dirac, (function() {
extractNamespacesAsync: extractNamespacesAsync,
invalidateNamespaceSymbolsCache: invalidateNamespaceSymbolsCache,
invalidateMacroNamespaceSymbolsCache: invalidateMacroNamespaceSymbolsCache,
invalidateNamespacesCache: invalidateNamespacesCache
invalidateNamespacesCache: invalidateNamespacesCache,
getMacroNamespaceNames: getMacroNamespaceNames

// ...

Expand Down
Loading

0 comments on commit 829d5c7

Please sign in to comment.