def internal_cd(args): """The internal CD command""" try: if len(args) == 0: os.chdir(expand_env_vars("~")) else: target = args[0] if target != u"\\" and target[1:] != u":\\": target = target.rstrip(u"\\") target = expand_env_vars(target.strip(u'"').strip(u" ")) os.chdir(target.encode(sys.getfilesystemencoding())) except OSError, error: stdout.write(u"\n" + str(error).replace("\\\\", "\\").decode(sys.getfilesystemencoding()))
def internal_cd(args): """The internal CD command""" try: if len(args) == 0: os.chdir(expand_env_vars('~')) else: target = args[0] if target != u'\\' and target[1:] != u':\\': target = target.rstrip(u'\\') target = expand_env_vars(target.strip(u'"').strip(u' ')) os.chdir(target.encode(sys.getfilesystemencoding())) except OSError, error: stdout.write(u'\n' + str(error).replace('\\\\', '\\').decode(sys.getfilesystemencoding()))
def internal_cd(args): """The internal CD command""" try: if len(args) == 0: os.chdir(expand_env_vars('~')) else: target = args[0] if target != u'\\' and target[1:] != u':\\': target = target.rstrip(u'\\') target = expand_env_vars(target.strip(u'"').strip(u' ')) os.chdir(target.encode(sys.getfilesystemencoding())) except OSError, error: stdout.write(u'\n' + str(error).replace('\\\\', '\\').decode( sys.getfilesystemencoding()))
def run_command(tokens): """Execute a command line (treat internal and external appropriately""" # Cleanup environment for var in pseudo_vars: if var in os.environ.keys(): del os.environ[var] if tokens[0] == 'exit': internal_exit('Bye!') elif tokens[0].lower() == 'cd' and [t for t in tokens if t in sep_tokens ] == []: # This is a single CD command -- use our custom, more handy CD internal_cd([unescape(t) for t in tokens[1:]]) else: if set(sep_tokens).intersection(tokens) == set([]): # This is a simple (non-compound) command # Crude hack so that we return to the prompt when starting GUI # applications: if we think that the first token on the given command # line is an executable, check its PE header to decide whether it's # GUI application. If it is, spawn the process and then get on with # life. cmd = expand_env_vars(tokens[0].strip('"')) dir, name = os.path.split(cmd) ext = os.path.splitext(name)[1] if not ext or ext in exec_extensions: # Executable given app = cmd else: # Not an executable -- search for the associated application if os.path.isfile(cmd): app = associated_application(ext) else: # No application will be spawned if the file doesn't exist app = None if app: executable = full_executable_path(app) if executable and os.path.splitext( executable)[1].lower() == '.exe': # This is an exe file, try to figure out whether it's a GUI # or console application if is_gui_application(executable): import subprocess s = u' '.join([expand_tilde(t) for t in tokens]) subprocess.Popen(s.encode(sys.getfilesystemencoding()), shell=True) return # Regular (external) command start_time = time.time() run_in_cmd(tokens) console_window = win32console.GetConsoleWindow() if win32gui.GetForegroundWindow( ) != console_window and time.time() - start_time > 15: # If the window is inactive, flash after long tasks win32gui.FlashWindowEx(console_window, win32con.FLASHW_ALL, 3, 750)
def run_command(tokens): """Execute a command line (treat internal and external appropriately""" # Cleanup environment for var in pseudo_vars: if var in os.environ.keys(): del os.environ[var] if tokens[0] == 'exit': internal_exit('Bye!') elif is_pure_cd(tokens): # This is a single CD command -- use our custom, more handy CD internal_cd([unescape(t) for t in tokens[1:]]) else: if set(sep_tokens).intersection(tokens) == set([]): # This is a simple (non-compound) command # Crude hack so that we return to the prompt when starting GUI # applications: if we think that the first token on the given command # line is an executable, check its PE header to decide whether it's # GUI application. If it is, spawn the process and then get on with # life. cmd = expand_env_vars(tokens[0].strip('"')) dir, name = os.path.split(cmd) ext = os.path.splitext(name)[1] if not ext or ext in exec_extensions: # Executable given app = cmd else: # Not an executable -- search for the associated application if os.path.isfile(cmd): app = associated_application(ext) else: # No application will be spawned if the file doesn't exist app = None if app: executable = full_executable_path(app) if executable and os.path.splitext(executable)[1].lower() == '.exe': # This is an exe file, try to figure out whether it's a GUI # or console application if is_gui_application(executable): import subprocess s = u' '.join([expand_tilde(t) for t in tokens]) subprocess.Popen(s.encode(sys.getfilesystemencoding()), shell=True) return # Regular (external) command start_time = time.time() run_in_cmd(tokens) console_window = win32console.GetConsoleWindow() if win32gui.GetForegroundWindow() != console_window and time.time() - start_time > 15: # If the window is inactive, flash after long t1asks win32gui.FlashWindowEx(console_window, win32con.FLASHW_ALL, 3, 750)
def init(): # %APPDATA% is not always defined (e.g. when using runas.exe) if "APPDATA" in os.environ.keys(): APPDATA = "%APPDATA%" else: APPDATA = "%USERPROFILE%\\Application Data" global pycmd_data_dir pycmd_data_dir = expand_env_vars(APPDATA + "\\PyCmd") # Create app data directory structure if not present if not os.path.isdir(pycmd_data_dir): os.mkdir(pycmd_data_dir) if not os.path.isdir(pycmd_data_dir + "\\tmp"): os.mkdir(pycmd_data_dir + "\\tmp") # Determine the "installation" directory global pycmd_install_dir pycmd_install_dir = os.path.dirname(os.path.abspath(sys.argv[0])) # Current state of the input (prompt, entered chars, history) global state state = InputState() # Read/initialize command history state.history.list = read_history(pycmd_data_dir + "\\history") # Read/initialize directory history global dir_hist dir_hist = DirHistory() dir_hist.locations = read_history(pycmd_data_dir + "\\dir_history") dir_hist.index = len(dir_hist.locations) - 1 dir_hist.visit_cwd() # Create temporary file global tmpfile (handle, tmpfile) = tempfile.mkstemp(dir=pycmd_data_dir + "\\tmp") os.close(handle) # Create result map file global resultMapFilePath (handle, resultMapFilePath) = tempfile.mkstemp(dir=pycmd_data_dir + "\\tmp") os.close(handle) os.environ["PYCMD_RESULT_MAP_FILE_PATH"] = resultMapFilePath # Create command line file global cmdLineFilePath (handle, cmdLineFilePath) = tempfile.mkstemp(dir=pycmd_data_dir + "\\tmp") os.close(handle) # Catch SIGINT to emulate Ctrl-C key combo signal.signal(signal.SIGINT, signal_handler)
def init(): # %APPDATA% is not always defined (e.g. when using runas.exe) if 'APPDATA' in os.environ.keys(): APPDATA = '%APPDATA%' else: APPDATA = '%USERPROFILE%\\Application Data' global pycmd_data_dir global winstate_full_path pycmd_data_dir = expand_env_vars(APPDATA + '\\PyCmd') winstate_full_path = os.path.join(pycmd_data_dir, windows_state_path) if not os.path.exists(winstate_full_path): open(winstate_full_path, 'a').close()
def init(): # %APPDATA% is not always defined (e.g. when using runas.exe) if 'APPDATA' in os.environ.keys(): APPDATA = '%APPDATA%' else: APPDATA = '%USERPROFILE%\\Application Data' global pycmd_data_dir pycmd_data_dir = expand_env_vars(APPDATA + '\\PyCmd') # Create app data directory structure if not present if not os.path.isdir(pycmd_data_dir): os.mkdir(pycmd_data_dir) if not os.path.isdir(pycmd_data_dir + '\\tmp'): os.mkdir(pycmd_data_dir + '\\tmp') # Determine the "installation" directory global pycmd_install_dir pycmd_install_dir = os.path.dirname(os.path.abspath(sys.argv[0])) # Current state of the input (prompt, entered chars, history) global state state = InputState() # Read/initialize command history state.history.list = read_history(pycmd_data_dir + '\\history') # Read/initialize directory history global dir_hist dir_hist = DirHistory() dir_hist.locations = read_history(pycmd_data_dir + '\\dir_history') dir_hist.index = len(dir_hist.locations) - 1 dir_hist.visit_cwd() # Read/initialize directory history global dir_hist_fixed dir_hist_fixed = DirHistory() dir_hist_fixed.locations = read_history(pycmd_data_dir + '\\dir_history_fix') dir_hist_fixed.index = len(dir_hist_fixed.locations) - 1 # Create temporary file global tmpfile (handle, tmpfile) = tempfile.mkstemp(dir=pycmd_data_dir + '\\tmp') os.close(handle) # Catch SIGINT to emulate Ctrl-C key combo signal.signal(signal.SIGINT, signal_handler)
def complete_file_alternate(line): """ Complete names of files or directories using an alternate tokenization This function tokenizes the line by tring to interpret the last token as a semicolon-separated list of paths, optionally preceded by an equals char. It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later (last_token_prefix, equal_char, last_token) = tokens[-1].replace('"', '').rpartition('=') last_token_prefix += equal_char paths = last_token.split(';') token = paths[-1] # print '\n\nTokens:', tokens, '\n\nCompleting:', token, '\n\n' (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [ elem for elem in os.listdir(dir_to_complete) if matcher.match(elem) ] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [ elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem) ] completions_files = [ elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem) ] completions = completions_dirs + completions_files if completions != []: # Find the longest common sequence common_string = find_common_prefix(prefix, completions) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(last_token + completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build and return the result result = line[0:len(line) - len(tokens[-1])] result += last_token_prefix + start_quote result += last_token[:len(last_token) - len(token)] result += completed_file return (result, completions) else: # No expansion was made, return original line return (line, [])
def complete_file_simple(line): """ Complete names of files or directories This function tokenizes the line and computes file and directory completions starting with the last token. It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later token = tokens[-1].replace('"', '') (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [elem for elem in os.listdir(dir_to_complete) if matcher.match(elem)] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem)] completions_files = [elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem)] completions = completions_dirs + completions_files if (len(tokens) == 1 or tokens[-2] in seq_tokens) and path_to_complete == '': # We are at the beginning of a command ==> also complete from the path completions_path = [] for elem_in_path in os.environ['PATH'].split(';'): dir_to_complete = expand_env_vars(elem_in_path) + '\\' try: completions_path += [elem for elem in os.listdir(dir_to_complete) if matcher.match(elem) and os.path.isfile(dir_to_complete + '\\' + elem) and has_exec_extension(elem) and not elem in completions and not elem in completions_path] except OSError: # Cannot complete, probably access denied pass # Add internal commands internal_commands = ['assoc', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', 'if', 'md', 'mkdir', 'move', 'path', 'pause', 'popd', 'prompt', 'pushd', 'rem', 'ren', 'rename', 'rd', 'rmdir', 'set', 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'verify', 'vol'] if sys.getwindowsversion()[0] >= 6: # Windows 7 or newer internal_commands.append('mklink') completions_path += [elem for elem in internal_commands if matcher.match(elem) and not elem in completions and not elem in completions_path] # Sort in lexical order (case ignored) completions_path.sort(key=str.lower) # Remove .com, .exe or .bat extension where possible completions_path_no_ext = [strip_extension(elem) for elem in completions_path] completions_path_nice = [] for i in range(0, len(completions_path_no_ext)): similar = [elem for elem in completions_path_no_ext if elem == completions_path_no_ext[i]] similar += [elem for elem in completions if strip_extension(elem) == completions_path_no_ext[i]] if len(similar) == 1 and has_exec_extension(completions_path[i]) and len(prefix) < len(completions_path[i]) - 3: # No similar executables, don't use extension completions_path_nice.append(completions_path_no_ext[i]) else: # Similar executables found, keep extension completions_path_nice.append(completions_path[i]) completions += completions_path_nice if completions != []: # Find the longest common sequence common_string = find_common_prefix(prefix, completions) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build the result result = line[0 : len(line) - len(tokens[-1])] + start_quote + completed_file if len(completions) == 1: # We can close the quotes if we have completed to a unique filename if start_quote == '"': end_quote = '"' else: end_quote = '' if result[-1] == '\\': # Directory -- we want the backslash (if any) AFTER the closing quote result = result[ : -1] + end_quote + '\\' else: # File -- add space if the completion is unique result += end_quote result += ' ' return (result, completions) else: # No expansion was made, return original line return (line, [])
def complete_wildcard(line): """ Complete file/dir wildcards This function tokenizes the line and computes file and directory completions starting with the last token which is a wildcard It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later token = tokens[-1].replace('"', '') (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [elem for elem in os.listdir(dir_to_complete) if matcher.match(elem)] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem)] completions_files = [elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem)] completions = completions_dirs + completions_files if completions != []: completed_suffixes = [] for c in completions: match = matcher.match(c) completed_suffixes.append(match.group(match.lastindex)) if len(completions) == 1: # Only one match, we can inline it and replace the wildcards common_string = completions[0] else: # Multiple matches, find the longest common sequence common_string = prefix + find_common_prefix(prefix, completed_suffixes) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build the result result = line[0 : len(line) - len(tokens[-1])] + start_quote + completed_file if len(completions) == 1 or \ not common_string.endswith('*') and \ max([len(c) for c in completed_suffixes]) == len(common_string) - len(prefix): # We can close the quotes if all the completions have the same suffix or # there exists only one matching file if start_quote == '"': end_quote = '"' else: end_quote = '' if result[-1] == '\\': # Directory -- we want the backslash (if any) AFTER the closing quote result = result[ : -1] + end_quote + '\\' else: # File -- add space if the completion is unique result += end_quote result += ' ' return (result, completions) else: # No expansion was made, return original line return (line, [])
def complete_file_alternate(line): """ Complete names of files or directories using an alternate tokenization This function tokenizes the line by tring to interpret the last token as a semicolon-separated list of paths, optionally preceded by an equals char. It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later (last_token_prefix, equal_char, last_token) = tokens[-1].replace('"', '').rpartition('=') last_token_prefix += equal_char paths = last_token.split(';') token = paths[-1] # print '\n\nTokens:', tokens, '\n\nCompleting:', token, '\n\n' (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [elem for elem in os.listdir(dir_to_complete) if matcher.match(elem)] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem)] completions_files = [elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem)] completions = completions_dirs + completions_files if completions != []: # Find the longest common sequence common_string = find_common_prefix(prefix, completions) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(last_token + completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build and return the result result = line[0 : len(line) - len(tokens[-1])] result += last_token_prefix + start_quote result += last_token[:len(last_token) - len(token)] result += completed_file return (result, completions) else: # No expansion was made, return original line return (line, [])
(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] ' stdout.write('\n' + message) rec = read_input() move_cursor(c_x, console.get_buffer_size()[1] - offset_from_bottom) stdout.write('\n' + ' ' * len(message)) move_cursor(c_x, console.get_buffer_size()[1] - offset_from_bottom) if rec.Char != '\t': if not ord(rec.Char) in [0, 8, 13, 27]: state.handle(ActionCode.ACTION_INSERT, rec.Char) continue if has_wildcards(tokens[-1]): # Substring matching wildcards will be printed in a different color path_sep = '/' if '/' in expand_env_vars(tokens[-1]) else '\\' tokens = parse_line(completed.rstrip(path_sep)) token = tokens[-1].replace('"', '') (_, _, prefix) = token.rpartition(path_sep) pattern = wildcard_to_regex(prefix + '*') else: # Length of the common prefix will be printed in a different color common_prefix_len = len(find_common_prefix(state.before_cursor, suggestions)) stdout.write('\n') for line in range(0, num_lines): # Print one line stdout.write('\r') for column in range(0, num_columns): if line + column * num_lines < len(suggestions): s = suggestions[line + column * num_lines]
def complete_wildcard(line): """ Complete file/dir wildcards This function tokenizes the line and computes file and directory completions starting with the last token which is a wildcard It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later token = tokens[-1].replace('"', '') (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [ elem for elem in os.listdir(dir_to_complete) if matcher.match(elem) ] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [ elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem) ] completions_files = [ elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem) ] completions = completions_dirs + completions_files if completions != []: completed_suffixes = [] for c in completions: match = matcher.match(c) completed_suffixes.append(match.group(match.lastindex)) if len(completions) == 1: # Only one match, we can inline it and replace the wildcards common_string = completions[0] else: # Multiple matches, find the longest common sequence common_string = prefix + find_common_prefix( prefix, completed_suffixes) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build the result result = line[0:len(line) - len(tokens[-1])] + start_quote + completed_file if len(completions) == 1 or \ not common_string.endswith('*') and \ max([len(c) for c in completed_suffixes]) == len(common_string) - len(prefix): # We can close the quotes if all the completions have the same suffix or # there exists only one matching file if start_quote == '"': end_quote = '"' else: end_quote = '' if result[-1] == '\\': # Directory -- we want the backslash (if any) AFTER the closing quote result = result[:-1] + end_quote + '\\' else: # File -- add space if the completion is unique result += end_quote result += ' ' return (result, completions) else: # No expansion was made, return original line return (line, [])
def complete_file_simple(line): """ Complete names of files or directories This function tokenizes the line and computes file and directory completions starting with the last token. It returns a pair: - the line expanded up to the longest common sequence among the completions - the list of all possible completions (first dirs, then files) """ tokens = parse_line(line) if tokens == [] or (line[-1] in sep_chars and parse_line(line) == parse_line(line + ' ')): tokens += [''] # This saves us some checks later token = tokens[-1].replace('"', '') (path_to_complete, _, prefix) = token.rpartition('\\') if path_to_complete == '' and token != '' and token[0] == '\\': path_to_complete = '\\' # print '\n\n', path_to_complete, '---', prefix, '\n\n' if path_to_complete == '': dir_to_complete = os.getcwd() elif path_to_complete == '\\': dir_to_complete = os.getcwd()[0:3] else: dir_to_complete = expand_env_vars(path_to_complete) + '\\' # This is the wildcard matcher used throughout the function matcher = wildcard_to_regex(prefix + '*') completions = [] if os.path.isdir(dir_to_complete): try: completions = [ elem for elem in os.listdir(dir_to_complete) if matcher.match(elem) ] except OSError: # Cannot complete, probably access denied pass # Sort directories first, also append '\'; then, files completions_dirs = [ elem + '\\' for elem in completions if os.path.isdir(dir_to_complete + '\\' + elem) ] completions_files = [ elem for elem in completions if os.path.isfile(dir_to_complete + '\\' + elem) ] completions = completions_dirs + completions_files if (len(tokens) == 1 or tokens[-2] in seq_tokens) and path_to_complete == '': # We are at the beginning of a command ==> also complete from the path completions_path = [] for elem_in_path in os.environ['PATH'].split(';'): dir_to_complete = expand_env_vars(elem_in_path) + '\\' try: completions_path += [ elem for elem in os.listdir(dir_to_complete) if matcher.match(elem) and os.path.isfile(dir_to_complete + '\\' + elem) and has_exec_extension(elem) and not elem in completions and not elem in completions_path ] except OSError: # Cannot complete, probably access denied pass # Add internal commands internal_commands = [ 'assoc', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', 'if', 'md', 'mkdir', 'move', 'path', 'pause', 'popd', 'prompt', 'pushd', 'rem', 'ren', 'rename', 'rd', 'rmdir', 'set', 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'verify', 'vol' ] if sys.getwindowsversion()[0] >= 6: # Windows 7 or newer internal_commands.append('mklink') completions_path += [ elem for elem in internal_commands if matcher.match(elem) and not elem in completions and not elem in completions_path ] # Sort in lexical order (case ignored) completions_path.sort(key=str.lower) # Remove .com, .exe or .bat extension where possible completions_path_no_ext = [ strip_extension(elem) for elem in completions_path ] completions_path_nice = [] for i in range(0, len(completions_path_no_ext)): similar = [ elem for elem in completions_path_no_ext if elem == completions_path_no_ext[i] ] similar += [ elem for elem in completions if strip_extension(elem) == completions_path_no_ext[i] ] if len(similar) == 1 and has_exec_extension( completions_path[i]) and len(prefix) < len( completions_path[i]) - 3: # No similar executables, don't use extension completions_path_nice.append(completions_path_no_ext[i]) else: # Similar executables found, keep extension completions_path_nice.append(completions_path[i]) completions += completions_path_nice if completions != []: # Find the longest common sequence common_string = find_common_prefix(prefix, completions) if path_to_complete == '': completed_file = common_string elif path_to_complete == '\\': completed_file = '\\' + common_string else: completed_file = path_to_complete + '\\' + common_string if expand_env_vars(completed_file).find(' ') >= 0 or \ (prefix != '' and [elem for elem in completions if contains_special_char(elem)] != []) or \ (prefix == '' and [elem for elem in completions if starts_with_special_char(elem)] != []): # We add quotes if one of the following holds: # * the (env-expanded) completed string contains whitespace # * there is a prefix and at least one of the valid completions contains whitespace # * there is no prefix and at least one completion _starts_ with whitespace start_quote = '"' else: start_quote = '' # Build the result result = line[0:len(line) - len(tokens[-1])] + start_quote + completed_file if len(completions) == 1: # We can close the quotes if we have completed to a unique filename if start_quote == '"': end_quote = '"' else: end_quote = '' if result[-1] == '\\': # Directory -- we want the backslash (if any) AFTER the closing quote result = result[:-1] + end_quote + '\\' else: # File -- add space if the completion is unique result += end_quote result += ' ' return (result, completions) else: # No expansion was made, return original line return (line, [])
if not ord(rec.Char) in [0, 8, 13, 27]: state.handle(ActionCode.ACTION_INSERT, rec.Char) continue stdout.write('\n') for line in range(0, num_lines): # Print one line 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 path_sep = '/' if '/' in expand_env_vars( tokens[-1]) else '\\' tokens = parse_line( completed.rstrip(path_sep)) token = tokens[-1].replace('"', '') (_, _, prefix) = token.rpartition(path_sep) match = wildcard_to_regex(prefix + '*').match(s) current_index = 0 for i in range(1, match.lastindex + 1): stdout.write( color.Fore.DEFAULT + color.Back.DEFAULT + appearance .colors.completion_match + s[current_index:match.start(i)] + color.Fore.DEFAULT +