Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/darklang/cli/completionPicker.dark
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ let create (promptText: String) (items: List<Completion.CompletionItem>) : State
let parsed = Completion.parseInput promptText
let commandPrefix =
if parsed.isCompletingCommand then ""
else parsed.commandName ++ " "
else
let completedArgs = Stdlib.List.dropLast parsed.args
let parts = Stdlib.List.append [parsed.commandName] completedArgs
(Stdlib.String.join parts " ") ++ " "

State
{ items = items
Expand Down
19 changes: 6 additions & 13 deletions packages/darklang/cli/config.dark
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,16 @@ let execute (state: Cli.AppState) (args: List<String>) : Cli.AppState =


let complete (_state: Cli.AppState) (args: List<String>) : List<Cli.Completion.CompletionItem> =
match args with
| [] ->
["get"; "set"; "list"]
|> Stdlib.List.map Cli.Completion.simple

| ["get"] ->
let configKeys =
[ "sync.default_instance"
"sync.interval_seconds"
"sync.auto_start" ]
|> Stdlib.List.map Cli.Completion.simple

| ["set"] ->
[ "sync.default_instance"
"sync.interval_seconds"
"sync.auto_start" ]
|> Stdlib.List.map Cli.Completion.simple

match args with
| [] ->
["get"; "set"; "list"] |> Stdlib.List.map Cli.Completion.simple
| ["get"] | ["set"] ->
configKeys |> Stdlib.List.map Cli.Completion.simple
| _ -> []


Expand Down
40 changes: 37 additions & 3 deletions packages/darklang/cli/core.dark
Original file line number Diff line number Diff line change
Expand Up @@ -364,12 +364,46 @@ module Registry =
// Completing command arguments
let handler = findCommand parsed.commandName
let completeFunc = handler.complete
completeFunc state parsed.args

// Split args into completed args and partial (last arg)
// parseInput appends "" for trailing space, so this always works:
// "branch switch " → args=["switch",""], completedArgs=["switch"], partial=""
// "branch sw" → args=["sw"], completedArgs=[], partial="sw"
// "branch " → args=[], completedArgs=[], partial=""
let (completedArgs, partial) =
match Stdlib.List.last parsed.args with
| Some lastArg -> (Stdlib.List.dropLast parsed.args, lastArg)
| None -> ([], "")

// Get all completions for the current position
let completions = completeFunc state completedArgs

if Stdlib.String.isEmpty partial then
completions
else
// Filter by what the user has typed so far
let filtered =
completions
|> Stdlib.List.filter (fun item ->
Stdlib.String.startsWith item.value partial)

// If centralized filtering found nothing, try direct call as fallback
// (supports commands with smart matching like path traversal)
match filtered with
| _ :: _ -> filtered
| [] -> completeFunc state parsed.args

let getCompletionHint (state: AppState) (input: String) : String =
let parsed = Completion.parseInput input
let completions = getCompletions state input
let partial = Completion.getPartialCompletion parsed
let parsed = Completion.parseInput input

let partial =
if parsed.isCompletingCommand then
parsed.commandName
else
match Stdlib.List.last parsed.args with
| Some lastArg -> lastArg
| None -> ""

let completionValues = completions |> Stdlib.List.map (fun item -> item.value)
Completion.getHintFromCompletions partial completionValues
Expand Down
33 changes: 3 additions & 30 deletions packages/darklang/cli/packages/db.dark
Original file line number Diff line number Diff line change
Expand Up @@ -422,41 +422,14 @@ let getDBNamesForCompletion (state: Cli.AppState) : List<String> =
name)


let completeDBName
(state: Cli.AppState)
(partial: String)
: List<Cli.Completion.CompletionItem> =
(getDBNamesForCompletion state)
|> Stdlib.List.filter (fun name -> Stdlib.String.startsWith name partial)
|> Stdlib.List.map Cli.Completion.simple


let complete
(state: Cli.AppState)
(args: List<String>)
: List<Cli.Completion.CompletionItem> =
let subcommands = [ "list"; "view"; "get"; "set"; "delete"; "drop"; "query"; "help" ]

match args with
| [] ->
subcommands |> Stdlib.List.map Cli.Completion.simple

| [ partial ] ->
subcommands
|> Stdlib.List.filter (fun cmd -> Stdlib.String.startsWith cmd partial)
[ "list"; "view"; "get"; "set"; "delete"; "drop"; "query"; "help" ]
|> Stdlib.List.map Cli.Completion.simple

| [ "view" ] -> completeDBName state ""
| [ "view"; partial ] -> completeDBName state partial
| [ "get" ] -> completeDBName state ""
| [ "get"; partial ] -> completeDBName state partial
| [ "set" ] -> completeDBName state ""
| [ "set"; partial ] -> completeDBName state partial
| [ "delete" ] -> completeDBName state ""
| [ "delete"; partial ] -> completeDBName state partial
| [ "drop" ] -> completeDBName state ""
| [ "drop"; partial ] -> completeDBName state partial
| [ "query" ] -> completeDBName state ""
| [ "query"; partial ] -> completeDBName state partial

