cse190largecodebases / group-project-idlemasters

group-project-idlemasters created by GitHub Classroom
Other
0 stars 1 forks source link

First proposal-Line Marking Feature for IDLE Code Editor #3

Open MerlinZCC opened 1 year ago

MerlinZCC commented 1 year ago

Line Marking Feature for IDLE Code Editor

Team members

Chenfei Yan, c4yan@ucsd.edu, A16444087

Jacky Hu, tihu@ucsd.edu, A16314797

Chengcheng Zhang, chz009@ucsd.edu, A16513041

Project summary

By highlighting individual lines or multiple lines, users can enhance their experience by visually distinguishing particular lines or sections of code for easier navigation or reference, especially in a large codebase. Moreover, users can select different colors for each highlighted area. Furthermore, users have the option to view only the highlighted blocks, allowing them to quickly navigate to those sections as needed.

Project outline/Feasibility analysis

Project Outline

Introduce a menu item in the IDLE editor under Options called Mark/Highlight Line Region. When no region is selected, the Mark/Highlight Line Region option will be unclickable. If users select a line region, the menu item Mark/Highlight Line Region becomes active, and upon hovering over it, a dropdown menu appears on the right side displaying all available colors. When users select a region that is already highlighted, the menu item should change to Unhighlight Line Region.

Note that when dealing with unhighlighting a line, this menu item should be active only if the selected region precisely matches the highlighted one.

Project Timeline

Week 7: Research how to use the tkinter package to create a menu item and bind it to a custom event handler function that captures user-selected regions.

Week 8: Implement the functionality to check if a selected region is already highlighted, and if so, provide a way to unhighlight it. If the region is not highlighted, use the colorchooser function to prompt the user to select a color and apply it to the selected region.

Week 9: Focus on testing and debugging the code to ensure it works as expected, including edge cases and user input validation. Consider adding additional features, such as the ability to customize the highlight colors or toggle between showing/hiding the highlighted regions.

Week 10: Refine the UI and user experience, incorporating user feedback and suggestions. Consider adding keyboard shortcuts or context menu options to improve accessibility and efficiency.

Feasibility analysis

Introduce the menu item by utilizing the bind function from the tkinter package, along with a custom event handler function. Within this function, begin by obtaining the user-selected region using get_region(). Next, determine if the region is highlighted. If it is, unhighlight the region; otherwise, employ the colorchooser function from the tkinter package to obtain the desired color from the user.

Nice-to-have feature

Keep track of the highlighted regions

Incorporate a Next Highlighted Region menu item under Option, which navigates to the subsequent highlighted region in the currently opened file. If no highlighted regions exist, this Next Highlighted Region menu item should be unclickable. Generate a JSON file containing information about all highlighted regions.The format would possibly be

[ 
    {
        “File_name”: project.py,
        “Information”: 
        [
            {
                “Line_number”: 1337,
                “Start_index”:20,
                “End_index”: 100,
                “Color”: “red”
            },
            {
                “Line_number”: 2000,
                “Start_index”:10,
                “End_index”: 15,
                “Color”: “green”
            }
        ]
    },
]

Upon opening a file, load the corresponding JSON file and locate the object with the same file_name. Next, bind the Next Highlighted Region to the goto_line_event() function. Each time the user clicks the menu item, the editor should navigate directly to the specified line number and advance the iterator to the next object in that file.

Persistent in the long run

It's important that those highlighted regions will be saved within the file and reloaded when the users access it next time.

In a manner similar to the #1 Nice-to-Have feature, when opening a file, load the associated JSON file and find the object with the matching file_name. Then, bind the Next Highlighted Region to the goto_line_event() function. Iterate through the list of JSON objects and apply color to all of them.

Comment section

To provide further context or clarification, users may wish to add comments or notes to specific highlighted regions, enhancing the user experience and making the feature more versatile. Introduce a comment menu item under Option that opens a popup window for users to input comments. This popup window should include an OK button and a Cancel button, similar to those found in the Go to Line feature in the IDLE editor. We might need to add an element in that object so that it is like:

{
    “Line_number”: 1337,
    “Start_index”:20,
    “End_index”: 100,
    “Color”: “red”,
    “Comment”: “This is a comment”
}

