Esempio n. 1
0
 def check_overflow(self, line):
     """
     Update the known location of a shown history to account for the
     possibility of overflowing the display buffer.
     """
     (buf_width, buf_height) = get_buffer_size()
     (cur_x, cur_y) = get_cursor()
     lines_written = len(line) / buf_width + 1
     if cur_y + lines_written > buf_height:
         self.offset_from_bottom += cur_y + lines_written - buf_height
Esempio n. 2
0
 def check_overflow(self, line):
     """
     Update the known location of a shown history to account for the
     possibility of overflowing the display buffer.
     """
     (buf_width, buf_height) = get_buffer_size()
     (cur_x, cur_y) = get_cursor()
     lines_written = len(line) // buf_width + 1
     if cur_y + lines_written > buf_height:
         self.offset_from_bottom += cur_y + lines_written - buf_height
Esempio n. 3
0
    def display(self):
        """
        Nicely formatted display of the location history, with current location
        highlighted. If a clean display is present on the screen, this
        overwrites it to perform an 'update'.
        """
        buffer_size = get_buffer_size()

        if self.shown and self.disp_size == buffer_size:
            # We just need to update the previous display, so we
            # go back to the original display start point
            move_cursor(0, buffer_size[1] - self.offset_from_bottom)
        else:
            # We need to redisplay, so remember the start point for
            # future updates
            self.disp_size = buffer_size
            self.offset_from_bottom = buffer_size[1] - get_cursor()[1]

        stdout.write('\n')
        lines_written = 2
        stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT)
        for i in range(len(self.locations)):
            location = self.locations[i]
            if i < 9:
                prefix = ' +%d  ' % (i + 1)
            else:
                prefix = ' %d  ' % (i + 1)
            lines_written += (len(prefix + location) / buffer_size[0] + 1)
            if i != self.index:
                # Non-selected entry, simply print 
                stdout.write(prefix + location + '\n')
            else:
                # Currently selected entry, print with highlight
                stdout.write(appearance.colors.dir_history_selection +
                             prefix +
                             location +
                             color.Fore.DEFAULT +
                             color.Back.DEFAULT)
                stdout.write(' ' * (buffer_size[0] - get_cursor()[0]))

        # Check whether we have overflown the buffer
        if lines_written > self.offset_from_bottom:
            self.offset_from_bottom = lines_written

        # Mark a clean display of the history
        self.shown = True
Esempio n. 4
0
    def display(self):
        """
        Nicely formatted display of the location history, with current location
        highlighted. If a clean display is present on the screen, this
        overwrites it to perform an 'update'.
        """
        buffer_size = get_buffer_size()

        if self.shown and self.disp_size == buffer_size:
            # We just need to update the previous display, so we
            # go back to the original display start point
            move_cursor(0, buffer_size[1] - self.offset_from_bottom)
        else:
            # We need to redisplay, so remember the start point for
            # future updates
            self.disp_size = buffer_size
            self.offset_from_bottom = buffer_size[1] - get_cursor()[1]

        stdout.write('\n')
        lines_written = 2
        stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT)
        for i in range(len(self.locations)):
            location = self.locations[i]
            prefix = ' %d  ' % (i + 1)
            lines_written += (len(prefix + location) / buffer_size[0] + 1)
            if i != self.index:
                # Non-selected entry, simply print 
                stdout.write(prefix + location + '\n')
            else:
                # Currently selected entry, print with highlight
                stdout.write(appearance.colors.dir_history_selection +
                             prefix +
                             location +
                             color.Fore.DEFAULT +
                             color.Back.DEFAULT)
                stdout.write(' ' * (buffer_size[0] - get_cursor()[0]))

        # Check whether we have overflown the buffer
        if lines_written > self.offset_from_bottom:
            self.offset_from_bottom = lines_written

        # Mark a clean display of the history
        self.shown = True
