<commit_before>import argparse
import json
import os
import readchar
import sys
import time

from subprocess import call, Popen, PIPE
from clint import resources
from clint.textui import puts, colored


def main():
    # Check arguments
    parser = argparse.ArgumentParser(prog='sshmenu', description='A convenient tool for bookmarking hosts and connecting to them via ssh.')
    parser.add_argument('-c', '--configname', default='config', help='Specify an alternate configuration name.')
    args = parser.parse_args()

    # Get config name
    config_name = '{configname}.json'.format(configname=args.configname)

    # First parameter is 'company' name, hence duplicate arguments
    resources.init('sshmenu', 'sshmenu')

    # If the config file doesn't exist, create an example config
    if resources.user.read(config_name) is None:
        example_config = {
            'targets': [
                {
                    'host': 'user@example-machine.local',
                    'friendly': 'This is an example target',
                    'options': []
                },
                {
                    'command': 'mosh',
                    'host': 'user@example-machine.local',
                    'friendly': 'This is an example target using mosh',
                    'options': []
                }
            ]
        }
        resources.user.write(config_name, json.dumps(example_config, indent=4))
        puts('I have created a new configuration file, please edit and run again:')
        puts(resources.user.path + os.path.sep + config_name)
    else:
        config = json.loads(resources.user.read(config_name))
        display_menu(config['targets'])

def get_terminal_height():
    # Return height of terminal as int
    tput = Popen(["tput", "lines"], stdout=PIPE)
    height, stderr = tput.communicate()

    return(int(height))

def display_menu(targets):
    # We need at least one target for our UI to make sense
    num_targets = len(targets)
    if num_targets <= 0:
        puts('Whoops, you don\'t have any targets listed in your config!')
        exit(0)

    # Determine the longest host and line length
    longest_host = -1
    longest_line = -1
    for index, target in enumerate(targets):
        length = len(target['host'])
        # Check host length
        if length > longest_host:
            longest_host = length

        # Generate description and check line length
        desc = '%2d ' % (index) + target['host'].ljust(longest_host) + ' | ' + target['friendly']
        target['desc'] = desc
        line_length = len(desc)
        if line_length > longest_line:
            longest_line = line_length

    # Clear screen
    call(['tput', 'clear'])

    # Save current cursor position so we can overwrite on list updates
    call(['tput', 'sc'])

    # Keep track of currently selected target
    selected_target = 0

    # Support input of long numbers
    number_buffer = []
    # Store time of last number that was entered
    number_last = round(time.time())
    # Get initial terminal height
    terminal_height = get_terminal_height()
    # Set initial visible target range. Subtract 2 because one line is used by the instructions, and one line is always empty at the bottom.
    visible_target_range = range(terminal_height - 2)

    while True:
        # Calculate height of terminal window in case it has been resized
        terminal_height = get_terminal_height()
        # Return to the saved cursor position
        call(['tput', 'rc'])

        # Redraw the instructions to make sure they don't disappear when resizing terminal
        puts(colored.cyan('Select a target (up (k), down (j), enter, ctrl+c to exit)'))

        # Recalculate visible targets based on selected_target
        if selected_target > max(visible_target_range):
            visible_start = selected_target - terminal_height + 3
            visible_end = selected_target + 1
            visible_target_range = range(visible_start, visible_end)

        elif selected_target < min(visible_target_range):
            visible_start = selected_target
            visible_end = selected_target + terminal_height - 2
            visible_target_range = range(visible_start, visible_end)

        # Print items
        for index, target in enumerate(targets):
            # Only print the items that are within the visible range.
            # Due to lines changing their position on the screen when scrolling,
            # we need to redraw the entire line + add padding to make sure all <commit_msg>Improve detection of when the terminal window has been resized.<commit_after>import argparse
import json
import os
import readchar
import sys
import time

from subprocess import call, Popen, PIPE
from clint import resources
from clint.textui import puts, colored