Introduce an additional menu item called Show Comment, and bind it to an event handler function that verifies whether the user has selected a region or if the user-selected region exactly matches the highlighted region. If not, this menu item should be unclickable. If it does match, display a read-only window that shows the comments stored in that object.

Checkpoint deliverables

Thu, May 18 Final Project Checkpoint 1:

  1. Complete the basic functionality of highlighting the region.

  2. Adding menu items to Option and binding them with their own event handler function.

  3. Adding keyboard shortcuts for each of the menu items.

Thu, Jun 1 Final Project Checkpoint 2:

  1. Implementing Nice to have feature(s)

Why ideas benefit the scope of the group project

This feature fits nicely for the goal of this class: working with large code bases. We get the chance of implementing tools that can enhance user experience in a unique way. The entire project scope is appropriate for a team of three since we also have some nice-to-have features where we can incorporate to scale up the complexity if necessary. All of these nice-to-have features necessitate read/write operations for the JSON file and the use of event handler functions, which implies that their implementation is more complex than it might initially appear.Overall, it will be a useful addition to Idle.

jyu283 commented 1 year ago

This will be your team's assigned project. We look forward to seeing the final product at the end of the course. Good luck!

jyu283 commented 1 year ago

Please keep this issue open.

jyu283 commented 1 year ago

Checking in after checkpoint one. Looks like you're making good progress. Keep up the good work!

J4cky1ove commented 1 year ago

CheckPoint II

Progress Report:

Our group project is approximately 70% complete. We have successfully implemented the fundamental feature of highlighting selected regions using multiple colors. Users can choose their preferred colors from a drop-down menu. The changes made for this functionality have been integrated into a specific file called highlight.py, which contains the HighlightParagraph class.

To ensure the highlighted regions persist, we store the relevant information in a JSON file. This enables us to view the highlighted regions when reopening the file at a later time.

Progress Update:

Challenges:

1.Tag name issue

We faced a glitch that significantly impacted the user experience. Suppose a file contains a line if a == 0 with parts if and 0 highlighted in red. If we change the highlight color for if to blue, the 0 would also switch to blue automatically. This occurred because changing the highlight color was inadvertently modifying the color of all text regions associated with the same tag.

We have addressed this by first checking whether the text region is already highlighted. If it is, we now remove the existing tag and assign a new tag, correlating with the updated color. Consequently, we apply the new color to all highlighted regions associated with this new tag name. So, if we go back to the if a == 0 example, where if and 0 are highlighted in red, and we decide to change if to blue, we first strip away the existing tag from if, assign a blue tag to if, and then apply the blue color only to this region. As a result, the 0 remains red, since the modification to if's tag does not affect it.

2.Selection color missing if the region is highlighted

We came across an issue where, if a region of text was highlighted and the user then selected a portion of this region or the whole region, the typical grey color associated with selection would not appear. Instead, the selected portion would retain its highlighted color. Upon consulting StackOverflow, we discovered that this anomaly was due to the selection priority being lower than the highlighting priority.

To rectify this, we introduced a line of code to adjust the priority so that the selected region is ranked higher than the highlighted region. We accomplished this by using the function tag_raise("sel"), which successfully resolved the problem.

3. Drop down menu with different parameters passing to function

We stumbled upon a problem involving the create_color_menu(self) and toggle_highlight(self, color) functions. Our goal was to allow users to select different colors from a dropdown menu, and to use these color choices as parameters for the toggle_highlight(self, color) function. However, due to the particular way that the dropdown menu was implemented using the add_command function in tkinter, we were unable to directly pass the color parameter into the function. For instance, in the case of blue color, using self.editwin.color_menu.add_command(label="blue", command=self.toggle_highlight), the toggle_highlight() function cannot accept any parameters. In this context, the command can only be linked to a function name without any parameters, which means no matter what colors user choose, it won't change how the function toggle_highlight(self) highlight that region so that even the user choose red, the highlighted region is still blue.

We resolved this issue by adjusting the toggle_highlighted(self) function to include a color parameter, i.e., toggle_highlighted(self, color). Furthermore, we modified the command to use a lambda expression, thereby avoiding a function call. So, for the blue color, the line becomes self.editwin.color_menu.add_command(label="blue", command=lambda: self.toggle_highlight("light blue")). This effectively allowed us to pass the color parameter as desired.

4. Redundant tag for unhighting

