Last active
September 27, 2015 02:18
-
-
Save livibetter/1196740 to your computer and use it in GitHub Desktop.
del-patches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 77e63fcbcd035d4ac321a1914100170172e734bb Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Thu, 8 Sep 2011 18:21:59 +0800 | |
Subject: [PATCH] Add new pos option below_curosr (bcur) | |
--- | |
README.markdown | 3 ++- | |
twmnd/twmnd.pro | 2 +- | |
twmnd/widget.cpp | 25 ++++++++++++++++++++++++- | |
twmnd/widget.h | 1 + | |
4 files changed, 28 insertions(+), 3 deletions(-) | |
diff --git a/README.markdown b/README.markdown | |
index 57a246b..aa45f95 100644 | |
--- a/README.markdown | |
+++ b/README.markdown | |
@@ -44,7 +44,8 @@ height=18 ; In pixel. | |
; Position of the notification slide. | |
position=top_right ; Accepted values: top_right (tr), top_left (tl), bottom_right (br), | |
- ; bottom_left (bl), top_center (tc), bottom_center (bc), center (c). | |
+ ; bottom_left (bl), top_center (tc), bottom_center (bc), center (c), | |
+ ; below_cursor (bcur). | |
; The animation to use when the slide appear | |
in_animation=38 ; see http://doc.qt.nokia.com/latest/qeasingcurve.html#Type-enum for types | |
diff --git a/twmnd/twmnd.pro b/twmnd/twmnd.pro | |
index 4766f53..dc77803 100644 | |
--- a/twmnd/twmnd.pro | |
+++ b/twmnd/twmnd.pro | |
@@ -10,7 +10,7 @@ TARGET = twmnd | |
TEMPLATE = app | |
CONFIG += release | |
DESTDIR = ../bin/ | |
-LIBS += `pkg-config --libs-only-l dbus-1` | |
+LIBS += `pkg-config --libs-only-l dbus-1` -lXfixes | |
QMAKE_CXXFLAGS += `pkg-config --cflags-only-I dbus-1` | |
target.path+=/usr/local/bin | |
diff --git a/twmnd/widget.cpp b/twmnd/widget.cpp | |
index 4448066..6896c17 100644 | |
--- a/twmnd/widget.cpp | |
+++ b/twmnd/widget.cpp | |
@@ -17,6 +17,9 @@ | |
#include <QShortcut> | |
#include <QIcon> | |
#include <QWheelEvent> | |
+#include <QCursor> | |
+#include <QX11Info> | |
+#include <X11/extensions/Xfixes.h> | |
#include "settings.h" | |
#include "shortcutgrabber.h" | |
@@ -272,6 +275,18 @@ void Widget::updateCenterAnimation(QVariant value) | |
show(); | |
} | |
+void Widget::updateBelowCursorAnimation(QVariant value) | |
+{ | |
+ const int finalWidth = qobject_cast<QPropertyAnimation*>(m_animation.animationAt(0))->endValue().toInt(); | |
+ const int finalHeight = m_animation.direction() == QAbstractAnimation::Forward ? m_messageQueue.front().data["size"]->toInt() : height(); | |
+ const int h = value.toInt() * finalHeight / finalWidth; | |
+ const QPoint p = QCursor::pos(); | |
+ const XFixesCursorImage *xcim = XFixesGetCursorImage(QX11Info::display()); | |
+ setGeometry(p.x() - finalWidth / 2, p.y() + xcim->height + 10, value.toInt(), h); | |
+ layout()->setSpacing(0); | |
+ show(); | |
+} | |
+ | |
void Widget::startBounce() | |
{ | |
QPropertyAnimation* anim = new QPropertyAnimation(this); | |
@@ -282,7 +297,8 @@ void Widget::startBounce() | |
QString position = m_messageQueue.front().data["pos"]->toString(); | |
if (position == "top_center" || position == "tc" || | |
position == "bottom_center" || position == "bc" || | |
- position == "center" || position == "c") | |
+ position == "center" || position == "c" || | |
+ position == "below_cursor" || position == "bcur") | |
anim->setEndValue(height()); | |
else | |
anim->setEndValue(40); | |
@@ -326,6 +342,8 @@ void Widget::updateBounceAnimation(QVariant value) | |
move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt()); | |
else if (position == "center" || position == "c") | |
move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt()); | |
+ else if (position == "below_cursor" || position == "bcur") | |
+ move(tmpBouncePos.x(), tmpBouncePos.y() - value.toInt()); | |
layout()->setSpacing(0); | |
show(); | |
} | |
@@ -439,6 +457,9 @@ void Widget::connectForPosition(QString position) | |
else if (position == "center" || position == "c") { | |
connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateCenterAnimation(QVariant))); | |
} | |
+ else if (position == "below_cursor" || position == "bcur") { | |
+ connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateBelowCursorAnimation(QVariant))); | |
+ } | |
else { | |
// top_right seems to be the classic case so fallback to it. | |
connect(anim, SIGNAL(valueChanged(QVariant)), this, SLOT(updateTopRightAnimation(QVariant))); | |
@@ -626,6 +647,8 @@ void Widget::updateFinalWidth() | |
updateBottomCenterAnimation(width); | |
else if (position == "center" || position == "c") | |
updateCenterAnimation(width); | |
+ else if (position == "below_cursor" || position == "bcur") | |
+ updateBelowCursorAnimation(width); | |
} | |
void Widget::onPrevious() | |
diff --git a/twmnd/widget.h b/twmnd/widget.h | |
index 2af2430..8a89869 100644 | |
--- a/twmnd/widget.h | |
+++ b/twmnd/widget.h | |
@@ -30,6 +30,7 @@ private slots: | |
void updateTopCenterAnimation(QVariant value); | |
void updateBottomCenterAnimation(QVariant value); | |
void updateCenterAnimation(QVariant value); | |
+ void updateBelowCursorAnimation(QVariant value); | |
void startBounce(); | |
void unbounce(); | |
void doneBounce(); | |
-- | |
1.7.3.4 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- video_device.c.original 2009-02-02 16:34:08.000000000 +0800 | |
+++ video_device.c 2009-02-02 16:32:10.000000000 +0800 | |
@@ -26,7 +26,7 @@ | |
#include <media/v4l2-ioctl.h> | |
#endif | |
-/*#define DEBUG*/ | |
+//#define DEBUG | |
#define KERNEL_PREFIX "AVLD device: " /* Prefix of each kernel message */ | |
#define VID_DUMMY_DEVICE 0 /* The type of device we create */ | |
@@ -446,14 +446,51 @@ | |
printk(KERNEL_PREFIX "entering v4l_read()\n"); | |
#endif | |
+ int waiting_time; | |
+ struct timeval current_time; | |
// if input size superior to the buffered image size | |
if (count > BUFFER_SIZE) { | |
printk(KERNEL_PREFIX "ERROR : you are attempting to read too much data : %d/%lu\n",count,BUFFER_SIZE); | |
return -EINVAL; | |
} | |
- memcpy(buf,image,count*sizeof(char)); | |
- | |
+ copy_to_user(buf,image,count*sizeof(char)); | |
+ | |
+ // Wait to simulate FPS if necessary | |
+ #ifdef DEBUG | |
+ printk(KERNEL_PREFIX "waiting v4l_read() : %d - %ld\n",count,BUFFER_SIZE); | |
+ #endif | |
+ if ( fps > 0 ) { | |
+ do_gettimeofday(¤t_time); | |
+ //printk(KERNEL_PREFIX "t2=%d.%d - t1=%d.%d\n",current_time.tv_sec,current_time.tv_usec,timer.tv_sec,timer.tv_usec); | |
+ | |
+ // Compute waiting_time | |
+ waiting_time = HZ/fps - HZ*( (current_time.tv_sec-timer.tv_sec)*USEC_PER_SEC + (current_time.tv_usec-timer.tv_usec) )/USEC_PER_SEC; | |
+ //waiting_time = MSEC_PER_SEC/fps - ( (current_time.tv_sec-timer.tv_sec)*MSEC_PER_SEC + (current_time.tv_usec-timer.tv_usec)/USEC_PER_MSEC ); | |
+ | |
+ // waits | |
+ if (waiting_time > 0) { | |
+ // solution 1 | |
+ interruptible_sleep_on_timeout (&wait,waiting_time); | |
+ | |
+ // solution 2 | |
+ //set_current_state(TASK_INTERRUPTIBLE); | |
+ //schedule_timeout(waiting_time); | |
+ | |
+ // solution 3 | |
+ //msleep_interruptible(waiting_time); | |
+ } | |
+ | |
+ do_gettimeofday(&timer); | |
+ } | |
+ // Wait reader before continue | |
+ else if ( fps < 0 ) { | |
+ #ifdef DEBUG | |
+ printk (KERN_INFO "fps value : %d\n",fps); | |
+ #endif | |
+ mutex_lock_interruptible(&lock); | |
+ } | |
+ | |
#ifdef DEBUG | |
printk(KERNEL_PREFIX "leaving v4l_read() : %d - %ld\n",count,BUFFER_SIZE); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: src/google.py | |
=================================================================== | |
--- src/google.py (revision 621) | |
+++ src/google.py (working copy) | |
@@ -903,6 +903,8 @@ | |
help='Label the machine being used.') | |
parser.add_option('-n', '--title', dest='title', | |
help='Title of the item') | |
+ parser.add_option('--new-title', dest='new_title', | |
+ help='Blogger only - new title to update a post.') | |
parser.add_option('--no-convert', dest='convert', | |
action='store_false', default=True, | |
help='Google Apps Premier only - do not convert the file' + | |
Index: src/googlecl/blogger/__init__.py | |
=================================================================== | |
--- src/googlecl/blogger/__init__.py (revision 621) | |
+++ src/googlecl/blogger/__init__.py (working copy) | |
@@ -70,9 +70,8 @@ | |
entry_list = client.UploadPosts(content_list, | |
blog_title=options.blog, | |
post_title=options.title, | |
- is_draft=_map_access_string(options.access)) | |
- if options.tags: | |
- client.LabelPosts(entry_list, options.tags) | |
+ is_draft=_map_access_string(options.access), | |
+ tags=options.tags) | |
def _run_delete(client, options, args): | |
@@ -82,6 +81,14 @@ | |
client.DeleteEntryList(post_entries, 'post', options.prompt) | |
+def _run_update(client, options, args): | |
+ content = ' '.join(options.src + args) | |
+ entry = client.UpdatePost(blog_title=options.blog, post_title=options.title, | |
+ post_new_title=options.new_title, content=content, | |
+ is_draft=_map_access_string(options.access), | |
+ tags=options.tags) | |
+ | |
+ | |
def _run_list(client, options, args): | |
titles_list = googlecl.build_titles_list(options.title, args) | |
entries = client.GetPosts(options.blog, titles_list, | |
@@ -104,6 +111,10 @@ | |
'post': googlecl.base.Task('Post content.', callback=_run_post, | |
required=['src', 'blog'], | |
optional=['title', 'tags', 'access']), | |
+ 'update': googlecl.base.Task('Update a post', callback=_run_update, | |
+ required=['blog', 'title'], | |
+ optional=['src', 'new-title', 'tags', | |
+ 'access']), | |
'list': googlecl.base.Task('List posts in a blog', | |
callback=_run_list, | |
required=['fields', 'blog', 'delimiter'], | |
Index: src/googlecl/blogger/service.py | |
=================================================================== | |
--- src/googlecl/blogger/service.py (revision 621) | |
+++ src/googlecl/blogger/service.py (working copy) | |
@@ -25,6 +25,7 @@ | |
import gdata.blogger.service | |
import logging | |
import os | |
+import sys | |
from googlecl import safe_encode | |
import googlecl.base | |
import googlecl.service | |
@@ -48,7 +49,8 @@ | |
gdata.blogger.service.BloggerService.__init__(self, account_type='GOOGLE') | |
googlecl.service.BaseServiceCL.__init__(self, SECTION_HEADER, config) | |
- def _upload_content(self, post_title, content, blog_id=None, is_draft=False): | |
+ def _upload_content(self, post_title, content, blog_id=None, is_draft=False, | |
+ tags=None): | |
"""Uploads content. | |
Keyword arguments: | |
@@ -57,6 +59,7 @@ | |
content: String to get posted. This may be contents from a file, but NOT | |
the path itself! | |
is_draft: If this content is a draft post or not. (Default False) | |
+ tags: String representation of tags in a comma separated list. | |
Returns: | |
Entry of post. (Returns same results as self.AddPost()) | |
@@ -68,6 +71,8 @@ | |
control = atom.Control() | |
control.draft = atom.Draft(text='yes') | |
entry.control = control | |
+ if tags: | |
+ entry = self.LabelPosts([entry], tags, do_update=False)[0] | |
return self.AddPost(entry, blog_id) | |
def _get_blog_id(self, blog_title=None, user_id='default'): | |
@@ -120,7 +125,7 @@ | |
GetPosts = get_posts | |
- def label_posts(self, post_entries, tags): | |
+ def label_posts(self, post_entries, tags, do_update=True): | |
"""Add or remove labels on a list of posts. | |
Keyword arguments: | |
@@ -148,15 +153,73 @@ | |
if add_set: | |
new_tags = [atom.Category(term=tag, scheme=scheme) for tag in add_set] | |
post.category.extend(new_tags) | |
- updated_post = self.UpdatePost(post) | |
- if updated_post: | |
- successes.append(updated_post) | |
+ if do_update: | |
+ updated_post = self.UpdatePost(post) | |
+ if updated_post: | |
+ successes.append(updated_post) | |
+ else: | |
+ successes.append(post) | |
return successes | |
LabelPosts = label_posts | |
+ def update_post(self, entry=None, blog_title=None, post_title=None, | |
+ post_new_title=None, content=None, is_draft=None, tags=None): | |
+ """Update a post. | |
+ | |
+ Keyword arguments: | |
+ entry: The post to be updated. If it's None, then use post_title to | |
+ search. | |
+ blog_title: Name of the blog to update. | |
+ post_title: Name of the post to search. | |
+ post_new_title: New title of the post. Set None if do not want to update. | |
+ content: String to update old content. This may be contents from a | |
+ file, but NOT the path itself! Set None if do not want to | |
+ update. | |
+ is_draft: Draft status to update the entry. Set None if do not want to | |
+ update. | |
+ tags: tags to update the entry using label_posts method. Set None if do | |
+ not want to update. | |
+ | |
+ Returns: | |
+ Updated post entry. | |
+ """ | |
+ max_size = 500000 | |
+ if not entry: | |
+ posts = self.GetPosts(blog_title=blog_title, post_titles=post_title) | |
+ entry = self.GetSingleEntry(posts) | |
+ if not entry: | |
+ LOG.error('Failed to find the post.') | |
+ return | |
+ | |
+ if post_new_title is not None: | |
+ entry.title = atom.Title(title_type='xhtml', text=post_new_title) | |
+ | |
+ if content: | |
+ if os.path.exists(content): | |
+ with open(content, 'r') as content_file: | |
+ content = content_file.read(max_size) | |
+ if content_file.read(1): | |
+ LOG.warning('Only read first ' + str(max_size) + | |
+ ' bytes of file ' + content_string) | |
+ entry.content = atom.Content(content_type='html', text=content) | |
+ | |
+ control = atom.Control() | |
+ control.draft = atom.Draft(text=['no', 'yes'][is_draft or 0]) | |
+ entry.control = control | |
+ try: | |
+ if tags: | |
+ entry = self.LabelPosts([entry], tags, do_update=False)[0] | |
+ self.Put(entry, entry.GetEditLink().href) | |
+ LOG.info('Post updated: %s', entry.GetHtmlLink().href) | |
+ except self.request_error, err: | |
+ LOG.error(safe_encode('Failed to update: ' + unicode(err))) | |
+ return entry | |
+ | |
+ UpdatePost = update_post | |
+ | |
def upload_posts(self, content_list, blog_title=None, post_title=None, | |
- is_draft=False): | |
+ is_draft=False, tags=None): | |
"""Uploads posts. | |
Args: | |
@@ -165,6 +228,7 @@ | |
post_title: Name to give the post(s). | |
is_draft: Set True to upload as private draft(s), False to make upload(s) | |
public. | |
+ tags: String representation of tags in a comma separated list. | |
Returns: | |
List of entries of successful posts. | |
@@ -191,7 +255,8 @@ | |
entry = self._upload_content(post_title or title, | |
content, | |
blog_id=blog_id, | |
- is_draft=is_draft) | |
+ is_draft=is_draft, | |
+ tags=tags) | |
except self.request_error, err: | |
LOG.error(safe_encode('Failed to post: ' + unicode(err))) | |
else: | |
Index: test_suite/test_blogger.sh | |
=================================================================== | |
--- test_suite/test_blogger.sh (revision 621) | |
+++ test_suite/test_blogger.sh (working copy) | |
@@ -32,6 +32,7 @@ | |
post_title="example post title" | |
+post_new_title="example new post title" | |
post_body="example post body" | |
post_tags="a,b" | |
@@ -45,7 +46,7 @@ | |
function check_posts_number { | |
should_be \ | |
- "python google.py blogger list --title \"$post_title\" --blog $blogname -u $auth_username" \ | |
+ "python google.py blogger list --title \"${2:-$post_title}\" --blog $blogname -u $auth_username" \ | |
$1 \ | |
0 \ | |
"blog post" \ | |
@@ -70,21 +71,27 @@ | |
if [[ $auth_executed == "0" ]]; then | |
auth_executed=1 | |
- python google.py blogger list --blog $blogname --force-auth -u $auth_username | |
+ python google.py blogger list --blog "$blogname" --force-auth -u $auth_username | |
fi | |
check_posts_number 0 | |
# Creating new blog post. | |
- python google.py blogger post --title "$post_title" --blog $blogname -u $auth_username "adlasdasd" | |
+ python google.py blogger post --title "$post_title" --blog "$blogname" -u $auth_username "adlasdasd" | |
check_posts_number 1 | |
# Tagging the blog post, unfortunately there is no way to check if it worked. | |
- python google.py blogger tag --blog $blogname --title "$post_title" -u $auth_username --tags "$post_tags" | |
+ python google.py blogger tag --blog "$blogname" --title "$post_title" -u $auth_username --tags "$post_tags" | |
+ # Updating the blog post's title, unfortunately there is no way to check if content is updated. | |
+ python google.py blogger update --blog "$blogname" --title "$post_title" -u $auth_username --new_title "$post_new_title" "blah new content" | |
+ | |
+ # check new updated post title | |
+ check_posts_number 1 "$post_new_title" | |
+ | |
# Deleting the blog post. | |
- python google.py blogger delete --blog $blogname --title "$post_title" -u $auth_username --yes | |
+ python google.py blogger delete --blog "$blogname" --title "$post_new_title" -u $auth_username --yes | |
check_posts_number 0 | |
Index: man/google.1 | |
=================================================================== | |
--- man/google.1 (revision 621) | |
+++ man/google.1 (working copy) | |
@@ -59,7 +59,7 @@ | |
.IP | |
Requires: (title OR query) Optional: photo | |
.PP | |
-Available tasks for service blogger: 'post', 'tag', 'list', 'delete' | |
+Available tasks for service blogger: 'post', 'tag', 'list', 'update', 'delete' | |
.IP | |
post: Post content. | |
.IP | |
@@ -73,6 +73,10 @@ | |
.IP | |
Requires: fields AND blog AND delimiter Optional: title, owner | |
.IP | |
+update: Update a post. | |
+.IP | |
+Requires: blog AND title Optional: src, new\-title, tags, access | |
+.IP | |
delete: Delete a post. | |
.IP | |
Requires: blog AND title |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From a69b0fb091e1000c2e35fb72f344914941177f40 Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Sat, 23 Jul 2011 15:33:51 +0800 | |
Subject: [PATCH 1/3] Make footnote to display other return symbol | |
<https://github.com/trentm/python-markdown2/issues/37> | |
--- | |
lib/markdown2.py | 5 ++++- | |
test/tm-cases/footnotes_return_symbol.html | 27 +++++++++++++++++++++++++++ | |
test/tm-cases/footnotes_return_symbol.opts | 1 + | |
test/tm-cases/footnotes_return_symbol.tags | 1 + | |
test/tm-cases/footnotes_return_symbol.text | 18 ++++++++++++++++++ | |
5 files changed, 51 insertions(+), 1 deletions(-) | |
create mode 100644 test/tm-cases/footnotes_return_symbol.html | |
create mode 100644 test/tm-cases/footnotes_return_symbol.opts | |
create mode 100644 test/tm-cases/footnotes_return_symbol.tags | |
create mode 100644 test/tm-cases/footnotes_return_symbol.text | |
diff --git a/lib/markdown2.py b/lib/markdown2.py | |
index 87e5123..1cfb761 100755 | |
--- a/lib/markdown2.py | |
+++ b/lib/markdown2.py | |
@@ -1650,6 +1650,9 @@ class Markdown(object): | |
return "\n\n".join(grafs) | |
def _add_footnotes(self, text): | |
+ # Currently the argument of footnote is backlink_innerhtml | |
+ backlink_innerhtml = self.extras['footnotes'] if self.extras['footnotes'] else '↩'; | |
+ | |
if self.footnotes: | |
footer = [ | |
'<div class="footnotes">', | |
@@ -1664,7 +1667,7 @@ class Markdown(object): | |
backlink = ('<a href="#fnref-%s" ' | |
'class="footnoteBackLink" ' | |
'title="Jump back to footnote %d in the text.">' | |
- '↩</a>' % (id, i+1)) | |
+ '%s</a>' % (id, i+1, backlink_innerhtml)) | |
if footer[-1].endswith("</p>"): | |
footer[-1] = footer[-1][:-len("</p>")] \ | |
+ ' ' + backlink + "</p>" | |
diff --git a/test/tm-cases/footnotes_return_symbol.html b/test/tm-cases/footnotes_return_symbol.html | |
new file mode 100644 | |
index 0000000..0d0c638 | |
--- /dev/null | |
+++ b/test/tm-cases/footnotes_return_symbol.html | |
@@ -0,0 +1,27 @@ | |
+<p>This is a para with a footnote.<sup class="footnote-ref" id="fnref-1"><a href="#fn-1">1</a></sup></p> | |
+ | |
+<p>This is another para with a footnote<sup class="footnote-ref" id="fnref-2"><a href="#fn-2">2</a></sup> in it. Actually it has two<sup class="footnote-ref" id="fnref-3"><a href="#fn-3">3</a></sup> of | |
+them. No, three<sup class="footnote-ref" id="fnref-4"><a href="#fn-4">4</a></sup>.</p> | |
+ | |
+<div class="footnotes"> | |
+<hr /> | |
+<ol> | |
+<li id="fn-1"> | |
+<p>Here is the body of the first footnote. <a href="#fnref-1" class="footnoteBackLink" title="Jump back to footnote 1 in the text.">^</a></p> | |
+</li> | |
+ | |
+<li id="fn-2"> | |
+<p>And of the second footnote.</p> | |
+ | |
+<p>This one has multiple paragraphs. <a href="#fnref-2" class="footnoteBackLink" title="Jump back to footnote 2 in the text.">^</a></p> | |
+</li> | |
+ | |
+<li id="fn-3"> | |
+<p>Here is a footnote body that starts on next line. <a href="#fnref-3" class="footnoteBackLink" title="Jump back to footnote 3 in the text.">^</a></p> | |
+</li> | |
+ | |
+<li id="fn-4"> | |
+<p>quickie "that looks like a link ref if not careful" <a href="#fnref-4" class="footnoteBackLink" title="Jump back to footnote 4 in the text.">^</a></p> | |
+</li> | |
+</ol> | |
+</div> | |
diff --git a/test/tm-cases/footnotes_return_symbol.opts b/test/tm-cases/footnotes_return_symbol.opts | |
new file mode 100644 | |
index 0000000..8220e00 | |
--- /dev/null | |
+++ b/test/tm-cases/footnotes_return_symbol.opts | |
@@ -0,0 +1 @@ | |
+{"extras": {"footnotes": "^"}} | |
diff --git a/test/tm-cases/footnotes_return_symbol.tags b/test/tm-cases/footnotes_return_symbol.tags | |
new file mode 100644 | |
index 0000000..9e26e29 | |
--- /dev/null | |
+++ b/test/tm-cases/footnotes_return_symbol.tags | |
@@ -0,0 +1 @@ | |
+footnotes | |
diff --git a/test/tm-cases/footnotes_return_symbol.text b/test/tm-cases/footnotes_return_symbol.text | |
new file mode 100644 | |
index 0000000..7d6e716 | |
--- /dev/null | |
+++ b/test/tm-cases/footnotes_return_symbol.text | |
@@ -0,0 +1,18 @@ | |
+This is a para with a footnote.[^1] | |
+ | |
+This is another para with a footnote[^2] in it. Actually it has two[^3] of | |
+them. No, three[^4]. | |
+ | |
+ | |
+[^1]: Here is the body of the first footnote. | |
+ | |
+[^2]: And of the second footnote. | |
+ | |
+ This one has multiple paragraphs. | |
+ | |
+[^3]: | |
+ Here is a footnote body that starts on next line. | |
+ | |
+[^4]: quickie "that looks like a link ref if not careful" | |
+ | |
+ | |
-- | |
1.7.3.4 | |
From 3a913a6fb9748a7c1c71ea2ac9497d195460790d Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Thu, 28 Jul 2011 18:27:57 +0800 | |
Subject: [PATCH 2/3] Make gen_perf_cases.py runnable | |
trentm#63 | |
--- | |
perf/gen_perf_cases.py | 10 +++++++--- | |
1 files changed, 7 insertions(+), 3 deletions(-) | |
diff --git a/perf/gen_perf_cases.py b/perf/gen_perf_cases.py | |
index ecd4c54..5a5a841 100755 | |
--- a/perf/gen_perf_cases.py | |
+++ b/perf/gen_perf_cases.py | |
@@ -20,7 +20,12 @@ def gen_aspn_cases(limit=0): | |
return | |
os.makedirs(base_dir) | |
sys.stdout.write("generate %s" % base_dir); sys.stdout.flush() | |
- recipes_path = expanduser("~/as/code.as.com/db/aspn/recipes.pprint") | |
+ for recipes_path in (expanduser("~/as/code.as.com/db/aspn/recipes.pprint"), 'recipes.pprint'): | |
+ if exists(recipes_path): | |
+ break | |
+ else: | |
+ print >>sys.stderr, 'Can not find recipes.pprint' | |
+ sys.exit(1) | |
recipe_dicts = eval(open(recipes_path).read()) | |
for i, r in enumerate(recipe_dicts): | |
sys.stdout.write('.'); sys.stdout.flush() | |
@@ -28,8 +33,7 @@ def gen_aspn_cases(limit=0): | |
f.write(r["desc"]) | |
f.close() | |
- for j, c in enumerate(sorted(r["comments"], | |
- key=operator.itemgetter("pub_date"))): | |
+ for j, c in enumerate(sorted(r["comments"])): | |
text = _markdown_from_aspn_html(c["comment"]) | |
headline = c["title"].strip() | |
if headline: | |
-- | |
1.7.3.4 | |
From 5b342bdecbfa38cc7582407fd6659bcefa21fc4e Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Sat, 13 Aug 2011 19:48:39 +0800 | |
Subject: [PATCH 3/3] Fix, refactor, clean up perf/*, and make output more clear. (trentm#63) | |
--- | |
perf/gen_perf_cases.py | 24 +++++--- | |
perf/perf.py | 147 +++++++++++++++++++++++++-------------------- | |
perf/time_markdown_pl.pl | 4 + | |
perf/util.py | 10 +--- | |
4 files changed, 103 insertions(+), 82 deletions(-) | |
diff --git a/perf/gen_perf_cases.py b/perf/gen_perf_cases.py | |
index ecd4c54..619335a 100755 | |
--- a/perf/gen_perf_cases.py | |
+++ b/perf/gen_perf_cases.py | |
@@ -1,26 +1,32 @@ | |
-#!/usr/bin/env python2.5 | |
+#!/usr/bin/env python | |
import os | |
from os.path import * | |
import sys | |
import re | |
-import datetime | |
from glob import glob | |
-import operator | |
import shutil | |
import codecs | |
+SEARCH_PATH = [expanduser("~/as/code.as.com/db/aspn"), '.'] | |
TMP = "tmp-" | |
def gen_aspn_cases(limit=0): | |
base_dir = TMP+'aspn-cases' | |
if exists(base_dir): | |
- print "'%s' exists, skipping" % base_dir | |
+ print "'%s' exists, skipping. If you want to regenerate, please manually delete it." % base_dir | |
return | |
os.makedirs(base_dir) | |
sys.stdout.write("generate %s" % base_dir); sys.stdout.flush() | |
- recipes_path = expanduser("~/as/code.as.com/db/aspn/recipes.pprint") | |
+ for recipes_path in SEARCH_PATH: | |
+ recipes_path = join(recipes_path, 'recipes.pprint') | |
+ if exists(recipes_path): | |
+ break | |
+ else: | |
+ print >>sys.stderr, 'Can not find recipes.pprint, please specify a path where can find the file.' | |
+ sys.exit(1) | |
recipe_dicts = eval(open(recipes_path).read()) | |
for i, r in enumerate(recipe_dicts): | |
sys.stdout.write('.'); sys.stdout.flush() | |
@@ -28,8 +34,7 @@ def gen_aspn_cases(limit=0): | |
f.write(r["desc"]) | |
f.close() | |
- for j, c in enumerate(sorted(r["comments"], | |
- key=operator.itemgetter("pub_date"))): | |
+ for j, c in enumerate(sorted(r["comments"])): | |
text = _markdown_from_aspn_html(c["comment"]) | |
headline = c["title"].strip() | |
if headline: | |
@@ -49,7 +54,7 @@ def gen_aspn_cases(limit=0): | |
def gen_test_cases(): | |
base_dir = TMP+"test-cases" | |
if exists(base_dir): | |
- print "'%s' exists, skipping" % base_dir | |
+ print "'%s' exists, skipping. If you want to regenerate, please manually delete it." % base_dir | |
return | |
os.makedirs(base_dir) | |
print "generate %s" % base_dir | |
@@ -273,6 +278,9 @@ if __name__ == "__main__": | |
limit = int(sys.argv[1]) | |
except: | |
limit = 0 | |
+ for i in range(1, len(sys.argv)): | |
+ # put them all in, it doesn't matter what they are. | |
+ SEARCH_PATH += sys.argv[i] | |
gen_aspn_cases(limit) | |
gen_test_cases() | |
diff --git a/perf/perf.py b/perf/perf.py | |
index ea6f10e..99a7d5d 100755 | |
--- a/perf/perf.py | |
+++ b/perf/perf.py | |
@@ -10,10 +10,10 @@ Example: | |
import os | |
import sys | |
-import timeit | |
import time | |
from os.path import * | |
from glob import glob | |
+from StringIO import StringIO | |
import optparse | |
from util import hotshotit | |
@@ -22,69 +22,87 @@ from util import hotshotit | |
clock = sys.platform == "win32" and time.clock or time.time | |
-@hotshotit | |
-def hotshot_markdown_py(cases_dir, repeat): | |
- time_markdown_py(cases_dir, repeat) | |
- | |
-def time_markdown_py(cases_dir, repeat): | |
+def init_markdown(): | |
sys.path.insert(0, join("..", "test")) | |
import markdown | |
del sys.path[0] | |
- markdowner = markdown.Markdown() | |
- times = [] | |
- for i in range(repeat): | |
- start = clock() | |
- for path in glob(join(cases_dir, "*.text")): | |
- f = open(path, 'r') | |
- content = f.read() | |
- f.close() | |
- try: | |
- markdowner.convert(content) | |
- markdowner.reset() | |
- except UnicodeError: | |
- pass | |
- end = clock() | |
- times.append(end - start) | |
- print " markdown.py: best of %d: %.3fs" % (repeat, min(times)) | |
+ return markdown.Markdown() | |
-@hotshotit | |
-def hotshot_markdown2_py(cases_dir, repeat): | |
- time_markdown2_py(cases_dir, repeat) | |
- | |
-def time_markdown2_py(cases_dir, repeat): | |
+def init_markdown2(): | |
sys.path.insert(0, "../lib") | |
import markdown2 | |
del sys.path[0] | |
- markdowner = markdown2.Markdown() | |
- times = [] | |
- for i in range(repeat): | |
- start = clock() | |
- for path in glob(join(cases_dir, "*.text")): | |
- f = open(path, 'r') | |
- content = f.read() | |
- f.close() | |
+ return markdown2.Markdown() | |
+ | |
+def run_py_markdown(mkd, markdowner, cases_dir): | |
+ global show_progress | |
+ for path in glob(join(cases_dir, "*.text")): | |
+ f = open(path, 'r') | |
+ content = f.read() | |
+ f.close() | |
+ try: | |
+ # Mute markdowner | |
+ sys.stdout = StringIO() | |
markdowner.convert(content) | |
- end = clock() | |
- times.append(end - start) | |
- print " markdown2.py: best of %d: %.3fs" % (repeat, min(times)) | |
+ if show_progress: | |
+ sys.__stdout__.write('.') | |
+ except Exception: | |
+ # Don't print out traceback, this is profiling, not unit testing. | |
+ sys.__stdout__.write('E') | |
+ finally: | |
+ # Release normally | |
+ sys.stdout.close() | |
+ sys.stdout = sys.__stdout__ | |
+ if mkd == 'markdown.py': | |
+ markdowner.reset() | |
+ sys.stdout.flush() | |
+ | |
+def run_pl_markdown(mkd, markdowner, cases_dir): | |
+ global show_progress | |
+ cmd = 'perl time_markdown_pl.pl "%s"' | |
+ if not show_progress: | |
+ cmd += ' mute' | |
+ os.system(cmd % cases_dir) | |
+ | |
+ | |
+MKD = { | |
+ 'markdown.py': { | |
+ 'init': init_markdown, | |
+ 'run': run_py_markdown, | |
+ }, | |
+ 'markdown2.py': { | |
+ 'init': init_markdown2, | |
+ 'run': run_py_markdown, | |
+ }, | |
+ 'Markdown.pl': { | |
+ 'init': lambda: None, | |
+ 'run': run_pl_markdown, | |
+ }, | |
+ } | |
+MKDS = MKD.keys() | |
+ | |
-def time_markdown_pl(cases_dir, repeat): | |
+@hotshotit | |
+def hotshot_py_markdown(mkd, cases_dir, repeat): | |
+ time_markdown(mkd, cases_dir, repeat) | |
+ | |
+def time_markdown(mkd, cases_dir, repeat): | |
+ markdowner = MKD[mkd]['init']() | |
times = [] | |
for i in range(repeat): | |
+ print '#%2d: ' % (i + 1), | |
+ sys.stdout.flush() | |
start = clock() | |
- os.system('perl time_markdown_pl.pl "%s"' % cases_dir) | |
+ MKD[mkd]['run'](mkd, markdowner, cases_dir) | |
end = clock() | |
times.append(end - start) | |
- print " Markdown.pl: best of %d: %.3fs" % (repeat, min(times)) | |
+ print "%s: best of %d: %.3fs" % (mkd, repeat, min(times)) | |
def time_all(cases_dir, repeat): | |
- time_markdown_pl(cases_dir, repeat=repeat) | |
- time_markdown_py(cases_dir, repeat=repeat) | |
- time_markdown2_py(cases_dir, repeat=repeat) | |
- | |
-def time_not_markdown_py(cases_dir, repeat): | |
- time_markdown_pl(cases_dir, repeat=repeat) | |
- time_markdown2_py(cases_dir, repeat=repeat) | |
+ for mkd in MKDS: | |
+ time_markdown(mkd, cases_dir, repeat=repeat) | |
#---- mainline | |
@@ -95,6 +113,7 @@ class _NoReflowFormatter(optparse.IndentedHelpFormatter): | |
return description or "" | |
def main(args=sys.argv): | |
+ global show_progress | |
usage = "python perf.py [-i all|markdown.py|markdown2.py|Markdown.pl] [cases-dir]" | |
parser = optparse.OptionParser(prog="perf", usage=usage, | |
description=__doc__, formatter=_NoReflowFormatter()) | |
@@ -104,10 +123,13 @@ def main(args=sys.argv): | |
parser.add_option("-i", "--implementation", | |
help="Markdown implementation(s) to run: all (default), " | |
"markdown.py, markdown2.py, Markdown.pl, not-markdown.py") | |
- parser.add_option("--hotshot", "--profile", dest="hotshot", | |
+ parser.add_option("-H", "--hotshot", dest="hotshot", | |
action="store_true", | |
help="profile and dump stats about a single run (not supported " | |
"for Markdown.pl)") | |
+ parser.add_option("-p", "--progress", dest="progress", | |
+ action="store_true", default=False, | |
+ help="Show the progress") | |
parser.set_defaults(implementation="all", hotshot=False, repeat=None) | |
opts, args = parser.parse_args() | |
@@ -123,31 +145,26 @@ def main(args=sys.argv): | |
if opts.repeat is None: | |
opts.repeat = opts.hotshot and 1 or 3 | |
+ show_progress = opts.progress | |
if opts.hotshot: | |
assert opts.implementation in ("markdown.py", "markdown2.py") | |
- timer_name = "hotshot_%s" \ | |
- % opts.implementation.lower().replace('.', '_').replace('-', '_') | |
- d = sys.modules[__name__].__dict__ | |
- if timer_name not in d: | |
- raise ValueError("no '%s' timer function" % timer_name) | |
- timer = d[timer_name] | |
print "Profile conversion of %s (plat=%s):" \ | |
% (os.path.join(cases_dir, "*.text"), sys.platform) | |
- timer(cases_dir, repeat=opts.repeat) | |
+ mkd = opts.implementation | |
+ hotshot_py_markdown(mkd, cases_dir, repeat=opts.repeat) | |
- os.system("python show_stats.py %s.prof" % timer_name) | |
+ os.system("python show_stats.py hotshot_%s.prof" % mkd) | |
else: | |
- timer_name = "time_%s" \ | |
- % opts.implementation.lower().replace('.', '_').replace('-', '_') | |
- | |
- d = sys.modules[__name__].__dict__ | |
- if timer_name not in d: | |
- raise ValueError("no '%s' timer function" % timer_name) | |
- timer = d[timer_name] | |
+ mkd = opts.implementation | |
+ if mkd not in MKDS and mkd != 'all': | |
+ raise ValueError("no such '%s' Markdown implementation" % mkd) | |
print "Time conversion of %s (plat=%s):" \ | |
% (os.path.join(cases_dir, "*.text"), sys.platform) | |
- timer(cases_dir, repeat=opts.repeat) | |
+ if mkd == 'all': | |
+ time_all(cases_dir, repeat=opts.repeat) | |
+ else: | |
+ time_markdown(mkd, cases_dir, repeat=opts.repeat) | |
if __name__ == "__main__": | |
sys.exit( main(sys.argv) ) | |
diff --git a/perf/time_markdown_pl.pl b/perf/time_markdown_pl.pl | |
index eed1110..7a2699d 100755 | |
--- a/perf/time_markdown_pl.pl | |
+++ b/perf/time_markdown_pl.pl | |
@@ -3,9 +3,13 @@ use Markdown; | |
my @text_files = <$ARGV[0]/*.text>; | |
my $file, $content; | |
+$| = 1; | |
for $file (@text_files) { | |
local(*INPUT, $/); | |
open (INPUT, $file) || die "can't open $file: $!"; | |
$content = <INPUT>; | |
Markdown::Markdown($content); | |
+ if ($ARGV[1] ne "mute") { | |
+ print "."; | |
+ } | |
} | |
diff --git a/perf/util.py b/perf/util.py | |
index 05a22a0..0b40489 100644 | |
--- a/perf/util.py | |
+++ b/perf/util.py | |
@@ -3,15 +3,7 @@ | |
"""Perf utility functions""" | |
-import os | |
-from os.path import basename | |
import sys | |
-import md5 | |
-import re | |
-import stat | |
-import textwrap | |
-import types | |
-from pprint import pprint, pformat | |
# Global dict for holding specific hotshot profilers | |
@@ -45,7 +37,7 @@ def hotshotit(func): | |
def wrapper(*args, **kw): | |
import hotshot | |
global hotshotProfilers | |
- prof_name = func.func_name+".prof" | |
+ prof_name = "hotshot_%s.prof" % args[0] | |
profiler = hotshotProfilers.get(prof_name) | |
if profiler is None: | |
profiler = hotshot.Profile(prof_name) | |
-- | |
1.7.3.4 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From ee9e90cd2320b4dea0afaac6aadb98c6be76fd7b Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Wed, 27 Jul 2011 08:09:39 +0800 | |
Subject: [PATCH 1/3] Add predefined styles for LineBox | |
--- | |
linebox.py | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
urwid/graphics.py | 91 ++++++++++++++++--- | |
2 files changed, 336 insertions(+), 14 deletions(-) | |
create mode 100755 linebox.py | |
diff --git a/linebox.py b/linebox.py | |
new file mode 100755 | |
index 0000000..e41339a | |
--- /dev/null | |
+++ b/linebox.py | |
@@ -0,0 +1,259 @@ | |
+#!/usr/bin/env python | |
+# | |
+# Urwid LineBox example program | |
+# Copyright (C) 2011 Yu-Jie Lin | |
+# | |
+# This library is free software; you can redistribute it and/or | |
+# modify it under the terms of the GNU Lesser General Public | |
+# License as published by the Free Software Foundation; either | |
+# version 2.1 of the License, or (at your option) any later version. | |
+# | |
+# This library is distributed in the hope that it will be useful, | |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
+# Lesser General Public License for more details. | |
+# | |
+# You should have received a copy of the GNU Lesser General Public | |
+# License along with this library; if not, write to the Free Software | |
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
+# | |
+# Urwid web site: http://excess.org/urwid/ | |
+ | |
+""" | |
+Urwid example demonstrating use of the LineBox widget. | |
+""" | |
+ | |
+import urwid | |
+ | |
+ | |
+class LineBoxDemo: | |
+ | |
+ LBOX_ATTRS = { | |
+ 'inset': { | |
+ 'tline': 'line dark', | |
+ 'lline': 'line dark', | |
+ 'tlcorner': 'line dark', | |
+ 'blcorner': 'line dark', | |
+ 'rline': 'line bright', | |
+ 'bline': 'line bright', | |
+ 'trcorner': 'line bright', | |
+ 'brcorner': 'line bright', | |
+ }, | |
+ 'outset': { | |
+ 'tline': 'line bright', | |
+ 'lline': 'line bright', | |
+ 'tlcorner': 'line bright', | |
+ 'blcorner': 'line bright', | |
+ 'rline': 'line dark', | |
+ 'bline': 'line dark', | |
+ 'trcorner': 'line dark', | |
+ 'brcorner': 'line dark', | |
+ }, | |
+ 'grooved/ridged': { | |
+ 'tline': 'line bright/dark', | |
+ 'lline': 'line bright/dark', | |
+ 'tlcorner': 'line bright/dark', | |
+ 'blcorner': 'line bright/dark', | |
+ 'rline': 'line dark/bright', | |
+ 'bline': 'line dark/bright', | |
+ 'trcorner': 'line dark/bright', | |
+ 'brcorner': 'line dark/bright', | |
+ }, | |
+ 'ridged/grooved': { | |
+ 'tline': 'line dark/bright', | |
+ 'lline': 'line dark/bright', | |
+ 'tlcorner': 'line dark/bright', | |
+ 'blcorner': 'line dark/bright', | |
+ 'rline': 'line bright/dark', | |
+ 'bline': 'line bright/dark', | |
+ 'trcorner': 'line bright/dark', | |
+ 'brcorner': 'line bright/dark', | |
+ }, | |
+ 'raised/lowered': { | |
+ 'tline': 'line bright/dark', | |
+ 'lline': 'line bright/dark', | |
+ 'tlcorner': 'line bright/dark', | |
+ 'blcorner': 'line bright/dark', | |
+ 'rline': 'line bright/dark', | |
+ 'bline': 'line bright/dark', | |
+ 'trcorner': 'line bright/dark', | |
+ 'brcorner': 'line bright/dark', | |
+ }, | |
+ 'lowered/raised': { | |
+ 'tline': 'line dark/bright', | |
+ 'lline': 'line dark/bright', | |
+ 'tlcorner': 'line dark/bright', | |
+ 'blcorner': 'line dark/bright', | |
+ 'rline': 'line dark/bright', | |
+ 'bline': 'line dark/bright', | |
+ 'trcorner': 'line dark/bright', | |
+ 'brcorner': 'line dark/bright', | |
+ }, | |
+ 'rainbow': { | |
+ 'tline': 'line black', | |
+ 'bline': 'line red', | |
+ 'lline': 'line green', | |
+ 'rline': 'line brown', | |
+ 'tlcorner': 'line blue', | |
+ 'trcorner': 'line magenta', | |
+ 'blcorner': 'line cyan', | |
+ 'brcorner': 'line yellow', | |
+ }, | |
+ 'default': {}, | |
+ } | |
+ | |
+ def __init__(self): | |
+ | |
+ is_utf8 = urwid.get_encoding_mode() == 'utf8' | |
+ | |
+ self.custom_style_chars = u'abcdefgh' | |
+ self.lbox_attr = 'default' | |
+ | |
+ self.style = 'single' | |
+ self.style_chars = None | |
+ lbox = self.create_lbox() | |
+ self.lbox = lbox | |
+ self.style_chars = self.lbox.style_chars | |
+ | |
+ style_name_width = max(len(name) for name in urwid.LineBox.STYLES.keys()) | |
+ style_rows = [('flow', urwid.Text('Styles:'))] | |
+ style_buttons = [] | |
+ styles = urwid.LineBox.STYLES.keys() | |
+ styles.sort() | |
+ for style in styles: | |
+ try: | |
+ if not is_utf8: | |
+ (urwid.LineBox.STYLES[style] or u'').encode('ascii') | |
+ except UnicodeEncodeError: | |
+ text = ' %%-%ds (UTF-8 mode required)' % style_name_width | |
+ row = urwid.Text(text % style) | |
+ row = urwid.AttrMap(row, 'option disable') | |
+ style_rows.append(row) | |
+ continue | |
+ | |
+ rb = urwid.RadioButton(style_buttons, style, state=style=='single') | |
+ if style != 'custom': | |
+ rb_style_chars = urwid.Text(urwid.LineBox.STYLES[style]) | |
+ else: | |
+ rb_style_chars = urwid.Edit('', self.custom_style_chars) | |
+ urwid.connect_signal(rb_style_chars, 'change', | |
+ self.change_style_chars) | |
+ rb_style_chars = urwid.Padding( | |
+ urwid.AttrMap( | |
+ rb_style_chars, 'custom style', 'custom style focus'), | |
+ width=8) | |
+ | |
+ urwid.connect_signal(rb, 'change', self.change_style) | |
+ | |
+ row = urwid.Columns([ | |
+ ('fixed', style_name_width + 4, rb), | |
+ rb_style_chars, | |
+ ], dividechars=1) | |
+ | |
+ row = urwid.AttrMap(row, 'option', 'option focus') | |
+ style_rows.append(row) | |
+ self.style_buttons = style_buttons | |
+ style_box = urwid.Pile(style_rows) | |
+ | |
+ attr_rows = [('flow', urwid.Text('Attributes:'))] | |
+ attr_buttons = [] | |
+ attrs = self.LBOX_ATTRS.keys() | |
+ attrs.sort() | |
+ for name in attrs: | |
+ rb = urwid.RadioButton(attr_buttons, name) | |
+ urwid.connect_signal(rb, 'change', self.change_attr) | |
+ row = urwid.AttrMap(rb, 'option', 'option focus') | |
+ attr_rows.append(row) | |
+ self.attr_buttons = attr_buttons | |
+ attr_box = urwid.Pile(attr_rows) | |
+ | |
+ style_attr_boxes = urwid.Columns([style_box, attr_box], dividechars=1) | |
+ header = urwid.Text('Urwid LineBox example program - F8 exits.') | |
+ header = urwid.AttrMap(header, 'title') | |
+ | |
+ body = urwid.Pile([ | |
+ ('flow', lbox), | |
+ ('flow', urwid.Divider()), | |
+ urwid.Filler(style_attr_boxes, valign='top'), | |
+ ]) | |
+ body = urwid.AttrMap(body, 'normal') | |
+ frame = urwid.Frame(body, header=header) | |
+ self.frame = frame | |
+ palette = [ | |
+ ('normal', 'black', 'white'), | |
+ ('title', 'white', 'dark red'), | |
+ ('option', 'white', 'dark blue'), | |
+ ('option disable', 'dark gray', 'dark blue'), | |
+ ('option focus', 'white', 'dark green'), | |
+ ('custom style', 'white', 'dark red'), | |
+ ('custom style focus', 'light blue', 'dark red'), | |
+ ('line bright', '', '', '', 'g80', 'white'), | |
+ ('line dark', '', '', '', 'g40', 'white'), | |
+ ('line bright/dark', '', '', '', 'g80', 'g40'), | |
+ ('line dark/bright', '', '', '', 'g40', 'g80'), | |
+ ('line black', 'black', 'white'), | |
+ ('line red', 'dark red', 'white'), | |
+ ('line green', 'dark green', 'white'), | |
+ ('line brown', 'brown', 'white'), | |
+ ('line blue', 'dark blue', 'white'), | |
+ ('line magenta', 'dark magenta', 'white'), | |
+ ('line cyan', 'dark cyan', 'white'), | |
+ ('line yellow', 'yellow', 'white'), | |
+ ] | |
+ | |
+ loop = urwid.MainLoop(frame, unhandled_input=self.unhandled_input) | |
+ loop.screen.set_terminal_properties(colors=256) | |
+ loop.screen.reset_default_terminal_palette() | |
+ loop.screen.register_palette(palette) | |
+ self.loop = loop | |
+ | |
+ def create_lbox(self): | |
+ | |
+ text = urwid.Text('Inside the LineBox') | |
+ return urwid.LineBox(text, 'LineBox Title', | |
+ style=self.style, style_chars=self.style_chars, | |
+ **self.LBOX_ATTRS[self.lbox_attr]) | |
+ | |
+ def change_attr(self, w, state): | |
+ | |
+ if state: | |
+ self.lbox_attr = w.label | |
+ self.lbox = self.create_lbox() | |
+ self.frame.body.base_widget.widget_list[0] = self.lbox | |
+ | |
+ def change_style(self, w, state): | |
+ | |
+ if state: | |
+ if w.label != 'custom': | |
+ self.lbox.set_style(w.label, | |
+ **self.LBOX_ATTRS[self.lbox_attr]) | |
+ else: | |
+ style_chars = self.custom_style_chars[:8] | |
+ style_chars += '?'*(8 - len(style_chars)) | |
+ self.lbox.set_style(w.label, style_chars, | |
+ **self.LBOX_ATTRS[self.lbox_attr]) | |
+ self.style = self.lbox.style | |
+ self.style_chars = self.lbox.style_chars | |
+ | |
+ def change_style_chars(self, w, text): | |
+ | |
+ self.custom_style_chars = text | |
+ for rbtn in self.style_buttons: | |
+ if rbtn.label == 'custom': | |
+ rbtn.set_state(True, do_callback=False) | |
+ self.change_style(rbtn, True) | |
+ return | |
+ | |
+ def run(self): | |
+ | |
+ self.loop.run() | |
+ | |
+ def unhandled_input(self, key): | |
+ | |
+ if key == 'f8': | |
+ raise urwid.ExitMainLoop | |
+ | |
+ | |
+if __name__ == '__main__': | |
+ demo = LineBoxDemo() | |
+ demo.run() | |
diff --git a/urwid/graphics.py b/urwid/graphics.py | |
index 092045c..e13ad8f 100755 | |
--- a/urwid/graphics.py | |
+++ b/urwid/graphics.py | |
@@ -92,6 +92,7 @@ class BigText(FixedWidget): | |
class LineBox(WidgetDecoration, WidgetWrap): | |
+ # Unused after adding predefined styles | |
ACS_HLINE = u'─' | |
ACS_VLINE = u'│' | |
@@ -100,17 +101,56 @@ class LineBox(WidgetDecoration, WidgetWrap): | |
ACS_LLCORNER = u'└' | |
ACS_LRCORNER = u'┘' | |
+ STYLES = { # tblrttbb | |
+ # lrlr | |
+ 'ascii' : u'--||++++', # default for non-UTF-8 | |
+ 'ascii-double' : u'==||++++', # default for non-UTF-8 | |
+ 'ascii-slash' :ur'--||/\\/', | |
+ 'ascii-wave' : u'~~||~~~~', | |
+ 'ascii-dots' : u'........', | |
+ 'ascii-asterisks' : u'********', | |
+ 'ascii-millionaire': u'$$$$$$$$', | |
+ 'single' : u'──││┌┐└┘', # default for UTF-8 | |
+ 'single-d-1' : u'╌╌╎╎┌┐└┘', | |
+ 'single-d-2' : u'┄┄┆┆┌┐└┘', | |
+ 'single-d-3' : u'┈┈┊┊┌┐└┘', | |
+ 'single-thick' : u'━━┃┃┏┓┗┛', | |
+ 'single-thick-d-1' : u'╍╍╏╏┏┓┗┛', | |
+ 'single-thick-d-2' : u'┅┅┇┇┏┓┗┛', | |
+ 'single-thick-d-3' : u'┉┉┋┋┏┓┗┛', | |
+ 'single-r' : u'──││╭╮╰╯', | |
+ 'double' : u'══║║╔╗╚╝', | |
+ 'double-h' : u'══││╒╕╘╛', | |
+ 'double-v' : u'──║║╓╖╙╜', | |
+ 'double-tl' : u'═─║│╔╕╙┘', | |
+ 'double-tl-r' : u'═─║│╔╕╙╯', | |
+ 'double-tr' : u'═─│║╒╗└╜', | |
+ 'double-tr-r' : u'═─│║╒╗╰╜', | |
+ 'double-bl' : u'─═║│╓┐╚╛', | |
+ 'double-bl-r' : u'─═║│╓╮╚╛', | |
+ 'double-br' : u'─═│║┌╖╘╝', | |
+ 'double-br-r' : u'─═│║╭╖╘╝', | |
+ 'block-full' : u'████████', | |
+ 'block-full-r' : u'████▟▙▜▛', | |
+ 'block-half' : u'▄▀▐▌▗▖▝▘', | |
+ 'block-half-tb' : u'▄▀██▄▄▀▀', | |
+ 'block-half-o' : u'▀▄▌▐▛▜▙▟', | |
+ 'block-half-o-tb' : u'▀▄██████', | |
+ 'none' : u' ', | |
+ 'custom' : None, | |
+ } | |
+ | |
def __init__(self, original_widget, title="", | |
tlcorner=None, tline=None, lline=None, | |
trcorner=None, blcorner=None, rline=None, | |
- bline=None, brcorner=None): | |
+ bline=None, brcorner=None, style=None, style_chars=None): | |
""" | |
Draw a line around original_widget. | |
Use 'title' to set an initial title text with will be centered | |
on top of the box. | |
- You can also override the widgets used for the lines/corners: | |
+ You can also apply attributes to the lines/corners: | |
tline: top line | |
bline: bottom line | |
lline: left line | |
@@ -119,9 +159,32 @@ class LineBox(WidgetDecoration, WidgetWrap): | |
trcorner: top right corner | |
blcorner: bottom left corner | |
brcorner: bottom right corner | |
+ | |
+ Use 'style' to choose style from predefined styles. See LineBox.STYLES. | |
+ | |
+ Use 'style_chars' to set characters for lines/corners and set 'style' to | |
+ 'custom' to take effective. 'style_chars' should be a string with eight | |
+ characters for as same order as for attributes above. | |
""" | |
self.title_widget = Text(self.format_title(title)) | |
+ WidgetDecoration.__init__(self, original_widget) | |
+ self.set_style(style, style_chars, | |
+ tlcorner, tline, lline, trcorner, | |
+ blcorner, rline, bline, brcorner) | |
+ def set_style(self, style=None, style_chars=None, | |
+ tlcorner=None, tline=None, lline=None, | |
+ trcorner=None, blcorner=None, rline=None, | |
+ bline=None, brcorner=None): | |
+ if not style: | |
+ style = 'single' if get_encodeing_mode() == 'utf8' else 'ascii' | |
+ if style != 'custom': | |
+ style_chars = LineBox.STYLES[style] | |
+ ctline, cbline, clline, crline, \ | |
+ ctlcorner, ctrcorner, cblcorner, cbrcorner = style_chars | |
+ self.style = style | |
+ self.style_chars = style_chars | |
+ | |
def use_attr( a, t ): | |
if a is not None: | |
t = AttrWrap(t, a) | |
@@ -130,31 +193,31 @@ class LineBox(WidgetDecoration, WidgetWrap): | |
return t | |
self.tline_widget = Columns([ | |
- Divider(self.ACS_HLINE), | |
+ Divider(ctline), | |
('flow', self.title_widget), | |
- Divider(self.ACS_HLINE), | |
+ Divider(ctline), | |
]) | |
tline = use_attr( tline, self.tline_widget) | |
- bline = use_attr( bline, Divider(self.ACS_HLINE)) | |
- lline = use_attr( lline, SolidFill(self.ACS_VLINE)) | |
- rline = use_attr( rline, SolidFill(self.ACS_VLINE)) | |
- tlcorner = use_attr( tlcorner, Text(self.ACS_ULCORNER)) | |
- trcorner = use_attr( trcorner, Text(self.ACS_URCORNER)) | |
- blcorner = use_attr( blcorner, Text(self.ACS_LLCORNER)) | |
- brcorner = use_attr( brcorner, Text(self.ACS_LRCORNER)) | |
+ bline = use_attr( bline, Divider(cbline)) | |
+ lline = use_attr( lline, SolidFill(clline)) | |
+ rline = use_attr( rline, SolidFill(crline)) | |
+ tlcorner = use_attr( tlcorner, Text(ctlcorner)) | |
+ trcorner = use_attr( trcorner, Text(ctrcorner)) | |
+ blcorner = use_attr( blcorner, Text(cblcorner)) | |
+ brcorner = use_attr( brcorner, Text(cbrcorner)) | |
+ | |
top = Columns([ ('fixed', 1, tlcorner), | |
tline, ('fixed', 1, trcorner) ]) | |
middle = Columns( [('fixed', 1, lline), | |
- original_widget, ('fixed', 1, rline)], box_columns = [0,2], | |
+ self.original_widget, ('fixed', 1, rline)], box_columns = [0,2], | |
focus_column = 1) | |
bottom = Columns([ ('fixed', 1, blcorner), | |
bline, ('fixed', 1, brcorner) ]) | |
pile = Pile([('flow',top),middle,('flow',bottom)], | |
focus_item = 1) | |
- WidgetDecoration.__init__(self, original_widget) | |
- WidgetWrap.__init__(self, pile) | |
+ self._set_w(pile) | |
def format_title(self, text): | |
if len(text) > 0: | |
-- | |
1.7.3.4 | |
From 5975e770ae10a23bf0d188aa0c742dc4cd0852d5 Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Thu, 28 Jul 2011 11:12:13 +0800 | |
Subject: [PATCH 2/3] fix typo in called function name | |
--- | |
urwid/graphics.py | 2 +- | |
1 files changed, 1 insertions(+), 1 deletions(-) | |
diff --git a/urwid/graphics.py b/urwid/graphics.py | |
index e13ad8f..df3ad3d 100755 | |
--- a/urwid/graphics.py | |
+++ b/urwid/graphics.py | |
@@ -177,7 +177,7 @@ class LineBox(WidgetDecoration, WidgetWrap): | |
trcorner=None, blcorner=None, rline=None, | |
bline=None, brcorner=None): | |
if not style: | |
- style = 'single' if get_encodeing_mode() == 'utf8' else 'ascii' | |
+ style = 'single' if get_encoding_mode() == 'utf8' else 'ascii' | |
if style != 'custom': | |
style_chars = LineBox.STYLES[style] | |
ctline, cbline, clline, crline, \ | |
-- | |
1.7.3.4 | |
From 6d9df852efc6c44d1a205248ea1817170ca3a3e0 Mon Sep 17 00:00:00 2001 | |
From: Yu-Jie Lin <livibetter@gmail.com> | |
Date: Tue, 6 Sep 2011 14:09:52 +0800 | |
Subject: [PATCH 3/3] Last small changes before killing this branch and repo. | |
will put a formatted patch on Gist if the deletion causes code/commits | |
missing. I think GitHub does duplicate code at where pull requests are | |
opened. But just be safe. | |
--- | |
urwid/graphics.py | 14 +++----------- | |
1 files changed, 3 insertions(+), 11 deletions(-) | |
diff --git a/urwid/graphics.py b/urwid/graphics.py | |
index df3ad3d..f51163b 100755 | |
--- a/urwid/graphics.py | |
+++ b/urwid/graphics.py | |
@@ -92,19 +92,11 @@ class BigText(FixedWidget): | |
class LineBox(WidgetDecoration, WidgetWrap): | |
- # Unused after adding predefined styles | |
- ACS_HLINE = u'─' | |
- ACS_VLINE = u'│' | |
- ACS_ULCORNER = u'┌' | |
- ACS_URCORNER = u'┐' | |
- ACS_LLCORNER = u'└' | |
- ACS_LRCORNER = u'┘' | |
- | |
- STYLES = { # tblrttbb | |
- # lrlr | |
+ STYLES = { # tblrttbb | |
+ # lrlr | |
'ascii' : u'--||++++', # default for non-UTF-8 | |
- 'ascii-double' : u'==||++++', # default for non-UTF-8 | |
+ 'ascii-double' : u'==||++++', | |
'ascii-slash' :ur'--||/\\/', | |
'ascii-wave' : u'~~||~~~~', | |
'ascii-dots' : u'........', | |
-- | |
1.7.3.4 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment