pytextedit 0.4: what’s next

I have quite a few things I want to do for 0.4:

  • Add syntax highlighting. Finally.
  • Improve the config system. All the files will be merged into one, and instead of having tons of config variables they will all be part of a dictionary called “CONFIG”. In addition to making “global” statements no longer necessary, it will make reading/writing the config file much simpler. (As all I would have to do is loop through the lines.)
  • Improve and re-add the file browser.
  • Improve and re-add the spellchecker.
  • Add a fullscreen toggle.
  • Add an embedded terminal.
  • Change the Options dialog to use actual tabs, or find some other way to make it more easily modified.
  • Add a checkbox in the Find/Replace dialogs for regexp searches.
  • Add a checkbox in the Find/Replace dialogs for searching backwards.
  • Add a basic debugger.
  • Add various improvements for coding. Auto-comment indenting, finding the closing bracket of code blocks, etc.
  • Add a dialog for searching for files.
  • Add a plugin system. Useless, of course, but why not?
  • Add a collaboration editing system. (Again, because why not?) Ideally real-time, but it almost certainly won’t be initially. This actually won’t be too hard (all it will be is a server for managing the edits, and a dialog on the client for connecting the the server and reading/writing the file).
  • And, of course, fix the countless bugs that will inevitably appear.

On a related note, I’ll be uploading snapshots of the code as I’m working on stuff occasionally, because it will probably be quite a while until this version is complete.


pytextedit 0.3 is complete!

So, I finally got this done.


Linux installer.


  • opt_font_size() now automatically returns focus to the text box. (This could cause slight annoyances if this option was chosen from the menu.)
  • Added “Options -> Revert to Default…”.
  • “Bookmarks -> Save Bookmarks…” now shows the correct message if there are no bookmarks. (Previously it said that there were no bookmarks to clear. Yay for copy-paste.)
  • “Bookmarks -> Open Bookmarks…” now switches back to the original directory after globbing the files, and then switches if needed for opening. Previously this would cause problems if no file was opened, as the directory wouldn’t be restored.
  • MDI-related functions now update the title and status bar correctly. Previously the filename/encoding status label would not be updated, the title was set inconsistently, and the statistics labels would only sometimes be updated.
  • Added “Tools -> Notes…”.
  • Fixed bug where clicking “Cancel” in “Documents -> Open…” would open a blank document.
  • Added folder “docs” for documentation.
  • Added documentation file “docs/macro_docs”.
  • Fixed bug where “Search -> Replace…” would auto-insert an incorrect string into the second entry.
  • If text is selected, “Tools -> Statistics…” will now show the starting and ending positions.
  • Added “Tools -> Insert Time (Words)”.
  • Moved the code for getting the last opened file into the setup section.
  • Added error checking for loading the program’s files during setup.
  • “File -> Favorites”, “Documents -> View”, and “Tools -> Macros -> Run” will now do nothing if the listbox was clicked on a blank item. Before this could cause some really odd behavior.
  • Changed a few menu items slightly.
  • Renamed “Code -> Escape Selected” to “Code -> Escape”.
  • Updated help_about() to make it follow the same conventions as the rest of the code.
  • Added “Help -> Help…”
  • Added macro parser.
  • Added macro keybindings.
  • Changed keybindings for “Options -> Enlarge Font” and “Options -> Shrink Font”.
  • Simplified file_exit().
  • Added “Tools -> Run Command…”.
  • file_exit() now checks all documents for unsaved changes.

What’s next?

There is a ton of stuff I still want to add. There’s the syntax highlighter, various improvements for coding, an overhaul to how the config files are set up, a plugin system (just because why not?), etc.

It will probably be a while until 0.4 is out, though, as I have quite a few other projects to work on that I’ve been forgetting about.

pytextedit: advanced macros

I’ve added a few more advanced features to the macros:

  • Variables.
  • Flags. (For changing the behavior of the parser.)
  • Execution of Python code.
  • Keybindings. (Although they aren’t shown in the video.)

The macro shown in the video:


# This is a demo macro, designed to show the
# features of the macro language.

# Define variables.
$test = Hello World!
$pos = end

# Open the file.
open /home/adam/
# Set the insert position to the end.
set_insert $pos
# Insert newlines.
insert_nl insert 2
# Insert the string
insert insert $test

# The macro language doesn't have any mathematical
# functions, so Python code has to be used for this
~ text_box.text_box.insert("insert", "\n\n" + str(1 + 2 + 3))

# Select the first line only.
sel_from 1.0 1.end

Variables are defined by placing a dollar sign (“$”) in front of the variable name, then placing the value. after a space, equal sign, and another space. For example, “$test = hello world”.

