CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-readline

GNU readline support for Python on platforms without readline

Pending
Overview
Eval results
Files

completion.mddocs/

Tab Completion

Comprehensive tab completion system with customizable completion functions, delimiter configuration, and completion context access. These functions enable sophisticated autocompletion behavior for interactive command-line applications.

Capabilities

Completion Function Management

Functions for setting up and managing custom completion behavior, allowing applications to provide context-aware autocompletion.

def set_completer(function=None):
    """
    Set or remove the completer function.
    
    Parameters:
    - function (callable, optional): Completer function called as function(text, state)
                                   for state in 0, 1, 2, ... until it returns None.
                                   If None, removes current completer.
    
    Returns:
    None
    """

def get_completer():
    """
    Return current completer function.
    
    Returns:
    callable or None: Current completer function, or None if no completer is set
    """

Usage Example:

import readline
import os
import glob

def file_completer(text, state):
    """Simple file completion example"""
    # Get all files/directories that start with text
    matches = glob.glob(text + '*')
    
    # Add trailing slash to directories
    matches = [match + '/' if os.path.isdir(match) else match for match in matches]
    
    # Return the match for this state, or None when exhausted
    return matches[state] if state < len(matches) else None

# Set the completer
readline.set_completer(file_completer)

# Enable tab completion
readline.parse_and_bind('tab: complete')

# Check current completer
current_completer = readline.get_completer()
print(f"Current completer: {current_completer}")

# Remove completer
readline.set_completer(None)

Advanced Completion Example

import readline
import keyword
import builtins

class PythonCompleter:
    def __init__(self):
        self.matches = []
    
    def complete(self, text, state):
        """Complete Python keywords, builtins, and local variables"""
        if state == 0:  # First call, generate matches
            self.matches = []
            
            # Add Python keywords
            self.matches.extend([kw for kw in keyword.kwlist if kw.startswith(text)])
            
            # Add built-in functions
            self.matches.extend([name for name in dir(builtins) if name.startswith(text)])
            
            # Add local variables (simplified)
            import __main__
            if hasattr(__main__, '__dict__'):
                local_vars = [name for name in __main__.__dict__.keys() 
                            if name.startswith(text) and not name.startswith('_')]
                self.matches.extend(local_vars)
        
        return self.matches[state] if state < len(self.matches) else None

# Set up Python completion
python_completer = PythonCompleter()
readline.set_completer(python_completer.complete)

Completion Context Access

Functions for accessing information about the current completion attempt, enabling context-sensitive completion behavior.

def get_completion_type():
    """
    Get the type of completion being attempted.
    
    Returns:
    int: Completion type code indicating the kind of completion
    """

def get_begidx():
    """
    Get the beginning index of the readline tab-completion scope.
    
    Returns:
    int: Starting index of text being completed within the line buffer
    """

def get_endidx():
    """
    Get the ending index of the readline tab-completion scope.
    
    Returns:
    int: Ending index of text being completed within the line buffer
    """

Usage Example:

import readline

def context_aware_completer(text, state):
    """Completer that uses completion context"""
    if state == 0:  # First call, analyze context
        # Get completion boundaries
        begidx = readline.get_begidx()
        endidx = readline.get_endidx()
        
        # Get the full line being edited
        line_buffer = readline.get_line_buffer()
        
        # Extract the word being completed and its context
        before_cursor = line_buffer[:begidx]
        completion_text = line_buffer[begidx:endidx]
        
        print(f"\nCompletion context:")
        print(f"  Line: '{line_buffer}'")
        print(f"  Before cursor: '{before_cursor}'")
        print(f"  Completing: '{completion_text}'")
        print(f"  Indexes: {begidx}-{endidx}")
        print(f"  Completion type: {readline.get_completion_type()}")
    
    # Simple completion for demonstration
    options = ['hello', 'help', 'history', 'home']
    matches = [opt for opt in options if opt.startswith(text)]
    return matches[state] if state < len(matches) else None

readline.set_completer(context_aware_completer)

Completion Delimiter Configuration

Functions for controlling which characters are treated as word boundaries during tab completion.