Esempio n. 5
0
def main():
    title_prefix = ""

    # Apply global and user configurations
    apply_settings(pycmd_install_dir + '\\init.py', (pycmd_install_dir, pycmd_data_dir))
    apply_settings(pycmd_data_dir + '\\init.py', (pycmd_install_dir, pycmd_data_dir))
    sanitize_settings()

    init_hooks = get_hooks(hook_types[0])
    if len(init_hooks) > 0:
        for hook in init_hooks.values():
            hook()
    # Parse arguments
    arg = 1
    while arg < len(sys.argv):
        switch = sys.argv[arg].upper()
        rest = ['"' + t + '"' if os.path.exists(t) else t
                for t in sys.argv[arg+1:]]
        if switch in ['/K', '-K']:
            # Run the specified command and continue
            if len(rest) > 0:
                run_command(rest)
                dir_hist.visit_cwd()
                break
        elif switch in ['/C', '-C']:
            # Run the specified command end exit
            if len(rest) > 0:
                run_command(rest)
            internal_exit()
        elif switch in ['/H', '/?', '-H']:
            # Show usage information and exit
            print_usage()
            internal_exit()
        elif switch in ['/T', '-T']:
            if arg == len(sys.argv) - 1:
                sys.stderr.write('PyCmd: no title specified to \'-t\'\n')
                print_usage()
                internal_exit()
            title_prefix = sys.argv[arg + 1] + ' - '
            arg += 1
        elif switch in ['/I', '-I']:
            if arg == len(sys.argv) - 1:
                sys.stderr.write('PyCmd: no script specified to \'-i\'\n')
                print_usage()
                internal_exit()
            apply_settings(sys.argv[arg + 1], (pycmd_install_dir, pycmd_data_dir))
            sanitize_settings()
            arg += 1
        elif switch in ['/Q', '-Q']:
            # Quiet mode: suppress messages
            behavior.quiet_mode = True
        else:
            # Invalid command line switch
            sys.stderr.write('PyCmd: unrecognized option `' + sys.argv[arg] + '\'\n')
            print_usage()
            internal_exit()
        arg += 1

    if not behavior.quiet_mode:
        # Print some splash text
        try:
            from buildinfo import build_info
        except ImportError:
            build_info = '<no build info>'

        print
        print 'Welcome to PyCmd %s!' % build_info
        print

    # Run an empty command to initialize environment
    run_command(['echo', '>', 'NUL'])

    # Main loop
    while True:
        # Prepare buffer for reading one line
        state.reset_line(appearance.prompt())
        scrolling = False
        auto_select = False
        force_repaint = True
        dir_hist.shown = False
        print

        while True:
            # Update console title and environment
            curdir = os.getcwd()
            curdir = curdir[0].upper() + curdir[1:]
            console.set_console_title(title_prefix + curdir + ' - PyCmd')
            os.environ['CD'] = curdir

            if state.changed() or force_repaint:
                prev_total_len = len(remove_escape_sequences(state.prev_prompt) + state.prev_before_cursor + state.prev_after_cursor)
                set_cursor_visible(False)
                cursor_backward(len(remove_escape_sequences(state.prev_prompt) + state.prev_before_cursor))
                sys.stdout.write('\r')

                # Update the offset of the directory history in case of overflow
                # Note that if the history display is marked as 'dirty'
                # (dir_hist.shown == False) the result of this action can be
                # ignored
                dir_hist.check_overflow(remove_escape_sequences(state.prompt))

                # Write current line
                sys.stdout.write('\r' + color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.prompt +
                          state.prompt +
                          color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text)
                line = state.before_cursor + state.after_cursor
                if state.history.filter == '':
                    sel_start, sel_end = state.get_selection_range()
                    sys.stdout.write(line[:sel_start] +
                                 appearance.colors.selection +
                                 line[sel_start: sel_end] +
                                 color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text +
                                 line[sel_end:])
                else:
                    pos = 0
                    colored_line = ''
                    for (start, end) in state.history.current()[1]:
                        colored_line += color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text + line[pos : start]
                        colored_line += appearance.colors.search_filter + line[start : end]
                        pos = end
                    colored_line += color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text + line[pos:]
                    sys.stdout.write(colored_line)

                # Erase remaining chars from old line
                to_erase = prev_total_len - len(remove_escape_sequences(state.prompt) + state.before_cursor + state.after_cursor)
                if to_erase > 0:
                    sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT + ' ' * to_erase)
                    cursor_backward(to_erase)

                # Move cursor to the correct position
                set_cursor_visible(True)
                cursor_backward(len(state.after_cursor))

            # Prepare new input state
            state.step_line()

            # Read and process a keyboard event
            rec = read_input()
            select = auto_select or is_shift_pressed(rec)

            # Will be overriden if Shift-PgUp/Dn is pressed
            force_repaint = not is_control_only(rec)

            #print '\n\n', rec.keyDown, rec.char, rec.virtualKeyCode, rec.controlKeyState, '\n\n'
            recChar = rec.CU.Char if PYPY else rec.Char
            if is_ctrl_pressed(rec) and not is_alt_pressed(rec):  # Ctrl-Something
                if recChar == chr(4):                  # Ctrl-D
                    if state.before_cursor + state.after_cursor == '':
                        internal_exit('\r\nBye!')
                    else:
                        state.handle(ActionCode.ACTION_DELETE)
                elif recChar == chr(31):                   # Ctrl-_
                    state.handle(ActionCode.ACTION_UNDO_EMACS)
                    auto_select = False
                elif rec.VirtualKeyCode == 75:          # Ctrl-K
                    state.handle(ActionCode.ACTION_KILL_EOL)
                elif rec.VirtualKeyCode == 32:          # Ctrl-Space
                    auto_select = True
                    state.reset_selection()
                elif rec.VirtualKeyCode == 71:          # Ctrl-G
                    if scrolling:
                        scrolling = False
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                        save_history(state.history.list,
                                     pycmd_data_dir + '\\history',
                                     1000)
                        auto_select = False
                elif rec.VirtualKeyCode == 65:          # Ctrl-A
                    state.handle(ActionCode.ACTION_HOME, select)
                elif rec.VirtualKeyCode == 69:          # Ctrl-E
                    state.handle(ActionCode.ACTION_END, select)
                elif rec.VirtualKeyCode == 66:          # Ctrl-B
                    state.handle(ActionCode.ACTION_LEFT, select)
                elif rec.VirtualKeyCode == 70:          # Ctrl-F
                    state.handle(ActionCode.ACTION_RIGHT, select)
                elif rec.VirtualKeyCode == 80:          # Ctrl-P
                    state.handle(ActionCode.ACTION_PREV)
                elif rec.VirtualKeyCode == 78:          # Ctrl-N
                    state.handle(ActionCode.ACTION_NEXT)
                elif rec.VirtualKeyCode == 37:          # Ctrl-Left
                    state.handle(ActionCode.ACTION_LEFT_WORD, select)
                elif rec.VirtualKeyCode == 39:          # Ctrl-Right
                    state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 46:          # Ctrl-Delete
                    state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 67:          # Ctrl-C
                    # The Ctrl-C signal is caught by our custom handler, and a
                    # synthetic keyboard event is created so that we can catch
                    # it here
                    if state.get_selection() != '':
                        state.handle(ActionCode.ACTION_COPY)
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                    auto_select = False
                elif rec.VirtualKeyCode == 88:          # Ctrl-X
                    state.handle(ActionCode.ACTION_CUT)
                    auto_select = False
                elif rec.VirtualKeyCode == 87:          # Ctrl-W
                    state.handle(ActionCode.ACTION_CUT)
                    auto_select = False
                elif rec.VirtualKeyCode == 86:          # Ctrl-V
                    state.handle(ActionCode.ACTION_PASTE)
                    auto_select = False
                elif rec.VirtualKeyCode == 89:          # Ctrl-Y
                    state.handle(ActionCode.ACTION_PASTE)
                    auto_select = False
                elif rec.VirtualKeyCode == 8:           # Ctrl-Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE_WORD)
                elif rec.VirtualKeyCode == 90:
                    if not is_shift_pressed(rec):       # Ctrl-Z
                        state.handle(ActionCode.ACTION_UNDO)
                    else:                               # Ctrl-Shift-Z
                        state.handle(ActionCode.ACTION_REDO)
                    auto_select = False
            elif is_alt_pressed(rec) and not is_ctrl_pressed(rec):      # Alt-Something
                if rec.VirtualKeyCode in [37, 39] + range(49, 59):      # Dir history
                    if state.before_cursor + state.after_cursor == '':
                        state.reset_prev_line()
                        if rec.VirtualKeyCode == 37:            # Alt-Left
                            changed = dir_hist.go_left()
                        elif rec.VirtualKeyCode == 39:          # Alt-Right
                            changed = dir_hist.go_right()
                        else:                                   # Alt-1..Alt-9
                            changed = dir_hist.jump(rec.VirtualKeyCode - 48)
                        if changed:
                            state.prev_prompt = state.prompt
                            state.prompt = appearance.prompt()
                        save_history(dir_hist.locations,
                                     pycmd_data_dir + '\\dir_history',
                                     dir_hist.max_len)
                        if dir_hist.shown:
                            dir_hist.display()
                            sys.stdout.write(state.prev_prompt)
                    else:
                        if rec.VirtualKeyCode == 37:            # Alt-Left
                            state.handle(ActionCode.ACTION_LEFT_WORD, select)
                        elif rec.VirtualKeyCode == 39:          # Alt-Right
                            state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 66:          # Alt-B
                    state.handle(ActionCode.ACTION_LEFT_WORD, select)
                elif rec.VirtualKeyCode == 70:          # Alt-F
                    state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 80:          # Alt-P
                    state.handle(ActionCode.ACTION_PREV)
                elif rec.VirtualKeyCode == 78:          # Alt-N
                    state.handle(ActionCode.ACTION_NEXT)
                elif rec.VirtualKeyCode == 68:          # Alt-D
                    if state.before_cursor + state.after_cursor == '':
                        dir_hist.display()
                        dir_hist.check_overflow(remove_escape_sequences(state.prev_prompt))
                        sys.stdout.write(state.prev_prompt)
                    else:
                        state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 87:          # Alt-W
                    state.handle(ActionCode.ACTION_COPY)
                    state.reset_selection()
                    auto_select = False
                elif rec.VirtualKeyCode == 46:          # Alt-Delete
                    state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 8:           # Alt-Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE_WORD)
                elif rec.VirtualKeyCode == 191:
                    state.handle(ActionCode.ACTION_EXPAND)
            elif is_shift_pressed(rec) and rec.VirtualKeyCode == 33:    # Shift-PgUp
                (_, t, _, b) = get_viewport()
                scroll_buffer(t - b + 2)
                scrolling = True
                force_repaint = False
            elif is_shift_pressed(rec) and rec.VirtualKeyCode == 34:    # Shift-PgDn
                (_, t, _, b) = get_viewport()
                scroll_buffer(b - t - 2)
                scrolling = True
                force_repaint = False
            else:                                       # Clean key (no modifiers)
                if recChar == chr(0):                  # Special key (arrows and such)
                    if rec.VirtualKeyCode == 37:        # Left arrow
                        state.handle(ActionCode.ACTION_LEFT, select)
                    elif rec.VirtualKeyCode == 39:      # Right arrow
                        state.handle(ActionCode.ACTION_RIGHT, select)
                    elif rec.VirtualKeyCode == 36:      # Home
                        state.handle(ActionCode.ACTION_HOME, select)
                    elif rec.VirtualKeyCode == 35:      # End
                        state.handle(ActionCode.ACTION_END, select)
                    elif rec.VirtualKeyCode == 38:      # Up arrow
                        state.handle(ActionCode.ACTION_PREV)
                    elif rec.VirtualKeyCode == 40:      # Down arrow
                        state.handle(ActionCode.ACTION_NEXT)
                    elif rec.VirtualKeyCode == 46:      # Delete
                        state.handle(ActionCode.ACTION_DELETE)
                elif recChar == chr(13):               # Enter
                    state.history.reset()
                    break
                elif recChar == chr(27):               # Esc
                    if scrolling:
                        scrolling = False
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                        save_history(state.history.list,
                                     pycmd_data_dir + '\\history',
                                     1000)
                        auto_select = False
                elif recChar == '\t':                  # Tab
                    sys.stdout.write(state.after_cursor)        # Move cursor to the end

                    tokens = parse_line(state.before_cursor)
                    if tokens == [] or state.before_cursor[-1] in sep_chars:
                        tokens.append('')   # This saves some checks later on
                    if tokens[-1].strip('"').count('%') % 2 == 1:
                        (completed, suggestions) = complete_env_var(state.before_cursor)
                    elif has_wildcards(tokens[-1]):
                        (completed, suggestions)  = complete_wildcard(state.before_cursor)
                    else:
                        (completed, suggestions)  = complete_file(state.before_cursor)

                    # Show multiple completions if available
                    if len(suggestions) > 1:
                        dir_hist.shown = False  # The displayed dirhist is no longer valid
                        column_width = max([len(s) for s in suggestions]) + 10
                        if column_width > console.get_buffer_size()[0] - 1:
                            column_width = console.get_buffer_size()[0] - 1
                        if len(suggestions) > (get_viewport()[3] - get_viewport()[1]) / 4:
                            # We print multiple columns to save space
                            num_columns = (console.get_buffer_size()[0] - 1) / column_width
                        else:
                            # We print a single column for clarity
                            num_columns = 1
                        num_lines = len(suggestions) / num_columns
                        if len(suggestions) % num_columns != 0:
                            num_lines += 1

                        num_screens = 1.0 * num_lines / (get_viewport()[3] - get_viewport()[1])
                        if num_screens >= 0.9:
                            # We ask for confirmation before displaying many completions
                            (c_x, c_y) = get_cursor()
                            offset_from_bottom = console.get_buffer_size()[1] - c_y
                            message = ' Scroll ' + str(int(round(num_screens))) + ' screens? [Tab] '
                            sys.stdout.write('\n' + message)
                            rec = read_input()
                            move_cursor(c_x, console.get_buffer_size()[1] - offset_from_bottom)
                            sys.stdout.write('\n' + ' ' * len(message))
                            move_cursor(c_x, console.get_buffer_size()[1] - offset_from_bottom)
                            if recChar != '\t':
                                continue

                        sys.stdout.write('\n')
                        for line in range(0, num_lines):
                            # Print one line
                            sys.stdout.write('\r')
                            for column in range(0, num_columns):
                                if line + column * num_lines < len(suggestions):
                                    s = suggestions[line + column * num_lines]
                                    if has_wildcards(tokens[-1]):
                                        # Print wildcard matches in a different color
                                        tokens = parse_line(completed.rstrip('\\'))
                                        token = tokens[-1].replace('"', '')
                                        (_, _, prefix) = token.rpartition('\\')
                                        match = wildcard_to_regex(prefix + '*').match(s)
                                        current_index = 0
                                        for i in range(1, match.lastindex + 1):
                                            sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT +
                                                         appearance.colors.completion_match +
                                                         s[current_index : match.start(i)] +
                                                         color.Fore.DEFAULT + color.Back.DEFAULT +
                                                         s[match.start(i) : match.end(i)])
                                            current_index = match.end(i)
                                        sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT + ' ' * (column_width - len(s)))
                                    else:
                                        # Print the common part in a different color
                                        common_prefix_len = len(find_common_prefix(state.before_cursor, suggestions))
                                        sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT +
                                                     appearance.colors.completion_match +
                                                     s[:common_prefix_len] +
                                                     color.Fore.DEFAULT + color.Back.DEFAULT +
                                                     s[common_prefix_len : ])
                                        sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT + ' ' * (column_width - len(s)))
                            sys.stdout.write('\n')
                        state.reset_prev_line()
                    state.handle(ActionCode.ACTION_COMPLETE, completed)
                elif rec.Char == chr(8):                # Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE)
                else:                                   # Regular character
                    state.handle(ActionCode.ACTION_INSERT, rec.Char)


        # Done reading line, now execute
        sys.stdout.write(state.after_cursor)        # Move cursor to the end
        sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT)
        line = (state.before_cursor + state.after_cursor).strip()
        tokens = parse_line(line)
        if tokens == [] or tokens[0] == '':
            continue
        else:
            print
            run_command(tokens)

        # Add to history
        state.history.add(line)
        save_history(state.history.list,
                     pycmd_data_dir + '\\history',
                     1000)


        # Add to dir history
        dir_hist.visit_cwd()
        save_history(dir_hist.locations,
                     pycmd_data_dir + '\\dir_history',
                     dir_hist.max_len)
