src/aoikhotkey/hotkey_spec_parser.py
def spec_parse(specs):
    """
    Parse hotkey spec list into hotkey info list.

    :param specs: Hotkey spec list.

    :return: Hotkey info list.
    """
    # Import here to avoid circular import.
    from .util.cmd import MuteNoti
    from .util.cmd import Noti

    # `Call in main thread` option
    _OPT_CALL_IN_MAIN_THREAD = '_OPT_CALL_IN_MAIN_THREAD'

    # `Key-up hotkey` option
    _OPT_KEY_UP_HOTKEY = '_OPT_KEY_UP_HOTKEY'

    # Hotkey info list
    hotkey_info_s = []

    # For given hotkey spec list's each hotkey spec
    for spec in specs:
        #
        full_spec = list(spec)

        # Get hotkey pattern
        hotkey_pattern = spec[0]

        # Get hotkey function list
        func_list = spec[1:]

        # Whether the hotkey type is key-sequence
        is_hotseq = False

        # Option list
        opt_s = []

        # If the hotkey pattern is None,
        # it means to add event function, not hotkey function.
        # This aims to co-work with code at 4QTR9.
        if hotkey_pattern is None:
            # Use the hotkey pattern as-is
            pass

        # If the hotkey pattern is list,
        # it is assumed to be a list of virtual keys.
        # This aims to co-work with code at 4JPY2.
        elif isinstance(hotkey_pattern, list):
            # Use the hotkey pattern as-is
            pass

        # If the hotkey pattern is string
        elif isinstance(hotkey_pattern, str):
            # If the hotkey pattern starts with `$`
            if hotkey_pattern.startswith('$'):
                # Add `call in main thread` option
                opt_s.append(_OPT_CALL_IN_MAIN_THREAD)

                # Remove the special character
                hotkey_pattern = hotkey_pattern[1:]

            # If the hotkey pattern starts with `~`
            if hotkey_pattern.startswith('~'):
                # Add `key-up hotkey` option
                opt_s.append(_OPT_KEY_UP_HOTKEY)

                # Remove the special character
                hotkey_pattern = hotkey_pattern[1:]

            # If the hotkey pattern starts with `::`,
            # it means key-sequence hotkey.
            if hotkey_pattern.startswith('::'):
                # If the key sequence is empty
                if hotkey_pattern in ('::', ':::', '::::'):
                    # Get error message
                    msg = 'Hot sequence can not be empty: {}.'.format(
                        repr(hotkey_pattern)
                    )

                    # Raise error
                    raise ValueError(msg)

                # If the key sequence is not empty.

                # Set is key-sequence be True
                is_hotseq = True

                # If the key sequence ends with `::`
                if hotkey_pattern.endswith('::'):
                    # Remove starting and ending `::`.
                    # This aims to be compatible with AutoHotkey.
                    hotkey_pattern = hotkey_pattern[2:-2]

                # If the key sequence not ends with `::`
                else:
                    # Remove starting `::`
                    hotkey_pattern = hotkey_pattern[2:]

                # Assert the key sequence is not empty
                assert hotkey_pattern

        # If the hotkey pattern is none of above
        else:
            # Raise error
            assert 0, hotkey_pattern

        # Normalized function list
        norm_func_s = []

        # NeedHotkeyInfo instance list
        need_info_instance_s = []

        # For the hotkey function list's each function item
        for func_item in func_list:
            # If the function item is string
            if isinstance(func_item, str):
                # If the string starts with `http://` or `https://`
                if func_item.startswith('http://') \
                        or func_item.startswith('https://'):
                    # Use the string as URL
                    url = func_item

                    # Create a function that opens the URL.
                    # `webbrowser.open` returns True so can not use `partial`.
                    def new_func(url=url):
                        # Open given URL
                        webbrowser.open(url)

                    # Use the created function as function item
                    func_item = new_func

                # If the string is existing directory path
                elif os.path.isdir(func_item):
                    # Prefix the string with `file://` protocol
                    url = 'file://' + func_item

                    # Create a function that opens the URL.
                    # `webbrowser.open` returns True so can not use `partial`.
                    def new_func(url=url):
                        # Open given URL
                        webbrowser.open(url)

                    # Use the created function as function item
                    func_item = new_func

                    #
                    if Noti not in full_spec and MuteNoti not in full_spec:
                        full_spec.append(MuteNoti)

                # If the string is none of above,
                # assume it is a command.
                else:
                    # Create a function that runs the command
                    def new_func(cmd=func_item):
                        # Split the command into parts
                        cmd_part_s = cmd.split()

                        # Run the command
                        Popen(cmd_part_s, shell=True)

                    # Use the created function as function item
                    func_item = new_func

            # If the function item is `NeedHotkeyInfo` instance
            elif isinstance(func_item, NeedHotkeyInfo):
                # Add the function item to the instance list
                need_info_instance_s.append(func_item)

            # If the function item is none of above
            else:
                # Use the function item as-is
                func_item = func_item

            # Add the function item to the normalized function list
            norm_func_s.append(func_item)

        # If the normalized function list contains only one item
        if len(norm_func_s) == 1:
            # Use the only item as hotkey function
            hotkey_func = norm_func_s[0]

        # If the normalized function list not contains only one item
        else:
            # Combine all functions into one
            hotkey_func = _CallAll(norm_func_s)

        # If `call in main thread` option is enabled
        if _OPT_CALL_IN_MAIN_THREAD in opt_s:
            # Tag the function as `call in main thread`
            hotkey_func = tag_call_in_main_thread(hotkey_func)

        # Whether is key-up hotkey
        is_key_up = _OPT_KEY_UP_HOTKEY in opt_s

        # If is key-sequence hotkey
        if is_hotseq:
            # If is key-up hotkey
            if is_key_up:
                # Get error message
                msg = 'Hot sequence can not be key-up hotkey.'

                # Raise error
                raise ValueError(msg)

            # If is not key-up hotkey

            # Set hotkey type be key-sequence
            hotkey_type = HOTKEY_TYPE_V_KS

        # If is key-up hotkey
        elif is_key_up:
            # Set hotkey type be key-up
            hotkey_type = HOTKEY_TYPE_V_UP

        # If is not key-up hotkey
        else:
            # Set hotkey type be key-down
            hotkey_type = HOTKEY_TYPE_V_DN

        # Get hotkey info
        hotkey_info = {
            HOTKEY_INFO_K_HOTKEY_TYPE: hotkey_type,
            HOTKEY_INFO_K_HOTKEY_PATTERN: hotkey_pattern,
            HOTKEY_INFO_K_HOTKEY_FUNC: hotkey_func,
            HOTKEY_INFO_K_HOTKEY_ORIG_SPEC: spec,
            HOTKEY_INFO_K_HOTKEY_ORIG_SPEC: spec,
            HOTKEY_INFO_K_HOTKEY_FULL_SPEC: tuple(full_spec),
            HOTKEY_INFO_K_NEED_HOTKEY_INFO_LIST: need_info_instance_s,
        }

        # Add the hotkey info to the hotkey info list
        hotkey_info_s.append(hotkey_info)

    # Return the hotkey info list
    return hotkey_info_s

    Parse hotkey spec list into hotkey info list.

    :param specs: Hotkey spec list.

    :return: Hotkey info list.
    
