-3

For more information, see this issue on GitHub.

I want to write an algorithm that's called when the user hits the Enter key after an opening brace. The expected behavior is detailed below.


1. Suppose we have an empty document. If we type an opening brace and hit Enter, the expected behavior is the following:

Enter image description here

This can be described as the following simple algorithm:

  1. If Enter is pressed after an opening brace, move the cursor to the next line and indent one more level beyond the opening brace's indentation.

  2. If the opening brace was not paired, insert a closing brace on the next line at the same indentation level as the opening brace. Else, if it was already paired, do nothing after 1.

In other words, what we don't want is for another closing brace to be inserted if we hit Enter after the opening brace that's already paired. Instead, we simply want to keep the indentation consistent:

Enter image description here


2. Now suppose we type another opening brace on Line 2, where the cursor is, and hit Enter. We expect a new pair to be generated, following the same algorithm described above:

Enter image description here


3. And if we go to Line 1, hit Enter a couple times to force the braces down, and then try to create a new block up top, we want this to be paired as well:

Enter image description here

The Problem

I'm having trouble implementing this behavior. I'm developing the text editor in C++ using Qt, but you don't have to worry about the framework specifics. It's just going to be a utility function that takes a given string named context and the index of the opening brace in question, and decides whether a closing brace should be inserted or not.

My current implementation satisfies scenarios #1 and #2, but not #3. The reason it does not satisfy #3 is because I'm using a queue for the opening braces.

I've also tried using a stack for the opening braces. Interestingly, this ends up satisfying #1 and #3, but not #2.

Question

How can I write an algorithm to determine whether a given brace already has a matching pair, in accordance with the expected behavior described above? Note that I've researched this on the site and do know how to determine whether a given opening brace has a matching closing brace. However, my current algorithm (linked above) does not work as intended (see description above for where it fails).

Clarification: you do NOT have to worry about the whole "indentation" thing. That's taken care of and works as intended. What doesn't work as intended is deciding whether a particular brace needs a matching pair.

AlexH
  • 1,087
  • 2
  • 10
  • 29
  • Before downvoting this into oblivion, please realize this is NOT a question about the horse that's been beaten into the afterlife, "balanced braces." – AlexH Apr 13 '19 at 13:51
  • 3
    This is likely being downvoted because "How can I write an algorithm to describe this behavior?" is way too broad of a question. You'll need to narrow down what you're asking. – Carcigenicate Apr 13 '19 at 14:03
  • @Carcigenicate Thanks for clarifying, I've edited my question so it's hopefully clearer. – AlexH Apr 13 '19 at 14:12
  • You're really looking for this answer: https://stackoverflow.com/a/28863720/2642059 but i can type it out for you. – Jonathan Mee Apr 13 '19 at 14:52

1 Answers1

1

This is not a complex problem to determine if there is a closing brace, it's the indentation that will be the difficult one. If there is any unmatched closing brace following the ope brace you have a match. The key in that is whether the brace is following your open brace. You could determine this by:

  1. Store the location of all unmatched closing braces; if one follows your cursor you don't need to insert a closing brace
  2. Dynamically evaluate the number of unmatched braces before your cursor (not counting unmatched closes) compared to the number of unmatched braces after your cursor; if you have a surplus of closing braces after your cursor then you don't need to insert a closing brace

If you're going with number 2, I've expanded this answer to your needs for counting braces before and after:

bool foo(const string& context, const size_t pos) {
    const auto it = next(cbegin(context), pos);
    const auto before = accumulate(cbegin(context), it, 0, [](const auto output, const auto input) {
        if(input == '{') {
            return output + 1;
        }
        else if(input == '}' && output > 0) {
            return output - 1;
        }
        else {
            return output;
        }
    });
    const auto after = accumulate(it, cend(context), 0, [](const auto output, const auto input) {
        if(input == '{') {
            return output + 1;
        }
        else if(input == '}') {
            return output - 1;
        }
        else {
            return output;
        }
    });

    return before + after >= 0;
}

This can be called, with the text in question (not including the inserted open brace), and the position in the string the brace is going to be inserted. Given your text is contained in const string bar and your cursor position is at const size_t baz you could call this function like: foo(bar, baz) If this returns true you need to add a closing brace.

Live Example

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • Thanks, but I'm having trouble understanding how this would work for {} --> {{}}, where you're nesting one set of new braces in an existing pair. The number of closing braces after the cursor would be 1, which is more than before, which would suggest we don't need to insert a closing brace. But we do. See #2 above. – AlexH Apr 13 '19 at 18:33
  • Yeah, this doesn't work. – AlexH Apr 13 '19 at 22:10
  • @AlexH I'll try to type up an example shortly but in your example you must calculate what's before the cursor. In this case +1 opens, now calculate following your cursor, that's -1 for a close. Since your number is greater than or equal to 0 you need to add a closing brace. In the case where there was already a closing brace there, your count would have been -2 giving you a total of -1, meaning no closing brace needed. – Jonathan Mee Apr 14 '19 at 02:31
  • I figured it out, but your suggested solution does not work. See [here](https://github.com/AleksandrHovhannisyan/Scribe-Text-Editor/blob/master/CustomTextEditor/utilityfunctions.cpp#L21) for my solution (works for all cases). – AlexH Apr 14 '19 at 18:28
  • @AlexH I've actually implemented my solution and written some simple tests. I believe it works for some cases that yours does not. Feel free to get back with me if you disagree? – Jonathan Mee Apr 15 '19 at 17:24