We discovered an issue where clicking the Unlight button turned the selected region to white. This action inadvertently created a tag name associated with this white color. The potential downside is that it might interfere with the Find Next Highlight function, as the "white" selected region would be classified as a selected region, despite it not truly being highlighted.

To counteract this, we introduced an if statement to verify whether the passed-in color is white. If it is, the corresponding tag is removed, ensuring that it will not be recognized as a highlighted region.

Remaining Work:

We have completed the majority of the proposed features. Our current priority is to develop comprehensive unit tests for the highlighting feature. Firstly, we will include basic tests to verify if a selected region is properly highlighted with the correct color tag. Secondly, we will test the "unhighlight" functionality to ensure that when applied to a highlighted region, the color is removed and the region no longer has a color tag. Lastly, we will create tests for the nice-to-have feature, which includes testing the "find-next-highlight" functionality and verifying that highlighted regions persist and are saved within the file.

Design Document:

Project Functionality:

Our project allows users to highlight selected text regions in various colors including blue, red, yellow, green, orange, and purple using a drop-down menu. In addition, we offer a feature that enables users to revert any highlighted region back to its original white color. Significantly, all highlighting changes made by the user are saved and persist even after the file is stored on their computer; when reopening the file, the highlights remain in place. Users have the option to navigate to the next highlighted section by clicking the Find Next Highlight button, which searches from the top to the bottom of the file. Moreover, they can swiftly jump to the very first highlighted segment by selecting the Find First Highlight button. image

User Interface:

When the user is not opening the new file window, those three buttons are unclickable, since it is unreasonble to highlight the text over interactive mode in IDLE.

image

Users are able to choose the color according to the provided drop-down menu.

image

In order to make the highlighting region not prevent readability of text and code, I adjust the color to be the shadow version of that color so that user will have better experience.

image

Implementation Overview:

Our initial step was to enable a rudimentary highlight feature in a single color, blue. We achieved this by creating a key binding linked to the function toggle_highlight(self). We utilized the existing function self.editwin.get_selection_indices() to obtain the start and end indices of the user-selected region. Subsequently, using self.editwin.text.tag_add(color, start, end), we tagged this selected region. We hardcoded the background color to blue by employing self.editwin.text.tag_config("blue", background="blue").

image

Following the same process as highlighting the selected region in blue, we then adapted the function toggle_highlight(self, color) in highlight.py to suit our purposes. The function, as it initially stood, hardcoded the background color as blue, but it needed modification to accommodate user-selected colors. Therefore, we changed the function header to toggle_highlight(self, color) and utilized the tkinter function self.editwin.text.tag_config(color_tag, background=color). This presented a potential issue of tag name overlap if we highlighted a selected region multiple times. Our solution was to remove all tags associated with that selected region before applying the new color.

At this stage, our task was to link this function to the buttons displayed in the user's menu bar. Our goal was to provide a dropdown menu from which users could select their desired color. To this end, we added a submenu called color_menu under Highlight Line Region, created through the line of tkinter code self.color_menu = Menu(self.menudict['edit'], tearoff=0) in the editor.py file. Also within the editor.py file, we created a HighlightParagraph instance (implemented in highlight.py). This allowed us to link the submenu as a dropdown to the Highlight Line Region button. Simultaneously, this gave us the ability to pass parameters to the function that highlights the paragraph when different color buttons are clicked.

After completing the basic highlight feature, we started working on getting the highlight information to be saved with the file. By doing this, the highlights will be visible again the next time the file is opened.

