Jez Higgins

Freelance software grandad
software created
extended or repaired


Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed

The Forest Road Reader, No 2.72 : STinC++ - edit, another five minute increment

STinC++ rewrites the programs in Software Tools in Pascal using C++

Now I’m able to start adding text into my editor, it makes sense that the next tiny step should be to be able to print it out. Or print some of it out at least.

The i command sets dot, the current line, to the most recent line entered. The p command prints lines, defaulting to dot. Therefore an i followed by a p should echo back the last thing you typed.

void editor::process(std::istream& in, std::ostream& out) {
  while(in.peek() != eof) {
    auto line = stiX::getline(in);

    if (line == "=")
      out << buffer_.dot() << "\n";
    else if (line == "i")
      do_insert(in, buffer_);
    else if (line == "p")
      do_print(out, buffer_);
    else
      out << "?\n";
  }
}

void do_print(std::ostream& out, edit_buffer& buffer) {
  auto index = buffer.dot();

  if (index == 0)
    out << "?";
  else
    out << buffer[index-1];

  out << "\n";
}
Console showing edit’s insert command followed by print

I don’t often use the word easy when talking about software, but let’s not kid ourselves here. This is easy stuff.

Fact is, pretty much all of the edit commands are going to be similarly straightforward - append, delete, change, write to file, read to file - they’re all just going to be a few lines of code each.

This is especially true so long as I carry on ignoring the real meat of the task. The complexity in edit comes not from the commands, but from the line addressing.

Line numbers are formed by the following components:

n a decimal number

. the current line ("dot")

$ the last line

/pattern/ a forward context search

\pattern\ a backward context search

Components may be combined with + or -, as in, for example

.+1 sum of . and 1

$-5 five lines before $

Line numbers are separated by commas or semicolons; a semicolon sets the current line to the most recent line number preceding.

The global prefixes cause repeated execution of a command, one for each line that matches (g) or does not match (x) a specified text pattern:

(1,$) g/pattern/command

(1,$) x/pattern/command

There’s a lot going on there. Line numbers can be given as a start and end pair, a single value, or omitted entirely. There are special characters, simple arithmetic, and line numbers can also be combined with search patterns.

Extending, say, p to support a pair of lines is going to be straightforward. I imagine the code will be something along the lines of

void do_print(std::ostream& out, size_t from, size_t to, edit_buffer& buffer) {
auto index = buffer.dot();

  if (to == 0) {
    out << "?\n";
    return;
  }

  for(auto i = from; i != to; ++i)
    out << buffer[index-1] << '\n';
}

Getting hold of from and to in the first place, though, is a nice little parsing problem. That’s where I’m off to next.

Source Code

The full source code, with tests and what-not, for edit, indeed the whole project, is available in the stiX GitHub repository. Forgive me if I suggest that you might find the history more interesting that the naked source.

Endnotes

This whole endeavour relies on Software Tools in Pascal and Software Tools, both by Brian W Kernighan and PJ Plauger. I love these books and commend them to you. They are both still in print, but new copies are, frankly, ridiculously expensive. Happily, there are plenty of second-hand copies around, or you can borrow them from The Internet Archive using the links above.

For this project I’ve been using JetBrain’s CLion, which I liked enough to buy and keep renewing a license for. I use it all the time now.


Tagged code, and software-tools-in-c++


Jez Higgins

Freelance software grandad
software created
extended or repaired

Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed