#! /usr/bin/env python3 # -*- coding: utf-8 -*- import sys import os if os.getcwd() not in sys.path: sys.path.append(os.getcwd()) from calculate_anything.currency import CurrencyService from calculate_anything.query.handlers import ( TimeQueryHandler, Base10QueryHandler, Base16QueryHandler, Base2QueryHandler, Base8QueryHandler, UnitsQueryHandler, CalculatorQueryHandler, PercentagesQueryHandler, ) from calculate_anything.query.handlers import MultiHandler from calculate_anything.lang import LanguageService from calculate_anything import logging from calculate_anything.preferences import Preferences from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.validation import Validator from prompt_toolkit.patch_stdout import patch_stdout from prompt_toolkit import HTML, PromptSession from prompt_toolkit.styles import Style # Setup Calculate Anything (Order is important) # Comment this line to get log messages (use patch stdout in such case) logging.disable_file_handler() logging.disable_stdout_handler() # Set the language preferences = Preferences() preferences.language.set('en_US') # Set some default currencies preferences.currency.set_default_currencies(['USD', 'EUR', 'CAD', 'BTC']) # Enable currency service and cache and run every day preferences.currency.enable_cache(60 * 60 * 24) # Set default cities for timezone conversion preferences.time.set_default_cities('London GB,Athens GR,Tokyo JP') preferences.commit() # End setup # Define keywords, change dictionary keys to whatever you want keywords = { 'time': { 'kw': 'time', # Calculate anything's internal keyword 'mode': 'time', 'mode_description': 'Time Converter', 'handlers': [TimeQueryHandler], }, 'dec': { 'kw': 'dec', # Calculate anything's internal keyword 'mode': 'dec', 'mode_description': 'Decimal Calculator', 'handlers': [Base10QueryHandler], }, 'hex': { 'kw': 'hex', # Calculate anything's internal keyword 'mode': 'hex', 'mode_description': 'Hex Calculator', 'handlers': [Base16QueryHandler], }, 'bin': { 'kw': 'bin', # Calculate anything's internal keyword 'mode': 'bin', 'mode_description': 'Binary Calculator', 'handlers': [Base2QueryHandler], }, 'oct': { 'kw': 'oct', # Calculate anything's internal keyword 'mode': 'oct', 'mode_description': 'Octal Calculator', 'handlers': [Base8QueryHandler], }, '=': { 'kw': '=', # Calculate anything's internal keyword 'mode': 'calculator', 'mode_description': 'Calculator and Unit converter', 'handlers': [ CalculatorQueryHandler, PercentagesQueryHandler, UnitsQueryHandler, ], }, } style = Style.from_dict( { 'bottom-toolbar': 'fg:#282a36 bg:#f8f8f2 reverse', } ) bindings = KeyBindings() class Program(Validator): """Some simple prompt_toolkit code to make this run""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.reset() def reset(self): self._kw = '' self._query = '' self._results = '' def _process_results(self, results): pad = ' ' * 400 results_strs = [] str_fmt = ( '\n' '' ) for result in results: results_strs.append( str_fmt.format(result.name, pad, result.description) ) return '\n'.join(results_strs) def validate(self, document): text = document.text self._kw = text.strip().split(' ', 1)[0] self._query = text[len(self._kw) :] if self._kw in keywords and self._query != '': handlers = keywords[self._kw]['handlers'] results = MultiHandler().handle(self._kw + self._query, *handlers) self._results = self._process_results(results) else: self._results = '' def handle_c_a(self, event): pos = event.current_buffer.cursor_position while event.current_buffer.cursor_position > 0: event.current_buffer.cursor_left() event.current_buffer.start_selection() while event.current_buffer.cursor_position < pos: event.current_buffer.cursor_right() def rprompt(self): key = self._kw if key not in keywords: mode = 'No mode selected' else: mode = keywords[key]['mode_description'] return HTML( ''.format(mode) ) def bottom_toolbar(self): if self._kw not in keywords: keystr = ', '.join(map('"{}"'.format, keywords)) # tb_str = '' tb_str = ' Use one of the keywords followed by space\n - [{}]' tb_str = tb_str.format(keystr) return [('class:bottom-toolbar', tb_str)] results = self._results if self._query.strip() == '' and not self._results: results = ' {} \n {}'.format( LanguageService().translate('no-result', 'misc'), LanguageService().translate( 'no-result-{}-description'.format( keywords[self._kw]['mode'] ), 'misc', ), ) elif not self._results: results = '\n' return HTML(results) # Some hacks when creating demos, don't put this in your code if os.environ.get('RECORD', '').lower() == 'true': sys.stdin = open('/dev/tty', 'r') program = Program() bindings.add('c-a')(program.handle_c_a) session = PromptSession( key_bindings=bindings, rprompt=program.rprompt, bottom_toolbar=program.bottom_toolbar, validator=program, validate_while_typing=True, wrap_lines=True, # refresh_interval=0.01, style=style, ) try: with patch_stdout(): while True: session.prompt('❯ ') program.reset() except KeyboardInterrupt as e: print(e) finally: CurrencyService().stop()