There are four problems that need to be solved in order to complete this feature:

  1. How should we get the highlight information? In solving this problem, we remembered the tag that we added to each highlight when we implemented the highlight feature. Then a possible solution was presented to us: Is there a way to get some information about highlights based on the tag? After checking chatGPT and Google, we found the answer in Methods on Text widgets in the Tkinter reference (https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/text-methods.html). checkpoint1 Then, we can find all the ranges of text in the widget that are tagged with different tagName and save it to a list. The information should look like below: [['1.2', '1.8', '1.16', '1.20', '3.1', '3.5'], ['1.9', '1.13', '3.8', '3.10'], ['5.0', '5.2'], ['4.2', '4.4'], [], [], []] Each sequence in the list represents the tag information of a color highlight.

  2. In what form the highlight information should be stored?

    After some research, we found that we can store our tag information in JSON data format. The JSON file contains a larger Python dictionary, which uses the filename to represent the key and stores the tag information list for each file.

    The JSON should look like below:

    {"/home/lanmei0914/CSE190/group-project-idlemasters/hello.py": [["1.2", "1.8", "1.16", "1.20", "3.1", "3.5"], ["1.9", "1.13", "3.8", "3.10"], ["5.0", "5.2"], ["4.2", "4.4"], [], [], []], "/home/lanmei0914/CSE190/group-project-idlemasters/pytest.py": [[], ["1.2", "1.6"], [], [], [], [], []]}

    In the above example, we store two files, '/home/lanmei0914/CSE190/group-project-idlemasters/hello.py' and '/home/ lanmei0914/CSE190/group-project-idlemasters/pytest.py', and the list after the colon is the same as the tag information obtained in (1)

  3. When should we choose to save this information?

    In solving this problem, we had two solutions: 1. save this information every time we add highlight; 2. write and save this information to the JSON file when the user chooses to save it. After some deliberation, we chose the latter because it was more logical for the user to save the information only when they wanted to.

    Then we need to find and understand the save function in idellib. After searching through VSCode, we found the file iomenu.py, where the writefile() function is responsible for the file's save feature. So we just need to update our JSON file when writefile() is called to store the highlight information.

  4. How should we rehighlight the file when we reopen it again?

    This problem becomes relatively simple after solving how to store tag information. We just need to read our stored JSON data when the open() function in iomenu.py have been called. Read our previously stored tag information in JSON data again according to filename, re-tagging each tag according to its information using the tag_add() function and rehighlight it background.

Up to this point, we have successfully completed the feature of storing and re-reading the highlighted information.

After that, we started working on the implementation of the feature to find the next highlight. With the above experience, we know how to get all the tag information, this gave us some inspiration on how to implement this feature. So the approximate steps to implement this feature are

  1. get all the tag information. We used the same method (tag_ranges()) in the feature "storing and re-reading the highlight information" to obtain tag information

  2. convert each color's tag information into tuples (s0, e0), (s1, e1), (s2, e2) ... where each si is the index just before the first character of the range and ei is the index just after the last character of the range. We found chatGPT to be very convenient and accurate in solving such problems, as long as it is given a simple ex checkpoint3 ample it can write a very good solution.

  3. combine all the tag information of different colors into a single tuple list We found chatGPT to be very convenient and accurate in solving such problems, as long as it is given a simple example it can write a very good solution. checkpoint2

  4. sort by si. The hard part here is that we need to rewrite the sort rules. The format of the index in tkinter is 'row.col' so we can't compare two indices in a simple float way because we want index 1.2 < 1.16>. The solution we end up using the .split() function to separate the row and col, and compare the row and col as int during the sort.

  5. find the next highlight tag index based on where the previous position of where find next highlight goes. Initially, we use a simple 0,1,2,3... to represent the previous position of where find next highlight goes in the sorted list of all tag information. Each time we just need set index + 1 to get the next highlight tag. But we found that with this simple approach if we delete or add a highlight tag, find the next highlight does not jump to the next correct tag well (sometimes it skips one or stays in place). So we choose to directly store the tkinter tag index information as the previous position of where find next highlight goes. And find the starting index of the next tag closest to the previous position of where find the next highlight go in the sorted list of all tag information

  6. move the insert pointer to the corresponding index. This step is relatively simple. we just use the code below to set the insert pointer to the corresponding index the same as what we did during Project 1.

    self.editwin.text.tag_remove("sel", "1.0", "end")
    self.editwin.text.mark_set("insert", next_tag)
    self.editwin.text.see("insert")
    self.editwin.set_line_and_column()

    So far we have completed the implementation of the "find next highlight feature"

J4cky1ove commented 1 year ago

Final Report

Progress Report:

Our group project is approximately 70% complete. We have successfully implemented the fundamental feature of highlighting selected regions using multiple colors. Users can choose their preferred colors from a drop-down menu. The changes made for this functionality have been integrated into a specific file called highlight.py, which contains the HighlightParagraph class.

To ensure the highlighted regions persist, we store the relevant information in a JSON file. This enables us to view the highlighted regions when reopening the file at a later time.

Progress Update:

Challenges:

1.Tag name issue