def set_completer_delims(string):
    """
    Set the readline word delimiters for tab-completion.
    
    Parameters:
    - string (str): Characters to treat as word delimiters
    
    Returns:
    None
    """

def get_completer_delims():
    """
    Get the readline word delimiters for tab-completion.
    
    Returns:
    str: Current word delimiter characters
    """

Usage Example:

import readline

# Check current delimiters
current_delims = readline.get_completer_delims()
print(f"Current delimiters: '{current_delims}'")

# Set custom delimiters (default is usually ' \t\n`@$><=;|&{(')
readline.set_completer_delims(' \t\n')  # Only space, tab, and newline

# For file path completion, you might want to exclude '/' and '.'
readline.set_completer_delims(' \t\n=')

# For programming language completion, include more programming symbols
readline.set_completer_delims(' \t\n`@$><=;|&{()}[].,')

Advanced Completion Patterns

Command-Specific Completion

import readline
import os
import subprocess

class CommandCompleter:
    def __init__(self):
        self.commands = {
            'cd': self._complete_directories,
            'ls': self._complete_files,
            'python': self._complete_python_files,
            'git': self._complete_git_commands,
        }
    
    def complete(self, text, state):
        line_buffer = readline.get_line_buffer()
        words = line_buffer.split()
        
        if not words:
            return None
        
        command = words[0]
        if command in self.commands:
            return self.commands[command](text, state, words)
        
        # Default file completion
        return self._complete_files(text, state, words)
    
    def _complete_directories(self, text, state, words):
        """Complete only directories for cd command"""
        import glob
        matches = [d for d in glob.glob(text + '*') if os.path.isdir(d)]
        matches = [d + '/' for d in matches]  # Add trailing slash
        return matches[state] if state < len(matches) else None
    
    def _complete_files(self, text, state, words):
        """Complete files and directories"""
        import glob
        matches = glob.glob(text + '*')
        matches = [m + '/' if os.path.isdir(m) else m for m in matches]
        return matches[state] if state < len(matches) else None
    
    def _complete_python_files(self, text, state, words):
        """Complete .py files"""
        import glob
        matches = glob.glob(text + '*.py')
        return matches[state] if state < len(matches) else None
    
    def _complete_git_commands(self, text, state, words):
        """Complete git subcommands"""
        if len(words) == 1:  # Completing git subcommand
            git_commands = ['add', 'commit', 'push', 'pull', 'status', 'log', 'diff', 'branch']
            matches = [cmd for cmd in git_commands if cmd.startswith(text)]
            return matches[state] if state < len(matches) else None
        return None

# Set up command-specific completion
command_completer = CommandCompleter()
readline.set_completer(command_completer.complete)

Multi-Level Completion

import readline

class HierarchicalCompleter:
    def __init__(self):
        self.completions = {
            'show': {
                'interface': ['eth0', 'eth1', 'lo', 'wlan0'],
                'route': ['default', 'table', 'all'],
                'ip': ['route', 'addr', 'link'],
            },
            'set': {
                'interface': ['eth0', 'eth1', 'wlan0'],
                'route': ['add', 'del', 'change'],
            }
        }
    
    def complete(self, text, state):
        line_buffer = readline.get_line_buffer()
        words = line_buffer.split()
        
        if not words:
            return None
        
        # Navigate through completion hierarchy
        current_level = self.completions
        for word in words[:-1]:  # All words except the one being completed
            if word in current_level and isinstance(current_level[word], dict):
                current_level = current_level[word]
            else:
                return None
        
        # Get matches at current level
        if isinstance(current_level, dict):
            matches = [key for key in current_level.keys() if key.startswith(text)]
        elif isinstance(current_level, list):
            matches = [item for item in current_level if item.startswith(text)]
        else:
            matches = []
        
        return matches[state] if state < len(matches) else None

# Set up hierarchical completion
hierarchical_completer = HierarchicalCompleter()
readline.set_completer(hierarchical_completer.complete)

Install with Tessl CLI

npx tessl i tessl/pypi-readline

docs

completion.md

configuration.md

history.md

hooks.md

index.md

line-editing.md

tile.json