def main():
    # Check arguments
    parser = argparse.ArgumentParser(prog='sshmenu', description='A convenient tool for bookmarking hosts and connecting to them via ssh.')
    parser.add_argument('-c', '--configname', default='config', help='Specify an alternate configuration name.')
    args = parser.parse_args()

    # Get config name
    config_name = '{configname}.json'.format(configname=args.configname)

    # First parameter is 'company' name, hence duplicate arguments
    resources.init('sshmenu', 'sshmenu')

    # If the config file doesn't exist, create an example config
    if resources.user.read(config_name) is None:
        example_config = {
            'targets': [
                {
                    'host': 'user@example-machine.local',
                    'friendly': 'This is an example target',
                    'options': []
                },
                {
                    'command': 'mosh',
                    'host': 'user@example-machine.local',
                    'friendly': 'This is an example target using mosh',
                    'options': []
                }
            ]
        }
        resources.user.write(config_name, json.dumps(example_config, indent=4))
        puts('I have created a new configuration file, please edit and run again:')
        puts(resources.user.path + os.path.sep + config_name)
    else:
        config = json.loads(resources.user.read(config_name))
        display_menu(config['targets'])

def get_terminal_height():
    # Return height of terminal as int
    tput = Popen(["tput", "lines"], stdout=PIPE)
    height, stderr = tput.communicate()

    return(int(height))

def display_menu(targets):
    # We need at least one target for our UI to make sense
    num_targets = len(targets)
    if num_targets <= 0:
        puts('Whoops, you don\'t have any targets listed in your config!')
        exit(0)

    # Determine the longest host and line length
    longest_host = -1
    longest_line = -1
    for index, target in enumerate(targets):
        length = len(target['host'])
        # Check host length
        if length > longest_host:
            longest_host = length

        # Generate description and check line length
        desc = '%2d ' % (index) + target['host'].ljust(longest_host) + ' | ' + target['friendly']
        target['desc'] = desc
        line_length = len(desc)
        if line_length > longest_line:
            longest_line = line_length

    # Clear screen
    call(['tput', 'clear'])

    # Save current cursor position so we can overwrite on list updates
    call(['tput', 'sc'])

    # Keep track of currently selected target
    selected_target = 0

    # Support input of long numbers
    number_buffer = []
    # Store time of last number that was entered
    number_last = round(time.time())
    # Get initial terminal height
    terminal_height = get_terminal_height()
    # Set initial visible target range. Subtract 2 because one line is used by the instructions, and one line is always empty at the bottom.
    visible_target_range = range(terminal_height - 2)

    while True:
        # Calculate height of terminal window in case it has been resized
        new_terminal_height = get_terminal_height()
        # Return to the saved cursor position
        call(['tput', 'rc'])

        # Redraw the instructions to make sure they don't disappear when resizing terminal
        puts(colored.cyan('Select a target (up (k), down (j), enter, ctrl+c to exit)'))

        # Recalculate visible targets based on selected_target
        move_down = False
        move_up = False
        if terminal_height != new_terminal_height:
            if selected_target + (terminal_height - 2) > num_targets:
                move_down = True
            else:
                move_up = True

            terminal_height = new_terminal_height

        if selected_target > max(visible_target_range) or move_down:
            visible_start = selected_target - terminal_height + 3
            visible_end = selected_target + 1
            visible_target_range = range(visible_start, visible_end)

        elif selected_target < min(visible_target_range) or move_up:
            visible_start = selected_target
            visible_end = selected_target + terminal_height - 2
            visible_target_range = range(visible_start, visible_end)

        # Print items
        for index, target in enumerate(targets):
            # Only print the items that are within the visible range.
            # Due to lines changing their position on the screen when scrolling,
            # we need to redraw the entire line + add padding to make sure all 
{'fraction_non_alphanumeric': 0.08490864927658676, 'fraction_numerical': 0.002640194318301827, 'mean_word_length': 2.476505139500734, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1025299', 'n_tokens_mistral': 2553, 'n_tokens_neox': 2443, 'n_words': 860}