CSCI 150 Lab 7: Line Editor
Overview
In this lab, you will practice using lists and strings in Python by implementing a very simple text editor, which allows you to create and edit text files one line at a time. This kind of editor, called a line editor, used to be the standard way to interact with a text file in the 1970's, when communication from computers to users tended to be via printers instead of screens.> Hi there! > I am adding stuff > to a file > print 0: Hi there! 1: I am adding stuff *2: to a file > append yes I am > print 0: Hi there! 1: I am adding stuff 2: to a file *3: yes I am > find am > print 0: Hi there! *1: I am adding stuff 2: to a file 3: yes I am > replace I was adding stuff > print 0: Hi there! *1: I was adding stuff 2: to a file 3: yes I am > next > print 0: Hi there! 1: I was adding stuff 2: to a file *3: yes I am > insert This is a newly inserted line > print 0: Hi there! 1: I was adding stuff 2: to a file *3: This is a newly inserted line 4: yes I am > line 0 > delete > print *0: I was adding stuff 1: to a file 2: This is a newly inserted line 3: yes I am > save stuff.txt Saving as stuff.txt... > quit
Step 1: Accumulation
Create a new Python file calledline_editor.py
, and put
your name, date, copyright notice, etc. at the top. Also,
don't forget to include the line
from typing import *which you will need in order to write type signatures involving lists.
Define a main()
function (and also call it as the very
last line in your file) which performs as follows:
- Create a variable containing a list of strings which will store the lines of the current document. It should start out as the empty list.
- As long as the user isn't done, prompt them for a line of text
(using the character
>
as a prompt) and append whatever they type to the current document. The user can indicate they are done by typingquit
. - After the user quits, print out the current document
line-by-line, with each line prefixed by its index and a colon, as
shown below. The document should not include the
final
quit
.
> Hello > there > lab 7 > quit 0: Hello 1: there 2: lab 7This isn't all that exciting yet, but we will build on it to do more interesting things!
Remember to decompose your code into other functions as appropriate. For example, you probably want to make a separate function to print the document at the end.
Step 2: Commands and Printing
In addition to simply entering lines of text to append to the current document, we are going to allow the user to enter various commands. Some commands have an argument and some don't.-
First, you should split the user's input into two parts: the first
word (up to the first space character) and everything else (the
argument). (Hint: try using
.split(' ', 1)
on the user input. What does it do?) - If the user enters just a single word with nothing after it, you should treat the argument as if it were the empty string. Save the argument in a variable for later; you won't use it in this step but you will need it soon.
-
Now check if the command is one you recognize. For now, we are
just going to add the
print
command: when the user typesprint
, print out the current document with its lines prefixed by their index, just as before. - Otherwise, append the user's original, un-split input to the current document, just like before.
print
whenever they
want, you can remove the code that prints the document after
they quit
.
Your editor now might look like this:
> Hello there > print 0: Hello there > How are you > doing today > print 0: Hello there 1: How are you 2: doing today > quit
Step 3: Tracking the current line
Modify your editor so that it keeps track of the index of the current line.- The current line should start out at 0.
- Every time a new line is appended to the end of the document, the current line becomes the index of the newly appended line.
- You should change the output of the
print
command so that it highlights the current line somehow (for example, with an asterisk, as shown in the example below). - Finally, add a
line
command which expects an index as an argument, and sets the current line to the given index; that is, it lets the user "jump" to a different line number. Be sure that your command prints an appropriate message instead of crashing if the argument toline
is not a number or is too small or too big to be a valid index.
> Hello there > print *0: Hello there > How are you? > print 0: Hello there *1: How are you? > line zero zero is not a valid integer. > line 5 5 is not a valid line number. > line 0 > print *0: Hello there 1: How are you? > I'm fine thanks > print 0: Hello there 1: How are you? *2: I'm fine thanks > quit
Step 4: Files
An editor isn't much good without being able to open and save files! In this step, you should add two commandsopen
and save
that let the user load a text document from a
file and save the current document to a file, respectively.
- The
open
command takes the name of a file as an argument. I have provided theopen_file
function below which you can copy into your code; just call this function when the user types theopen
command. (You don't need to understand how this function works!) You should also reset the current line to zero.# Open the file with the given name and return its contents as a list # of strings, one per line; OR print a warning and return the empty # list if there is an error opening the file (e.g. if the file does # not exist). def open_file(filename: str) -> List[str]: try: print("Opening " + filename + "...") f = open(filename, 'r') lines = [l.rstrip() for l in f.readlines()] f.close() return lines except: print("Warning, file " + filename + " does not exist, loaded empty document.") return []
- Likewise, the
save
command takes a filename as an argument; again, just copy the belowsave_file
function and call it. Note that the function expects astr
, not aList[str]
: before calling the function you will have to turn the document from a list of strings, each representing one line, into a single giant string representing the entire document. (Hint: usejoin
.)# Write the given string to the file with the given name. def save_file(filename: str, contents: str): try: print("Saving as " + filename + "...") f = open(filename, 'w') f.write(contents) f.close() except: print("Something went wrong saving " + filename + "!")
> Hello there > I am going to save this > to a file > print 0: Hello there 1: I am going to save this *2: to a file > save file.txt Saving as file.txt... > quit > Hello > print *0: Hello > open file.txt Opening file.txt... > print *0: Hello there 1: I am going to save this 2: to a file > quit
Step 5: Editing!
Now we can finally get to some more serious editing! You should add the following commands to your editor:append
: this command simply appends whatever follows it as a new line at the end of the current document. This is necessary to allow appending lines that would otherwise look like they start with a command. Be sure that the current line is updated to the newly appended line.> How do I > print this? *0: How do I > append print this? > print 0: How do I *1: print this?
insert
: this command inserts its argument as a new line just before the current line. The index of the current line should remain the same (so the newly inserted line becomes the current line).> open file.txt Opening file.txt... > print *0: Hello there 1: I am going to save this 2: to a file > insert This is a new first line > print *0: This is a new first line 1: Hello there 2: I am going to save this 3: to a file > line 2 > print 0: This is a new first line 1: Hello there *2: I am going to save this 3: to a file > insert This comes after 'Hello there' and before 'I am going to save this' > print 0: This is a new first line 1: Hello there *2: This comes after 'Hello there' and before 'I am going to save this' 3: I am going to save this 4: to a file
delete
: delete the current line. The index of the current line remains the same. Make sure to check that the current line is a valid index that can be deleted.> delete Can't delete past end of document. > open file.txt Opening file.txt... > print *0: Hello there 1: I am going to save this 2: to a file > line 1 > delete > print 0: Hello there *1: to a file
replace
: replace the current line.> replace Nope Can't replace past end of document. > open file.txt Opening file.txt... > print *0: Hello there 1: I am going to save this 2: to a file > line 1 > replace I am going to write this > print 0: Hello there *1: I am going to write this 2: to a file
Step 6: Finding
Finally, let's provide a way for the user to quickly search through a document.- Add a
find
command which searches for its argument in the document, starting from the beginning of the document. It should either set the current line to the first line containing the search term, or set the current line to the first index after the end of the document if the search term is not found.> open file.txt Opening file.txt... > line 2 > print 0: Hello there 1: I am going to save this *2: to a file > find pizza > print 0: Hello there 1: I am going to save this 2: to a file > find am > print 0: Hello there *1: I am going to save this 2: to a file
- Add a
next
command, which finds the next occurrence of the previous search term starting with the line after the current line. That is, by callingfind
and then repeatedly callingnext
, the user can step through occurrences of the search term one by one.> open file.txt Opening file.txt... > I am going to search > for the word am > This line doesn't have it > But I am sure this one does > print 0: Hello there 1: I am going to save this 2: to a file 3: I am going to search 4: for the word am 5: This line doesn't have it *6: But I am sure this one does > find am > print 0: Hello there *1: I am going to save this 2: to a file 3: I am going to search 4: for the word am 5: This line doesn't have it 6: But I am sure this one does > next > print 0: Hello there 1: I am going to save this 2: to a file *3: I am going to search 4: for the word am 5: This line doesn't have it 6: But I am sure this one does > next > print 0: Hello there 1: I am going to save this 2: to a file 3: I am going to search *4: for the word am 5: This line doesn't have it 6: But I am sure this one does > next > print 0: Hello there 1: I am going to save this 2: to a file 3: I am going to search 4: for the word am 5: This line doesn't have it *6: But I am sure this one does > next > print 0: Hello there 1: I am going to save this 2: to a file 3: I am going to search 4: for the word am 5: This line doesn't have it 6: But I am sure this one does
Just for fun
Save a copy of your lab in another file, just in case. Then, try openingline_editor.py
itself in your editor, and making
a few changes. Rejoice that we now have screens and two-dimensional
editor interfaces so you normally don't have to put up with this.
What to turn in
line_editor.py
Grading
- To earn a C, complete Steps 1 and 2.
- To earn a B, complete Steps 3 and 4.
- To earn an A, complete Step 5.
- To earn a 100, complete Step 6.
© Brent Yorgey, Hendrix College