canontra-0.1.0.0: src/Canontra/CLI/Completions.hs
{-# LANGUAGE OverloadedStrings #-}
{- |
Module : Canontra.CLI.Completions
Description : Shell autocompletion script generators for canontra CLI.
Generates native, self-contained completion scripts for:
- Bash (using complete -F _canontra)
- Zsh (using compdef _canontra)
- Fish (using complete -c canontra)
- PowerShell (using Register-ArgumentCompleter)
-}
module Canontra.CLI.Completions
( ShellType (..)
, generateCompletionScript
, parseShellType
) where
import Data.Text (Text)
import qualified Data.Text as T
-- | Supported target shells for autocompletions.
data ShellType
= ShellBash
| ShellZsh
| ShellFish
| ShellPowerShell
deriving stock (Eq, Ord, Show)
-- | Parses a shell name string into a 'ShellType'.
parseShellType :: String -> Maybe ShellType
parseShellType s = case map toLowerChar s of
"bash" -> Just ShellBash
"zsh" -> Just ShellZsh
"fish" -> Just ShellFish
"powershell" -> Just ShellPowerShell
"pwsh" -> Just ShellPowerShell
_ -> Nothing
where
toLowerChar c
| c >= 'A' && c <= 'Z' = toEnum (fromEnum c + 32)
| otherwise = c
-- | Generates the autocompletion script for the specified shell.
generateCompletionScript :: ShellType -> Text
generateCompletionScript shell = case shell of
ShellBash -> bashCompletions
ShellZsh -> zshCompletions
ShellFish -> fishCompletions
ShellPowerShell -> powerShellCompletions
-- ============================================================================
-- Bash Completion Script
-- ============================================================================
bashCompletions :: Text
bashCompletions = T.unlines
[ "#!/usr/bin/env bash"
, "# Canontra Bash autocompletion script"
, "_canontra()"
, "{"
, " local cur prev words cword"
, " _init_completion || return"
, ""
, " local commands=\"fp fingerprint compare diff graph verify repository repo impact slice watch commit evolution cache export completions version\""
, ""
, " if [ $cword -eq 1 ]; then"
, " COMPREPLY=( $(compgen -W \"${commands}\" -- \"${cur}\") )"
, " return 0"
, " fi"
, ""
, " case \"${words[1]}\" in"
, " fp|fingerprint)"
, " case \"${prev}\" in"
, " -l|--language)"
, " COMPREPLY=( $(compgen -W \"python typescript javascript go rust\" -- \"${cur}\") )"
, " return 0"
, " ;;"
, " esac"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--json --hash -q -l --language --help\" -- \"${cur}\") )"
, " else"
, " _filedir"
, " fi"
, " ;;"
, " compare)"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--diff --json --help\" -- \"${cur}\") )"
, " else"
, " _filedir"
, " fi"
, " ;;"
, " diff)"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--json --help\" -- \"${cur}\") )"
, " else"
, " _filedir"
, " fi"
, " ;;"
, " graph)"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--scope --calls --deps --cfg --dfg --json --help\" -- \"${cur}\") )"
, " else"
, " _filedir"
, " fi"
, " ;;"
, " cache)"
, " if [ $cword -eq 2 ]; then"
, " COMPREPLY=( $(compgen -W \"info verify clean prune\" -- \"${cur}\") )"
, " elif [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--json --help\" -- \"${cur}\") )"
, " else"
, " _filedir -d"
, " fi"
, " ;;"
, " export)"
, " case \"${prev}\" in"
, " -f|--format)"
, " COMPREPLY=( $(compgen -W \"sarif dot\" -- \"${cur}\") )"
, " return 0"
, " ;;"
, " -g|--graph)"
, " COMPREPLY=( $(compgen -W \"calls cfg dfg\" -- \"${cur}\") )"
, " return 0"
, " ;;"
, " -o|--output|-b|--base)"
, " _filedir"
, " return 0"
, " ;;"
, " esac"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"-f --format -o --output -b --base -g --graph --help\" -- \"${cur}\") )"
, " else"
, " _filedir"
, " fi"
, " ;;"
, " completions)"
, " COMPREPLY=( $(compgen -W \"bash zsh fish powershell\" -- \"${cur}\") )"
, " ;;"
, " repo|repository)"
, " if [[ \"${cur}\" == -* ]]; then"
, " COMPREPLY=( $(compgen -W \"--json --cache --help\" -- \"${cur}\") )"
, " else"
, " _filedir -d"
, " fi"
, " ;;"
, " *)"
, " _filedir"
, " ;;"
, " esac"
, "}"
, "complete -F _canontra canontra"
]
-- ============================================================================
-- Zsh Completion Script
-- ============================================================================
zshCompletions :: Text
zshCompletions = T.unlines
[ "#compdef canontra"
, "# Canontra Zsh autocompletion script"
, ""
, "_canontra() {"
, " local -a commands"
, " commands=("
, " 'fp:Compute deterministic multi-tier fingerprints'"
, " 'fingerprint:Alias for fp'"
, " 'compare:Compare fingerprints between two files'"
, " 'diff:Generate fine-grained structural and semantic diff diagnostics'"
, " 'graph:Inspect call graph, CFG, DFG, scope tree, or dependency graph'"
, " 'verify:Verify repeat-execution determinism'"
, " 'repo:Compute aggregated repository fingerprint'"
, " 'repository:Alias for repo'"
, " 'impact:Compute fine-grained semantic change impact slice'"
, " 'slice:Trace upstream caller slice and downstream dependencies'"
, " 'watch:Start interactive live terminal Merkle DAG watcher session'"
, " 'commit:Fingerprint repository at a git commit'"
, " 'evolution:Compare repository evolution across two git revisions'"
, " 'cache:Inspect, verify, clean, or prune incremental binary cache'"
, " 'export:Export diagnostics (SARIF) or graphs (DOT)'"
, " 'completions:Generate shell autocompletions'"
, " 'version:Display engine version'"
, " )"
, ""
, " _arguments -C \\"
, " '1: :->command' \\"
, " '*:: :->args'"
, ""
, " case $state in"
, " command)"
, " _describe -t commands 'canontra command' commands"
, " ;;"
, " args)"
, " case $words[1] in"
, " fp|fingerprint)"
, " _arguments \\"
, " '(-l --language)'{-l,--language}'[Source language]:language:(python typescript javascript go rust)' \\"
, " '--json[Output as JSON manifest]' \\"
, " '(-q --hash)'{-q,--hash}'[Output only composite hash]' \\"
, " '1:source file:_files'"
, " ;;"
, " cache)"
, " local -a cache_cmds"
, " cache_cmds=('info:Inspect cache statistics' 'verify:Verify CRC32 integrity' 'clean:Remove cache file' 'prune:Remove orphaned entries')"
, " _describe -t cache_cmds 'cache command' cache_cmds"
, " ;;"
, " export)"
, " _arguments \\"
, " '(-f --format)'{-f,--format}'[Export format]:format:(sarif dot)' \\"
, " '(-o --output)'{-o,--output}'[Destination file]:output file:_files' \\"
, " '(-b --base)'{-b,--base}'[Baseline file]:baseline file:_files' \\"
, " '(-g --graph)'{-g,--graph}'[Graph type]:graph:(calls cfg dfg)' \\"
, " '1:source file:_files'"
, " ;;"
, " completions)"
, " _arguments '1:shell:(bash zsh fish powershell)'"
, " ;;"
, " *)"
, " _files"
, " ;;"
, " esac"
, " ;;"
, " esac"
, "}"
, ""
, "_canontra \"$@\""
]
-- ============================================================================
-- Fish Completion Script
-- ============================================================================
fishCompletions :: Text
fishCompletions = T.unlines
[ "# Canontra Fish autocompletion script"
, "complete -c canontra -f"
, ""
, "# Primary commands"
, "complete -c canontra -n '__fish_use_subcommand' -a fp -d 'Compute deterministic multi-tier fingerprints'"
, "complete -c canontra -n '__fish_use_subcommand' -a compare -d 'Compare fingerprints between two files'"
, "complete -c canontra -n '__fish_use_subcommand' -a diff -d 'Generate fine-grained structural and semantic diffs'"
, "complete -c canontra -n '__fish_use_subcommand' -a graph -d 'Inspect call graph, CFG, DFG, scope, or deps'"
, "complete -c canontra -n '__fish_use_subcommand' -a verify -d 'Verify repeat-execution determinism'"
, "complete -c canontra -n '__fish_use_subcommand' -a repo -d 'Compute aggregated repository fingerprint'"
, "complete -c canontra -n '__fish_use_subcommand' -a impact -d 'Compute semantic change impact slice'"
, "complete -c canontra -n '__fish_use_subcommand' -a slice -d 'Trace upstream caller slice and dependencies'"
, "complete -c canontra -n '__fish_use_subcommand' -a watch -d 'Start live terminal Merkle DAG watcher session'"
, "complete -c canontra -n '__fish_use_subcommand' -a cache -d 'Inspect, verify, clean, or prune binary cache'"
, "complete -c canontra -n '__fish_use_subcommand' -a export -d 'Export diagnostics (SARIF) or graphs (DOT)'"
, "complete -c canontra -n '__fish_use_subcommand' -a completions -d 'Generate shell autocompletions'"
, "complete -c canontra -n '__fish_use_subcommand' -a version -d 'Display engine version'"
, ""
, "# Cache subcommands"
, "complete -c canontra -n '__fish_seen_subcommand_from cache' -a info -d 'Inspect cache statistics'"
, "complete -c canontra -n '__fish_seen_subcommand_from cache' -a verify -d 'Verify CRC32 slab page integrity'"
, "complete -c canontra -n '__fish_seen_subcommand_from cache' -a clean -d 'Remove binary cache file'"
, "complete -c canontra -n '__fish_seen_subcommand_from cache' -a prune -d 'Remove orphaned deleted records'"
, ""
, "# Export options"
, "complete -c canontra -n '__fish_seen_subcommand_from export' -s f -l format -x -a 'sarif dot' -d 'Export format'"
, "complete -c canontra -n '__fish_seen_subcommand_from export' -s g -l graph -x -a 'calls cfg dfg' -d 'Graph type for DOT'"
, "complete -c canontra -n '__fish_seen_subcommand_from export' -s o -l output -F -d 'Output file path'"
, "complete -c canontra -n '__fish_seen_subcommand_from export' -s b -l base -F -d 'Baseline file for SARIF diff'"
, ""
, "# Completions options"
, "complete -c canontra -n '__fish_seen_subcommand_from completions' -a 'bash zsh fish powershell' -d 'Target shell'"
]
-- ============================================================================
-- PowerShell Completion Script
-- ============================================================================
powerShellCompletions :: Text
powerShellCompletions = T.unlines
[ "# Canontra Windows PowerShell and PowerShell Core autocompletion script"
, "Register-ArgumentCompleter -Native -CommandName canontra -ScriptBlock {"
, " param($wordToComplete, $commandAst, $cursorPosition)"
, ""
, " $commands = @("
, " [System.Management.Automation.CompletionResult]::new('fp', 'fp', 'ParameterValue', 'Compute deterministic multi-tier fingerprints'),"
, " [System.Management.Automation.CompletionResult]::new('fingerprint', 'fingerprint', 'ParameterValue', 'Alias for fp'),"
, " [System.Management.Automation.CompletionResult]::new('compare', 'compare', 'ParameterValue', 'Compare fingerprints between two files'),"
, " [System.Management.Automation.CompletionResult]::new('diff', 'diff', 'ParameterValue', 'Generate fine-grained structural and semantic diff diagnostics'),"
, " [System.Management.Automation.CompletionResult]::new('graph', 'graph', 'ParameterValue', 'Inspect call graph, CFG, DFG, scope tree, or dependency graph'),"
, " [System.Management.Automation.CompletionResult]::new('verify', 'verify', 'ParameterValue', 'Verify repeat-execution determinism'),"
, " [System.Management.Automation.CompletionResult]::new('repo', 'repo', 'ParameterValue', 'Compute aggregated repository fingerprint'),"
, " [System.Management.Automation.CompletionResult]::new('repository', 'repository', 'ParameterValue', 'Alias for repo'),"
, " [System.Management.Automation.CompletionResult]::new('impact', 'impact', 'ParameterValue', 'Compute fine-grained semantic change impact slice'),"
, " [System.Management.Automation.CompletionResult]::new('slice', 'slice', 'ParameterValue', 'Trace upstream caller slice and downstream dependencies'),"
, " [System.Management.Automation.CompletionResult]::new('watch', 'watch', 'ParameterValue', 'Start live terminal Merkle DAG watcher session'),"
, " [System.Management.Automation.CompletionResult]::new('cache', 'cache', 'ParameterValue', 'Inspect, verify, clean, or prune incremental binary cache'),"
, " [System.Management.Automation.CompletionResult]::new('export', 'export', 'ParameterValue', 'Export diagnostics (SARIF) or graphs (DOT)'),"
, " [System.Management.Automation.CompletionResult]::new('completions', 'completions', 'ParameterValue', 'Generate shell autocompletions'),"
, " [System.Management.Automation.CompletionResult]::new('version', 'version', 'ParameterValue', 'Display engine version')"
, " )"
, ""
, " $elements = $commandAst.CommandElements"
, " if ($elements.Count -le 2) {"
, " $commands | Where-Object { $_.CompletionText -like \"$wordToComplete*\" }"
, " return"
, " }"
, ""
, " $subCommand = $elements[1].Extent.Text"
, " switch ($subCommand) {"
, " 'cache' {"
, " @('info', 'verify', 'clean', 'prune') | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {"
, " [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', \"Cache $_\")"
, " }"
, " }"
, " 'completions' {"
, " @('bash', 'zsh', 'fish', 'powershell') | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {"
, " [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', \"Shell $_\")"
, " }"
, " }"
, " 'export' {"
, " if ($wordToComplete -like '-*') {"
, " @('--format', '-f', '--output', '-o', '--base', '-b', '--graph', '-g', '--help') | Where-Object { $_ -like \"$wordToComplete*\" }"
, " }"
, " }"
, " }"
, "}"
]