Skip to content

chore(completion) - generate shell script in a much more automated way #3981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
99b5636
Completion.sh is generated in a much more automated way. It requires…
catull Jan 13, 2017
746e964
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 13, 2017
f9800b7
Merge from master
catull Jan 15, 2017
8045f0e
Now the completion shell script is generated out of TypeScript code e…
catull Jan 15, 2017
cab0460
Work around 100-character line length limit.
catull Jan 18, 2017
e397ff8
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 18, 2017
293e97b
Solution for the redirection. Actually, with the new solution, there…
catull Jan 18, 2017
a459242
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 18, 2017
a4c299c
merge from master
catull Jan 21, 2017
b249f5a
Replace console.log() with this.ui.writeLine().
catull Jan 21, 2017
0f3c82e
Rewrote comkpletion.ts, deeply inspired by help.ts.
catull Jan 22, 2017
3de15a5
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 22, 2017
a56a1ea
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 22, 2017
5c999a2
rawArgs are not used. this.ui.writeLine always prepends ANSI codes i…
catull Jan 22, 2017
4e10a23
Do not consider easter-egg, destroy or github-pages-deploy.
catull Jan 22, 2017
c390dab
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 22, 2017
69d1b55
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 22, 2017
6a840d6
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 23, 2017
443fbed
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 24, 2017
9f7335b
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 27, 2017
da3d31a
Merge from master to test new options of
catull Jan 28, 2017
1739176
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 31, 2017
ed1e303
Resolving review findings.
catull Jan 31, 2017
58a5646
Merge branch 'master' into enhancement-automation-of-completion-script
catull Jan 31, 2017
e322284
Merge branch 'master' into enhancement-automation-of-completion-script
catull Feb 1, 2017
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,19 +285,19 @@ To turn on auto completion use the following commands:

For bash:
```bash
ng completion 1>> ~/.bashrc 2>>&1
ng completion --bash 1>> ~/.bashrc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop the 1 in 1>>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, changed it in completion.ts, too.

source ~/.bashrc
```

For zsh:
```bash
ng completion 1>> ~/.zshrc 2>>&1
ng completion --zsh 1>> ~/.zshrc
source ~/.zshrc
```

Windows users using gitbash:
```bash
ng completion 1>> ~/.bash_profile 2>>&1
ng completion --bash 1>> ~/.bash_profile
source ~/.bash_profile
```

Expand Down
169 changes: 164 additions & 5 deletions packages/angular-cli/commands/completion.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,176 @@
import * as path from 'path';
import * as fs from 'fs';
import * as path from 'path';

const stringUtils = require('ember-cli-string-utils');
const Command = require('../ember-cli/lib/models/command');
const lookupCommand = require('../ember-cli/lib/cli/lookup-command');

function extractOptions(opts: any): String {
const output: String[] = [];

for (let index = 0; index < opts.length; index++) {
const element = opts[index];
output.push('--' + element.name);
if (element.aliases) {
output.push('-' + element.aliases[0]);
}
}

return output.sort().join(' ');
}

export interface CompletionCommandOptions {
all?: boolean;
bash?: boolean;
zsh?: boolean;
};

const commandsToIgnore = [
'easter-egg',
'destroy',
'github-pages-deploy' // errors because there is no base github-pages command
];

const optsNg: String[] = [];

const CompletionCommand = Command.extend({
name: 'completion',
description: 'Adds autocomplete functionality to `ng` commands and subcommands',
works: 'everywhere',
run: function() {
const scriptPath = path.resolve(__dirname, '..', 'utilities', 'completion.sh');
const scriptOutput = fs.readFileSync(scriptPath, 'utf8');
availableOptions: [
{ name: 'all', type: Boolean, default: true, aliases: ['a'] },
{ name: 'bash', type: Boolean, default: false, aliases: ['b'] },
{ name: 'zsh', type: Boolean, default: false, aliases: ['z'] }
],

run: function (commandOptions: CompletionCommandOptions) {
commandOptions.all = !commandOptions.bash && !commandOptions.zsh;

const commandFiles = fs.readdirSync(__dirname)
.filter(file => file.match(/\.ts$/) && !file.match(/\.run.ts$/))
.map(file => path.parse(file).name)
.filter(file => {
return commandsToIgnore.indexOf(file) < 0;
})
.map(file => file.toLowerCase());

const commandMap = commandFiles.reduce((acc: any, curr: string) => {
let classifiedName = stringUtils.classify(curr);
let defaultImport = require(`./${curr}`).default;

acc[classifiedName] = defaultImport;

return acc;
}, {});

let caseBlock = '';

commandFiles.forEach(cmd => {
const Command = lookupCommand(commandMap, cmd);
const com: String[] = [];

const command = new Command({
ui: this.ui,
project: this.project,
commands: this.commands,
tasks: this.tasks
});

optsNg.push(command.name);
com.push(command.name);

if (command.aliases) {
command.aliases.forEach((element: String) => {
optsNg.push(element);
com.push(element);
});
}

if (command.availableOptions && command.availableOptions[0]) {
let opts = extractOptions (command.availableOptions);
caseBlock = caseBlock + ' ' + com.sort().join('|') + ') opts="' + opts + '" ;;\n';
}
});

caseBlock = 'ng|help) opts="' + optsNg.sort().join(' ') + '" ;;\n' +
caseBlock +
' *) opts="" ;;';

console.log(`###-begin-ng-completion###
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use stripIndent from common-tags and indent the whole string? Look at other places where we use it for an example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

#

# ng command completion script
# This command supports 3 cases.
# 1. (Default case) It prints a common completion initialisation for both Bash and Zsh.
# It is the result of either calling "ng completion" or "ng completion -a".
# 2. Produce Bash-only completion: "ng completion -b" or "ng completion --bash".
# 3. Produce Zsh-only completion: "ng completion -z" or "ng completion --zsh".
#
# Installation: ng completion -b 1>> ~/.bashrc
# or ng completion -z 1>> ~/.zshrc
#
`);

if (commandOptions.all && !commandOptions.bash) {
console.log('if test ".$(type -t complete 2>/dev/null || true)" = ".builtin"; then');
}

if (commandOptions.all || commandOptions.bash) {
console.log(`_ng_completion() {
local cword pword opts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here; use stripIndent so we keep the indentation in the code (I don't care much about the generated files).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, too.


COMPREPLY=()
cword=\${COMP_WORDS[COMP_CWORD]}
pword=\${COMP_WORDS[COMP_CWORD - 1]}

case \${pword} in
${caseBlock}
esac

COMPREPLY=( $(compgen -W '\${opts}' -- $cword) )

return 0
}

complete -o default -F _ng_completion ng
`);
}

if (commandOptions.all) {
console.log(
'elif test ".$(type -w compctl 2>/dev/null || true)" = ".compctl: builtin" ; then');
}

if (commandOptions.all || commandOptions.zsh) {
console.log(`_ng_completion () {
local words cword opts
read -Ac words
read -cn cword
let cword-=1

case $words[cword] in
${caseBlock}
esac

setopt shwordsplit
reply=($opts)
unset shwordsplit
}

compctl -K _ng_completion ng
`);
}

if (commandOptions.all) {
console.log(`else
echo "Shell builtin command 'complete' or 'compctl' is redefined; cannot perform ng completion."
return 1
fi
`);
}

console.log('###-end-ng-completion###');

console.log(scriptOutput);
}
});

Expand Down
85 changes: 0 additions & 85 deletions packages/angular-cli/utilities/completion.sh

This file was deleted.