diff --git a/src/completions.ts b/src/completions.ts index c2b7c4e80..d4feab044 100644 --- a/src/completions.ts +++ b/src/completions.ts @@ -9,6 +9,9 @@ import * as vscode from 'vscode'; import * as session from './session'; +import { extendSelection } from './selection'; +import { cleanLine } from './lineCache'; + // Get with names(roxygen2:::default_tags()) const roxygenTagCompletionItems = [ @@ -93,11 +96,16 @@ export class LiveCompletionItemProvider implements vscode.CompletionItemProvider }); } - if (trigger === undefined || trigger === '"' || trigger === '\'') { + if (trigger === undefined || trigger === '[' || trigger === ',' || trigger === '"' || trigger === '\'') { const bracketItems = getBracketCompletionItems(document, position, token); items.push(...bracketItems); } + if (trigger === undefined || trigger === '(' || trigger === ',') { + const pipelineItems = getPipelineCompletionItems(document, position, token); + items.push(...pipelineItems); + } + return items; } } @@ -149,3 +157,53 @@ function getBracketCompletionItems(document: vscode.TextDocument, position: vsco } return items; } + +function getPipelineCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken) { + const items: vscode.CompletionItem[] = []; + const range = extendSelection(position.line, (x) => document.lineAt(x).text, document.lineCount); + let symbol: string; + + for (let i = range.startLine; i <= range.endLine; i++) { + if (token.isCancellationRequested) { + break; + } + + const line = document.lineAt(i); + if (line.isEmptyOrWhitespace) { + continue; + } + + const cleanedLine = cleanLine(line.text); + if (cleanedLine.length === 0) { + continue; + } + + const pipeSymbolIndex = line.text.search(/([\w_.]+)\s*(%.+%|\|>)/); + if (pipeSymbolIndex < 0) { + break; + } + + const symbolPosition = new vscode.Position(i, pipeSymbolIndex); + const symbolRange = document.getWordRangeAtPosition(symbolPosition); + + if (symbolRange !== undefined) { + symbol = document.getText(symbolRange); + } + + break; + } + + if (!token.isCancellationRequested && symbol !== undefined) { + const obj = session.globalenv[symbol]; + if (obj !== undefined && obj.names !== undefined) { + const doc = new vscode.MarkdownString('Element of `' + symbol + '`'); + obj.names.map((name: string) => { + const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Field); + item.detail = '[session]'; + item.documentation = doc; + items.push(item); + }); + } + } + return items; +} diff --git a/src/extension.ts b/src/extension.ts index a6cdbc5a2..5a2111cb7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -164,7 +164,7 @@ export async function activate(context: vscode.ExtensionContext): Promise string, endLine: number; } { const lc = new LineCache(getLine, lineCount); - const getLineFromCache = (x) => lc.getLineFromCache(x); - const getEndsInOperatorFromCache = (x) => lc.getEndsInOperatorFromCache(x); + const getLineFromCache = (x: number) => lc.getLineFromCache(x); + const getEndsInOperatorFromCache = (x: number) => lc.getEndsInOperatorFromCache(x); let lookingForward = true; /* poss[1] is the farthest point reached looking forward from line, and poss[0] is the farthest point reached looking backward from line. */