We faced a glitch that significantly impacted the user experience. Suppose a file contains a line if a == 0 with parts if and 0 highlighted in red. If we change the highlight color for if to blue, the 0 would also switch to blue automatically. This occurred because changing the highlight color was inadvertently modifying the color of all text regions associated with the same tag.

We have addressed this by first checking whether the text region is already highlighted. If it is, we now remove the existing tag and assign a new tag, correlating with the updated color. Consequently, we apply the new color to all highlighted regions associated with this new tag name. So, if we go back to the if a == 0 example, where if and 0 are highlighted in red, and we decide to change if to blue, we first strip away the existing tag from if, assign a blue tag to if, and then apply the blue color only to this region. As a result, the 0 remains red, since the modification to if's tag does not affect it.

2.Selection color missing if the region is highlighted

We came across an issue where, if a region of text was highlighted and the user then selected a portion of this region or the whole region, the typical grey color associated with selection would not appear. Instead, the selected portion would retain its highlighted color. Upon consulting StackOverflow, we discovered that this anomaly was due to the selection priority being lower than the highlighting priority.

To rectify this, we introduced a line of code to adjust the priority so that the selected region is ranked higher than the highlighted region. We accomplished this by using the function tag_raise("sel"), which successfully resolved the problem.

3. Drop down menu with different parameters passing to function

We stumbled upon a problem involving the create_color_menu(self) and toggle_highlight(self, color) functions. Our goal was to allow users to select different colors from a dropdown menu, and to use these color choices as parameters for the toggle_highlight(self, color) function. However, due to the particular way that the dropdown menu was implemented using the add_command function in tkinter, we were unable to directly pass the color parameter into the function. For instance, in the case of blue color, using self.editwin.color_menu.add_command(label="blue", command=self.toggle_highlight), the toggle_highlight() function cannot accept any parameters. In this context, the command can only be linked to a function name without any parameters, which means no matter what colors user choose, it won't change how the function toggle_highlight(self) highlight that region so that even the user choose red, the highlighted region is still blue.

We resolved this issue by adjusting the toggle_highlighted(self) function to include a color parameter, i.e., toggle_highlighted(self, color). Furthermore, we modified the command to use a lambda expression, thereby avoiding a function call. So, for the blue color, the line becomes self.editwin.color_menu.add_command(label="blue", command=lambda: self.toggle_highlight("light blue")). This effectively allowed us to pass the color parameter as desired.

4. Redundant tag for unhighting

We discovered an issue where clicking the Unlight button turned the selected region to white. This action inadvertently created a tag name associated with this white color. The potential downside is that it might interfere with the Find Next Highlight function, as the "white" selected region would be classified as a selected region, despite it not truly being highlighted.

To counteract this, we introduced an if statement to verify whether the passed-in color is white. If it is, the corresponding tag is removed, ensuring that it will not be recognized as a highlighted region.

Design Document:

Project Functionality:

Our project allows users to highlight selected text regions in various colors including blue, red, yellow, green, orange, and purple using a drop-down menu. In addition, we offer a feature that enables users to revert any highlighted region back to its original white color. Significantly, all highlighting changes made by the user are saved and persist even after the file is stored on their computer; when reopening the file, the highlights remain in place. Users have the option to navigate to the next highlighted section by clicking the Find Next Highlight button, which searches from the top to the bottom of the file. Moreover, they can swiftly jump to the very first highlighted segment by selecting the Find First Highlight button. image

User Interface:

When the user is not opening the new file window, those three buttons are unclickable, since it is unreasonble to highlight the text over interactive mode in IDLE.

image

Users are able to choose the color according to the provided drop-down menu.

image

In order to make the highlighting region not prevent readability of text and code, I adjust the color to be the shadow version of that color so that user will have better experience.

image

Implementation Overview:

Our initial step was to enable a rudimentary highlight feature in a single color, blue. We achieved this by creating a key binding linked to the function toggle_highlight(self). We utilized the existing function self.editwin.get_selection_indices() to obtain the start and end indices of the user-selected region. Subsequently, using self.editwin.text.tag_add(color, start, end), we tagged this selected region. We hardcoded the background color to blue by employing self.editwin.text.tag_config("blue", background="blue").

image

