From 9a8289f1f9ff1ff3588e09d06a7192c4d1500ce7 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 14:45:05 +0100 Subject: [PATCH 01/14] refactor: used RootCommand and ScriptEntry --- lib/installer.dart | 4 +- .../installer/completion_installation.dart | 145 +++++++----------- lib/src/installer/installer.dart | 5 + lib/src/installer/root_command.dart | 42 +++++ lib/src/installer/script_entry.dart | 50 ++++++ .../shell_completion_configuration.dart | 21 +++ 6 files changed, 175 insertions(+), 92 deletions(-) create mode 100644 lib/src/installer/installer.dart create mode 100644 lib/src/installer/root_command.dart create mode 100644 lib/src/installer/script_entry.dart diff --git a/lib/installer.dart b/lib/installer.dart index fe5ee55..d34b03a 100644 --- a/lib/installer.dart +++ b/lib/installer.dart @@ -2,7 +2,5 @@ /// {@canonicalFor system_shell.SystemShell} library installer; -export 'src/installer/completion_installation.dart'; -export 'src/installer/exceptions.dart'; -export 'src/installer/shell_completion_configuration.dart'; +export 'src/installer/installer.dart'; export 'src/system_shell.dart'; diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index 5f6064f..508ca6e 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -65,6 +65,7 @@ class CompletionInstallation { /// shell. It is null if the current shell is unknown. final ShellCompletionConfiguration? configuration; + /// {@template completion_config_dir} /// Define the [Directory] in which the /// completion configuration files will be stored. /// @@ -73,6 +74,7 @@ class CompletionInstallation { /// /// If [isWindows] is false, it will return the directory defined by /// $XDG_CONFIG_HOME/.dart_cli_completion or $HOME/.dart_cli_completion + /// {@endtemplate} @visibleForTesting Directory get completionConfigDir { if (isWindows) { @@ -112,8 +114,7 @@ class CompletionInstallation { } logger.detail( - 'Installing completion for the command $rootCommand ' - 'on ${configuration.name}', + '''Installing completion for the command $rootCommand on ${configuration.name}''', ); createCompletionConfigDir(); @@ -135,8 +136,7 @@ class CompletionInstallation { final completionConfigDirPath = completionConfigDir.path; logger.info( - 'Creating completion configuration directory ' - 'at $completionConfigDirPath', + '''Creating completion configuration directory at $completionConfigDirPath''', ); if (completionConfigDir.existsSync()) { @@ -163,28 +163,24 @@ class CompletionInstallation { @visibleForTesting bool writeCompletionScriptForCommand(String rootCommand) { final configuration = this.configuration!; - final completionConfigDirPath = completionConfigDir.path; - final commandScriptName = '$rootCommand.${configuration.name}'; - final commandScriptPath = path.join( - completionConfigDirPath, - commandScriptName, - ); + final rootCommandScriptFile = RootCommand( + name: rootCommand, + shellName: configuration.name, + ).commandScriptFile(completionConfigDir); + logger.info( - 'Writing completion script for $rootCommand on $commandScriptPath', + '''Writing completion script for $rootCommand on ${rootCommandScriptFile.path}''', ); - - final scriptFile = File(commandScriptPath); - - if (scriptFile.existsSync()) { + if (rootCommandScriptFile.existsSync()) { logger.warn( - 'A script file for $rootCommand was already found on ' - '$commandScriptPath.', + '''A script file for $rootCommand was already found on ${rootCommandScriptFile.path}''', ); return false; } - scriptFile.writeAsStringSync(configuration.scriptTemplate(rootCommand)); - + rootCommandScriptFile.writeAsStringSync( + configuration.scriptTemplate(rootCommand), + ); return true; } @@ -193,37 +189,42 @@ class CompletionInstallation { @visibleForTesting void writeCompletionConfigForShell(String rootCommand) { final configuration = this.configuration!; - final completionConfigDirPath = completionConfigDir.path; + final completionConfig = + configuration.completionScriptFile(completionConfigDir); - final configPath = path.join( - completionConfigDirPath, - configuration.completionConfigForShellFileName, + logger.info( + '''Adding config for $rootCommand config entry to ${completionConfig.path}''', ); - logger.info('Adding config for $rootCommand config entry to $configPath'); - - final configFile = File(configPath); - if (!configFile.existsSync()) { - logger.info('No file found at $configPath, creating one now'); - configFile.createSync(); + if (!completionConfig.existsSync()) { + logger.info( + '''No file found at ${completionConfig.path}, creating one now''', + ); + completionConfig.createSync(); } - final commandScriptName = '$rootCommand.${configuration.name}'; - final containsLine = - configFile.readAsStringSync().contains(commandScriptName); + final command = RootCommand( + name: rootCommand, + shellName: configuration.name, + ); + final commandEntry = command.entry; - if (containsLine) { + if (commandEntry.existsIn(completionConfig)) { logger.warn( - 'A config entry for $rootCommand was already found on $configPath.', + '''A config entry for $rootCommand was already found on ${completionConfig.path}.''', ); return; } - _sourceScriptOnFile( - configFile: configFile, - scriptName: rootCommand, - scriptPath: path.join(completionConfigDirPath, commandScriptName), - ); + final rootCommandScriptFile = + command.commandScriptFile(completionConfigDir); + // TODO(alestiago): Use a template function to create the content. + final content = ''' +## {Completion config for "$rootCommand" +${configuration.sourceLineTemplate(rootCommandScriptFile.path)} +'''; + commandEntry.appendTo(completionConfig, content: content); + logger.info('Added config to ${completionConfig.path}'); } String get _shellRCFilePath => @@ -236,19 +237,13 @@ class CompletionInstallation { final configuration = this.configuration!; logger.info( - 'Adding dart cli completion config entry ' - 'to $_shellRCFilePath', + '''Adding dart cli completion config entry to $_shellRCFilePath''', ); - final completionConfigDirPath = completionConfigDir.path; - - final completionConfigPath = path.join( - completionConfigDirPath, - configuration.completionConfigForShellFileName, - ); + final shellCompletionConfigFile = + configuration.completionScriptFile(completionConfigDir); final shellRCFile = File(_shellRCFilePath); - if (!shellRCFile.existsSync()) { throw CompletionInstallationException( rootCommand: rootCommand, @@ -257,24 +252,25 @@ class CompletionInstallation { } final containsLine = - shellRCFile.readAsStringSync().contains(completionConfigPath); + shellRCFile.readAsStringSync().contains(shellCompletionConfigFile.path); if (containsLine) { - logger.warn('A completion config entry was already found on' - ' $_shellRCFilePath.'); + logger.warn( + '''A completion config entry was already found on $_shellRCFilePath''', + ); return; } - _sourceScriptOnFile( - configFile: shellRCFile, - scriptName: 'Completion', - description: 'Completion scripts setup. ' - 'Remove the following line to uninstall', - scriptPath: path.join( - completionConfigDir.path, - configuration.completionConfigForShellFileName, - ), + // TODO(alestiago): Define a template function instead. + final content = ''' +Completion scripts setup. Remove the following line to uninstall. +${configuration.sourceLineTemplate(shellCompletionConfigFile.path)} +'''; + const ScriptEntry('Completion').appendTo( + shellRCFile, + content: content, ); + logger.info('Added config to ${shellRCFile.path}'); } /// Tells the user to source the shell configuration file. @@ -291,35 +287,6 @@ class CompletionInstallation { ) ..level = level; } - - void _sourceScriptOnFile({ - required File configFile, - required String scriptName, - required String scriptPath, - String? description, - }) { - assert( - configFile.existsSync(), - 'Sourcing a script line into an nonexistent config file.', - ); - - final configFilePath = configFile.path; - - description ??= 'Completion config for "$scriptName"'; - - configFile.writeAsStringSync( - mode: FileMode.append, - ''' -\n## [$scriptName] -## $description -${configuration!.sourceLineTemplate(scriptPath)} -## [/$scriptName] - -''', - ); - - logger.info('Added config to $configFilePath'); - } } /// Resolve the home from a path string diff --git a/lib/src/installer/installer.dart b/lib/src/installer/installer.dart new file mode 100644 index 0000000..adfc4e4 --- /dev/null +++ b/lib/src/installer/installer.dart @@ -0,0 +1,5 @@ +export 'completion_installation.dart'; +export 'exceptions.dart'; +export 'root_command.dart'; +export 'script_entry.dart'; +export 'shell_completion_configuration.dart'; diff --git a/lib/src/installer/root_command.dart b/lib/src/installer/root_command.dart new file mode 100644 index 0000000..4f37c19 --- /dev/null +++ b/lib/src/installer/root_command.dart @@ -0,0 +1,42 @@ +import 'dart:io'; +import 'package:cli_completion/installer.dart'; +import 'package:path/path.dart' as path; + +/// {@template root_command} +/// A root command with [name] that has been ran in [shellName]. +/// {@endtemplate} +class RootCommand { + /// {@macro root_command} + const RootCommand({ + required this.name, + required this.shellName, + }); + + /// The root name of the command. + /// + /// For example the name would be `flutter` given `flutter create`. + final String name; + + /// {@macro shell_name} + /// + /// Indicates where this [RootCommand] originated from. + final String shellName; + + /// The command script file for this [RootCommand]. + /// + /// A completion script file contains the completion script for a specific + /// command and shell. + /// + /// The [completionConfigDir] denotes where the completion script file for + /// this [RootCommand] should be located. + File commandScriptFile(Directory completionConfigDir) { + final commandScriptPath = path.join( + completionConfigDir.path, + '$name.$shellName', + ); + return File(commandScriptPath); + } + + /// A script entry for this [RootCommand]. + ScriptEntry get entry => ScriptEntry(name); +} diff --git a/lib/src/installer/script_entry.dart b/lib/src/installer/script_entry.dart new file mode 100644 index 0000000..585aba7 --- /dev/null +++ b/lib/src/installer/script_entry.dart @@ -0,0 +1,50 @@ +import 'dart:io'; + +/// {@template script_entry} +/// A script entry is a section of a file that is starts with [startComment] +/// and ends with [endComment]. +/// {@endtemplate} +class ScriptEntry { + /// {@macro script_entry} + const ScriptEntry(this.name); + + /// The name of the entry. + final String name; + + /// The start comment of the entry. + String get startComment => '\n## [$name]'; + + /// The end comment of the entry. + String get endComment => '## [/$name]\n'; + + /// Whether there is an entry with [name] in [file]. + /// + /// If the [file] does not exist, this will return false. + bool existsIn(File file) { + if (!file.existsSync()) return false; + final content = file.readAsStringSync(); + // TODO(alestiago): Refine logic with regular expressions. + return content.contains(startComment) && content.contains(endComment); + } + + /// Adds an entry with [name] to the end of the [file]. + /// + /// If the [file] does not exist, it will be created. + /// + /// If [content] is not null, it will be added within the entry. + void appendTo(File file, {String? content}) { + if (!file.existsSync()) { + file.createSync(recursive: true); + } + + final entry = StringBuffer() + ..writeln(startComment) + ..writeln(content) + ..writeln(endComment); + + file.writeAsStringSync( + entry.toString(), + mode: FileMode.append, + ); + } +} diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index e028a13..edf1bfe 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -1,6 +1,10 @@ +import 'dart:io'; + import 'package:cli_completion/installer.dart'; import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; + /// A type definition for functions that creates the content of a /// completion script given a [rootCommand] typedef CompletionScriptTemplate = String Function(String rootCommand); @@ -38,7 +42,9 @@ class ShellCompletionConfiguration { } } + /// {@template shell_name} /// A descriptive string to identify the shell among others. + /// {@endtemplate} final String name; /// The location of a config file that is run upon shell start. @@ -53,6 +59,21 @@ class ShellCompletionConfiguration { /// The name for the config file for this shell. String get completionConfigForShellFileName => '$name-config.$name'; + + /// The configuration file for this shell. + /// + /// A configuration file for this shell is a barrel file that sources + /// the completion script for [RootCommand]s. + /// + /// The [completionConfigDir] denotes where the completion script file + /// should be located. + File completionScriptFile(Directory completionConfigDir) { + final commandScriptPath = path.join( + completionConfigDir.path, + '$name-config.$name', + ); + return File(commandScriptPath); + } } /// A [ShellCompletionConfiguration] for zsh. From 3c94a729a142dc411ede71a3d96c6ccf17a76433 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 14:54:04 +0100 Subject: [PATCH 02/14] feat: ammended output --- lib/src/installer/completion_installation.dart | 10 ++++------ lib/src/installer/script_entry.dart | 6 +++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index 508ca6e..aaa088d 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -220,9 +220,8 @@ class CompletionInstallation { command.commandScriptFile(completionConfigDir); // TODO(alestiago): Use a template function to create the content. final content = ''' -## {Completion config for "$rootCommand" -${configuration.sourceLineTemplate(rootCommandScriptFile.path)} -'''; +## Completion config for "$rootCommand" +${configuration.sourceLineTemplate(rootCommandScriptFile.path)}'''; commandEntry.appendTo(completionConfig, content: content); logger.info('Added config to ${completionConfig.path}'); } @@ -263,9 +262,8 @@ ${configuration.sourceLineTemplate(rootCommandScriptFile.path)} // TODO(alestiago): Define a template function instead. final content = ''' -Completion scripts setup. Remove the following line to uninstall. -${configuration.sourceLineTemplate(shellCompletionConfigFile.path)} -'''; +## Completion scripts setup. Remove the following line to uninstall +${configuration.sourceLineTemplate(shellCompletionConfigFile.path)}'''; const ScriptEntry('Completion').appendTo( shellRCFile, content: content, diff --git a/lib/src/installer/script_entry.dart b/lib/src/installer/script_entry.dart index 585aba7..b699b77 100644 --- a/lib/src/installer/script_entry.dart +++ b/lib/src/installer/script_entry.dart @@ -12,10 +12,10 @@ class ScriptEntry { final String name; /// The start comment of the entry. - String get startComment => '\n## [$name]'; + String get startComment => '\n## [$name] '; /// The end comment of the entry. - String get endComment => '## [/$name]\n'; + String get endComment => '\n## [/$name]\n'; /// Whether there is an entry with [name] in [file]. /// @@ -39,7 +39,7 @@ class ScriptEntry { final entry = StringBuffer() ..writeln(startComment) - ..writeln(content) + ..write(content) ..writeln(endComment); file.writeAsStringSync( From b0368618425dd260f8c500af50634f9ae9e35763 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:08:28 +0100 Subject: [PATCH 03/14] docs: documentation changes --- lib/src/installer/root_command.dart | 4 +++- lib/src/installer/script_entry.dart | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/installer/root_command.dart b/lib/src/installer/root_command.dart index 4f37c19..c097a5d 100644 --- a/lib/src/installer/root_command.dart +++ b/lib/src/installer/root_command.dart @@ -14,7 +14,9 @@ class RootCommand { /// The root name of the command. /// - /// For example the name would be `flutter` given `flutter create`. + /// For example: + /// - The name would be `flutter` given `flutter create`. + /// - The name would be `git` given `git commit`. final String name; /// {@macro shell_name} diff --git a/lib/src/installer/script_entry.dart b/lib/src/installer/script_entry.dart index b699b77..1e45f15 100644 --- a/lib/src/installer/script_entry.dart +++ b/lib/src/installer/script_entry.dart @@ -1,8 +1,8 @@ import 'dart:io'; /// {@template script_entry} -/// A script entry is a section of a file that is starts with [startComment] -/// and ends with [endComment]. +/// A script entry is a section of a file that starts with [startComment] and +/// ends with [endComment]. /// {@endtemplate} class ScriptEntry { /// {@macro script_entry} From 0540be762503a7ab997383da2af2de9a852c7fb3 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:10:18 +0100 Subject: [PATCH 04/14] docs: added TODO --- lib/src/installer/shell_completion_configuration.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index edf1bfe..1c7f806 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -58,6 +58,8 @@ class ShellCompletionConfiguration { final CompletionScriptTemplate scriptTemplate; /// The name for the config file for this shell. + // TODO(alestiago): Remove this getter in favour of [completionScriptFile] and + // then using path to extract the name. String get completionConfigForShellFileName => '$name-config.$name'; /// The configuration file for this shell. From c37dbe8bf681078e5c6a54e334358e322cfcb98e Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:17:47 +0100 Subject: [PATCH 05/14] refactor: renamed rootCommand to executable --- .../installer/completion_installation.dart | 75 ++++++++++--------- lib/src/installer/exceptions.dart | 10 +-- .../{root_command.dart => executable.dart} | 20 ++--- lib/src/installer/installer.dart | 2 +- .../shell_completion_configuration.dart | 2 +- .../completion_command_runner_test.dart | 3 +- .../completion_installation_test.dart | 5 +- 7 files changed, 60 insertions(+), 57 deletions(-) rename lib/src/installer/{root_command.dart => executable.dart} (64%) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index aaa088d..2c42bbd 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -92,38 +92,39 @@ class CompletionInstallation { } } - /// Install completion configuration files for a [rootCommand] in the + /// Install completion configuration files for a [executableName] in the /// current shell. /// /// It will create: /// - A completion script file in [completionConfigDir] that is named after - /// the [rootCommand] and the current shell (e.g. `very_good.bash`). + /// the [executableName] and the current shell (e.g. `very_good.bash`). /// - A config file in [completionConfigDir] that is named after the current /// shell (e.g. `bash-config.bash`) that sources the aforementioned /// completion script file. /// - A line in the shell config file (e.g. `.bash_profile`) that sources /// the aforementioned config file. - void install(String rootCommand) { + void install(String executableName) { final configuration = this.configuration; if (configuration == null) { throw CompletionInstallationException( message: 'Unknown shell.', - rootCommand: rootCommand, + executableName: executableName, ); } logger.detail( - '''Installing completion for the command $rootCommand on ${configuration.name}''', + '''Installing completion for the command $executableName on ${configuration.name}''', ); createCompletionConfigDir(); - final completionFileCreated = writeCompletionScriptForCommand(rootCommand); - writeCompletionConfigForShell(rootCommand); - writeToShellConfigFile(rootCommand); + final completionFileCreated = + writeCompletionScriptForExecutable(executableName); + writeCompletionConfigForShell(executableName); + writeToShellConfigFile(executableName); if (completionFileCreated) { - _logSourceInstructions(rootCommand); + _logSourceInstructions(executableName); } } @@ -149,10 +150,10 @@ class CompletionInstallation { completionConfigDir.createSync(); } - /// Creates a configuration file exclusively to [rootCommand] and the + /// Creates a configuration file exclusively to [executableName] and the /// identified shell. /// - /// The file will be named after the [rootCommand] and the current shell + /// The file will be named after the [executableName] and the current shell /// (e.g. `very_good.bash`). /// /// The file will be created in [completionConfigDir]. @@ -161,39 +162,39 @@ class CompletionInstallation { /// /// Returns true if the file was created, false otherwise. @visibleForTesting - bool writeCompletionScriptForCommand(String rootCommand) { + bool writeCompletionScriptForExecutable(String executableName) { final configuration = this.configuration!; - final rootCommandScriptFile = RootCommand( - name: rootCommand, + final executableCompletionScriptFile = Executable( + name: executableName, shellName: configuration.name, - ).commandScriptFile(completionConfigDir); + ).completionScriptFile(completionConfigDir); logger.info( - '''Writing completion script for $rootCommand on ${rootCommandScriptFile.path}''', + '''Writing completion script for $executableName on ${executableCompletionScriptFile.path}''', ); - if (rootCommandScriptFile.existsSync()) { + if (executableCompletionScriptFile.existsSync()) { logger.warn( - '''A script file for $rootCommand was already found on ${rootCommandScriptFile.path}''', + '''A script file for $executableName was already found on ${executableCompletionScriptFile.path}''', ); return false; } - rootCommandScriptFile.writeAsStringSync( - configuration.scriptTemplate(rootCommand), + executableCompletionScriptFile.writeAsStringSync( + configuration.scriptTemplate(executableName), ); return true; } - /// Adds a reference for the command-specific config file created on - /// [writeCompletionScriptForCommand] the the global completion config file. + /// Adds a reference for the executable-specific config file created on + /// [writeCompletionScriptForExecutable] the the global completion config file. @visibleForTesting - void writeCompletionConfigForShell(String rootCommand) { + void writeCompletionConfigForShell(String executableName) { final configuration = this.configuration!; final completionConfig = configuration.completionScriptFile(completionConfigDir); logger.info( - '''Adding config for $rootCommand config entry to ${completionConfig.path}''', + '''Adding config for $executableName config entry to ${completionConfig.path}''', ); if (!completionConfig.existsSync()) { @@ -203,26 +204,26 @@ class CompletionInstallation { completionConfig.createSync(); } - final command = RootCommand( - name: rootCommand, + final executable = Executable( + name: executableName, shellName: configuration.name, ); - final commandEntry = command.entry; + final executableEntry = executable.entry; - if (commandEntry.existsIn(completionConfig)) { + if (executableEntry.existsIn(completionConfig)) { logger.warn( - '''A config entry for $rootCommand was already found on ${completionConfig.path}.''', + '''A config entry for $executableName was already found on ${completionConfig.path}.''', ); return; } - final rootCommandScriptFile = - command.commandScriptFile(completionConfigDir); + final executableScriptFile = + executable.completionScriptFile(completionConfigDir); // TODO(alestiago): Use a template function to create the content. final content = ''' -## Completion config for "$rootCommand" -${configuration.sourceLineTemplate(rootCommandScriptFile.path)}'''; - commandEntry.appendTo(completionConfig, content: content); +## Completion config for "$executableName" +${configuration.sourceLineTemplate(executableScriptFile.path)}'''; + executableEntry.appendTo(completionConfig, content: content); logger.info('Added config to ${completionConfig.path}'); } @@ -232,7 +233,7 @@ ${configuration.sourceLineTemplate(rootCommandScriptFile.path)}'''; /// Write a source to the completion global script in the shell configuration /// file, which its location is described by the [configuration]. @visibleForTesting - void writeToShellConfigFile(String rootCommand) { + void writeToShellConfigFile(String executableName) { final configuration = this.configuration!; logger.info( @@ -245,7 +246,7 @@ ${configuration.sourceLineTemplate(rootCommandScriptFile.path)}'''; final shellRCFile = File(_shellRCFilePath); if (!shellRCFile.existsSync()) { throw CompletionInstallationException( - rootCommand: rootCommand, + executableName: executableName, message: 'No configuration file found at ${shellRCFile.path}', ); } @@ -272,7 +273,7 @@ ${configuration.sourceLineTemplate(shellCompletionConfigFile.path)}'''; } /// Tells the user to source the shell configuration file. - void _logSourceInstructions(String rootCommand) { + void _logSourceInstructions(String executableName) { final level = logger.level; logger ..level = Level.info diff --git a/lib/src/installer/exceptions.dart b/lib/src/installer/exceptions.dart index 06106b1..7236b3d 100644 --- a/lib/src/installer/exceptions.dart +++ b/lib/src/installer/exceptions.dart @@ -5,16 +5,16 @@ class CompletionInstallationException implements Exception { /// {@macro completion_installation_exception} CompletionInstallationException({ required this.message, - required this.rootCommand, + required this.executableName, }); /// The error message for this exception final String message; - /// The command for which the installation failed. - final String rootCommand; + /// The executable name for which the installation failed. + final String executableName; @override - String toString() => 'Could not install completion scripts for $rootCommand: ' - '$message'; + String toString() => + '''Could not install completion scripts for $executableName: $message'''; } diff --git a/lib/src/installer/root_command.dart b/lib/src/installer/executable.dart similarity index 64% rename from lib/src/installer/root_command.dart rename to lib/src/installer/executable.dart index c097a5d..65bc104 100644 --- a/lib/src/installer/root_command.dart +++ b/lib/src/installer/executable.dart @@ -5,33 +5,33 @@ import 'package:path/path.dart' as path; /// {@template root_command} /// A root command with [name] that has been ran in [shellName]. /// {@endtemplate} -class RootCommand { +class Executable { /// {@macro root_command} - const RootCommand({ + const Executable({ required this.name, required this.shellName, }); - /// The root name of the command. + /// The name of the executable. /// /// For example: - /// - The name would be `flutter` given `flutter create`. - /// - The name would be `git` given `git commit`. + /// - `flutter` given `flutter create`. + /// - `git` given `git commit`. final String name; /// {@macro shell_name} /// - /// Indicates where this [RootCommand] originated from. + /// Indicates where this [Executable] originated from. final String shellName; - /// The command script file for this [RootCommand]. + /// The completion script file for this [Executable]. /// /// A completion script file contains the completion script for a specific /// command and shell. /// /// The [completionConfigDir] denotes where the completion script file for - /// this [RootCommand] should be located. - File commandScriptFile(Directory completionConfigDir) { + /// this [Executable] should be located. + File completionScriptFile(Directory completionConfigDir) { final commandScriptPath = path.join( completionConfigDir.path, '$name.$shellName', @@ -39,6 +39,6 @@ class RootCommand { return File(commandScriptPath); } - /// A script entry for this [RootCommand]. + /// A script entry for this [Executable]. ScriptEntry get entry => ScriptEntry(name); } diff --git a/lib/src/installer/installer.dart b/lib/src/installer/installer.dart index adfc4e4..ad3422c 100644 --- a/lib/src/installer/installer.dart +++ b/lib/src/installer/installer.dart @@ -1,5 +1,5 @@ export 'completion_installation.dart'; export 'exceptions.dart'; -export 'root_command.dart'; +export 'executable.dart'; export 'script_entry.dart'; export 'shell_completion_configuration.dart'; diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index 1c7f806..1298d74 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -65,7 +65,7 @@ class ShellCompletionConfiguration { /// The configuration file for this shell. /// /// A configuration file for this shell is a barrel file that sources - /// the completion script for [RootCommand]s. + /// the completion script for [Executable]s. /// /// The [completionConfigDir] denotes where the completion script file /// should be located. diff --git a/test/src/command_runner/completion_command_runner_test.dart b/test/src/command_runner/completion_command_runner_test.dart index 982b8aa..859c03d 100644 --- a/test/src/command_runner/completion_command_runner_test.dart +++ b/test/src/command_runner/completion_command_runner_test.dart @@ -154,7 +154,8 @@ void main() { when( () => commandRunner.completionInstallation.install('test'), ).thenThrow( - CompletionInstallationException(message: 'oops', rootCommand: 'test'), + CompletionInstallationException( + message: 'oops', executableName: 'test'), ); await commandRunner.run(['ahoy']); diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index c57307c..de7fb30 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -166,7 +166,8 @@ void main() { expect(configFile.existsSync(), false); installation.createCompletionConfigDir(); - var result = installation.writeCompletionScriptForCommand('very_good'); + var result = + installation.writeCompletionScriptForExecutable('very_good'); expect(configFile.existsSync(), true); expect(result, true); @@ -186,7 +187,7 @@ void main() { ), ); - result = installation.writeCompletionScriptForCommand('very_good'); + result = installation.writeCompletionScriptForExecutable('very_good'); expect(result, false); From 117e2b1f8a89d3ec8f05e722de6ded20993859d2 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:19:29 +0100 Subject: [PATCH 06/14] docs: executable docs --- lib/src/installer/executable.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/installer/executable.dart b/lib/src/installer/executable.dart index 65bc104..aa09989 100644 --- a/lib/src/installer/executable.dart +++ b/lib/src/installer/executable.dart @@ -3,7 +3,7 @@ import 'package:cli_completion/installer.dart'; import 'package:path/path.dart' as path; /// {@template root_command} -/// A root command with [name] that has been ran in [shellName]. +/// An executable that originated from [shellName]. /// {@endtemplate} class Executable { /// {@macro root_command} From 42795c9953cb60abe5f1b8e5341ad8e5bf4f7250 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:21:42 +0100 Subject: [PATCH 07/14] docs: improved executable docs --- lib/src/installer/executable.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/installer/executable.dart b/lib/src/installer/executable.dart index aa09989..29d89da 100644 --- a/lib/src/installer/executable.dart +++ b/lib/src/installer/executable.dart @@ -27,7 +27,7 @@ class Executable { /// The completion script file for this [Executable]. /// /// A completion script file contains the completion script for a specific - /// command and shell. + /// executable and shell. /// /// The [completionConfigDir] denotes where the completion script file for /// this [Executable] should be located. From 9fce2e25784d6d9e8e6512664f44fef00ae36414 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:30:46 +0100 Subject: [PATCH 08/14] chore: analzyer issues --- lib/src/installer/completion_installation.dart | 3 ++- test/src/command_runner/completion_command_runner_test.dart | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index 2c42bbd..bf62dfb 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -186,7 +186,8 @@ class CompletionInstallation { } /// Adds a reference for the executable-specific config file created on - /// [writeCompletionScriptForExecutable] the the global completion config file. + /// [writeCompletionScriptForExecutable] the the global completion config + /// file. @visibleForTesting void writeCompletionConfigForShell(String executableName) { final configuration = this.configuration!; diff --git a/test/src/command_runner/completion_command_runner_test.dart b/test/src/command_runner/completion_command_runner_test.dart index 859c03d..2959280 100644 --- a/test/src/command_runner/completion_command_runner_test.dart +++ b/test/src/command_runner/completion_command_runner_test.dart @@ -155,7 +155,9 @@ void main() { () => commandRunner.completionInstallation.install('test'), ).thenThrow( CompletionInstallationException( - message: 'oops', executableName: 'test'), + message: 'oops', + executableName: 'test', + ), ); await commandRunner.run(['ahoy']); From 666b7d65105e0149aa673b64fda452c908726d9f Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:33:05 +0100 Subject: [PATCH 09/14] docs: todo comment --- lib/src/installer/executable.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/installer/executable.dart b/lib/src/installer/executable.dart index 29d89da..a2bb9f9 100644 --- a/lib/src/installer/executable.dart +++ b/lib/src/installer/executable.dart @@ -22,6 +22,7 @@ class Executable { /// {@macro shell_name} /// /// Indicates where this [Executable] originated from. + // TODO(alestiago): Consider removing this member from [Executable]. final String shellName; /// The completion script file for this [Executable]. From 7f463359a9bb0188b36507e7732206ffb35770da Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:34:32 +0100 Subject: [PATCH 10/14] docs: todo comment --- lib/src/installer/script_entry.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/installer/script_entry.dart b/lib/src/installer/script_entry.dart index 1e45f15..3f4eb23 100644 --- a/lib/src/installer/script_entry.dart +++ b/lib/src/installer/script_entry.dart @@ -32,6 +32,7 @@ class ScriptEntry { /// If the [file] does not exist, it will be created. /// /// If [content] is not null, it will be added within the entry. + // TODO(alestiago): Consider having content as a member of the class. void appendTo(File file, {String? content}) { if (!file.existsSync()) { file.createSync(recursive: true); From b79867627bec01a034aeb86a3ec128bb60c9a9aa Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 15:35:24 +0100 Subject: [PATCH 11/14] test: added fixme comment --- test/src/installer/completion_installation_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/installer/completion_installation_test.dart b/test/src/installer/completion_installation_test.dart index de7fb30..d2aab3a 100644 --- a/test/src/installer/completion_installation_test.dart +++ b/test/src/installer/completion_installation_test.dart @@ -298,6 +298,7 @@ void main() { test( 'installing completion for a command when it is already installed', () { + // FIXME(alestiago): Look into this test failure. final installation = CompletionInstallation( logger: logger, isWindows: false, From 2f5ccadce6eebdf34ca86945207cc7a80d0b53f7 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 18:32:39 +0100 Subject: [PATCH 12/14] refactor: removed completionConfigForShellFileName --- .../shell_completion_configuration.dart | 5 --- .../shell_completion_configuration_test.dart | 38 ++++++++++++++----- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index 1298d74..c36bf7c 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -57,11 +57,6 @@ class ShellCompletionConfiguration { /// Generates the contents of a completion script. final CompletionScriptTemplate scriptTemplate; - /// The name for the config file for this shell. - // TODO(alestiago): Remove this getter in favour of [completionScriptFile] and - // then using path to extract the name. - String get completionConfigForShellFileName => '$name-config.$name'; - /// The configuration file for this shell. /// /// A configuration file for this shell is a barrel file that sources diff --git a/test/src/installer/shell_completion_configuration_test.dart b/test/src/installer/shell_completion_configuration_test.dart index 9778690..71bfab4 100644 --- a/test/src/installer/shell_completion_configuration_test.dart +++ b/test/src/installer/shell_completion_configuration_test.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:cli_completion/installer.dart'; +import 'package:path/path.dart' as path; import 'package:test/test.dart'; void main() { @@ -46,11 +49,18 @@ fi '''); }); - test('completionConfigForShellFileName', () { - expect( - zshConfiguration.completionConfigForShellFileName, - 'zsh-config.zsh', - ); + group('completionScriptFile', () { + test('name is valid', () { + final file = zshConfiguration.completionScriptFile(Directory('/tmp')); + expect(path.basename(file.path), 'zsh-config.zsh'); + }); + + test('path is relative to directory', () { + final directory = Directory('/tmp'); + final file = zshConfiguration.completionScriptFile(directory); + final expectedPath = path.join(directory.path, 'zsh-config.zsh'); + expect(file.path, expectedPath); + }); }); }); @@ -103,11 +113,19 @@ fi '''); }); - test('completionConfigForShellFileName', () { - expect( - bashConfiguration.completionConfigForShellFileName, - 'bash-config.bash', - ); + group('completionScriptFile', () { + test('name is valid', () { + final file = + bashConfiguration.completionScriptFile(Directory('/tmp')); + expect(path.basename(file.path), 'bash-config.bash'); + }); + + test('path is relative to directory', () { + final directory = Directory('/tmp'); + final file = bashConfiguration.completionScriptFile(directory); + final expectedPath = path.join(directory.path, 'bash-config.bash'); + expect(file.path, expectedPath); + }); }); }); }); From 954e5b63b2143a86dfb20c1931675b45d1d68b96 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 9 May 2023 19:17:12 +0100 Subject: [PATCH 13/14] refactor[WIP]: doing ExecutableCompletionConfiguration --- .../installer/completion_installation.dart | 44 +++--- lib/src/installer/executable.dart | 45 ------ .../executable_completion_configuration.dart | 136 ++++++++++++++++++ .../shell_completion_configuration.dart | 22 ++- lib/src/system_shell.dart | 1 + 5 files changed, 176 insertions(+), 72 deletions(-) delete mode 100644 lib/src/installer/executable.dart create mode 100644 lib/src/installer/executable_completion_configuration.dart diff --git a/lib/src/installer/completion_installation.dart b/lib/src/installer/completion_installation.dart index bf62dfb..aae63ef 100644 --- a/lib/src/installer/completion_installation.dart +++ b/lib/src/installer/completion_installation.dart @@ -164,9 +164,10 @@ class CompletionInstallation { @visibleForTesting bool writeCompletionScriptForExecutable(String executableName) { final configuration = this.configuration!; - final executableCompletionScriptFile = Executable( - name: executableName, - shellName: configuration.name, + final executableCompletionScriptFile = + ExecutableCompletionConfiguration.fromShellConfiguration( + executabelName: executableName, + shellConfiguration: configuration, ).completionScriptFile(completionConfigDir); logger.info( @@ -191,41 +192,42 @@ class CompletionInstallation { @visibleForTesting void writeCompletionConfigForShell(String executableName) { final configuration = this.configuration!; - final completionConfig = + final shellCompletionConfig = configuration.completionScriptFile(completionConfigDir); logger.info( - '''Adding config for $executableName config entry to ${completionConfig.path}''', + '''Adding config for $executableName config entry to ${shellCompletionConfig.path}''', ); - if (!completionConfig.existsSync()) { + if (!shellCompletionConfig.existsSync()) { logger.info( - '''No file found at ${completionConfig.path}, creating one now''', + '''No file found at ${shellCompletionConfig.path}, creating one now''', ); - completionConfig.createSync(); + shellCompletionConfig.createSync(); } - final executable = Executable( - name: executableName, - shellName: configuration.name, + final executable = ExecutableCompletionConfiguration.fromShellConfiguration( + executabelName: executableName, + shellConfiguration: configuration, ); final executableEntry = executable.entry; - if (executableEntry.existsIn(completionConfig)) { + if (executableEntry.existsIn(shellCompletionConfig)) { logger.warn( - '''A config entry for $executableName was already found on ${completionConfig.path}.''', + '''A config entry for $executableName was already found on ${shellCompletionConfig.path}.''', ); return; } - final executableScriptFile = - executable.completionScriptFile(completionConfigDir); - // TODO(alestiago): Use a template function to create the content. - final content = ''' -## Completion config for "$executableName" -${configuration.sourceLineTemplate(executableScriptFile.path)}'''; - executableEntry.appendTo(completionConfig, content: content); - logger.info('Added config to ${completionConfig.path}'); + final executableScriptFile = executable.completionScriptFile( + completionConfigDir, + ); + final content = configuration.completionReferenceTemplate( + executableName: executableName, + executableScriptFilePath: executableScriptFile.path, + ); + executableEntry.appendTo(shellCompletionConfig, content: content); + logger.info('Added config to ${shellCompletionConfig.path}'); } String get _shellRCFilePath => diff --git a/lib/src/installer/executable.dart b/lib/src/installer/executable.dart deleted file mode 100644 index a2bb9f9..0000000 --- a/lib/src/installer/executable.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'dart:io'; -import 'package:cli_completion/installer.dart'; -import 'package:path/path.dart' as path; - -/// {@template root_command} -/// An executable that originated from [shellName]. -/// {@endtemplate} -class Executable { - /// {@macro root_command} - const Executable({ - required this.name, - required this.shellName, - }); - - /// The name of the executable. - /// - /// For example: - /// - `flutter` given `flutter create`. - /// - `git` given `git commit`. - final String name; - - /// {@macro shell_name} - /// - /// Indicates where this [Executable] originated from. - // TODO(alestiago): Consider removing this member from [Executable]. - final String shellName; - - /// The completion script file for this [Executable]. - /// - /// A completion script file contains the completion script for a specific - /// executable and shell. - /// - /// The [completionConfigDir] denotes where the completion script file for - /// this [Executable] should be located. - File completionScriptFile(Directory completionConfigDir) { - final commandScriptPath = path.join( - completionConfigDir.path, - '$name.$shellName', - ); - return File(commandScriptPath); - } - - /// A script entry for this [Executable]. - ScriptEntry get entry => ScriptEntry(name); -} diff --git a/lib/src/installer/executable_completion_configuration.dart b/lib/src/installer/executable_completion_configuration.dart new file mode 100644 index 0000000..84c5623 --- /dev/null +++ b/lib/src/installer/executable_completion_configuration.dart @@ -0,0 +1,136 @@ +import 'dart:io'; +import 'package:cli_completion/installer.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; + +/// A type definition for functions that creates the content of a +/// completion script given a [executableName]. +typedef CompletionScriptTemplate = String Function(String executableName); + +/// {@template executable_completion_configuration} +/// An executable that originated from [shellName]. +/// {@endtemplate} +class ExecutableCompletionConfiguration { + /// {@macro executable_completion_configuration} + const ExecutableCompletionConfiguration({ + required this.name, + required this.shellName, + required this.sourceLineTemplate, + }); + + /// Creates a [ExecutableCompletionConfiguration] given the current + /// [ShellCompletionConfiguration]. + factory ExecutableCompletionConfiguration.fromShellConfiguration({ + required String executabelName, + required ShellCompletionConfiguration shellConfiguration, + }) { + final CompletionScriptTemplate scriptTemplate; + switch (shellConfiguration.name) { + case 'zsh': + scriptTemplate = zshCompletionScriptTemplate; + break; + case 'bash': + } + + return ExecutableCompletionConfiguration( + name: executabelName, + shellName: shellConfiguration.name, + sourceLineTemplate: shellConfiguration.sourceLineTemplate, + ); + } + + /// The name of the executable. + /// + /// For example: + /// - `flutter` given `flutter create`. + /// - `git` given `git commit`. + final String name; + + /// {@macro shell_name} + /// + /// Indicates where this [ExecutableCompletionConfiguration] originated from. + final String shellName; + + /// {@macro source_line_template} + final SourceStringTemplate sourceLineTemplate; + + /// The completion script file for this [ExecutableCompletionConfiguration]. + /// + /// A completion script file contains the completion script for a specific + /// executable and shell. + /// + /// The [completionConfigDir] denotes where the completion script file for + /// this [ExecutableCompletionConfiguration] should be located. + File completionScriptFile(Directory completionConfigDir) { + final commandScriptPath = path.join( + completionConfigDir.path, + '$name.$shellName', + ); + return File(commandScriptPath); + } + + /// A script entry for this [ExecutableCompletionConfiguration]. + ScriptEntry get entry => ScriptEntry(name); +} + +/// The [CompletionScriptTemplate] for a zsh shell. +@visibleForTesting +CompletionScriptTemplate zshCompletionScriptTemplate = ( + String executableName, +) { + // Completion script for zsh. + // + // Based on https://github.com/mklabs/tabtab/blob/master/lib/scripts/zsh.sh + return ''' +if type compdef &>/dev/null; then + _${executableName}_completion () { + local reply + local si=\$IFS + + IFS=\$'\n' reply=(\$(COMP_CWORD="\$((CURRENT-1))" COMP_LINE="\$BUFFER" COMP_POINT="\$CURSOR" $executableName completion -- "\${words[@]}")) + IFS=\$si + + if [[ -z "\$reply" ]]; then + _path_files + else + _describe 'values' reply + fi + } + compdef _${executableName}_completion $executableName +fi +'''; +}; + +/// The [CompletionScriptTemplate] for a bash shell. +@visibleForTesting +CompletionScriptTemplate bashCompletionScriptTemplate = ( + String executableName, +) { + // Completion script for bash. + // + // Based on https://github.com/mklabs/tabtab/blob/master/lib/scripts/bash.sh + return ''' +if type complete &>/dev/null; then + _${executableName}_completion () { + local words cword + if type _get_comp_words_by_ref &>/dev/null; then + _get_comp_words_by_ref -n = -n @ -n : -w words -i cword + else + cword="\$COMP_CWORD" + words=("\${COMP_WORDS[@]}") + fi + local si="\$IFS" + IFS=\$'\n' COMPREPLY=(\$(COMP_CWORD="\$cword" \\ + COMP_LINE="\$COMP_LINE" \\ + COMP_POINT="\$COMP_POINT" \\ + $executableName completion -- "\${words[@]}" \\ + 2>/dev/null)) || return \$? + IFS="\$si" + if type __ltrim_colon_completions &>/dev/null; then + __ltrim_colon_completions "\${words[cword]}" + fi + } + complete -o default -F _${executableName}_completion $executableName +fi +'''; +}; diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index c36bf7c..870269e 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -5,12 +5,8 @@ import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -/// A type definition for functions that creates the content of a -/// completion script given a [rootCommand] -typedef CompletionScriptTemplate = String Function(String rootCommand); - /// A type definition for functions that describes -/// the source line given a [scriptPath] +/// the source line given a [scriptPath]. typedef SourceStringTemplate = String Function(String scriptPath); /// {@template shell_completion_configuration} @@ -45,22 +41,36 @@ class ShellCompletionConfiguration { /// {@template shell_name} /// A descriptive string to identify the shell among others. /// {@endtemplate} + // TODO: Remove name for the enhanced enumeration. final String name; /// The location of a config file that is run upon shell start. /// Eg: .bash_profile or .zshrc final String shellRCFile; + /// {@template source_line_template} /// Generates a line to sources of a script file. + /// {@endtemplate} final SourceStringTemplate sourceLineTemplate; /// Generates the contents of a completion script. final CompletionScriptTemplate scriptTemplate; + /// The template for the completion reference that is added to the + /// completion script file of this shell. + String completionReferenceTemplate({ + required String executableName, + required String executableScriptFilePath, + }) { + return ''' +## Completion config for "$executableName" +${sourceLineTemplate(executableScriptFilePath)}'''; + } + /// The configuration file for this shell. /// /// A configuration file for this shell is a barrel file that sources - /// the completion script for [Executable]s. + /// the completion script for [ExecutableCompletionConfiguration]s. /// /// The [completionConfigDir] denotes where the completion script file /// should be located. diff --git a/lib/src/system_shell.dart b/lib/src/system_shell.dart index 77963cd..ad5ffeb 100644 --- a/lib/src/system_shell.dart +++ b/lib/src/system_shell.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:path/path.dart' as path; /// The supported shells. +// TODO(alestiago): Add name to this enum. enum SystemShell { /// The Zsh shell: https://www.zsh.org/ zsh, From f2d4b1dd26378e9e0133059dd3dfc7872a2ec2d9 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Wed, 10 May 2023 14:14:21 +0100 Subject: [PATCH 14/14] docs: added TODO --- lib/src/installer/executable_completion_configuration.dart | 2 ++ lib/src/installer/shell_completion_configuration.dart | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/src/installer/executable_completion_configuration.dart b/lib/src/installer/executable_completion_configuration.dart index 84c5623..2758ca7 100644 --- a/lib/src/installer/executable_completion_configuration.dart +++ b/lib/src/installer/executable_completion_configuration.dart @@ -49,6 +49,7 @@ class ExecutableCompletionConfiguration { /// {@macro shell_name} /// /// Indicates where this [ExecutableCompletionConfiguration] originated from. + // TODO(alestiago): Consider replacing with enum and enhanced enumeration with string name member. final String shellName; /// {@macro source_line_template} @@ -73,6 +74,7 @@ class ExecutableCompletionConfiguration { ScriptEntry get entry => ScriptEntry(name); } +// TODO(alestiago): Consider subclassing instead of using a factory. /// The [CompletionScriptTemplate] for a zsh shell. @visibleForTesting CompletionScriptTemplate zshCompletionScriptTemplate = ( diff --git a/lib/src/installer/shell_completion_configuration.dart b/lib/src/installer/shell_completion_configuration.dart index 870269e..8228c15 100644 --- a/lib/src/installer/shell_completion_configuration.dart +++ b/lib/src/installer/shell_completion_configuration.dart @@ -83,6 +83,7 @@ ${sourceLineTemplate(executableScriptFilePath)}'''; } } +// TODO(alestiago): Consider subclassing instead of using a factory. /// A [ShellCompletionConfiguration] for zsh. @visibleForTesting final zshConfiguration = ShellCompletionConfiguration._(