Skip to content

Commit

Permalink
Activate auto-completion for non-GNUReadline
Browse files Browse the repository at this point in the history
  • Loading branch information
zonuexe committed Jul 11, 2022
1 parent 064b869 commit b5b0e93
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 22 deletions.
16 changes: 16 additions & 0 deletions src/Readline/GNUReadline.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Psy\Readline;

use Psy\TabCompletion\AutoCompleter;

/**
* A Readline interface implementation for GNU Readline.
*
Expand Down Expand Up @@ -176,4 +178,18 @@ public function writeHistory(): bool

return true;
}

public function activateAutoCompleter(AutoCompleter $autoCompleter): void
{
\readline_completion_function([$autoCompleter, 'callback']);
}

public function deactivateAutoCompleter(): void
{
// PHP didn't implement the whole readline API when they first switched
// to libedit. And they still haven't.
if (\function_exists('readline_callback_handler_remove')) {
\readline_callback_handler_remove();
}
}
}
27 changes: 27 additions & 0 deletions src/Readline/HoaAutocompleterAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Psy\Readline;

use Psy\TabCompletion\AutoCompleter;
use Psy\Readline\Hoa\Autocompleter as HoaAutocompleter;

class HoaAutocompleterAdapter implements HoaAutocompleter
{
/** @var AutoCompleter */
private $autoCompleter;

public function __construct(AutoCompleter $autoCompleter)
{
$this->autoCompleter = $autoCompleter;
}

public function complete(string $prefix, int $index, array $info)
{
return $this->autoCompleter->complete($prefix, $index, $info);
}

public function getWordDefinition(): string
{
return '.';
}
}
12 changes: 12 additions & 0 deletions src/Readline/Readline.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

namespace Psy\Readline;

use Psy\TabCompletion\AutoCompleter;

/**
* An interface abstracting the various readline_* functions.
*/
Expand Down Expand Up @@ -80,4 +82,14 @@ public function redisplay();
* @return bool Success
*/
public function writeHistory(): bool;

/**
* Activete auto completer for tab completion.
*/
public function activateAutoCompleter(AutoCompleter $autoCompleter): void;

/**
* Deactivete auto completer for tab completion.
*/
public function deactivateAutoCompleter(): void;
}
11 changes: 11 additions & 0 deletions src/Readline/Transient.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Psy\Readline;

use Psy\Exception\BreakException;
use Psy\TabCompletion\AutoCompleter;

/**
* An array-based Readline emulation implementation.
Expand Down Expand Up @@ -152,4 +153,14 @@ private function getStdin()

return $this->stdin;
}

public function activateAutoCompleter(AutoCompleter $autoCompleter): void
{
// noop
}

public function deactivateAutoCompleter(): void
{
// noop
}
}
11 changes: 11 additions & 0 deletions src/Readline/Userland.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Psy\Readline\Hoa\ConsoleTput as HoaConsoleTput;
use Psy\Readline\Hoa\Readline as HoaReadline;
use Psy\Readline\Hoa\Ustring as HoaUstring;
use Psy\TabCompletion\AutoCompleter;

/**
* Userland Readline implementation.
Expand Down Expand Up @@ -158,4 +159,14 @@ public function writeHistory(): bool
{
return true;
}

public function activateAutoCompleter(AutoCompleter $autoCompleter): void
{
$this->hoaReadline->setAutocompleter(new HoaAutocompleterAdapter($autoCompleter));
}

public function deactivateAutoCompleter(): void
{
// noop
}
}
2 changes: 1 addition & 1 deletion src/Shell.php
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,7 @@ protected function initializeTabCompletion()
$this->addMatchersToAutoCompleter($this->getDefaultMatchers());
$this->addMatchersToAutoCompleter($this->matchers);

$this->autoCompleter->activate();
$this->readline->activateAutoCompleter($this->autoCompleter);
}

/**
Expand Down
34 changes: 13 additions & 21 deletions src/TabCompletion/AutoCompleter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Psy\TabCompletion;

use Psy\Readline\Readline;
use Psy\TabCompletion\Matcher\AbstractMatcher;

/**
Expand All @@ -23,6 +24,9 @@ class AutoCompleter
/** @var Matcher\AbstractMatcher[] */
protected $matchers;

/** @var ?Readline */
protected $readline;

/**
* Register a tab completion Matcher.
*
Expand All @@ -33,24 +37,15 @@ public function addMatcher(AbstractMatcher $matcher)
$this->matchers[] = $matcher;
}

/**
* Activate readline tab completion.
*/
public function activate()
{
\readline_completion_function([&$this, 'callback']);
}

/**
* Handle readline completion.
*
* @param string $input Readline current word
* @param int $index Current word index
* @param array $info readline_info() data
*
* @return array
* @param array{line_buffer: string, end: int} $info {@see readline_info()} data
* @return list<string>
*/
public function processCallback(string $input, int $index, array $info = []): array
public function complete(string $input, int $index, array $info = []): array
{
// Some (Windows?) systems provide incomplete `readline_info`, so let's
// try to work around it.
Expand Down Expand Up @@ -78,15 +73,13 @@ public function processCallback(string $input, int $index, array $info = []): ar
}
}

$matches = \array_unique($matches);

return !empty($matches) ? $matches : [''];
return \array_values(\array_unique($matches)) ?: [''];
}

/**
* The readline_completion_function callback handler.
*
* @see processCallback
* @see AutoCompleter::complete()
*
* @param string $input
* @param int $index
Expand All @@ -95,18 +88,17 @@ public function processCallback(string $input, int $index, array $info = []): ar
*/
public function callback(string $input, int $index): array
{
return $this->processCallback($input, $index, \readline_info());
return $this->complete($input, $index, \readline_info());
}

/**
* Remove readline callback handler on destruct.
*/
public function __destruct()
{
// PHP didn't implement the whole readline API when they first switched
// to libedit. And they still haven't.
if (\function_exists('readline_callback_handler_remove')) {
\readline_callback_handler_remove();
if (isset($this->readline)) {
$this->readline->deactivateCompletion();
$this->readline = null;
}
}
}

0 comments on commit b5b0e93

Please sign in to comment.