Esempio n. 6
0
                    elif has_wildcards(tokens[-1]):
                        (completed,
                         suggestions) = complete_wildcard(state.before_cursor)
                    else:
                        (completed,
                         suggestions) = complete_file(state.before_cursor)

                    cursor_backward(len(state.before_cursor))
                    state.handle(ActionCode.ACTION_COMPLETE, completed)
                    stdout.write(state.before_cursor + state.after_cursor)

                    # Show multiple completions if available
                    if len(suggestions) > 1:
                        dir_hist.shown = False  # The displayed dirhist is no longer valid
                        column_width = max([len(s) for s in suggestions]) + 10
                        if column_width > console.get_buffer_size()[0] - 1:
                            column_width = console.get_buffer_size()[0] - 1
                        if len(suggestions) > (get_viewport()[3] -
                                               get_viewport()[1]) / 4:
                            # We print multiple columns to save space
                            num_columns = (console.get_buffer_size()[0] -
                                           1) / column_width
                        else:
                            # We print a single column for clarity
                            num_columns = 1
                        num_lines = len(suggestions) / num_columns
                        if len(suggestions) % num_columns != 0:
                            num_lines += 1

                        num_screens = 1.0 * num_lines / (get_viewport()[3] -
                                                         get_viewport()[1])
Esempio n. 7
0
def list_and_switch():
    winstate_full_path = os.path.join(pycmd_data_dir, windows_state_path)
    with open(winstate_full_path, 'r') as f:
        winstate = f.readlines()
    winstate.reverse()

    first_line = True
    index = 0
    orig_index = -1
    index_map = []
    remove_hwnd_list = []
    columns = console.get_buffer_size()[0] - 3
    currHwnd = py_GetConsoleWindow()

    for line in winstate:
        orig_index += 1
        states = line.split(winstate_separator)
        if len(states) != 3:
            print("Warning: unsupported line for windows switch: ", line)
            continue

        hwnd  = int(states[0])
        if hwnd == currHwnd:
            continue
        if not py_IsWindow(hwnd):
            remove_hwnd_list.append(hwnd)
            continue

        curr_index_char = chr(ord('a') + index)
        index += 1
        index_map.append(orig_index)
        pwd = states[1].strip() + '> '
        cmd = states[2].strip()

        if len(pwd) > columns:
            pwd = pwd[0: column - 5] + '...> '
            cmd = ''
        else:
            left_columns = columns - len(pwd)
            if len(cmd) > left_columns:
                if left_columns >= 3:
                    cmd = cmd[0:left_columns - 3] + '...'

        if first_line:
            sys.stdout.write('\n\n')
            first_line = False

        if index % 2 == 0:
            color_str_cmd = color.Fore.RED + color.Fore.CLEAR_BRIGHT
            color_str_pwd = color.Fore.RED + color.Fore.SET_BRIGHT
        else:
            color_str_cmd = color.Fore.GREEN + color.Fore.CLEAR_BRIGHT
            color_str_pwd = color.Fore.GREEN + color.Fore.SET_BRIGHT
        sys.stdout.write(color_str_pwd + curr_index_char + ': ' + pwd + color_str_cmd + cmd + '\n')

    if index == 0:
        return
    sys.stdout.write(color.Fore.DEFAULT + '\n')
    message = ' Press a-z to switch to target PyCmd, space to ignore: '
    sys.stdout.write(message)

    rec = console.read_input()
    select_id = ord(rec.Char) - ord('a')
    #TODO: refresh current line instead of output new line?
    # Why 1 '\n' doesn't work? Know why, because cmd prompt is up for 1 line,
    # which occupies the message line scrolled by 1 line
    #sys.stdout.write('\n\n')
    sys.stdout.write('\r' + ' ' * len(message))
    if 0 <= select_id < index:
        to_line = winstate[index_map[select_id]]
        to_line_list = to_line.split(winstate_separator)
        to_hwnd = int(to_line_list[0])
        PyCmdUtils.SwitchToHwnd(to_hwnd)

        update_window_state(to_line_list[1], to_line_list[2], to_hwnd, remove_hwnd_list)
