Skip to content

Instantly share code, notes, and snippets.

@ralphbean
Created November 12, 2012 18:28

Revisions

  1. Adam Hayes revised this gist Nov 11, 2012. 1 changed file with 41 additions and 84 deletions.
    125 changes: 41 additions & 84 deletions simple_file_completer.py
    Original file line number Diff line number Diff line change
    @@ -2,6 +2,7 @@
    import readline
    import os
    import re
    import sys

    # This will tab-complete from the working directory, starting from /, and going
    # through the sub-directories, but it doesn't behave quite the way you expect.
    @@ -13,7 +14,7 @@

    #RE_SPACE = re.compile(".*\s+$", re.M) # Not sure what this does.

    possible_completions = os.listdir(".")
    possible_completions = []

    # This will be changed to a class, so that the list possible_completions can be saved
    # between calls, rather than using a global definition.
    @@ -25,106 +26,62 @@ def complete_path(text, state):

    # Changed the type of "line" to a string. (It was a list in the last
    # version.)
    def db(line):
    line = line + "\n"
    with open("debugging.txt","a") as f:
    f.write(line)

    line = readline.get_line_buffer()
    print "\n" + str(line) + "\n"

    try:
    if line == "":

    # Nothing has been typed yet, so the default starting path is the
    # working directory.

    possible_completions = os.listdir(".")

    elif not "/" in line:

    # The line is not empty, but does not contain a "/". This must be
    # a partial file name in the working directory.

    temporary_completion_list = os.listdir(".")

    # Keep only the entries where the last sub-string after
    # the last "/" matches partial_file_name.

    possible_completions = []
    for one_item in temporary_completion_list:
    this_partial_file_name = one_item.rsplit("/",1)[1]
    if this_partial_file_name == line:
    possible_completions.append(one_item)

    else:

    # Need to treat a path that refers to a directory, as well as one
    # that refers to a file or partial file name.

    try:

    # Assume that the line typed so far is a directory, and try to
    # get a listing of its contents. This will handle either e.g.
    # /home/jenny/mydir/ or /home/jenny/mydir

    possible_completions = os.listdir(line)

    except:

    # In the final version, examine the exception--error 20 from os
    # is "Not a directory" and will elucidate the problem.

    # See if the path is a directory followed by a file name or
    # partial file name. e.g. "/home/jenny/mydir/blah": if the
    # path does not end in "/", strip off everything to the right
    # of the last "/", and see if that is a valid directory.

    if not line.endswith("/"):

    # If it ends with "/", then it must be a directory name
    # (valid or not).

    try:
    line = readline.get_line_buffer()
    # print "\n" + str(line) + "\n"
    # db(line)

    # Strip off the last word.
    # Example: /home/jenny/mydir/blah --> /home/jenny/mydir/
    # Expand the user name "~" if it is in line. It does not necessarily exist.
    line = os.path.expanduser(line)

    path, partial_file_name = line.rsplit("/",1)
    temporary_completion_list = os.listdir(path)
    # REMEMBER TO EXPAND ALL PATHS.

    # Keep only the entries where the last sub-string after
    # the last "/" matches partial_file_name.
    if line == "":
    # Use the working directory to start.
    directory = os.path.abspath(".")
    basename = ""

    possible_completions = []
    for one_item in temporary_completion_list:
    this_partial_file_name = one_item.rsplit("/",1)[1]
    if this_partial_file_name == partial_file_name:
    possible_completions.append(one_item)

    ### This is repeated code and can be moved to another
    ### method.
    # Split the line into base name (blah.txt) and directory (/home/jenny
    # without the end slash). "/home" has base name "home" and directory "/".
    # "/home/" has base name "" and directory "/home".

    except:

    # /home/jenny/mydir/ was not a valid directory.
    else:
    base_name = os.path.basename(line)
    directory = os.path.dirname(line)
    if directory == "":
    directory = os.path.abspath(".")
    db("dir " + directory + " base " + base_name + " line " + line)

    try:

    # See if the line refers to a directory followed by a
    if os.path.exists(directory):
    if os.path.isdir(directory):
    base_name = ""
    if not line.endswith("/"):
    directory = directory + "/"

    # If nothing works, don't try any more completion. The
    # user will have to fix the path.
    pass
    if not os.path.exists(directory):
    possible_completions = []

    else:
    # Find all files in this directory.
    possible_completions = os.listdir(directory)

    except:
    pass
    db(line + " " + str(possible_completions))

    for one_file in possible_completions:
    if one_file.startswith(text) and state == 0:
    return one_file
    for one in possible_completions:
    if state < len(possible_completions):
    if line in one or line == "" or line == directory or basename in one:
    return one
    else:
    state -= 1


    print os.listdir("/home/hayes/testing.py")
    #print os.listdir("/home/hayes/testing.py")
    readline.parse_and_bind("tab: complete")
    readline.set_completer(complete_path)
    while True:
  2. Adam Hayes revised this gist Nov 10, 2012. 1 changed file with 110 additions and 41 deletions.
    151 changes: 110 additions & 41 deletions simple_file_completer.py
    100644 → 100755
    Original file line number Diff line number Diff line change
    @@ -2,64 +2,133 @@
    import readline
    import os
    import re
    from pprint import *

    # This will tab-complete from the working directory, starting from /, and going through the sub-directories,
    # but it doesn't behave quite the way you expect.
    # For instance, it chooses for you if there are two partial matches.
    # The readline call to def complete does not pass a
    # leading "/" in the "text" variable, so I had to start using get_line_buffer and really don't find
    # much use for the variables "text" and "state".
    # Isn't there a "right" way to do this? It seems like it ought to be a built-in in readline!
    # Not sure what RE_SPACE is for.
    # This will tab-complete from the working directory, starting from /, and going
    # through the sub-directories, but it doesn't behave quite the way you expect.
    # For instance, it chooses for you if there are two partial matches.

    RE_SPACE = re.compile('.*\s+$', re.M)
    # The readline call to def complete_path does not pass a leading "/" in the "text"
    # variable, so I had to start using get_line_buffer and really don't find much
    # use for the variables "text" and "state".

    COMMANDS = os.listdir('.')
    #RE_SPACE = re.compile(".*\s+$", re.M) # Not sure what this does.

    possible_completions = os.listdir(".")

    # This will be changed to a class, so that the list possible_completions can be saved
    # between calls, rather than using a global definition.

    def complete_path(text, state):

    # NOTE THAT THE LEADING / WILL NOT COME THROUGH IN text. This is why only
    # the line buffer is used below, not the "text" field passed from readline.

    # Changed the type of "line" to a string. (It was a list in the last
    # version.)

    line = readline.get_line_buffer()
    print "\n" + str(line) + "\n"

    def complete(text, state):
    line = readline.get_line_buffer().split()
    # NOTE THAT THE LEADING / WILL NOT COME THROUGH IN text.
    try:
    if line == []:
    path = "."
    COMMANDS = os.listdir(path)
    elif line[0] == "/": # Readline will never return a leading "/".
    COMMANDS = os.listdir("/")
    elif line == "" or line == "." or line == "./":
    path = "."
    COMMANDS = os.listdir(path)
    if line == "":

    # Nothing has been typed yet, so the default starting path is the
    # working directory.

    possible_completions = os.listdir(".")

    elif not "/" in line:

    # The line is not empty, but does not contain a "/". This must be
    # a partial file name in the working directory.

    temporary_completion_list = os.listdir(".")

    # Keep only the entries where the last sub-string after
    # the last "/" matches partial_file_name.

    possible_completions = []
    for one_item in temporary_completion_list:
    this_partial_file_name = one_item.rsplit("/",1)[1]
    if this_partial_file_name == line:
    possible_completions.append(one_item)

    else:
    if "/" in line[0]:
    if line[0] == "/":
    base_path = "/"
    else:
    base_path = line[0].rsplit("/",1)[0] + "/"
    partial_file_name = line[0].rsplit("/")[-1]
    else:
    base_path = "."
    partial_file_name = line[0]
    COMMANDS = os.listdir(base_path)
    for one_file in COMMANDS:
    if one_file.startswith(partial_file_name):
    if not state:
    return one_file

    # Need to treat a path that refers to a directory, as well as one
    # that refers to a file or partial file name.

    try:

    # Assume that the line typed so far is a directory, and try to
    # get a listing of its contents. This will handle either e.g.
    # /home/jenny/mydir/ or /home/jenny/mydir

    possible_completions = os.listdir(line)

    except:

    # In the final version, examine the exception--error 20 from os
    # is "Not a directory" and will elucidate the problem.

    # See if the path is a directory followed by a file name or
    # partial file name. e.g. "/home/jenny/mydir/blah": if the
    # path does not end in "/", strip off everything to the right
    # of the last "/", and see if that is a valid directory.

    if not line.endswith("/"):

    # If it ends with "/", then it must be a directory name
    # (valid or not).

    try:

    # Strip off the last word.
    # Example: /home/jenny/mydir/blah --> /home/jenny/mydir/

    path, partial_file_name = line.rsplit("/",1)
    temporary_completion_list = os.listdir(path)

    # Keep only the entries where the last sub-string after
    # the last "/" matches partial_file_name.

    possible_completions = []
    for one_item in temporary_completion_list:
    this_partial_file_name = one_item.rsplit("/",1)[1]
    if this_partial_file_name == partial_file_name:
    possible_completions.append(one_item)

    ### This is repeated code and can be moved to another
    ### method.

    except:

    # /home/jenny/mydir/ was not a valid directory.

    try:

    # See if the line refers to a directory followed by a

    # If nothing works, don't try any more completion. The
    # user will have to fix the path.
    pass


    except:
    print "exception"
    COMMANDS = os.listdir(".")
    pass

    for one_file in COMMANDS:
    for one_file in possible_completions:
    if one_file.startswith(text) and state == 0:
    return one_file
    else:
    state -= 1


    print os.listdir("/home/hayes/testing.py")
    readline.parse_and_bind("tab: complete")
    readline.set_completer(complete)
    readline.set_completer(complete_path)
    while True:
    file_name = raw_input('Enter filename: ')
    file_name = raw_input("Enter file name: ")
    print file_name


  3. adamhayes renamed this gist Nov 8, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. adamhayes created this gist Nov 8, 2012.
    65 changes: 65 additions & 0 deletions simple_file_completer.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,65 @@
    #!/usr/bin/env python
    import readline
    import os
    import re
    from pprint import *

    # This will tab-complete from the working directory, starting from /, and going through the sub-directories,
    # but it doesn't behave quite the way you expect.
    # For instance, it chooses for you if there are two partial matches.
    # The readline call to def complete does not pass a
    # leading "/" in the "text" variable, so I had to start using get_line_buffer and really don't find
    # much use for the variables "text" and "state".
    # Isn't there a "right" way to do this? It seems like it ought to be a built-in in readline!
    # Not sure what RE_SPACE is for.

    RE_SPACE = re.compile('.*\s+$', re.M)

    COMMANDS = os.listdir('.')

    def complete(text, state):
    line = readline.get_line_buffer().split()
    # NOTE THAT THE LEADING / WILL NOT COME THROUGH IN text.
    try:
    if line == []:
    path = "."
    COMMANDS = os.listdir(path)
    elif line[0] == "/": # Readline will never return a leading "/".
    COMMANDS = os.listdir("/")
    elif line == "" or line == "." or line == "./":
    path = "."
    COMMANDS = os.listdir(path)
    else:
    if "/" in line[0]:
    if line[0] == "/":
    base_path = "/"
    else:
    base_path = line[0].rsplit("/",1)[0] + "/"
    partial_file_name = line[0].rsplit("/")[-1]
    else:
    base_path = "."
    partial_file_name = line[0]
    COMMANDS = os.listdir(base_path)
    for one_file in COMMANDS:
    if one_file.startswith(partial_file_name):
    if not state:
    return one_file

    except:
    print "exception"
    COMMANDS = os.listdir(".")

    for one_file in COMMANDS:
    if one_file.startswith(text) and state == 0:
    return one_file
    else:
    state -= 1


    readline.parse_and_bind("tab: complete")
    readline.set_completer(complete)
    while True:
    file_name = raw_input('Enter filename: ')
    print file_name