2009-09-28 11:24

Bookrest: it was meant to be a stylesheet editor.

In my original post about it I was referring to Bookrest as a stylesheet editor for rst2pdf, because that's what I wanted, a way to test style changes and see what they did.

Of course, one thing lead to another and it's starting to look more like a word processor than anything else, but ... well, how about a stylesheet editor?

Sure, you can use the "Style" tab, and edit at will, but that's not exactly fun for everyone.

So, let's work on one. Here's the video of the current status:

Of course, this is about 1/20th of the stylesheet editor, but at least the dialog is there, and most of the remaining work is wiring dialogs, which is quick using designer.

2009-09-25 14:35

It shall be called Bookrest, and it has an outline view.

Yes, the program known so far as "my rst2pdf editor/previewer application" is now called Bookrest.

What's a bookrest? It's a thing you put a book on.

Why Bookrest? I hope someday people will have books open in bookrest. Plus, it ends with "rest", which is the preferred abbreviation for reStructured Text.

And what's the outline view? It's a clickable tree with the outline of the document, of course.

As usual, let's go to the video:

The background rendering was done using python's awesome multiprocessing module.

2009-09-24 08:44

This is why I like having a blog, also, I am **old**.

These are the visitors of this site in the last 10 minutes or so:

visitors1

Let's see: Belgium, the Netherlands, USA, Turkey, Brazil, Thailand, Austria.

I know most people are not impressed by this kind of thing anymore, but I am old enough to have had to buy ftp sites on CD (Remember the Infomagic collection? I had like 10 of those).

In 1994 I was one of the first ten or so to have a mail account in my university ( in fact, since I had root, I could have been the first one ;-) and the web was a wasteland ... you could not even find porn!

So, knowing that my blog has some sort of a following, even if it's a handful of people and that it's close to being 10 freaking years old, and it comes from a time when they were not even called blogs... is making me feel strange today.

This blog is one of the specific things I have done longer.

  • I have been a husband for 4 years.
  • I have been a dad for 3.
  • I was active in KDE for 4.
  • My company is about 2 years old

Of course there are obvious and/or fuzzy things I have done much longer:

  • I have been involved in free software 15 years.
  • I have worked with computers 18 years
  • I have programmed 30 years (started on paper, kids!)
  • I have inhaled and exhaled regularly for 38 years

But a specific thing, I can point at and say "that's mine, I did it"? This blog is proobably my longest-lived project.

I don't see myself not having it. I see myself not posting for a month or so, I do that every now and then, but not having a blog? I can't see it.

I have added things though, so it's not a static deadend thing.

I am loving screencasts (thanks to qt-recordmydesktop and youtube). I enjoy twitter and identi.ca very much.

So, this rambling post is just my unfocused way of saying that what I love about having a blog is that someone reads it. So, let's do something worth blogging about ;-)

2009-09-23 18:43

rst2pdf previewer: a new feature

I am in the middle of that honeymoon you get starting a new app. Every new feature seems tobe just 50 lines of code away, there is no legacy code (in fact, you are creating that legacy code), and you learn new tricks all the time.

So, I did a new feature today.

A day or two ago, my editor started showing a yellow bar highlighting the current line.

But then I though... wouldn't it be more useful to have a similar bar following you in the PDF?

That way, when you are on a given line, you can immediately see where you are in the output. Neat, right?

Here is a video showing it:

Sadly it's not perfect, and probably never will be because of docutils limitations, but it's pretty nice!

2009-09-22 13:33

More fun with rst2pdf, poppler and PyQt

First: I really, really need a name for this thing. I am tired of saying "my rst2pdf previewer/editor app".

Now, here's a video of how it looks nowadays after all the yak shaving (sorry about my english, I write lots of it, but never speak it):

As you can see, the basic app is fairly complete, even if it lacks all the amenities that would make someone use it (like, search? save? ;-).

It has one big problem, though: I can't publish it yet.

Why? Because I need to use poppler from PyQt, and the code I found to do it has no license (see the code).

I am trying to contact the author (Rajeev J Sebastian), so there should be news soon!

As soon as that's cleared, the PDF widget is a whole post by itself, because it's pretty neat, if I may say so myself.

UPDATE: the binding is now under MIT license, thanks to Rajeev Sebastian!

2009-09-22 04:01

Yak Shavings for September 22, 2009

yak shaving
(idiomatic) Any apparently useless activity which, by allowing you to overcome intermediate difficulties, allows you to solve a larger problem.

This yak is starting to look better.

For my second pile of yak shavings: turning QPlainTextEdit into a decent editing widget for programmers.