Esempio n. 8
0
def list_and_switch():
    winstate_full_path = os.path.join(pycmd_data_dir, windows_state_path)
    with open(winstate_full_path, 'r') as f:
        winstate = f.readlines()
    winstate.reverse()

    first_line = True
    index = 0
    orig_index = -1
    index_map = []
    remove_hwnd_list = []
    columns = console.get_buffer_size()[0] - 3
    currHwnd = py_GetConsoleWindow()

    for line in winstate:
        orig_index += 1
        states = line.split(winstate_separator)
        if len(states) != 3:
            print("Warning: unsupported line for windows switch: ", line)
            continue

        hwnd = int(states[0])
        if hwnd == currHwnd:
            continue
        if not py_IsWindow(hwnd):
            remove_hwnd_list.append(hwnd)
            continue

        curr_index_char = chr(ord('a') + index)
        index += 1
        index_map.append(orig_index)
        pwd = states[1].strip() + '> '
        cmd = states[2].strip()

        if len(pwd) > columns:
            pwd = pwd[0:column - 5] + '...> '
            cmd = ''
        else:
            left_columns = columns - len(pwd)
            if len(cmd) > left_columns:
                if left_columns >= 3:
                    cmd = cmd[0:left_columns - 3] + '...'

        if first_line:
            sys.stdout.write('\n\n')
            first_line = False

        if index % 2 == 0:
            color_str_cmd = color.Fore.RED + color.Fore.CLEAR_BRIGHT
            color_str_pwd = color.Fore.RED + color.Fore.SET_BRIGHT
        else:
            color_str_cmd = color.Fore.GREEN + color.Fore.CLEAR_BRIGHT
            color_str_pwd = color.Fore.GREEN + color.Fore.SET_BRIGHT
        sys.stdout.write(color_str_pwd + curr_index_char + ': ' + pwd +
                         color_str_cmd + cmd + '\n')

    if index == 0:
        return
    sys.stdout.write(color.Fore.DEFAULT + '\n')
    message = ' Press a-z to switch to target PyCmd, space to ignore: '
    sys.stdout.write(message)

    rec = console.read_input()
    select_id = ord(rec.Char) - ord('a')
    #TODO: refresh current line instead of output new line?
    # Why 1 '\n' doesn't work? Know why, because cmd prompt is up for 1 line,
    # which occupies the message line scrolled by 1 line
    #sys.stdout.write('\n\n')
    sys.stdout.write('\r' + ' ' * len(message))
    if 0 <= select_id < index:
        to_line = winstate[index_map[select_id]]
        to_line_list = to_line.split(winstate_separator)
        to_hwnd = int(to_line_list[0])
        PyCmdUtils.SwitchToHwnd(to_hwnd)

        update_window_state(to_line_list[1], to_line_list[2], to_hwnd,
                            remove_hwnd_list)