| [ "view" ] | [ "get" ] | [ "set" ] | [ "delete" ] | [ "drop" ] | [ "query" ] ->
(getDBNamesForCompletion state) |> Stdlib.List.map Cli.Completion.simple
| _ -> []
4 changes: 0 additions & 4 deletions packages/darklang/cli/packages/undo.dark
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,4 @@ let help (state: Cli.AppState) : Cli.AppState =
let complete (_state: Cli.AppState) (args: List<String>) : List<Cli.Completion.CompletionItem> =
match args with
| [] -> ["fn"; "type"; "value"] |> Stdlib.List.map Cli.Completion.simple
| [partial] ->
["fn"; "type"; "value"]
|> Stdlib.List.filter (fun item -> Stdlib.String.startsWith item partial)
|> Stdlib.List.map Cli.Completion.simple
| _ -> []
9 changes: 4 additions & 5 deletions packages/darklang/cli/scm/branch.dark
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,10 @@ let execute (state: AppState) (args: List<String>) : AppState =

let complete (_state: AppState) (args: List<String>) : List<Completion.CompletionItem> =
match args with
| [] -> [ "list"; "create"; "switch"; "rename"; "delete" ] |> Stdlib.List.map Completion.simple
| [ "switch"; _ ] ->
let branches = SCM.Branch.list ()
Stdlib.List.map branches (fun b -> Completion.simple b.name)
| [ "delete"; _ ] ->
| [] ->
[ "list"; "create"; "switch"; "rename"; "delete" ]
|> Stdlib.List.map Completion.simple
| [ "switch" ] | [ "delete" ] ->
let branches = SCM.Branch.list ()
Stdlib.List.map branches (fun b -> Completion.simple b.name)
| _ -> []
Expand Down
33 changes: 6 additions & 27 deletions packages/darklang/cli/scripts.dark
Original file line number Diff line number Diff line change
Expand Up @@ -136,41 +136,20 @@ let execute (state: AppState) (args: List<String>) : AppState =

let complete (_state: AppState) (args: List<String>) : List<Completion.CompletionItem> =
match args with
// if hitting `tab` right after typing `scripts`, recommend subcommands
// Recommend subcommands
| [] ->
["list"; "view"; "add"; "edit"; "delete"; "run"]
|> Stdlib.List.map Completion.simple

// no completions here
| ["list"] | ["add"] -> []

// we're referencing some specific script - recommend names
// Referencing a specific script - recommend names
| ["view"] | ["edit"] | ["delete"] | ["run"] ->
// Complete script names
let scripts = Builtin.pmScriptsList ()
scripts
|> Stdlib.List.map (fun s -> s.name)
|> Stdlib.List.map Completion.simple

| [subcommand] ->
// Partial subcommand completion
["list"; "view"; "add"; "edit"; "delete"; "run"]
|> Stdlib.List.filter (fun cmd -> Stdlib.String.startsWith cmd subcommand)
|> Stdlib.List.map Completion.simple

| ["view"; _] | ["delete"; _] | ["run"; _] ->
// CLEANUP why are we ignoring them?
// We should be recommending based on the names available
[]

| ["edit"; _scriptName] ->
// For edit with script name, could show current content hint but keep simple
[]

| "add" :: _ | "edit" :: _ :: _ ->
// For add or edit with content, no completion needed
[]

// No completions for these
| ["list"] | ["add"] -> []
// For add or edit with content, no completion needed
| "add" :: _ | "edit" :: _ :: _ -> []
| _ -> []


Expand Down
13 changes: 11 additions & 2 deletions packages/darklang/cli/utils/completion.dark
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type ParsedInput =

let parseInput (input: String) : ParsedInput =
let trimmed = Stdlib.String.trim input
let endsWithSpace = Stdlib.String.endsWith input " "

if Stdlib.String.isEmpty trimmed then
ParsedInput { commandName = ""; args = []; isCompletingCommand = true }
Expand All @@ -38,8 +39,16 @@ let parseInput (input: String) : ParsedInput =

match words with
| [] -> ParsedInput { commandName = ""; args = []; isCompletingCommand = true }
| [command] -> ParsedInput { commandName = command; args = []; isCompletingCommand = true }
| command :: args -> ParsedInput { commandName = command; args = args; isCompletingCommand = false }
| [command] ->
if endsWithSpace then
ParsedInput { commandName = command; args = []; isCompletingCommand = false }
else
ParsedInput { commandName = command; args = []; isCompletingCommand = true }
| command :: rest ->
if endsWithSpace then
ParsedInput { commandName = command; args = Stdlib.List.append rest [""]; isCompletingCommand = false }
else
ParsedInput { commandName = command; args = rest; isCompletingCommand = false }


let getPartialCompletion (parsed: ParsedInput) : String =
Expand Down