As work advanced in my rst2pdf editor (BTW: need a name!), it became obvious that the piece of the UI the user will use most is just a couple of plain text editors.

Qt comes with a widget for that, of course, called QPlainTextEdit. However, it's a very, very bad widget for programmers.

Here's the least I wanted:

  1. Syntax highlighting for two languages: restructured text and javascript. This yak is already shaved.
  2. Line numbers
  3. Current line highlight
  4. Error highlight when it makes sense (like, in the stylesheet)

One way to achieve this would be to dump QPlainTextEdit and use QSciScintilla which is the basis for the code editor in eric and (another version) in scite.

However, I experienced a bad bug in QSciScintilla, where I can't type accented characters! Without that, (decent) spanish is impossible, and the bug seems to be at least two years old, so... no go.

So, did I get those features? I say yes!

Here is the video (yes, I am getting addicted to making these, since qt-recordmydesktop makes them so easy ;-):

The basis for this is the Code Editor example that comes with Qt itself, plus a bit of my own handywork.

First, I ported Code Editor from C++ to Python, which was very simple and took a few minutes. That takes care of points 2 and 3.

Then, the syntax highlight was plugged in, which was point 1.

Then, how about realtime javascript validation? Easy using simplejson! Just make sure to run this whenever you want validation (I do it on every keystroke).

Replace self.ui.style.toPlainText with whatever your widget is called, of course:

def validateStyle(self):
    style=unicode(self.ui.style.toPlainText())
    #no point in validating an empty string
    if not style.strip():
        return
    pos=None
    try:
        json.loads(style)
    except ValueError, e:
        s=str(e)
        print s
        if s == 'No JSON object could be decoded':
            pos=0
        elif s.startswith('Expecting '):
            pos=int(s.split(' ')[-1][:-1])
        else:
            print 'UNKNOWN ERROR'

    # This makes a red bar appear in the line
    # containing position pos
    self.ui.style.highlightError(pos)

highlightError(pos) simply stores pos in the Code Editor, which will draw a red bar in that line, the same way it highlights the current line.

And that's it. Here is the code for codeeditor.py

2009-09-21 10:17

Yak Shavings for september 21, 2009

yak shaving
(idiomatic) Any apparently useless activity which, by allowing you to overcome intermediate difficulties, allows you to solve a larger problem.

And boy, are my yaks hairy!

I started trying to do a rst2pdf stylesheet editor (see here).

One thing lead to another, and I have now at least three interesting mini-projects because of it.

Here's today's: abuse pygments to use it as a generic syntax highlighter in a Qt interface.

Why pygments? Because it's the only reStructured Text highlighter I found. That's probably because reSt is pretty damn hard to highlight!

AFAIK, this is the first time anyone has managed to use pygments for this, in an editable window. And there are good reasons for that:

  • It's pure python, so maybe you expect it to be too slow
  • It doesn't do partial or progressive lexing, so you need to lex the whole thing (again, maybe you expect it to be too slow)
  • It has a file-oriented API, it generates a file with all the formatting in it, and for this kind of thing we need to access stuff in the middle of the data.

So, of course, it turns out it works pretty well, as you can see in this video:

Lesson learned: computers are fast nowadays.

Here's the code for highlighter.py with extensive comments.

You can just run it and get the same demo you saw on the video (minus the typing ;-)

2009-09-19 14:49

Having a little fun with poppler, PyQt and rst2pdf

Inspired by a post by André Roberge I wanted to see if rst2pdf was too slow to be used for real-time previews in a restructured text editor.

It would also be very useful, for example, as a way to test stylesheet changes, making rst2pdf much more useful in general.

And after a couple of hours of gentle hacking, you know... it doesn't suck at all. I implemented the (still very primitive) PDF viewer using a python/poppler/Qt binding I found via google, the UI is PyQt.

Here's the video:

A note: the video was recorded using qt-recordmydesktop and that program is awesome. It was trivial to do.

I expect this will not be good enough when long documents are processed, but the rst2pdf manual (about 25 pages) renders in 5 seconds.

2009-09-17 16:59

An innocent question...

There is a very funny thread currently in the PyAr (Python Argentina) mailing list.

It all started when "Galileo Galilei" asked about how to do a very simple thing. He presented this code:

age = int(raw_input('How old are you?'))
if age<18:
    print 'You are underage'
else:
    print 'You are a grownup'

Ok, the original was... not quite as polite, but the code is the same. So far, nothing strange. But then he asked this:

How can I make it so that if the user enters something that is not a number, it does something like this:

print 'I have no supercow powers'

or maybe

print 'Typing error'

You can probably imagine that asking this kind of thing should produce maybe two answers. Right?