Esempio n. 9
0
                            expanded_token = expanded_token + '..\\'
                        
                        tokens[-1] = expanded_token
                        completed = ' '.join(tokens)
                    elif tokens[-1].strip('"').count('%') % 2 == 1:
                        (completed, suggestions) = complete_env_var(state.before_cursor)
                    elif has_wildcards(tokens[-1]):
                        (completed, suggestions)  = complete_wildcard(state.before_cursor)
                    else:
                        (completed, suggestions)  = complete_file(state.before_cursor)

                    # Show multiple completions if available
                    if len(suggestions) > 1:
                        dir_hist.shown = False  # The displayed dirhist is no longer valid
                        column_width = max([len(s) for s in suggestions]) + 10
                        if column_width > console.get_buffer_size()[0] - 1:
                            column_width = console.get_buffer_size()[0] - 1
                        if len(suggestions) > (get_viewport()[3] - get_viewport()[1]) / 4:
                            # We print multiple columns to save space
                            num_columns = (console.get_buffer_size()[0] - 1) / column_width
                        else:
                            # We print a single column for clarity
                            num_columns = 1
                        num_lines = len(suggestions) / num_columns
                        if len(suggestions) % num_columns != 0:
                            num_lines += 1

                        num_screens = 1.0 * num_lines / (get_viewport()[3] - get_viewport()[1])
                        if num_screens >= 0.9:
                            # We ask for confirmation before displaying many completions
                            (c_x, c_y) = get_cursor()