Parse hotkey spec list into hotkey info list.
Parse hotkey spec list into hotkey info list .
def spec_parse(specs):
    from .util.cmd import MuteNoti
    from .util.cmd import Noti
    _OPT_CALL_IN_MAIN_THREAD = '_OPT_CALL_IN_MAIN_THREAD'
    _OPT_KEY_UP_HOTKEY = '_OPT_KEY_UP_HOTKEY'
    hotkey_info_s = []
    for spec in specs:
        full_spec = list(spec)
         Get hotkey pattern
        hotkey_pattern = spec[0]
         Get hotkey function list
        func_list = spec[1:]
         Whether the hotkey type is key-sequence
        is_hotseq = False
         Option list
        opt_s = []
         If the hotkey pattern is None,
         it means to add event function, not hotkey function.
         This aims to co-work with code at 4QTR9.
        if hotkey_pattern is None:
             Use the hotkey pattern as-is
            pass
         If the hotkey pattern is list,
         it is assumed to be a list of virtual keys.
         This aims to co-work with code at 4JPY2.
        elif isinstance(hotkey_pattern, list):
             Use the hotkey pattern as-is
            pass
         If the hotkey pattern is string
        elif isinstance(hotkey_pattern, str):
             If the hotkey pattern starts with `$`
            if hotkey_pattern.startswith('$'):
                 Add `call in main thread` option
                opt_s.append(_OPT_CALL_IN_MAIN_THREAD)
                 Remove the special character
                hotkey_pattern = hotkey_pattern[1:]
             If the hotkey pattern starts with `~`
            if hotkey_pattern.startswith('~'):
                 Add `key-up hotkey` option
                opt_s.append(_OPT_KEY_UP_HOTKEY)
                 Remove the special character
                hotkey_pattern = hotkey_pattern[1:]
             If the hotkey pattern starts with `::`,
             it means key-sequence hotkey.
            if hotkey_pattern.startswith('::'):
                 If the key sequence is empty
                if hotkey_pattern in ('::', ':::', '::::'):
                     Get error message
                    msg = 'Hot sequence can not be empty: {}.'.format(
                        repr(hotkey_pattern)
                    )
                     Raise error
                    raise ValueError(msg)
                 If the key sequence is not empty.
                 Set is key-sequence be True
                is_hotseq = True
                 If the key sequence ends with `::`
                if hotkey_pattern.endswith('::'):
                     Remove starting and ending `::`.
                     This aims to be compatible with AutoHotkey.
                    hotkey_pattern = hotkey_pattern[2:-2]
                 If the key sequence not ends with `::`
                else:
                     Remove starting `::`
                    hotkey_pattern = hotkey_pattern[2:]
                 Assert the key sequence is not empty
                assert hotkey_pattern
         If the hotkey pattern is none of above
        else:
             Raise error
            assert 0, hotkey_pattern
         Normalized function list
        norm_func_s = []
         NeedHotkeyInfo instance list
        need_info_instance_s = []
         For the hotkey function list's each function item
        for func_item in func_list:
             If the function item is string
            if isinstance(func_item, str):
                 If the string starts with `http://` or `https://`
                if func_item.startswith('http://') \
                        or func_item.startswith('https://'):
                     Use the string as URL
                    url = func_item
                     Create a function that opens the URL.
                     `webbrowser.open` returns True so can not use `partial`.
                    def new_func(url=url):
                         Open given URL
                        webbrowser.open(url)
                     Use the created function as function item
                    func_item = new_func
                 If the string is existing directory path
                elif os.path.isdir(func_item):
                     Prefix the string with `file://` protocol
                    url = 'file://' + func_item
                     Create a function that opens the URL.
                     `webbrowser.open` returns True so can not use `partial`.
                    def new_func(url=url):
                         Open given URL
                        webbrowser.open(url)
                     Use the created function as function item
                    func_item = new_func
                    if Noti not in full_spec and MuteNoti not in full_spec:
                        full_spec.append(MuteNoti)
                 If the string is none of above,
                 assume it is a command.
                else:
                     Create a function that runs the command
                    def new_func(cmd=func_item):
                         Split the command into parts
                        cmd_part_s = cmd.split()
                         Run the command
                        Popen(cmd_part_s, shell=True)
                     Use the created function as function item
                    func_item = new_func
             If the function item is `NeedHotkeyInfo` instance
            elif isinstance(func_item, NeedHotkeyInfo):
                 Add the function item to the instance list
                need_info_instance_s.append(func_item)
             If the function item is none of above
            else:
                 Use the function item as-is
                func_item = func_item
             Add the function item to the normalized function list
            norm_func_s.append(func_item)
         If the normalized function list contains only one item
        if len(norm_func_s) == 1:
             Use the only item as hotkey function
            hotkey_func = norm_func_s[0]
         If the normalized function list not contains only one item
        else:
             Combine all functions into one
            hotkey_func = _CallAll(norm_func_s)
         If `call in main thread` option is enabled
        if _OPT_CALL_IN_MAIN_THREAD in opt_s:
             Tag the function as `call in main thread`
            hotkey_func = tag_call_in_main_thread(hotkey_func)
         Whether is key-up hotkey
        is_key_up = _OPT_KEY_UP_HOTKEY in opt_s
         If is key-sequence hotkey
        if is_hotseq:
             If is key-up hotkey
            if is_key_up:
                 Get error message
                msg = 'Hot sequence can not be key-up hotkey.'
                 Raise error
                raise ValueError(msg)
             If is not key-up hotkey
             Set hotkey type be key-sequence
            hotkey_type = HOTKEY_TYPE_V_KS
         If is key-up hotkey
        elif is_key_up:
             Set hotkey type be key-up
            hotkey_type = HOTKEY_TYPE_V_UP
         If is not key-up hotkey
        else:
             Set hotkey type be key-down
            hotkey_type = HOTKEY_TYPE_V_DN
         Get hotkey info
        hotkey_info = {
            HOTKEY_INFO_K_HOTKEY_TYPE: hotkey_type,
            HOTKEY_INFO_K_HOTKEY_PATTERN: hotkey_pattern,
            HOTKEY_INFO_K_HOTKEY_FUNC: hotkey_func,
            HOTKEY_INFO_K_HOTKEY_ORIG_SPEC: spec,
            HOTKEY_INFO_K_HOTKEY_ORIG_SPEC: spec,
            HOTKEY_INFO_K_HOTKEY_FULL_SPEC: tuple(full_spec),
            HOTKEY_INFO_K_NEED_HOTKEY_INFO_LIST: need_info_instance_s,
        }
         Add the hotkey info to the hotkey info list
        hotkey_info_s.append(hotkey_info)
     Return the hotkey info list
    return hotkey_info_s
