function completer( repl ) {
	return complete;

	/**
	* Callback invoked upon a user entering the TAB character at the command prompt.
	*
	* @private
	* @param {string} line - current line
	* @param {Function} clbk - completion callback
	* @returns {void}
	*/
	function complete( line, clbk ) {
		var match;
		var exts;
		var res;

		debug( 'Line: %s', line );

		// Initialize an array for storing completion results:
		res = [];

		// Test if the line has an incomplete `require` expression:
		match = line.match( requireRegExp() );
		if ( match ) {
			debug( 'Detected incomplete `require` expression.' );

			exts = objectKeys( repl._context.require.extensions );
			debug( 'Supported `require` filename extensions: %s', exts.join( ', ' ) );

			line = completeRequire( res, match[ 1 ], repl._context.module.paths, exts ); // eslint-disable-line max-len
			res = normalize( res );

			debug( 'Completion filter: %s', line );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		// Test if the line has an incomplete file system expression:
		match = line.match( fsRegExp() );
		if ( match ) {
			debug( 'Detected incomplete file system expression.' );

			debug( 'Expression: %s', match[ 0 ] );
			debug( 'File system API: %s', match[ 1 ] );
			debug( 'Path to complete: %s', match[ 3 ] );
			line = completeFS( res, match[ 0 ], match[ 1 ], match[ 3 ] );
			res = normalize( res );

			debug( 'Completion filter: %s', line );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		// Test if the line has an incomplete workspace expression:
		match = line.match( workspaceRegExp() );
		if ( match ) {
			debug( 'Detected incomplete workspace expression.' );

			debug( 'Expression: %s', match[ 0 ] );
			debug( 'Workspace API: %s', match[ 1 ] );
			debug( 'Value to complete: %s', match[ 3 ] );
			line = completeWorkspace( res, repl, match[ 0 ], match[ 1 ], match[ 3 ] ); // eslint-disable-line max-len
			res = normalize( res );

			debug( 'Completion filter: %s', line );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		// Test if the line has an incomplete tutorial expression:
		match = line.match( tutorialRegExp() );
		if ( match ) {
			debug( 'Detected incomplete tutorial expression.' );

			debug( 'Expression: %s', match[ 0 ] );
			debug( 'Tutorial API: %s', match[ 1 ] );
			debug( 'Value to complete: %s', match[ 3 ] );
			line = completeTutorial( res, repl, match[ 0 ], match[ 1 ], match[ 3 ] ); // eslint-disable-line max-len
			res = normalize( res );

			debug( 'Completion filter: %s', line );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		// Test if the line has an incomplete settings expression:
		match = line.match( settingsRegExp() );
		if ( match ) {
			debug( 'Detected incomplete settings expression.' );

			debug( 'Expression: %s', match[ 0 ] );
			debug( 'Settings API: %s', match[ 1 ] );
			debug( 'Value to complete: %s', match[ 3 ] );
			line = completeSettings( res, repl, match[ 0 ], match[ 1 ], match[ 3 ] ); // eslint-disable-line max-len
			res = normalize( res );

			debug( 'Completion filter: %s', line );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		// Sanity check that we are attempting to complete something which is completable:
		if ( reservedCharsRegExp().test( line[ repl._rli.cursor-1 ] ) ) {
			debug( 'Detected attempt to trigger completion after a special character.' );
			debug( 'Results: %s', res.join( ', ' ) );
			return clbk( null, [ res, line ] );
		}
		debug( 'Attempting to complete an incomplete expression.' );
		line = completeExpression( res, repl._context, line );
		res = normalize( res );
		debug( 'Results: %s', res.join( ', ' ) );
		return clbk( null, [ res, line ] );
	}
}
Returns a callback for supporting TAB completion in a REPL environment.

@private
@param {REPL} repl - REPL instance
@returns {Function} TAB completion callback