Esempio n. 10
0
def main():
    title_prefix = ""

    # Apply global and user configurations
    apply_settings(pycmd_install_dir + '\\init.py',
                   (pycmd_install_dir, pycmd_data_dir))
    apply_settings(pycmd_data_dir + '\\init.py',
                   (pycmd_install_dir, pycmd_data_dir))
    sanitize_settings()

    init_hooks = get_hooks(hook_types[0])
    if len(init_hooks) > 0:
        for hook in init_hooks.values():
            hook()
    # Parse arguments
    arg = 1
    while arg < len(sys.argv):
        switch = sys.argv[arg].upper()
        rest = [
            '"' + t + '"' if os.path.exists(t) else t
            for t in sys.argv[arg + 1:]
        ]
        if switch in ['/K', '-K']:
            # Run the specified command and continue
            if len(rest) > 0:
                run_command(rest)
                dir_hist.visit_cwd()
                break
        elif switch in ['/C', '-C']:
            # Run the specified command end exit
            if len(rest) > 0:
                run_command(rest)
            internal_exit()
        elif switch in ['/H', '/?', '-H']:
            # Show usage information and exit
            print_usage()
            internal_exit()
        elif switch in ['/T', '-T']:
            if arg == len(sys.argv) - 1:
                sys.stderr.write('PyCmd: no title specified to \'-t\'\n')
                print_usage()
                internal_exit()
            title_prefix = sys.argv[arg + 1] + ' - '
            arg += 1
        elif switch in ['/I', '-I']:
            if arg == len(sys.argv) - 1:
                sys.stderr.write('PyCmd: no script specified to \'-i\'\n')
                print_usage()
                internal_exit()
            apply_settings(sys.argv[arg + 1],
                           (pycmd_install_dir, pycmd_data_dir))
            sanitize_settings()
            arg += 1
        elif switch in ['/Q', '-Q']:
            # Quiet mode: suppress messages
            behavior.quiet_mode = True
        else:
            # Invalid command line switch
            sys.stderr.write('PyCmd: unrecognized option `' + sys.argv[arg] +
                             '\'\n')
            print_usage()
            internal_exit()
        arg += 1

    if not behavior.quiet_mode:
        # Print some splash text
        try:
            from buildinfo import build_info
        except ImportError:
            build_info = '<no build info>'

        print
        print 'Welcome to PyCmd %s!' % build_info
        print

    # Run an empty command to initialize environment
    run_command(['echo', '>', 'NUL'])

    # Main loop
    while True:
        # Prepare buffer for reading one line
        state.reset_line(appearance.prompt())
        scrolling = False
        auto_select = False
        force_repaint = True
        dir_hist.shown = False
        print

        while True:
            # Update console title and environment
            curdir = os.getcwd()
            curdir = curdir[0].upper() + curdir[1:]
            console.set_console_title(title_prefix + curdir + ' - PyCmd')
            os.environ['CD'] = curdir

            if state.changed() or force_repaint:
                prev_total_len = len(
                    remove_escape_sequences(state.prev_prompt) +
                    state.prev_before_cursor + state.prev_after_cursor)
                set_cursor_visible(False)
                cursor_backward(
                    len(
                        remove_escape_sequences(state.prev_prompt) +
                        state.prev_before_cursor))
                sys.stdout.write('\r')

                # Update the offset of the directory history in case of overflow
                # Note that if the history display is marked as 'dirty'
                # (dir_hist.shown == False) the result of this action can be
                # ignored
                dir_hist.check_overflow(remove_escape_sequences(state.prompt))

                # Write current line
                sys.stdout.write('\r' + color.Fore.DEFAULT +
                                 color.Back.DEFAULT +
                                 appearance.colors.prompt + state.prompt +
                                 color.Fore.DEFAULT + color.Back.DEFAULT +
                                 appearance.colors.text)
                line = state.before_cursor + state.after_cursor
                if state.history.filter == '':
                    sel_start, sel_end = state.get_selection_range()
                    sys.stdout.write(line[:sel_start] +
                                     appearance.colors.selection +
                                     line[sel_start:sel_end] +
                                     color.Fore.DEFAULT + color.Back.DEFAULT +
                                     appearance.colors.text + line[sel_end:])
                else:
                    pos = 0
                    colored_line = ''
                    for (start, end) in state.history.current()[1]:
                        colored_line += color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text + line[
                            pos:start]
                        colored_line += appearance.colors.search_filter + line[
                            start:end]
                        pos = end
                    colored_line += color.Fore.DEFAULT + color.Back.DEFAULT + appearance.colors.text + line[
                        pos:]
                    sys.stdout.write(colored_line)

                # Erase remaining chars from old line
                to_erase = prev_total_len - len(
                    remove_escape_sequences(state.prompt) +
                    state.before_cursor + state.after_cursor)
                if to_erase > 0:
                    sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT +
                                     ' ' * to_erase)
                    cursor_backward(to_erase)

                # Move cursor to the correct position
                set_cursor_visible(True)
                cursor_backward(len(state.after_cursor))

            # Prepare new input state
            state.step_line()

            # Read and process a keyboard event
            rec = read_input()
            select = auto_select or is_shift_pressed(rec)

            # Will be overriden if Shift-PgUp/Dn is pressed
            force_repaint = not is_control_only(rec)

            #print '\n\n', rec.keyDown, rec.char, rec.virtualKeyCode, rec.controlKeyState, '\n\n'
            recChar = rec.CU.Char if PYPY else rec.Char
            if is_ctrl_pressed(
                    rec) and not is_alt_pressed(rec):  # Ctrl-Something
                if recChar == chr(4):  # Ctrl-D
                    if state.before_cursor + state.after_cursor == '':
                        internal_exit('\r\nBye!')
                    else:
                        state.handle(ActionCode.ACTION_DELETE)
                elif recChar == chr(31):  # Ctrl-_
                    state.handle(ActionCode.ACTION_UNDO_EMACS)
                    auto_select = False
                elif rec.VirtualKeyCode == 75:  # Ctrl-K
                    state.handle(ActionCode.ACTION_KILL_EOL)
                elif rec.VirtualKeyCode == 32:  # Ctrl-Space
                    auto_select = True
                    state.reset_selection()
                elif rec.VirtualKeyCode == 71:  # Ctrl-G
                    if scrolling:
                        scrolling = False
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                        save_history(state.history.list,
                                     pycmd_data_dir + '\\history', 1000)
                        auto_select = False
                elif rec.VirtualKeyCode == 65:  # Ctrl-A
                    state.handle(ActionCode.ACTION_HOME, select)
                elif rec.VirtualKeyCode == 69:  # Ctrl-E
                    state.handle(ActionCode.ACTION_END, select)
                elif rec.VirtualKeyCode == 66:  # Ctrl-B
                    state.handle(ActionCode.ACTION_LEFT, select)
                elif rec.VirtualKeyCode == 70:  # Ctrl-F
                    state.handle(ActionCode.ACTION_RIGHT, select)
                elif rec.VirtualKeyCode == 80:  # Ctrl-P
                    state.handle(ActionCode.ACTION_PREV)
                elif rec.VirtualKeyCode == 78:  # Ctrl-N
                    state.handle(ActionCode.ACTION_NEXT)
                elif rec.VirtualKeyCode == 37:  # Ctrl-Left
                    state.handle(ActionCode.ACTION_LEFT_WORD, select)
                elif rec.VirtualKeyCode == 39:  # Ctrl-Right
                    state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 46:  # Ctrl-Delete
                    state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 67:  # Ctrl-C
                    # The Ctrl-C signal is caught by our custom handler, and a
                    # synthetic keyboard event is created so that we can catch
                    # it here
                    if state.get_selection() != '':
                        state.handle(ActionCode.ACTION_COPY)
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                    auto_select = False
                elif rec.VirtualKeyCode == 88:  # Ctrl-X
                    state.handle(ActionCode.ACTION_CUT)
                    auto_select = False
                elif rec.VirtualKeyCode == 87:  # Ctrl-W
                    state.handle(ActionCode.ACTION_CUT)
                    auto_select = False
                elif rec.VirtualKeyCode == 86:  # Ctrl-V
                    state.handle(ActionCode.ACTION_PASTE)
                    auto_select = False
                elif rec.VirtualKeyCode == 89:  # Ctrl-Y
                    state.handle(ActionCode.ACTION_PASTE)
                    auto_select = False
                elif rec.VirtualKeyCode == 8:  # Ctrl-Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE_WORD)
                elif rec.VirtualKeyCode == 90:
                    if not is_shift_pressed(rec):  # Ctrl-Z
                        state.handle(ActionCode.ACTION_UNDO)
                    else:  # Ctrl-Shift-Z
                        state.handle(ActionCode.ACTION_REDO)
                    auto_select = False
            elif is_alt_pressed(
                    rec) and not is_ctrl_pressed(rec):  # Alt-Something
                if rec.VirtualKeyCode in [37, 39] + range(49,
                                                          59):  # Dir history
                    if state.before_cursor + state.after_cursor == '':
                        state.reset_prev_line()
                        if rec.VirtualKeyCode == 37:  # Alt-Left
                            changed = dir_hist.go_left()
                        elif rec.VirtualKeyCode == 39:  # Alt-Right
                            changed = dir_hist.go_right()
                        else:  # Alt-1..Alt-9
                            changed = dir_hist.jump(rec.VirtualKeyCode - 48)
                        if changed:
                            state.prev_prompt = state.prompt
                            state.prompt = appearance.prompt()
                        save_history(dir_hist.locations,
                                     pycmd_data_dir + '\\dir_history',
                                     dir_hist.max_len)
                        if dir_hist.shown:
                            dir_hist.display()
                            sys.stdout.write(state.prev_prompt)
                    else:
                        if rec.VirtualKeyCode == 37:  # Alt-Left
                            state.handle(ActionCode.ACTION_LEFT_WORD, select)
                        elif rec.VirtualKeyCode == 39:  # Alt-Right
                            state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 66:  # Alt-B
                    state.handle(ActionCode.ACTION_LEFT_WORD, select)
                elif rec.VirtualKeyCode == 70:  # Alt-F
                    state.handle(ActionCode.ACTION_RIGHT_WORD, select)
                elif rec.VirtualKeyCode == 80:  # Alt-P
                    state.handle(ActionCode.ACTION_PREV)
                elif rec.VirtualKeyCode == 78:  # Alt-N
                    state.handle(ActionCode.ACTION_NEXT)
                elif rec.VirtualKeyCode == 68:  # Alt-D
                    if state.before_cursor + state.after_cursor == '':
                        dir_hist.display()
                        dir_hist.check_overflow(
                            remove_escape_sequences(state.prev_prompt))
                        sys.stdout.write(state.prev_prompt)
                    else:
                        state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 87:  # Alt-W
                    state.handle(ActionCode.ACTION_COPY)
                    state.reset_selection()
                    auto_select = False
                elif rec.VirtualKeyCode == 46:  # Alt-Delete
                    state.handle(ActionCode.ACTION_DELETE_WORD)
                elif rec.VirtualKeyCode == 8:  # Alt-Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE_WORD)
                elif rec.VirtualKeyCode == 191:
                    state.handle(ActionCode.ACTION_EXPAND)
            elif is_shift_pressed(
                    rec) and rec.VirtualKeyCode == 33:  # Shift-PgUp
                (_, t, _, b) = get_viewport()
                scroll_buffer(t - b + 2)
                scrolling = True
                force_repaint = False
            elif is_shift_pressed(
                    rec) and rec.VirtualKeyCode == 34:  # Shift-PgDn
                (_, t, _, b) = get_viewport()
                scroll_buffer(b - t - 2)
                scrolling = True
                force_repaint = False
            else:  # Clean key (no modifiers)
                if recChar == chr(0):  # Special key (arrows and such)
                    if rec.VirtualKeyCode == 37:  # Left arrow
                        state.handle(ActionCode.ACTION_LEFT, select)
                    elif rec.VirtualKeyCode == 39:  # Right arrow
                        state.handle(ActionCode.ACTION_RIGHT, select)
                    elif rec.VirtualKeyCode == 36:  # Home
                        state.handle(ActionCode.ACTION_HOME, select)
                    elif rec.VirtualKeyCode == 35:  # End
                        state.handle(ActionCode.ACTION_END, select)
                    elif rec.VirtualKeyCode == 38:  # Up arrow
                        state.handle(ActionCode.ACTION_PREV)
                    elif rec.VirtualKeyCode == 40:  # Down arrow
                        state.handle(ActionCode.ACTION_NEXT)
                    elif rec.VirtualKeyCode == 46:  # Delete
                        state.handle(ActionCode.ACTION_DELETE)
                elif recChar == chr(13):  # Enter
                    state.history.reset()
                    break
                elif recChar == chr(27):  # Esc
                    if scrolling:
                        scrolling = False
                    else:
                        state.handle(ActionCode.ACTION_ESCAPE)
                        save_history(state.history.list,
                                     pycmd_data_dir + '\\history', 1000)
                        auto_select = False
                elif recChar == '\t':  # Tab
                    sys.stdout.write(
                        state.after_cursor)  # Move cursor to the end

                    tokens = parse_line(state.before_cursor)
                    if tokens == [] or state.before_cursor[-1] in sep_chars:
                        tokens.append('')  # This saves some checks later on
                    if tokens[-1].strip('"').count('%') % 2 == 1:
                        (completed,
                         suggestions) = complete_env_var(state.before_cursor)
                    elif has_wildcards(tokens[-1]):
                        (completed,
                         suggestions) = complete_wildcard(state.before_cursor)
                    else:
                        (completed,
                         suggestions) = complete_file(state.before_cursor)

                    # Show multiple completions if available
                    if len(suggestions) > 1:
                        dir_hist.shown = False  # The displayed dirhist is no longer valid
                        column_width = max([len(s) for s in suggestions]) + 10
                        if column_width > console.get_buffer_size()[0] - 1:
                            column_width = console.get_buffer_size()[0] - 1
                        if len(suggestions) > (get_viewport()[3] -
                                               get_viewport()[1]) / 4:
                            # We print multiple columns to save space
                            num_columns = (console.get_buffer_size()[0] -
                                           1) / column_width
                        else:
                            # We print a single column for clarity
                            num_columns = 1
                        num_lines = len(suggestions) / num_columns
                        if len(suggestions) % num_columns != 0:
                            num_lines += 1

                        num_screens = 1.0 * num_lines / (get_viewport()[3] -
                                                         get_viewport()[1])
                        if num_screens >= 0.9:
                            # We ask for confirmation before displaying many completions
                            (c_x, c_y) = get_cursor()
                            offset_from_bottom = console.get_buffer_size(
                            )[1] - c_y
                            message = ' Scroll ' + str(int(
                                round(num_screens))) + ' screens? [Tab] '
                            sys.stdout.write('\n' + message)
                            rec = read_input()
                            move_cursor(
                                c_x,
                                console.get_buffer_size()[1] -
                                offset_from_bottom)
                            sys.stdout.write('\n' + ' ' * len(message))
                            move_cursor(
                                c_x,
                                console.get_buffer_size()[1] -
                                offset_from_bottom)
                            if recChar != '\t':
                                continue

                        sys.stdout.write('\n')
                        for line in range(0, num_lines):
                            # Print one line
                            sys.stdout.write('\r')
                            for column in range(0, num_columns):
                                if line + column * num_lines < len(
                                        suggestions):
                                    s = suggestions[line + column * num_lines]
                                    if has_wildcards(tokens[-1]):
                                        # Print wildcard matches in a different color
                                        tokens = parse_line(
                                            completed.rstrip('\\'))
                                        token = tokens[-1].replace('"', '')
                                        (_, _, prefix) = token.rpartition('\\')
                                        match = wildcard_to_regex(prefix +
                                                                  '*').match(s)
                                        current_index = 0
                                        for i in range(1, match.lastindex + 1):
                                            sys.stdout.write(
                                                color.Fore.DEFAULT +
                                                color.Back.DEFAULT + appearance
                                                .colors.completion_match +
                                                s[current_index:match.start(i)]
                                                + color.Fore.DEFAULT +
                                                color.Back.DEFAULT +
                                                s[match.start(i):match.end(i)])
                                            current_index = match.end(i)
                                        sys.stdout.write(
                                            color.Fore.DEFAULT +
                                            color.Back.DEFAULT + ' ' *
                                            (column_width - len(s)))
                                    else:
                                        # Print the common part in a different color
                                        common_prefix_len = len(
                                            find_common_prefix(
                                                state.before_cursor,
                                                suggestions))
                                        sys.stdout.write(
                                            color.Fore.DEFAULT +
                                            color.Back.DEFAULT +
                                            appearance.colors.completion_match
                                            + s[:common_prefix_len] +
                                            color.Fore.DEFAULT +
                                            color.Back.DEFAULT +
                                            s[common_prefix_len:])
                                        sys.stdout.write(
                                            color.Fore.DEFAULT +
                                            color.Back.DEFAULT + ' ' *
                                            (column_width - len(s)))
                            sys.stdout.write('\n')
                        state.reset_prev_line()
                    state.handle(ActionCode.ACTION_COMPLETE, completed)
                elif rec.Char == chr(8):  # Backspace
                    state.handle(ActionCode.ACTION_BACKSPACE)
                else:  # Regular character
                    state.handle(ActionCode.ACTION_INSERT, rec.Char)

        # Done reading line, now execute
        sys.stdout.write(state.after_cursor)  # Move cursor to the end
        sys.stdout.write(color.Fore.DEFAULT + color.Back.DEFAULT)
        line = (state.before_cursor + state.after_cursor).strip()
        tokens = parse_line(line)
        if tokens == [] or tokens[0] == '':
            continue
        else:
            print
            run_command(tokens)

        # Add to history
        state.history.add(line)
        save_history(state.history.list, pycmd_data_dir + '\\history', 1000)

        # Add to dir history
        dir_hist.visit_cwd()
        save_history(dir_hist.locations, pycmd_data_dir + '\\dir_history',
                     dir_hist.max_len)