def spec_parse ( specs ) : from . util . cmd import MuteNoti from . util . cmd import Noti _OPT_CALL_IN_MAIN_THREAD = '_OPT_CALL_IN_MAIN_THREAD' _OPT_KEY_UP_HOTKEY = '_OPT_KEY_UP_HOTKEY' hotkey_info_s = [ ] for spec in specs : full_spec = list ( spec ) hotkey_pattern = spec [ 0 ] func_list = spec [ 1 : ] is_hotseq = False opt_s = [ ] if hotkey_pattern is None : pass elif isinstance ( hotkey_pattern , list ) : pass elif isinstance ( hotkey_pattern , str ) : if hotkey_pattern . startswith ( '$' ) : opt_s . append ( _OPT_CALL_IN_MAIN_THREAD ) hotkey_pattern = hotkey_pattern [ 1 : ] if hotkey_pattern . startswith ( '~' ) : opt_s . append ( _OPT_KEY_UP_HOTKEY ) hotkey_pattern = hotkey_pattern [ 1 : ] if hotkey_pattern . startswith ( '::' ) : if hotkey_pattern in ( '::' , ':::' , '::::' ) : msg = 'Hot sequence can not be empty: {}.' . format ( repr ( hotkey_pattern ) ) raise ValueError ( msg ) is_hotseq = True if hotkey_pattern . endswith ( '::' ) : hotkey_pattern = hotkey_pattern [ 2 : - 2 ] else : hotkey_pattern = hotkey_pattern [ 2 : ] assert hotkey_pattern else : assert 0 , hotkey_pattern norm_func_s = [ ] need_info_instance_s = [ ] for func_item in func_list : if isinstance ( func_item , str ) : if func_item . startswith ( 'http://' ) or func_item . startswith ( 'https://' ) : url = func_item def new_func ( url = url ) : webbrowser . open ( url ) func_item = new_func elif os . path . isdir ( func_item ) : url = 'file://' + func_item def new_func ( url = url ) : webbrowser . open ( url ) func_item = new_func if Noti not in full_spec and MuteNoti not in full_spec : full_spec . append ( MuteNoti ) else : def new_func ( cmd = func_item ) : cmd_part_s = cmd . split ( ) Popen ( cmd_part_s , shell = True ) func_item = new_func elif isinstance ( func_item , NeedHotkeyInfo ) : need_info_instance_s . append ( func_item ) else : func_item = func_item norm_func_s . append ( func_item ) if len ( norm_func_s ) == 1 : hotkey_func = norm_func_s [ 0 ] else : hotkey_func = _CallAll ( norm_func_s ) if _OPT_CALL_IN_MAIN_THREAD in opt_s : hotkey_func = tag_call_in_main_thread ( hotkey_func ) is_key_up = _OPT_KEY_UP_HOTKEY in opt_s if is_hotseq : if is_key_up : msg = 'Hot sequence can not be key-up hotkey.' raise ValueError ( msg ) hotkey_type = HOTKEY_TYPE_V_KS elif is_key_up : hotkey_type = HOTKEY_TYPE_V_UP else : hotkey_type = HOTKEY_TYPE_V_DN hotkey_info = { HOTKEY_INFO_K_HOTKEY_TYPE : hotkey_type , HOTKEY_INFO_K_HOTKEY_PATTERN : hotkey_pattern , HOTKEY_INFO_K_HOTKEY_FUNC : hotkey_func , HOTKEY_INFO_K_HOTKEY_ORIG_SPEC : spec , HOTKEY_INFO_K_HOTKEY_ORIG_SPEC : spec , HOTKEY_INFO_K_HOTKEY_FULL_SPEC : tuple ( full_spec ) , HOTKEY_INFO_K_NEED_HOTKEY_INFO_LIST : need_info_instance_s , } hotkey_info_s . append ( hotkey_info ) return hotkey_info_s
Parse hotkey spec list into hotkey info list.
Parse hotkey spec list into hotkey info list .
"""
    Parse hotkey spec list into hotkey info list.

    :param specs: Hotkey spec list.

    :return: Hotkey info list.
    """ # Import here to avoid circular import. # `Call in main thread` option # `Key-up hotkey` option # Hotkey info list # For given hotkey spec list's each hotkey spec # # Get hotkey pattern # Get hotkey function list # Whether the hotkey type is key-sequence # Option list # If the hotkey pattern is None, # it means to add event function, not hotkey function. # This aims to co-work with code at 4QTR9. # Use the hotkey pattern as-is # If the hotkey pattern is list, # it is assumed to be a list of virtual keys. # This aims to co-work with code at 4JPY2. # Use the hotkey pattern as-is # If the hotkey pattern is string # If the hotkey pattern starts with `$` # Add `call in main thread` option # Remove the special character # If the hotkey pattern starts with `~` # Add `key-up hotkey` option # Remove the special character # If the hotkey pattern starts with `::`, # it means key-sequence hotkey. # If the key sequence is empty # Get error message # Raise error # If the key sequence is not empty. # Set is key-sequence be True # If the key sequence ends with `::` # Remove starting and ending `::`. # This aims to be compatible with AutoHotkey. # If the key sequence not ends with `::` # Remove starting `::` # Assert the key sequence is not empty # If the hotkey pattern is none of above # Raise error # Normalized function list # NeedHotkeyInfo instance list # For the hotkey function list's each function item # If the function item is string # If the string starts with `http://` or `https://` # Use the string as URL # Create a function that opens the URL. # `webbrowser.open` returns True so can not use `partial`. # Open given URL # Use the created function as function item # If the string is existing directory path # Prefix the string with `file://` protocol # Create a function that opens the URL. # `webbrowser.open` returns True so can not use `partial`. # Open given URL # Use the created function as function item # # If the string is none of above, # assume it is a command. # Create a function that runs the command # Split the command into parts # Run the command # Use the created function as function item # If the function item is `NeedHotkeyInfo` instance # Add the function item to the instance list # If the function item is none of above # Use the function item as-is # Add the function item to the normalized function list # If the normalized function list contains only one item # Use the only item as hotkey function # If the normalized function list not contains only one item # Combine all functions into one # If `call in main thread` option is enabled # Tag the function as `call in main thread` # Whether is key-up hotkey # If is key-sequence hotkey # If is key-up hotkey # Get error message # Raise error # If is not key-up hotkey # Set hotkey type be key-sequence # If is key-up hotkey # Set hotkey type be key-up # If is not key-up hotkey # Set hotkey type be key-down # Get hotkey info # Add the hotkey info to the hotkey info list # Return the hotkey info list
Hotkey info list.
Hotkey info list .
specs
Hotkey spec list.
Hotkey spec list .