Monday | 15 APR 2024
[ previous ]
[ next ]

EVA - Fixing Backspace

Title:
Date: 2024-01-27
Tags:  pick, editor, basic

I've had a bug in my [EVA] editor that shows up relatively rarely but it was a major bug. It get's into an infinite loop and you need to exit it by using the debugger. You can fudge the DONE variable to get out and save your work but I did lose 1 file to this error which was disappointing.

It only ever seemed to come up in markdown files and so it was never a super high priority. I knew it had something to do with long lines as the multiline stuff was all after the fact. 90% of the code I write is probably on a single line so it wasn't often that I had to deal with wrapping. Blog posts however are a series of long lines so it makes sense that I would have the issue here.

I thought I found it when I discovered the [multiline delete bug]. Unfortunately it was unrelated but thanks to hunting for this bug I found that bug.

I was finally able to duplicate it and it was actually a really simple problem. It was an issue I had noticed before. In my editor, when there is a long line and you hit the backspace to delete stuff, it does some some updates to the screen. This works but there was an issue where the first and only character on a new line wouldn't disappear when you press the backspace. It would sit there. The next backspace would delete both the first and only character on the line and then the last character on the previous line.

The infinite loop triggers when you hit a backspace on the first and only character on a line and it's sitting there. When you press a character to do an insert, this triggers the loop.

Once I was able to consistently trigger the bug, I quickly realized that this was going to be a error in some comparison. Some boundary check was missing something. It was in my [least favourite subroutine].

*********************  S U B R O U T I N E  *********************
*
* UPDATE LINE GIVEN A REAL.LINE.NUMBER
*
* 1. GET ALL LINES THAT BELONG TO REAL.LINE.NUMBER
* 2. DELETE THEM
* 3. CHUNK THE RAW.LINE
* 4. INSERT THEM BACK INTO LINES
*
UPDATE.LINE:NULL
*
   LOCATE(REAL.LINE.NUMBER,LINE.NUMBERS;LINE.START.POS) ELSE LINE.START.POS = CURRENT.LINE
*
   DONE = FALSE
   LINE.POS = LINE.START.POS
*
   LOOP UNTIL DONE DO
      IF LINE.NUMBERS<LINE.POS> = REAL.LINE.NUMBER THEN
         LINES = DELETE(LINES,LINE.POS)
         LINE.NUMBERS = DELETE(LINE.NUMBERS,LINE.POS)
      END ELSE
         DONE = TRUE
      END
   REPEAT
*
   RAW.LINE = RAW.LINES<REAL.LINE.NUMBER>
   RAW.LINE.LEN = LEN(RAW.LINE)
   IF RAW.LINE.LEN = 0 THEN RAW.LINE.LEN = 1
*
   INSERT.LINE.POS = LINE.START.POS
*
   IF RAW.LINE.LEN >= VIEW.WIDTH AND MOD(RAW.LINE.LEN,VIEW.WIDTH) = 0 THEN
      RAW.LINE.LEN = RAW.LINE.LEN + 1
   END
*
   FOR J = 1 TO RAW.LINE.LEN STEP VIEW.WIDTH
      LINES = INSERT(LINES,INSERT.LINE.POS;RAW.LINE[J,VIEW.WIDTH])
      LINE.NUMBERS = INSERT(LINE.NUMBERS,INSERT.LINE.POS;REAL.LINE.NUMBER)
      INSERT.LINE.POS = INSERT.LINE.POS + 1
   NEXT J
*
   RETURN
*

The issue was in:

   IF RAW.LINE.LEN >= VIEW.WIDTH AND MOD(RAW.LINE.LEN,VIEW.WIDTH) = 0 THEN

This IF check didn't have the = originally, it was just >. This meant that when the long line lost the character that pushed it over a single line, my editor screwed up the place that it thought it was at. Changing this to be greater than or equal to made it so that when that boundary was hit, my editor would do the right thing and keep the empty line still available. This way you can still type on that line or hit backspace and go up one line at the correct time. In the old version of the code, the editor moved up one line but didn't do the clearing. This meant when you were typing, it had no idea where things were supposed to go.

Incoming Links

  1. [ Ideas in 2024 ]