Following the same process as highlighting the selected region in blue, we then adapted the function toggle_highlight(self, color) in highlight.py to suit our purposes. The function, as it initially stood, hardcoded the background color as blue, but it needed modification to accommodate user-selected colors. Therefore, we changed the function header to toggle_highlight(self, color) and utilized the tkinter function self.editwin.text.tag_config(color_tag, background=color). This presented a potential issue of tag name overlap if we highlighted a selected region multiple times. Our solution was to remove all tags associated with that selected region before applying the new color.

At this stage, our task was to link this function to the buttons displayed in the user's menu bar. Our goal was to provide a dropdown menu from which users could select their desired color. To this end, we added a submenu called color_menu under Highlight Line Region, created through the line of tkinter code self.color_menu = Menu(self.menudict['edit'], tearoff=0) in the editor.py file. Also within the editor.py file, we created a HighlightParagraph instance (implemented in highlight.py). This allowed us to link the submenu as a dropdown to the Highlight Line Region button. Simultaneously, this gave us the ability to pass parameters to the function that highlights the paragraph when different color buttons are clicked.

After completing the basic highlight feature, we started working on getting the highlight information to be saved with the file. By doing this, the highlights will be visible again the next time the file is opened.

There are four problems that need to be solved in order to complete this feature:

  1. How should we get the highlight information? In solving this problem, we remembered the tag that we added to each highlight when we implemented the highlight feature. Then a possible solution was presented to us: Is there a way to get some information about highlights based on the tag? After checking chatGPT and Google, we found the answer in Methods on Text widgets in the Tkinter reference (https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/text-methods.html). checkpoint1 Then, we can find all the ranges of text in the widget that are tagged with different tagName and save it to a list. The information should look like below: [['1.2', '1.8', '1.16', '1.20', '3.1', '3.5'], ['1.9', '1.13', '3.8', '3.10'], ['5.0', '5.2'], ['4.2', '4.4'], [], [], []] Each sequence in the list represents the tag information of a color highlight.

  2. In what form the highlight information should be stored?

    After some research, we found that we can store our tag information in JSON data format. The JSON file contains a larger Python dictionary, which uses the filename to represent the key and stores the tag information list for each file.

    The JSON should look like below:

    {"/home/lanmei0914/CSE190/group-project-idlemasters/hello.py": [["1.2", "1.8", "1.16", "1.20", "3.1", "3.5"], ["1.9", "1.13", "3.8", "3.10"], ["5.0", "5.2"], ["4.2", "4.4"], [], [], []], "/home/lanmei0914/CSE190/group-project-idlemasters/pytest.py": [[], ["1.2", "1.6"], [], [], [], [], []]}

    In the above example, we store two files, '/home/lanmei0914/CSE190/group-project-idlemasters/hello.py' and '/home/ lanmei0914/CSE190/group-project-idlemasters/pytest.py', and the list after the colon is the same as the tag information obtained in (1)

  3. When should we choose to save this information?

    In solving this problem, we had two solutions: 1. save this information every time we add highlight; 2. write and save this information to the JSON file when the user chooses to save it. After some deliberation, we chose the latter because it was more logical for the user to save the information only when they wanted to.

    Then we need to find and understand the save function in idellib. After searching through VSCode, we found the file iomenu.py, where the writefile() function is responsible for the file's save feature. So we just need to update our JSON file when writefile() is called to store the highlight information.

  4. How should we rehighlight the file when we reopen it again?

    This problem becomes relatively simple after solving how to store tag information. We just need to read our stored JSON data when the open() function in iomenu.py have been called. Read our previously stored tag information in JSON data again according to filename, re-tagging each tag according to its information using the tag_add() function and rehighlight it background.

Up to this point, we have successfully completed the feature of storing and re-reading the highlighted information.

