Commits

Yuya Nishihara committed 9574ee3

clean up patches in upstream

Comments (0)

Files changed (4)

8bittest.mbox

-From fujiwara@ascade.co.jp Wed Jul 21 22:45:58 2010
-Delivered-To: yuya@tcha.org
-Received: by 10.142.251.11 with SMTP id y11cs244264wfh;
-        Wed, 21 Jul 2010 06:46:08 -0700 (PDT)
-Received: by 10.114.77.10 with SMTP id z10mr272943waa.168.1279719967414;
-        Wed, 21 Jul 2010 06:46:07 -0700 (PDT)
-Return-Path: <mercurial-devel-bounces@selenic.com>
-Received: from waste.org (waste.org [173.11.57.241])
-        by mx.google.com with ESMTP id g8si16135285ibb.64.2010.07.21.06.46.07;
-        Wed, 21 Jul 2010 06:46:07 -0700 (PDT)
-Received-SPF: neutral (google.com: 173.11.57.241 is neither permitted nor denied by best guess record for domain of mercurial-devel-bounces@selenic.com) client-ip=173.11.57.241;
-Authentication-Results: mx.google.com; spf=neutral (google.com: 173.11.57.241 is neither permitted nor denied by best guess record for domain of mercurial-devel-bounces@selenic.com) smtp.mail=mercurial-devel-bounces@selenic.com
-Received: from localhost (localhost [127.0.0.1])
-	by waste.org (Postfix) with ESMTP id DE0EB7418A;
-	Wed, 21 Jul 2010 08:46:06 -0500 (CDT)
-X-Virus-Scanned: Debian amavisd-new at waste.org
-Received: from waste.org ([127.0.0.1])
-	by localhost (waste.org [127.0.0.1]) (amavisd-new, port 10024)
-	with LMTP id QigSFReClSLY; Wed, 21 Jul 2010 08:46:06 -0500 (CDT)
-Received: from waste.org (localhost [127.0.0.1])
-	by waste.org (Postfix) with ESMTP id C6D1C74172;
-	Wed, 21 Jul 2010 08:46:04 -0500 (CDT)
-X-Original-To: mercurial-devel@waste.org
-Delivered-To: mercurial-devel@waste.org
-Received: from localhost (localhost [127.0.0.1])
-	by waste.org (Postfix) with ESMTP id 7CCD974172
-	for <mercurial-devel@waste.org>; Wed, 21 Jul 2010 08:46:03 -0500 (CDT)
-X-Virus-Scanned: Debian amavisd-new at waste.org
-Received: from waste.org ([127.0.0.1])
-	by localhost (waste.org [127.0.0.1]) (amavisd-new, port 10024)
-	with LMTP id gid4aXQygF8A for <mercurial-devel@waste.org>;
-	Wed, 21 Jul 2010 08:46:00 -0500 (CDT)
-Received: from ext-host1001.ascade.co.jp (ext-host0001.ascade.co.jp
-	[218.224.228.194]) by waste.org (Postfix) with ESMTP id 401D274170
-	for <mercurial-devel@selenic.com>; Wed, 21 Jul 2010 08:46:00 -0500 (CDT)
-Received: from server0003.ascade.co.jp (server0003.ascade.co.jp [10.1.1.58])
-	by ext-host1001.ascade.co.jp (Postfix) with ESMTP id 6C1C42F708
-	for <mercurial-devel@selenic.com>; Wed, 21 Jul 2010 22:45:59 +0900 (JST)
-Received: from juju.dzone.foozy.private (server0003.ascade.co.jp [10.1.1.58])
-	by server0003.ascade.co.jp (Postfix) with ESMTP id 5896A2B148
-	for <mercurial-devel@selenic.com>; Wed, 21 Jul 2010 22:45:59 +0900 (JST)
-MIME-Version: 1.0
-Subject: [PATCH] i18n: safety writing into non-ASCII named files on any shell
-	implementation
-X-Mercurial-Node: c83103eb88b4f795a7c7068303ab1c147823e42b
-Message-Id: <c83103eb88b4f795a7c7.1279719958@juju.dzone.foozy.private>
-User-Agent: Mercurial-patchbomb/1.6
-Date: Wed, 21 Jul 2010 22:45:58 +0900
-From: FUJIWARA Katsunori <fujiwara@ascade.co.jp>
-To: mercurial-devel@selenic.com
-X-BeenThere: mercurial-devel@selenic.com
-X-Mailman-Version: 2.1.11
-Precedence: list
-List-Id: <mercurial-devel.selenic.com>
-List-Unsubscribe: <http://selenic.com/mailman/options/mercurial-devel>,
-	<mailto:mercurial-devel-request@selenic.com?subject=unsubscribe>
-List-Archive: <http://selenic.com/pipermail/mercurial-devel>
-List-Post: <mailto:mercurial-devel@selenic.com>
-List-Help: <mailto:mercurial-devel-request@selenic.com?subject=help>
-List-Subscribe: <http://selenic.com/mailman/listinfo/mercurial-devel>,
-	<mailto:mercurial-devel-request@selenic.com?subject=subscribe>
-Content-Type: text/plain;
-  charset="us-ascii"
-Content-Transfer-Encoding: 7bit
-Sender: mercurial-devel-bounces@selenic.com
-Errors-To: mercurial-devel-bounces@selenic.com
-Status: R
-X-Status: N
-X-KMail-EncryptionState:  
-X-KMail-SignatureState:  
-X-KMail-MDN-Sent:  
-
-# HG changeset patch
-# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
-# Date 1279718904 -32400
-# Branch stable
-# Node ID c83103eb88b4f795a7c7068303ab1c147823e42b
-# Parent  9e874ee0fe97ffd00fe13300f4cdf6b44921e71d
-i18n: safety writing into non-ASCII named files on any shell implementation
-
-some shell implementation (e.g.: dash) can not handle redirection into
-non-ASCII UTF-8 named file correctly.
-
-this patch uses instant python script to write data into such files.
-
-diff -r 9e874ee0fe97 -r c83103eb88b4 tests/test-encoding-align
---- a/tests/test-encoding-align	Tue Jul 13 03:04:14 2010 +0200
-+++ b/tests/test-encoding-align	Wed Jul 21 22:28:24 2010 +0900
-@@ -8,17 +8,21 @@
- hg init t
- cd t
- 
--python << EOF
-+cat << EOF > names.py
- # (byte, width) = (6, 4)
- s = "\xe7\x9f\xad\xe5\x90\x8d"
- # (byte, width) = (7, 7): odd width is good for alignment test
- m = "MIDDLE_"
- # (byte, width) = (18, 12)
- l = "\xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d"
-+EOF
- 
--f = file('s', 'w'); f.write(s); f.close()
--f = file('m', 'w'); f.write(m); f.close()
--f = file('l', 'w'); f.write(l); f.close()
-+python <<EOF
-+import names
-+
-+f = file('s', 'w'); f.write(names.s); f.close()
-+f = file('m', 'w'); f.write(names.m); f.close()
-+f = file('l', 'w'); f.write(names.l); f.close()
- 
- # instant extension to show list of options
- f = file('showoptlist.py', 'w'); f.write("""# encoding: utf-8
-@@ -29,9 +33,9 @@
- cmdtable = {
-     'showoptlist':
-         (showoptlist,
--         [('s', 'opt1', '', 'short width',  '""" + s + """'),
--          ('m', 'opt2', '', 'middle width', '""" + m + """'),
--          ('l', 'opt3', '', 'long width',   '""" + l + """')
-+         [('s', 'opt1', '', 'short width',  '""" + names.s + """'),
-+          ('m', 'opt2', '', 'middle width', '""" + names.m + """'),
-+          ('l', 'opt3', '', 'long width',   '""" + names.l + """')
-          ],
-          ""
-         )
-@@ -69,25 +73,33 @@
- touch $L
- hg add $L
- 
-+# for safety append to non-ASCII UTF-8 named files
-+# on any shell implementatoins
-+cat <<EOF > append.py
-+import sys
-+import names
-+
-+namelist = [ names.s, names.m, names.l ]
-+
-+for i in xrange(len(namelist)):
-+    f = file(namelist[i], 'a');
-+    f.write('%s(%d)\n' % (sys.argv[1], (i + 1)));
-+    f.close()
-+EOF
-+
- #### commit(1)
- 
--echo 'first line(1)' >> $S
--echo 'first line(2)' >> $M
--echo 'first line(3)' >> $L
-+python append.py 'first line'
- hg commit -m 'first commit' -u $S -d "1000000 0"
- 
- #### commit(2)
- 
--echo 'second line(1)' >> $S
--echo 'second line(2)' >> $M
--echo 'second line(3)' >> $L
-+python append.py 'second line'
- hg commit -m 'second commit' -u $M -d "1000000 0"
- 
- #### commit(3)
- 
--echo 'third line(1)' >> $S
--echo 'third line(2)' >> $M
--echo 'third line(3)' >> $L
-+python append.py 'third line'
- hg commit -m 'third commit' -u $L -d "1000000 0"
- 
- #### check
-_______________________________________________
-Mercurial-devel mailing list
-Mercurial-devel@selenic.com
-http://selenic.com/mailman/listinfo/mercurial-devel

colwidth.diff

-# HG changeset patch
-# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
-# Date 1279382810 -32400
-# Branch stable
-# Node ID d342305f7635e607eef62fbfc9dc6f0e13be34d4
-# Parent  76454cbc11e48d692262843d0c87e81bbb2c053c
-i18n: use encoding.colwidth() instead of len() for correct column width
-
-Some encoding and language combinations (e.g.: UTF-8 and Japanese)
-cause encoding characters into sequence of bytes more than column
-width of them.
-
-So, encoding.colwidth() should be applied instread of len() on i18n
-strings.
-
-In addition to it, formatting by '%*s'/'%-*s' also uses "number of
-bytes" to calculate space padding size, and should be fixed, too.
-
-diff --git a/mercurial/commands.py b/mercurial/commands.py
---- a/mercurial/commands.py
-+++ b/mercurial/commands.py
-@@ -152,8 +152,9 @@
-         for f in funcmap:
-             l = [f(n) for n, dummy in lines]
-             if l:
--                ml = max(map(len, l))
--                pieces.append(["%*s" % (ml, x) for x in l])
-+                sized = [(x, encoding.colwidth(x)) for x in l]
-+                ml = max([w for x, w in sized])
-+                pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
- 
-         if pieces:
-             for p, l in zip(zip(*pieces), lines):
-@@ -2053,9 +2054,9 @@
-     if multioccur:
-         msg = _("\n[+] marked option can be specified multiple times")
-         if ui.verbose and name != 'shortlist':
--            opt_output.append((msg, ()))
-+            opt_output.append((msg, None))
-         else:
--            opt_output.insert(-1, (msg, ()))
-+            opt_output.insert(-1, (msg, None))
- 
-     if not name:
-         ui.write(_("\nadditional help topics:\n\n"))
-@@ -2067,16 +2068,20 @@
-             ui.write(" %-*s  %s\n" % (topics_len, t, desc))
- 
-     if opt_output:
--        opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
--        for first, second in opt_output:
--            if second:
--                initindent = ' %-*s  ' % (opts_len, first)
--                hangindent = ' ' * (opts_len + 3)
--                ui.write('%s\n' % (util.wrap(second,
-+        colwidth = encoding.colwidth
-+        # normalize: (opt or message, desc or None, width of opt)
-+        entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
-+                   for opt, desc in opt_output]
-+        hanging = max([e[2] for e in entries])
-+        for opt, desc, width in entries:
-+            if desc:
-+                initindent = ' %s%s  ' % (opt, ' ' * (hanging - width))
-+                hangindent = ' ' * (hanging + 3)
-+                ui.write('%s\n' % (util.wrap(desc,
-                                              initindent=initindent,
-                                              hangindent=hangindent)))
-             else:
--                ui.write("%s\n" % first)
-+                ui.write("%s\n" % opt)
- 
- def identify(ui, repo, source=None,
-              rev=None, num=None, id=None, branch=None, tags=None):
-diff --git a/mercurial/patch.py b/mercurial/patch.py
---- a/mercurial/patch.py
-+++ b/mercurial/patch.py
-@@ -11,7 +11,7 @@
- 
- from i18n import _
- from node import hex, nullid, short
--import base85, cmdutil, mdiff, util, diffhelpers, copies
-+import base85, cmdutil, mdiff, util, diffhelpers, copies, encoding
- 
- gitre = re.compile('diff --git a/(.*) b/(.*)')
- 
-@@ -1644,10 +1644,14 @@
-     maxtotal, maxname = 0, 0
-     totaladds, totalremoves = 0, 0
-     hasbinary = False
--    for filename, adds, removes, isbinary in stats:
-+
-+    sized = [(filename, adds, removes, isbinary, encoding.colwidth(filename))
-+             for filename, adds, removes, isbinary in stats]
-+
-+    for filename, adds, removes, isbinary, namewidth in sized:
-         totaladds += adds
-         totalremoves += removes
--        maxname = max(maxname, len(filename))
-+        maxname = max(maxname, namewidth)
-         maxtotal = max(maxtotal, adds + removes)
-         if isbinary:
-             hasbinary = True
-@@ -1667,15 +1671,17 @@
-         # if there were at least some changes.
-         return max(i * graphwidth // maxtotal, int(bool(i)))
- 
--    for filename, adds, removes, isbinary in stats:
-+    for filename, adds, removes, isbinary, namewidth in sized:
-         if git and isbinary:
-             count = 'Bin'
-         else:
-             count = adds + removes
-         pluses = '+' * scale(adds)
-         minuses = '-' * scale(removes)
--        output.append(' %-*s |  %*s %s%s\n' % (maxname, filename, countwidth,
--                                               count, pluses, minuses))
-+        output.append(' %s%s |  %*s %s%s\n' %
-+                      (filename, ' ' * (maxname - namewidth),
-+                       countwidth, count,
-+                       pluses, minuses))
- 
-     if stats:
-         output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
-diff --git a/tests/test-encoding-align b/tests/test-encoding-align
-new file mode 100755
---- /dev/null
-+++ b/tests/test-encoding-align
-@@ -0,0 +1,134 @@
-+#!/bin/sh
-+
-+########################################
-+
-+hg init t
-+cd t
-+
-+python << EOF
-+# (byte, width) = (6, 4)
-+s = "\xe7\x9f\xad\xe5\x90\x8d"
-+# (byte, width) = (7, 7): odd width is good for alignment test
-+m = "MIDDLE_"
-+# (byte, width) = (18, 12)
-+l = "\xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d"
-+
-+f = file('s', 'w'); f.write(s); f.close()
-+f = file('m', 'w'); f.write(m); f.close()
-+f = file('l', 'w'); f.write(l); f.close()
-+
-+# instant extension to show list of options
-+f = file('showoptlist.py', 'w'); f.write("""# encoding: utf-8
-+def showoptlist(ui, repo, *pats, **opts):
-+    '''dummy command to show option descriptions'''
-+    return 0
-+
-+cmdtable = {
-+    'showoptlist':
-+        (showoptlist,
-+         [('s', 'opt1', '', 'short width',  '""" + s + """'),
-+          ('m', 'opt2', '', 'middle width', '""" + m + """'),
-+          ('l', 'opt3', '', 'long width',   '""" + l + """')
-+         ],
-+         ""
-+        )
-+}
-+""")
-+f.close()
-+EOF
-+
-+########################################
-+#### alignment of:
-+####     - option descriptions in help
-+
-+cat <<EOF > .hg/hgrc
-+[extensions]
-+ja_ext = ${PWD}/showoptlist.py
-+EOF
-+echo '% check alignment of option descriptions in help'
-+HGENCODING=utf-8 hg help showoptlist
-+
-+########################################
-+#### alignment of:
-+####     - user names in annotate
-+####     - file names in diffstat
-+
-+#### add files
-+
-+touch `cat s`
-+HGENCODING=utf-8 hg add `cat s`
-+touch `cat m`
-+HGENCODING=utf-8 hg add `cat m`
-+touch `cat l`
-+HGENCODING=utf-8 hg add `cat l`
-+
-+#### commit(1)
-+
-+cat <<EOF >> `cat s`
-+first line(1)
-+EOF
-+cat <<EOF >> `cat m`
-+first line(2)
-+EOF
-+cat <<EOF >> `cat l`
-+first line(3)
-+EOF
-+HGENCODING=utf-8 hg commit -m 'first commit' -u `cat s` -d "1000000 0"
-+
-+#### commit(2)
-+
-+cat <<EOF >> `cat s`
-+second line(1)
-+EOF
-+cat <<EOF >> `cat m`
-+second line(2)
-+EOF
-+cat <<EOF >> `cat l`
-+second line(3)
-+EOF
-+HGENCODING=utf-8 hg commit -m 'second commit' -u `cat m` -d "1000000 0"
-+
-+#### commit(3)
-+
-+cat <<EOF >> `cat s`
-+third line(1)
-+EOF
-+cat <<EOF >> `cat m`
-+third line(2)
-+EOF
-+cat <<EOF >> `cat l`
-+third line(3)
-+EOF
-+HGENCODING=utf-8 hg commit -m 'third commit' -u `cat l` -d "1000000 0"
-+
-+#### check
-+
-+echo '% check alignment of user names in annotate'
-+HGENCODING=utf-8 hg annotate -u `cat m`
-+echo '% check alignment of filenames in diffstat'
-+HGENCODING=utf-8 hg diff -c tip --stat
-+
-+########################################
-+#### alignment of:
-+####     - branch names in list
-+####     - tag names in list
-+
-+#### add branches/tags
-+
-+HGENCODING=utf-8 hg branch `cat s`
-+HGENCODING=utf-8 hg tag -d "1000000 0" `cat s`
-+HGENCODING=utf-8 hg branch `cat m`
-+HGENCODING=utf-8 hg tag -d "1000000 0" `cat m`
-+HGENCODING=utf-8 hg branch `cat l`
-+HGENCODING=utf-8 hg tag -d "1000000 0" `cat l`
-+
-+#### check
-+
-+echo '% check alignment of branches'
-+HGENCODING=utf-8 hg tags
-+echo '% check alignment of tags'
-+HGENCODING=utf-8 hg tags
-+
-+########################################
-+
-+exit 0
-diff --git a/tests/test-encoding-align.out b/tests/test-encoding-align.out
-new file mode 100644
---- /dev/null
-+++ b/tests/test-encoding-align.out
-@@ -0,0 +1,34 @@
-+% check alignment of option descriptions in help
-+hg showoptlist 
-+
-+dummy command to show option descriptions
-+
-+options:
-+
-+ -s --opt1 短名          short width
-+ -m --opt2 MIDDLE_       middle width
-+ -l --opt3 長い長い名前  long width
-+
-+use "hg -v help showoptlist" to show global options
-+% check alignment of user names in annotate
-+        短名: first line(2)
-+     MIDDLE_: second line(2)
-+長い長い名前: third line(2)
-+% check alignment of filenames in diffstat
-+ MIDDLE_      |  1 +
-+ 短名         |  1 +
-+ 長い長い名前 |  1 +
-+ 3 files changed, 3 insertions(+), 0 deletions(-)
-+marked working directory as branch 短名
-+marked working directory as branch MIDDLE_
-+marked working directory as branch 長い長い名前
-+% check alignment of branches
-+tip                                5:afc60d8eed19
-+長い長い名前                       4:19fe74d09ba0
-+MIDDLE_                            3:8a20997d2281
-+短名                               2:0cc06ffa3461
-+% check alignment of tags
-+tip                                5:afc60d8eed19
-+長い長い名前                       4:19fe74d09ba0
-+MIDDLE_                            3:8a20997d2281
-+短名                               2:0cc06ffa3461

mq-qrename-subdir.diff

-# HG changeset patch
-# User Yuya Nishihara <yuya@tcha.org>
-# Date 1274894677 -32400
-# Node ID 102b2d44d73064c2620fe54a91cc5cea41afb9bf
-# Parent  1107888a1ad1624ac32b53954f41c8219b420e08
-mq: fixed ENOENT when qrename to new/directory.patch
-
-MQ patch name can contain slashes, e.g. 'foo/bar.patch'.
-
-Currently "qnew foo/bar.patch" works, but
-"qrename foo/bar.patch new/dir.patch" fails with
-"No such file or directory".
-
-Also added test case for "qnew foo/bar.patch"
-
-diff --git a/hgext/mq.py b/hgext/mq.py
---- a/hgext/mq.py
-+++ b/hgext/mq.py
-@@ -2298,6 +2298,9 @@ def rename(ui, repo, patch, name=None, *
-         q.applied[info[0]] = statusentry(info[1], name)
-     q.applied_dirty = 1
- 
-+    destdir = os.path.dirname(absdest)
-+    if not os.path.isdir(destdir):
-+        os.makedirs(destdir)
-     util.rename(q.join(patch), absdest)
-     r = q.qrepo()
-     if r:
-diff --git a/tests/test-mq-qnew b/tests/test-mq-qnew
---- a/tests/test-mq-qnew
-+++ b/tests/test-mq-qnew
-@@ -25,6 +25,12 @@ runtest() {
- 
-     hg qinit -c
- 
-+    echo '% qnew with name containing slash'
-+    hg qnew foo/bar.patch
-+    hg qseries
-+    hg qpop
-+    hg qdelete foo/bar.patch
-+
-     echo '% qnew with uncommitted changes'
-     echo a > somefile
-     hg add somefile
-diff --git a/tests/test-mq-qnew.out b/tests/test-mq-qnew.out
---- a/tests/test-mq-qnew.out
-+++ b/tests/test-mq-qnew.out
-@@ -8,6 +8,10 @@ abort: ".hgignore" cannot be used as the
- abort: ".mqfoo" cannot be used as the name of a patch
- abort: "foo#bar" cannot be used as the name of a patch
- abort: "foo:bar" cannot be used as the name of a patch
-+% qnew with name containing slash
-+foo/bar.patch
-+popping foo/bar.patch
-+patch queue now empty
- % qnew with uncommitted changes
- uncommitted.patch
- % qnew implies add
-@@ -58,6 +62,10 @@ abort: ".hgignore" cannot be used as the
- abort: ".mqfoo" cannot be used as the name of a patch
- abort: "foo#bar" cannot be used as the name of a patch
- abort: "foo:bar" cannot be used as the name of a patch
-+% qnew with name containing slash
-+foo/bar.patch
-+popping foo/bar.patch
-+patch queue now empty
- % qnew with uncommitted changes
- uncommitted.patch
- % qnew implies add
-diff --git a/tests/test-mq-qrename b/tests/test-mq-qrename
---- a/tests/test-mq-qrename
-+++ b/tests/test-mq-qrename
-@@ -22,6 +22,9 @@ ls .hg/patches/bar
- hg qrename bar/renamed baz
- hg qseries
- ls .hg/patches/baz
-+hg qrename baz new/dir
-+hg qseries
-+ls .hg/patches/new/dir
- cd ..
- 
- echo % test patch being renamed before committed
-diff --git a/tests/test-mq-qrename.out b/tests/test-mq-qrename.out
---- a/tests/test-mq-qrename.out
-+++ b/tests/test-mq-qrename.out
-@@ -5,4 +5,6 @@ bar/renamed
- renamed
- baz
- .hg/patches/baz
-+new/dir
-+.hg/patches/new/dir
- % test patch being renamed before committed
 zsh-qmove.diff
 hgencoding-js.diff
 mq-commit-editor-hack.diff
-8bittest.mbox
-colwidth.diff
 bom.diff
 bom-config.diff
-mq-qrename-subdir.diff
 atomictemp-fileattr.diff
 atomictemp-symlink.diff
 main-is-frozen.diff
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.