¿Cuanto browser entra en 128 líneas de código?
Lo que me gustaba de ese browser de 42 líneas era que no era el ejemplo típico, donde meten una vista de Webkit en una ventana, cargan una página y te tratan de convencer de que son unos bananas. Esa versión son 7 líneas:
import sys from PyQt4 import QtGui,QtCore,QtWebKit app=QtGui.QApplication(sys.argv) wb=QtWebKit.QWebView() wb.setUrl(QtCore.QUrl('http://www.python.org')) wb.show() sys.exit(app.exec_())
O 6 si lo soportara un poco más feo.
¡Pero igual, el de 42 se veía útil!
Esos botones que se ven funcionaban correctamente, habilitando y deshabilitandose en el momento correcto, la entrada de URL cambiaba cuando hacías click en un link, y otras cositas así.
Ahí decidí empezar un pequeño proyecto intermitente de code golf: meter el mejor browser que pueda en 128 líneas de código (sin contar comentarios ni blancos), usando solo PyQt4.
Eso tiene un propósito útil: siempre sospeché que si uno asume PyQt como parte del sistema base, la mayoría de las aplicaciones entrarían en diskettes. Esta entra unas 500 veces en uno de 1.44MB (¡así que podés usar los de 360 de commodore sin duplidisk!)
hasta ahora van 50 líneas, y tiene los siguientes features:
Zoom in (Ctrl++)
Zoom out (Ctrl+-)
Reset Zoom (Ctrl+=)
Buscar (Ctrl+F)
Esconder búsqueda (Esc)
Botones de atrás/adelante y recargar
Entrada de URL que coincide con la página + autocompletado desde la historia + arregla la URL puesta a mano (agrega http://, esas cosas)
Plugins (incluído flash, que hay que bajar aparte ;-)
El título de la ventana muestra el título de la página (sin propaganda del browser)
Barra de progreso para la carga de la página
Barra de estado que muestra el destino de los links cuando pasas el mouse
Toma una URL en la línea de comando (o abre http://python.org
Multiplataforma (funciona donde funciona QtWebKit)
Faltan tabs y soporte de proxy. Espero que lleven unas 40 líneas más, pero creo que ya es el más capaz de todos estos browsers de ejemplo.
El código... no es tan terrible. Uso muchos lambdas, y los argumentos keyword de PyQt para conectar señales, que hacen que algunas líneas sean muy largas, pero no muy difíciles. Se podría achicar bastante todavía!
Aquí está en acción:
Y aquí está el código:
#!/usr/bin/env python "A web browser that will never exceed 128 lines of code. (not counting blanks)" import sys from PyQt4 import QtGui,QtCore,QtWebKit class MainWindow(QtGui.QMainWindow): def __init__(self, url): QtGui.QMainWindow.__init__(self) self.sb=self.statusBar() self.pbar = QtGui.QProgressBar() self.pbar.setMaximumWidth(120) self.wb=QtWebKit.QWebView(loadProgress = self.pbar.setValue, loadFinished = self.pbar.hide, loadStarted = self.pbar.show, titleChanged = self.setWindowTitle) self.setCentralWidget(self.wb) self.tb=self.addToolBar("Main Toolbar") for a in (QtWebKit.QWebPage.Back, QtWebKit.QWebPage.Forward, QtWebKit.QWebPage.Reload): self.tb.addAction(self.wb.pageAction(a)) self.url = QtGui.QLineEdit(returnPressed = lambda:self.wb.setUrl(QtCore.QUrl.fromUserInput(self.url.text()))) self.tb.addWidget(self.url) self.wb.urlChanged.connect(lambda u: self.url.setText(u.toString())) self.wb.urlChanged.connect(lambda: self.url.setCompleter(QtGui.QCompleter(QtCore.QStringList([QtCore.QString(i.url().toString()) for i in self.wb.history().items()]), caseSensitivity = QtCore.Qt.CaseInsensitive))) self.wb.statusBarMessage.connect(self.sb.showMessage) self.wb.page().linkHovered.connect(lambda l: self.sb.showMessage(l, 3000)) self.search = QtGui.QLineEdit(returnPressed = lambda: self.wb.findText(self.search.text())) self.search.hide() self.showSearch = QtGui.QShortcut("Ctrl+F", self, activated = lambda: (self.search.show() , self.search.setFocus())) self.hideSearch = QtGui.QShortcut("Esc", self, activated = lambda: (self.search.hide(), self.wb.setFocus())) self.quit = QtGui.QShortcut("Ctrl+Q", self, activated = self.close) self.zoomIn = QtGui.QShortcut("Ctrl++", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()+.2)) self.zoomOut = QtGui.QShortcut("Ctrl+-", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()-.2)) self.zoomOne = QtGui.QShortcut("Ctrl+=", self, activated = lambda: self.wb.setZoomFactor(1)) self.wb.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) self.sb.addPermanentWidget(self.search) self.sb.addPermanentWidget(self.pbar) self.wb.load(url) if __name__ == "__main__": app=QtGui.QApplication(sys.argv) if len(sys.argv) > 1: url = QtCore.QUrl.fromUserInput(sys.argv[1]) else: url = QtCore.QUrl('http://www.python.org') wb=MainWindow(url) wb.show() sys.exit(app.exec_())
You sir, are a scholar and a gentleman.
Protip: use Github gists if you want any sense of permanence in your pastebin.
Fantastic, cool example. On a side note, do you have any tips for debubbing Javascript with WebKit
Thanks, no I don't :-(
At least not beyond showing the inspector and working from there?
Here is my attempt using the luakit browser framework: https://gist.github.com/855103 I've gone with a modal approach and have managed to squeeze a few more key bindings in.
That's very interesting!
I tried this out, and it actually works just fine. Only thing is the browsing experience is a bit slow. At first I thought it was a Python thing...but since PyQt wraps the native Qt framework which is written in C or C++ (not sure) shouldn't the browsing experience be somewhat fast? I realize that it's not going to probably be as fast as the mainstream browsers which have a ton of optimizations but just wondering if you could shed some light.
In my computer I don't see it as significantly slower than other browsers, but I do have a fast-ish computer.
I believe (but this is really just a vague memory) that the Javascript engine in Qt's webkit is not up to par with other implementations, maybe that is ;art of the problem.
Another thing is that there is no persistent disk cache, so it should feel fairly slower than other browsers for sites you visit frequently.
http://patx.me/fastpatx << fastPATX is a web browser I wrote. Its very good. Not quite as small as yours... but it does and looks a tad better.
This is a very nice minimal browser. I'd like to use it in a Sphinx documentation watcher (which is just a small bit of extra code on top of your work) - as I don't see a license on your code, is it OK for me to use it in this way? I'm planning to release the result under the MIT license. Thanks!
That's just fine for me! The code is under a MIT license. Ping me if you need help with something :-)
Thanks, Roberto. I've posted about my application of your work to easing the development flow when working on Sphinx documentation: http://pymolurus.blogspot.c...
BTW: latest code is at http://devicenzo.googlecode... (since I don't seem to have linked it on this post)