Bluebird’s blog
Black Green Blue Red Gold
RSS
  • Home PageHome
  • About Me

Rendering engine for Vy [part 2]

, vi clones Add comments

Vi and a few old-style editors have the characteristics that they wrap long lines, so that all parts of the lines are visible on screen. This is different from most modern or IDE editors, that let part of the line be hidden, and you have to scroll to the right to see the hidden part. For programming, I believe it is a saner choice to see the whole line on screen. When reading code, you want to grab the content of the line.

So, I am working on the line wrapping code of Vy. There is no syntax highlighting and I am using a fixed pitch font. So, the situation is quite simple, I need to break lines so that they fit on screen. I know the number of characters that fit on a screen line, I know how many characters a line have. Initially, I thought it would be quite simple. Actually, the first implementation is super simple. But then comes the small details that make it tricky.

Insert Cursor

In vi, in insert mode, the cursor can be on a non-existing character (when you press A for example). So, I have to look where the cursor is and add an extra character to some lines in a few specific situations. No big deal.

Tabs

Tabs depending on a config, can be 4 characters or 8 characters wide. But more importantly, a char is a single character that is rendered to multiple characters. I can have a line composed of 4 characters, which renders to 4×8 = 32 characters on screen. This makes the line-breaking really more complicated. It means that I can not compute the length of the screen line based on its character count. This has a big impact on the performance of the line breaking algorithm. With one character in the buffer equal one character on screen, rendering code is simple. For example, for a screen width of 80 characters, and a line of 100 characters, I can split the line at 80 and have a second line of 20 characters. But not with variable width characters such as tab.

One suboptimal algorithm for variable width characters is to start from an empty line, then add characters one by one, until the screen width of the line exceeds the width of the screen. However, this is really unefficient. For a reasonable editing window of 80 columns x 50 lines, filled by a lot of characters, it could mean up to 400 operations to display the lines on screen. That’s too much, especially if you consider that there are other possibilities.

The algorithm that I consider is to use a dichotomy: split the line at a good estimate of the length, check the number of tabs, calculate the width of the rendered split line, check if the line fits exactly in the screen and if not, look for another position. A dichotomy will work in every case, but I believe that for regular case of screen, where lines are mostly between 80 and 160 character wide, a little optimisation in finding the next point can diminish the number of operations to break the line correctly. In any case, pure dichotomy will find the length of the screen line in log(number of line characters) iterations, where naive algorithm would need (number of screen characters) iterations.

Cursor moving

Something is that I really underestimated is the work necessary to handle cursor moving. Cursor moves all the time, so this algorithm is called frequently. And cursor moving is trickier than line-breaking, because when the cursor moves, the screen window needs to scroll to follow the cursor. But it needs to scroll on the right screen line, which can be tricky to compute. For example, if I have a screen size of 10 columns x 5 lines (that’s small but who knows ?) and I display a text with lines of 35 characters each, moving the cursor around triggers many recalculation of which portions of which lines to display. Calculating that is not really difficult. What is difficult is calculating it in an efficient manner, so that there is a minimum of recalculations.

Special Case

Something that looks trivial but creates complication : how to represent an emtpy file ? And an empty line of a file ? Those are special cases which need special handling. My buffer is implemented as a list of line, each line containing the buffer line content excluding the \n . Now, an empty buffer is an empty list, or a list with an empty line ? When the cursor is on an empty line, it is actually on a character that does not exist in the buffer. Small details like this create lot of special cases.

Conclusion

We will see how I cope with all this. I am happy that I will have tests to help me, and python to code quickly. It will sure make my life easier.


October 9th, 2007  

Leave a Reply

  • RSS Thomas's blog

    • Playing with clang and Qt January 10, 2010
    • How to use flex and bison with qmake (my own way) November 22, 2009
    • Wonders from a KDE fan and developer about some KDE design choices November 10, 2009
    • Installing an avr cross compiler in gentoo July 27, 2009
    • tags displayed in hg activity extension June 15, 2009
    • feedback about converting eigen2 to mercurial May 18, 2009
    • mercurial and ipv6 May 7, 2009
    • how to handle translations for an application that is both qt-only and KDE ? May 2, 2009
    • Fixing qmake missing rule for *.ts -> *.qm March 10, 2009
    • updating to KDE 4.2.1 : delete your plasma files (again) March 6, 2009
  • RSS Freehackers labs

    • PyTiCroque - PyTiCroque 0.5 est sorti.
    • Mercurial activity extension - Release 1.2
    • Symia - 0.2 released with misc fixes
    • Emerge activity - Release 1.0 for EmergeActivity
    • PyTiCroque - PyTiCroque 0.43 est sorti.
    • Symia - Announcing symia 0.1
    • Zeta Platform - Pre-compiled kernel for Zeta
    • Zeta Platform - Zeta platform 0.7 released
    • Convex Processing - 1.0 released
    • Opale - Final release for Opale 1.0
  • Meta

    • Log in
    • Entries RSS
    • Comments RSS
    • WordPress.org
Categories
  • python
  • vi clones
About Me

My name is Philippe, I am doing free software for fun, and propritary software for money and a little bit of fun as well.

Copyright © 2010 Bluebird’s blog All Rights Reserved XHTML CSS THEME by I SOFTWARE REVIEWS