That is indeed the case, and you can see that in the answer by Facundo Batista or Ezequiel.

Except... what if we wanted it to keep asking in case the user entered not-a-number?

Then, my friends... it's about taste, and it's all Juan Pedro Fisanotti's fault.

Here's my take:

while True:
    edad=raw_input('¿Cuantos años tenes?')
    if edad.isdigit():
        break
    print 'No ingresaste un numero!'

Yes, I admit, a bit old fashioned. And there was a cry of "no, break sucks, it's not right", which leads to this by Manuel Aráoz

age = raw_input('Your age?')
while not age.isdigit():
    print "That's not a number!"
    age = raw_input('Your age?')

Which caused cries of "Having raw_input twice is ugly!", which leads to (again by Manuel Aráoz):

get_age = lambda: raw_input('Your age?')
age = get_age()
while not age.isdigit():
    print 'Not a number!'
    age = get_age()

Here Patricio Molina digs up PEP 315.

And then Alejandro Santos says something like "This is easier in C, because we can assign a value to age in the while's condition". Please remember this.

Now Pablo Zilliani gives his version, which is, I must say, perfect in some ways:

age = reset = msg = 'Age?: '
while not age.isdigit():
    age = raw_input(msg)
    msg = "%r is not a number!, %s" % (age, reset)

print age

Here Gabriel Genellina decides to defend break by hitting everyone in the head using Knuth which should have a much stronger effect than Hitler.

And now, we start veering into weird waters. Here is what news proposes, which I must say, I admire... from a respectful distance.

First, the relevant code:

edad = "0" # Entra igual la primera vez

while firstTrue (not edad.isdigit()):
    edad = raw_input ("¿Cuantos años tenes? ")
    if not edad.isdigit():
        print "No ingresaste un nro!"

But what, exactly, is firstTrue?

import inspect

def firstTrue(cond):
    """ devuelve True siempre la primera vez que se la ejecuta,
    las veces subsiguientes evalua la condicion """
    stack = inspect.stack()[1] # El stack del programa llamador
    line = stack[2] # Nro de linea desde la que llame a firstTrue
    del stack

    if not "line" in firstTrue.__dict__:
        # Primera vez que llamo a la funcion
        firstTrue.line = line
        return True
    elif firstTrue.line != line:
        # Llame a la funcion desde otro punto del programa
        firstTrue.line = line
    return True

    return cond

Then, I bring up generators, which leads to Claudio Freire's, which almost works, too:

age = ''
def invalidAge():
    yield True
    while not age.isdigit():
        print "Not a number"
        yield True
    yield False

for i in invalidAge():
    age = raw_input("Age please: ")

print age

And then Fabian Gallina is the second one to bring up C's assignments inside conditions.

You know, I can't accept that. I will not accept C being easier for this.

So, with a little help from the python cookbook...

age=[1]

while not age |asig| raw_input('Age? '):
    print 'Not a number!'

print u'You are %s years old'%age[0]

You may ask, what's |asig|? Glad you asked!

class Infix:
    def __init__(self, function):
        self.function = function
    def __ror__(self, other):
        return Infix(lambda x, self=self, other=other: self.function(other, x))
    def __or__(self, other):
        return self.function(other)
    def __rlshift__(self, other):
        return Infix(lambda x, self=self, other=other: self.function(other, x))
    def __rshift__(self, other):
        return self.function(other)
    def __call__(self, value1, value2):
        return self.function(value1, value2)

def opasigna (x,y):
    x[0]=y
    return y.isdigit()

asig=Infix(opasigna)

And then, Pablo posts this gem:

import inspect

def assign(var, value):
    stack = inspect.stack()[1][0]
    stack.f_locals [var] = value
    del stack
    return value

while not assign("age", raw_input('Age? ')).isdigit():
    print u'Not a number!'

print u'You are %s years old' % age

Which is, IMVHO, about as far from trivial as you can get here. Of course the thread is not dead yet ;-)

2009-09-16 22:51

A few more pics from Pycon Argentina 2009

I really, really hate to see myself on pictures, but my wife asks for evidence that I spent two days locked up with 400 nerds, so here they are:

These are from the PyQt+WxPython+PyGtk panel (pyqt.pdf):

Charla PyQt+Wx+PyGtk 1Charla PyQt+Wx+PyGtk 2Charla PyQt+Wx+PyGtk 3

And this one is from the failed lightning talk about Hettinger's tiny "spreadsheet" (hoja.pdf):

Charla Relampago Hoja de Calculo

All pictures by Ariel Kanterewicz (Kant) licenced CC-by.

Contents © 2000-2019 Roberto Alsina