blob: 6a09084e0e37b18e06986b278bdd5a0ab68e2858 [file] [log] [blame]
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as pathos;
const _binNameReplacement = '{{binName}}';
const _funcNameReplacement = '{{funcName}}';
/*
* Must be at least one char.
* Must start with a letter or number
* Can contain letters, numbers, '_', '-', '.'
* Must end with letter or number
*/
final _binNameMatch = RegExp(r'^[a-zA-Z0-9]((\w|-|\.)*[a-zA-Z0-9])?$');
/*
* Format for unified bash and zsh completion script:
* https://npmjs.org/
* https://github.com/isaacs/npm/blob/master/lib/utils/completion.sh
*
* Inspiration for auto-generating completion scripts:
* https://github.com/mklabs/node-tabtab
* https://github.com/mklabs/node-tabtab/blob/master/lib/completion.sh
*/
String generateCompletionScript(List<String> binaryNames) {
if (binaryNames.isEmpty) {
throw ArgumentError('Provide the name of at least of one command');
}
for (final binName in binaryNames) {
if (!_binNameMatch.hasMatch(binName)) {
final msg = 'The provided name - "$binName" - is invalid\n'
'It must match regex: ${_binNameMatch.pattern}';
throw StateError(msg);
}
}
final buffer = StringBuffer();
final prefix =
LineSplitter.split(_prefix).map((l) => '# $l'.trim()).join('\n');
buffer..writeln(prefix)..writeln();
for (final binName in binaryNames) {
buffer.writeln(_printBinName(binName));
}
final detailLines = [
'Generated ${DateTime.now().toUtc()}',
];
if (Platform.script.scheme == 'file') {
var scriptPath = Platform.script.toFilePath();
scriptPath = pathos.absolute(pathos.normalize(scriptPath));
detailLines.add('By $scriptPath');
}
final details = detailLines.map((l) => '## $l').join('\n');
buffer.write(details);
return buffer.toString();
}
String _printBinName(String binName) {
final templateContents = _template.replaceAll(_binNameReplacement, binName);
var funcName = binName.replaceAll('.', '_');
funcName = '__${funcName}_completion';
return templateContents.replaceAll(_funcNameReplacement, funcName);
}
const _prefix = '''
Installation:
Via shell config file ~/.bashrc (or ~/.zshrc)
Append the contents to config file
'source' the file in the config file
You may also have a directory on your system that is configured
for completion files, such as:
/usr/local/etc/bash_completion.d/
''';
const _template = r'''
###-begin-{{binName}}-completion-###
if type complete &>/dev/null; then
{{funcName}}() {
local si="$IFS"
IFS=$'\n' COMPREPLY=($(COMP_CWORD="$COMP_CWORD" \
COMP_LINE="$COMP_LINE" \
COMP_POINT="$COMP_POINT" \
{{binName}} completion -- "${COMP_WORDS[@]}" \
2>/dev/null)) || return $?
IFS="$si"
}
complete -F {{funcName}} {{binName}}
elif type compdef &>/dev/null; then
{{funcName}}() {
si=$IFS
compadd -- $(COMP_CWORD=$((CURRENT-1)) \
COMP_LINE=$BUFFER \
COMP_POINT=0 \
{{binName}} completion -- "${words[@]}" \
2>/dev/null)
IFS=$si
}
compdef {{funcName}} {{binName}}
elif type compctl &>/dev/null; then
{{funcName}}() {
local cword line point words si
read -Ac words
read -cn cword
let cword-=1
read -l line
read -ln point
si="$IFS"
IFS=$'\n' reply=($(COMP_CWORD="$cword" \
COMP_LINE="$line" \
COMP_POINT="$point" \
{{binName}} completion -- "${words[@]}" \
2>/dev/null)) || return $?
IFS="$si"
}
compctl -K {{funcName}} {{binName}}
fi
###-end-{{binName}}-completion-###
''';