After that, we started working on the implementation of the feature to find the next highlight. With the above experience, we know how to get all the tag information, this gave us some inspiration on how to implement this feature. So the approximate steps to implement this feature are

  1. get all the tag information. We used the same method (tag_ranges()) in the feature "storing and re-reading the highlight information" to obtain tag information

  2. convert each color's tag information into tuples (s0, e0), (s1, e1), (s2, e2) ... where each si is the index just before the first character of the range and ei is the index just after the last character of the range. We found chatGPT to be very convenient and accurate in solving such problems, as long as it is given a simple ex checkpoint3 ample it can write a very good solution.

  3. combine all the tag information of different colors into a single tuple list We found chatGPT to be very convenient and accurate in solving such problems, as long as it is given a simple example it can write a very good solution. checkpoint2

  4. sort by si. The hard part here is that we need to rewrite the sort rules. The format of the index in tkinter is 'row.col' so we can't compare two indices in a simple float way because we want index 1.2 < 1.16>. The solution we end up using the .split() function to separate the row and col, and compare the row and col as int during the sort.

  5. find the next highlight tag index based on where the previous position of where find next highlight goes. Initially, we use a simple 0,1,2,3... to represent the previous position of where find next highlight goes in the sorted list of all tag information. Each time we just need set index + 1 to get the next highlight tag. But we found that with this simple approach if we delete or add a highlight tag, find the next highlight does not jump to the next correct tag well (sometimes it skips one or stays in place). So we choose to directly store the tkinter tag index information as the previous position of where find next highlight goes. And find the starting index of the next tag closest to the previous position of where find the next highlight go in the sorted list of all tag information

  6. move the insert pointer to the corresponding index. This step is relatively simple. we just use the code below to set the insert pointer to the corresponding index the same as what we did during Project 1.

    self.editwin.text.tag_remove("sel", "1.0", "end")
    self.editwin.text.mark_set("insert", next_tag)
    self.editwin.text.see("insert")
    self.editwin.set_line_and_column()

    So far we have completed the implementation of the "find next highlight feature"

Testing:

setup(): In this function, we first create a Tkinter root window and create a Tkinter Text. After that, we can successfully mock the editor window and the flist object inside the editor windows for the testing environment. We also create an HighlightPargraph Object in order to test each of the functions inside it.

tearDown(): In this function we destroy the Tkinter root window to make sure after each run of the test function, we will clean up the testing environment.

Besides the setup() and teardown() function in testing file, the tests we created are listed follwoing:

test_toggle_highlight

In this test, we are testing basic funcionality of highlighting function. Since we already created a text as user input in setup(), what we should do right now is to highlight part of this text, and then check whether this part of the text has a tag with that name of the color. So we basically selected the whole first line as our selected region by setting the start index to 1.0 and end index to 2.0. Then, we simply called function toggle_highlight, and then we checked the tag name one character by one character. If any of the character does not have that expected tag name, it will fail this test.

test_highlight_save

In this test, we are testing the function save_highlight() in highlight.py. We first use the toggle_highlight (this function was already tested before, so we can be 100% sure it is safe and okay to use) to set some of the highlight values. After we set the highlight value, we called save_highlight() to save the highlight information to the data.json. And we open the data.json file manually to check if the saved list is the same as what we except using the assertEqual() method.

test_highlight_reopen

In this test, we are testing the function reload_highlight() in highlight.py. We first used the assertNotIn() to check there is no tag information in the text to make sure the text is clean before we called the reload_highlight to reload the tag and highlight information. After we check the text is clean, we will call reload_highlight() to reload the tag information from the data.json. After the function is called, we will use the same way we check in test_toggle_highlight to check if all the highlight information has been set correctly.

test_next_wrap

In this test, we are testing the function next_highlight() in highlight.py. We first set up the test environment by creating three highlights with different colors and corresponding start and end indices. Next, we call the next_highlight() function on the self.highlighter object, passing in the event object. This function is responsible for moving the cursor to the next highlight in the text. Finally, we use the assertEqual() method to verify that the cursor position ("insert") matches the start index of the first highlight ('1.0'). This confirms that the next_highlight() function successfully wraps around to the first highlight when reaching the end of the text. This test ensures that the next_highlight() function behaves correctly and handles wrapping around when navigating through highlights in the text.

test_next_normal

n this test, we are testing the next_highlight() function in highlight.py. We first set up the test environment by creating three highlights with different colors and corresponding start and end indices. Next, we call the next_highlight() function on the self.highlighter object, passing in the event object. This function is responsible for moving the cursor to the next highlight in the text. Finally, we use the assertEqual() method to verify that the cursor position ("insert") matches the start index of the first highlight ('3.0'). This confirms that the next_highlight() function correctly moves the cursor to the next highlight according to the order of appearance in the text. This test ensures that the next_highlight() function behaves correctly and navigates to the next highlight in the text based on the highlight order.