@@ -17,6 +17,8 @@ import { printAsMs } from '../../../util/text/time';
1717import { codeInline } from '../../../documentation/doc-util/doc-code' ;
1818import type { FlowrConfigOptions } from '../../../config' ;
1919import type { ReplOutput } from '../../../cli/repl/commands/repl-main' ;
20+ import type { CommandCompletions } from '../../../cli/repl/core' ;
21+ import { fileProtocol } from '../../../r-bridge/retriever' ;
2022
2123export interface LinterQuery extends BaseQueryFormat {
2224 readonly type : 'linter' ;
@@ -47,8 +49,9 @@ function rulesFromInput(output: ReplOutput, rulesPart: readonly string[]): {vali
4749 } , { valid : [ ] as ( LintingRuleNames | ConfiguredLintingRule ) [ ] , invalid : [ ] as string [ ] } ) ;
4850}
4951
52+ const rulesPrefix = 'rules:' ;
53+
5054function linterQueryLineParser ( output : ReplOutput , line : readonly string [ ] , _config : FlowrConfigOptions ) : ParsedQueryLine {
51- const rulesPrefix = 'rules:' ;
5255 let rules : ( LintingRuleNames | ConfiguredLintingRule ) [ ] | undefined = undefined ;
5356 let input : string | undefined = undefined ;
5457 if ( line . length > 0 && line [ 0 ] . startsWith ( rulesPrefix ) ) {
@@ -66,6 +69,37 @@ function linterQueryLineParser(output: ReplOutput, line: readonly string[], _con
6669 return { query : [ { type : 'linter' , rules : rules } ] , rCode : input } ;
6770}
6871
72+ function linterQueryCompleter ( line : readonly string [ ] , startingNewArg : boolean , _config : FlowrConfigOptions ) : CommandCompletions {
73+ const rulesPrefixNotPresent = line . length == 0 || ( line . length == 1 && line [ 0 ] . length < rulesPrefix . length ) ;
74+ const rulesNotFinished = line . length == 1 && line [ 0 ] . startsWith ( rulesPrefix ) && ! startingNewArg ;
75+ const endOfRules = line . length == 1 && startingNewArg || line . length == 2 ;
76+
77+ if ( rulesPrefixNotPresent ) {
78+ return { completions : [ `${ rulesPrefix } ` ] } ;
79+ } else if ( endOfRules ) {
80+ return { completions : [ fileProtocol ] } ;
81+ } else if ( rulesNotFinished ) {
82+ const rulesWithoutPrefix = line [ 0 ] . slice ( rulesPrefix . length ) ;
83+ const usedRules = rulesWithoutPrefix . split ( ',' ) . map ( r => r . trim ( ) ) ;
84+ const allRules = Object . keys ( LintingRules ) ;
85+ const unusedRules = allRules . filter ( r => ! usedRules . includes ( r ) ) ;
86+ const lastRule = usedRules [ usedRules . length - 1 ] ;
87+ const lastRuleIsUnfinished = ! allRules . includes ( lastRule ) ;
88+
89+ if ( lastRuleIsUnfinished ) {
90+ // Return all rules that have not been added yet
91+ return { completions : unusedRules , argumentPart : lastRule } ;
92+ } else if ( unusedRules . length > 0 ) {
93+ // Add a comma, if the current last rule is complete
94+ return { completions : [ ',' ] , argumentPart : '' } ;
95+ } else {
96+ // All rules are used, complete with a space
97+ return { completions : [ ' ' ] , argumentPart : '' } ;
98+ }
99+ }
100+ return { completions : [ ] } ;
101+ }
102+
69103export const LinterQueryDefinition = {
70104 executor : executeLinterQuery ,
71105 asciiSummarizer : ( formatter , _analyzer , queryResults , result ) => {
@@ -76,8 +110,9 @@ export const LinterQueryDefinition = {
76110 }
77111 return true ;
78112 } ,
79- fromLine : linterQueryLineParser ,
80- schema : Joi . object ( {
113+ completer : linterQueryCompleter ,
114+ fromLine : linterQueryLineParser ,
115+ schema : Joi . object ( {
81116 type : Joi . string ( ) . valid ( 'linter' ) . required ( ) . description ( 'The type of the query.' ) ,
82117 rules : Joi . array ( ) . items (
83118 Joi . string ( ) . valid ( ...Object . keys ( LintingRules ) ) ,
0 commit comments