Variables can contain any letter or number, and are case-sensitive. It is not, however, recommended to have variables like “$test” and “$test2”, where the second is the same name as the first with the addition of a number, as this causes problems. (This should be fixed soon!)

Using variables is just as simple; insert the variable name where you wish the value to go: “insert end $test.”

Flags are put on the first line, started with a “!”. In this example, I’m using “!more_dlg” which shows more information in the macro completion dialog. (Currently the only other one is “!supress_dlg”, which hides this dialog.

Starting a line with “~ ” will pass the rest of the line to Python’s exec statement/function, allowing execution of Python code. This can be useful when there’s something you need to do that the macro language doesn’t support. In this video I’m using it for inserting the results of a mathematical operation.

pytextedit: documentation

I figured it would be good to finally get around to writing some documentation for this project, especially with the addition of the macros (because otherwise, how would you know what all the commands are?).


There’s a new menu item called “Help -> Help” that when clicked will show the window in the top right, with a list of the topics. When one of the list items is clicked on, another window will appear with the documentation for that topic.

Or if for some reason you don’t like this interface, you can also simply open the file “docs/macro_docs”, as the contents of the text box are read from that file.

I might work on formatting the text a bit later (headings, code, etc.). It looks a bit ugly right now.

Oh, and I just realised that first sentence is really awkward and has a typo. And a punctuation error. I’m going to have to change that…

Python: getting the time

(I can never come up with good blog titles.)

Anyway, this is a Python script to get the time, but not in the normal boring way of simply presenting numbers. Instead, this shows it in words.

import datetime
import sys

now =
hour = now.hour
hour2 = hour
minute = now.minute

if hour == 12:
    time = "noon"
elif hour == 0 or hour == 24:
    time = "midnight"
elif hour >= 3 and hour < 12:
    time = "in the morning"
elif hour > 12 and hour <= 21:
    time = "in the afternoon"
elif hour > 21 or hour < 3:
    time = "at night"

if time == "noon" or time == "midnight":

if hour > 12:
    hour -= 12
if minute <= 30:
    sep = "after"
    sep = "until"
    minute = 60 - minute
    hour += 1
    hour2 += 1
    if hour > 12:
        hour -= 12
    if minute == 0:
        print("%d %s" % (hour, time))

if hour2 == 0 or hour2 == 24:
    print("%d %s midnight" % (minute, sep))
elif hour2 == 12:
    print("%d %s noon" % (minute, sep))
    print("%d %s %d %s" % (minute, sep, hour, time))

So if the time was 4:37 PM (which it is as I’m writing this), it will show “23 until 5 in the afternoon”. Other possibilities include “noon”, “midnight”, “14 after 6 in the morning”, “1 at night”, “23 after noon”, etc.

pytextedit: another macro demo

Here’s another short demo, this time showing slightly more complex macros.

I now have almost all the commands implemented; the only ones left are the search_replace_* functions, which I’m having a bit of trouble with. Basically, because parameters are separated by a space when there is a parameter that contains a space it gets split up. With most commands (search, for example) this isn’t a problem, as there is only one parameter so all I have to do is join the parts back together. With replace, however, there are two parameters, so I don’t know where to join them. I might simply have to resort to using an arbitrary separator that is unlikely to be part of the replace string(s).

Also, I implemented basic single-line comments, and extra blank lines are now skipped.

pytextedit: macro demo

This video shows how macro execution is going to work in pytextedit 0.3. (Also, it gave me an excuse to mess around with desktop recording software.)

(You may need to set the quality to 720p to actually see anything that’s happening.)

If it’s not entirely obvious by watching the video, the current way to execute macros is by choosing them from a listbox, opened by selecting the “Tools -> Macro -> Run Macro…” menu command, which then parses them. Later I’ll add keybindings, but for now I’m focusing on getting the most important stuff implemented. Anyway, in the video the cursor was at the position “1.0”, but after executing the macro it is at “2.4”. set_insert is the only command I have implemented, but now that the base system is complete adding more commands is relatively easy.

Several functions are needed to run the macros. One for selecting which macro to run, another for loading it, and another for parsing and executing each line. I broke up the functions for selecting and loading to allow more flexibility, so macros can be chosen in other ways besides the “Run Macro” dialog (for example, keybindings or even starting a macro from within another). The function for executing was shown in the video, and here in case it was hard to read:

def tools_macro_parse(line, text, macro):
    """Parses and executes each line of the macro."""
    # Split the macro into components on each space.
    mac_comp = text.split(" ")
    # Execute the line.
        # set_insert location
        if mac_comp[0] == "set_insert":
            text_box.text_box.mark_set("insert", mac_comp[1])
        # Execution was successful.
        return True
    # If there was any error:
        showerror("Run Macro", "Error executing macro \"%s\":\n%d: %s" % (macro, line, text))
        return False