Ticket #5653: docstring.5.patch

File docstring.5.patch, 25.0 KB (added by jhpalmieri, 12 years ago)

cumulative against 4.0.alpha0. Apply only this patch.

  • new file doc/en/introspect/__init__.py

    # HG changeset patch
    # User J. H. Palmieri <palmieri@math.washington.edu>
    # Date 1242769953 25200
    # Node ID f18bb3d2781a5c3b651f0e1129c4a28c3c283afd
    # Parent  7488340543618251888907e60499593a1c911890
    pretty docstrings
    
    diff -r 748834054361 -r f18bb3d2781a doc/en/introspect/__init__.py
    - +  
     1 
  • new file doc/en/introspect/conf.py

    diff -r 748834054361 -r f18bb3d2781a doc/en/introspect/conf.py
    - +  
     1# -*- coding: utf-8 -*-
     2# Sage introspection build configuration file.
     3# See sage.server.notebook.cell.set_introspect_html() for details.
     4
     5import sys, os
     6sys.path.append(os.environ['SAGE_DOC'])
     7from common.conf import *
     8
     9extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath']
     10
     11templates_path = ['templates']
     12html_static_path = ['static']
     13
     14html_use_modindex = False
     15html_use_index = False
     16html_split_index = False
     17html_copy_source = False
  • new file doc/en/introspect/static/empty

    diff -r 748834054361 -r f18bb3d2781a doc/en/introspect/static/empty
    - +  
     1
  • new file doc/en/introspect/templates/layout.html

    diff -r 748834054361 -r f18bb3d2781a doc/en/introspect/templates/layout.html
    - +  
     1<div class="docstring">
     2    {% block body %} {% endblock %}
     3</div>
  • sage/misc/sagedoc.py

    diff -r 748834054361 -r f18bb3d2781a sage/misc/sagedoc.py
    a b  
    2020#*****************************************************************************
    2121
    2222import os
    23 #('\\item', '*'), \
    24 substitutes = [('\\_','_'),\
    25                ('\\item', '* '), \
    26                ('\\to', '-->'), \
    27                ('<BLANKLINE>',''), \
    28                ('\\leq', '<='), \
    29                ('\\geq', '>='), \
    30                ('\\le', '<='), \
    31                ('\\ge', '>='), \
    32                ('\\bf', ''),\
    33                ('\\sage', 'SAGE'), \
    34                ('\\SAGE', 'SAGE'), \
    35                ('\\rm', ''), \
    36                ('cdots', '...'), \
    37                ('\\cdot', ' *'), \
    38                ('$',''), ('\\',''), ('backslash','\\'), \
    39                ('begin{enumerate}',''), ('end{enumerate}',''), \
    40                ('begin{description}',''), ('end{description}',''), \
    41                ('begin{itemize}',''), ('end{itemize}',''), \
    42                ('begin{verbatim}',''), ('end{verbatim}',''), \
    43                ('mapsto', ' |--> '), \
    44                ('ldots', '...'), ('note{','NOTE: ')]
    45 
     23# two kinds of substitutions: math, which should only be done on the
     24# command line -- in the notebook, these should instead by taken care
     25# of by jsMath -- and nonmath, which should be done always.
     26math_substitutes = [('\\to', '-->'),
     27                    ('\\leq', '<='),
     28                    ('\\geq', '>='),
     29                    ('\\le', '<='),
     30                    ('\\ge', '>='),
     31                    ('cdots', '...'),
     32                    ('\\cdot', ' *'),
     33                    (' \\times', ' x'),
     34                    ('\\times', ' x'),
     35                    ('backslash','\\'),
     36                    ('mapsto', ' |--> '),
     37                    ('ldots', '...')]
     38nonmath_substitutes = [('\\_','_'),
     39                       ('\\item', '* '),
     40                       ('<BLANKLINE>',''),
     41                       ('\\bf', ''),
     42                       ('\\sage', 'SAGE'),
     43                       ('\\SAGE', 'SAGE'),
     44                       ('\\rm', ''),
     45                       ('backslash','\\'),
     46                       ('begin{enumerate}',''),
     47                       ('end{enumerate}',''),
     48                       ('begin{description}',''),
     49                       ('end{description}',''),
     50                       ('begin{itemize}',''),
     51                       ('end{itemize}',''),
     52                       ('begin{verbatim}',''),
     53                       ('end{verbatim}',''),
     54                       ('note{','NOTE: ')]
    4655
    4756def _rmcmd(s, cmd, left='', right=''):
    4857    """
     
    112121itempattern = re.compile(r"\\item\[?([^]]*)\]? *(.*)")
    113122itemreplace = r"* \1 \2"
    114123
    115 def detex(s):
     124def detex(s, embedded=False):
    116125    """nodetex
    117126    This strips LaTeX commands from a string; it is used by the
    118127    ``format`` function to process docstrings for display from the
    119128    command line interface.
    120129
    121     INPUT: ``s``, a string.
     130    INPUT:
     131
     132    - ``s`` - string
     133    - ``embedded`` - boolean (optional, default False)
     134
     135    If ``embedded`` is False, then do the replacements in both
     136    ``math_substitutes`` and ``nonmath_substitutes``.  If True, then
     137    only do ``nonmath_substitutes``.
    122138
    123139    OUTPUT: string
    124140
     
    129145        'Some math: `n >= k`.  A website: sagemath.org.'
    130146        sage: detex(r'More math: `x \mapsto y`.  {\bf Bold face}.')
    131147        'More math: `x  |-->  y`.  { Bold face}.'
    132         sage: detex(r'$a, b, c, \ldots, z$')
    133         'a, b, c, ..., z'
     148        sage: detex(r'`a, b, c, \ldots, z`')
     149        '`a, b, c, ..., z`'
     150        sage: detex(r'`a, b, c, \ldots, z`', embedded=True)
     151        '`a, b, c, \\\\ldots, z`'
    134152    """
    135153    s = _rmcmd(s, 'url')
    136154    s = _rmcmd(s, 'code')
     
    142160    s = _rmcmd(s, 'subsubsection')
    143161    s = _rmcmd(s, 'note', 'NOTE: ', '')
    144162    s = _rmcmd(s, 'emph', '*', '*')
     163    s = _rmcmd(s, 'textbf', '*', '*')
    145164
    146165    s = re.sub(itempattern, itemreplace, s)
    147    
    148     for a,b in substitutes:
     166
     167    if not embedded: # not in the notebook
     168        for a,b in math_substitutes:  # do math substitutions
     169            s = s.replace(a,b)
     170        s = s.replace('\\','')        # nuke backslashes
     171        s = s.replace('.. math::\n', '')  # get rid of .. math:: directives
     172    else:
     173        s = s.replace('\\','\\\\')    # double up backslashes for jsMath
     174    for a,b in nonmath_substitutes:
    149175        s = s.replace(a,b)
    150176    return s
    151177
    152 def format(s):
     178def format(s, embedded=False):
    153179    """
    154180    Format Sage documentation ``s`` for viewing with IPython.
    155181
     
    157183    text, and if ``s`` contains a string of the form "<<<obj>>>",
    158184    then it replaces it with the docstring for "obj".
    159185
    160     INPUT: ``s`` - string
     186    INPUT:
     187
     188    - ``s`` - string
     189    - ``embedded`` - boolean (optional, default False)
    161190
    162191    OUTPUT: string
    163192
     193    Set ``embedded`` equal to True if formatting for use in the
     194    notebook; this just gets passed as an argument to ``detex``.
     195
    164196    EXAMPLES::
    165197
    166198        sage: from sage.misc.sagedoc import format
     
    216248            t = 'Definition: ' + t0 + '\n\n' + t1
    217249            docs.add(obj)
    218250        s = s[:i] + '\n' + t + s[i+6+j:]
    219            
     251
    220252    if 'nodetex' not in directives:
    221         s = detex(s)
     253        s = detex(s, embedded=embedded)
    222254    return s
    223255
    224256def format_src(s):
  • sage/misc/sageinspect.py

    diff -r 748834054361 -r f18bb3d2781a sage/misc/sageinspect.py
    a b  
    114114
    115115import inspect
    116116import os
     117EMBEDDED_MODE = False
    117118
    118119def isclassinstance(obj):
    119120    r"""
     
    400401        if s[:4] == 'self':
    401402            s = s[4:]
    402403        s = s.lstrip(',').strip()
     404        # for use with typesetting the definition with the notebook:
     405        # sometimes s contains "*args" or "**keywds", and the
     406        # asterisks confuse ReST/sphinx/docutils, so escape them:
     407        # change * to \*, and change ** to \**.
     408        if EMBEDDED_MODE:
     409            s = s.replace('**', '\\**')  # replace ** with \**
     410            t = ''
     411            while True:  # replace * with \*
     412                i = s.find('*')
     413                if i == -1:
     414                    break
     415                elif i > 0 and s[i-1] == '\\':
     416                    if s[i+1] == "*":
     417                        t += s[:i+2]
     418                        s = s[i+2:]
     419                    else:
     420                        t += s[:i+1]
     421                        s = s[i+1:]
     422                    continue
     423                elif i > 0 and s[i-1] == '*':
     424                    t += s[:i+1]
     425                    s = s[i+1:]
     426                    continue
     427                else:
     428                    t += s[:i] + '\\*'
     429                    s = s[i+1:]
     430            s = t + s
    403431        return obj_name + '(' + s + ')'
    404432    except (AttributeError, TypeError, ValueError):
    405433        return '%s( [noargspec] )'%obj_name
     
    439467
    440468    if r is None:
    441469        return ''
    442     s = sage.misc.sagedoc.format(str(r))
     470
     471    s = sage.misc.sagedoc.format(str(r), embedded=EMBEDDED_MODE)
    443472
    444473    # If there is a Cython embedded position, it needs to be stripped
    445474    pos = _extract_embedded_position(s)
  • sage/server/notebook/cell.py

    diff -r 748834054361 -r f18bb3d2781a sage/server/notebook/cell.py
    a b  
    3434
    3535import os, shutil
    3636
    37 from   sage.misc.misc import word_wrap
     37from   sage.misc.misc import word_wrap, SAGE_DOC
    3838from   sage.misc.html import math_parse
    3939from   sage.misc.preparser import strip_string_literals
    4040from   sage.misc.package   import is_package_installed
     
    4646else:
    4747    JEDITABLE_TINYMCE = False
    4848
     49# Introspection.  The cache directory is a module-scope variable set
     50# in the first call to Cell.set_introspect_html().
     51import errno, hashlib, time
     52from sphinx.application import Sphinx
     53_SAGE_INTROSPECT = None
    4954
    5055class Cell_generic:
    5156    def is_interactive_cell(self):
     
    14301435    #################
    14311436    # Introspection #
    14321437    #################
    1433     def set_introspect_html(self, html, completing=False):
    1434         if completing:
     1438    def set_introspect_html(self, html, completing=False, verbose=False):
     1439        """
     1440        If ``verbose`` is True, print verbose output about notebook
     1441        introspection to the command-line.  However, the argument
     1442        ``verbose`` is not easily accessible now -- if you need to
     1443        debug, you have to edit this file, changing its value to True,
     1444        and run 'sage -b'.
     1445        """
     1446        if html == "" or completing:
    14351447            self.__introspect_html = html
     1448        elif html.find("`") == -1 and html.find("::") == -1:
     1449            # html doesn't seem to be in ReST format so use docutils
     1450            # to process the preamble ("**File:**" etc.)  and put
     1451            # everything else in a <pre> block.
     1452            i = html.find("**Docstring:**")
     1453            if i != -1:
     1454                preamble = html[:i+14]
     1455                from docutils.core import publish_parts
     1456                preamble = publish_parts(html[:i+14], writer_name='html')['body']
     1457                html = html[i+14:]
     1458            else:
     1459                preamble = ""
     1460            self.__introspect_html = '<div class="docstring">' + preamble + '<pre>' + html + '</pre></div>'
    14361461        else:
    1437             html = escape(html).strip()
    1438             self.__introspect_html = '<pre class="introspection">'+html+'</pre>'
     1462            # html is in ReST format, so use Sphinx to process it
     1463           
     1464            # Set the location of the introspection cache, "permanent"
     1465            # or temporary.  The former, DOT_SAGE/sage_notebook/doc,
     1466            # can pool queries from multiple worksheet processes.  The
     1467            # latter is exclusive to a worksheet's process.  The Sage
     1468            # cleaner should delete the temporary directory (or
     1469            # directories) after the notebook server exits.
     1470            global _SAGE_INTROSPECT
     1471
     1472            if _SAGE_INTROSPECT is None:
     1473                from sage.misc.misc import DOT_SAGE, tmp_dir
     1474                # It's important to use os.path.join, instead of +,
     1475                # because Sphinx counts on normalized paths.  It's also
     1476                # more portable.
     1477                std_doc_dir = os.path.join(DOT_SAGE, 'sage_notebook/doc')
     1478                try:
     1479                    os.makedirs(std_doc_dir)
     1480                    _SAGE_INTROSPECT = std_doc_dir
     1481                except OSError, error:
     1482                    if error.errno == errno.EEXIST:
     1483                        if os.access(std_doc_dir, os.R_OK | os.W_OK | os.X_OK):
     1484                            _SAGE_INTROSPECT = std_doc_dir
     1485                        else:
     1486                            _SAGE_INTROSPECT = tmp_dir()
     1487                    else:
     1488                        _SAGE_INTROSPECT = tmp_dir()
     1489                if verbose:
     1490                    print 'Introspection cache: ', _SAGE_INTROSPECT
     1491                       
     1492            # We get a quick checksum of the input.  MD5 admits
     1493            # collisions, but we're not concerned about such security
     1494            # issues here.  Of course, if performance permits, we can
     1495            # choose a more robust hash function.
     1496            hash = hashlib.md5(html).hexdigest()
     1497            base_name = os.path.join(_SAGE_INTROSPECT, hash)
     1498            html_name = base_name + '.html'
     1499
     1500            # Multiple processes might try to read/write the target
     1501            # HTML file simultaneously.  We use a file-based lock.
     1502            # Since we care only about the target's contents, and
     1503            # we've configured Sphinx accordingly, we allow multiple
     1504            # simultaneous instances of Sphinx, as long as their
     1505            # targets are different.  Systems which don't properly
     1506            # implement os.O_EXCL may require coarser locking.
     1507
     1508            # The Pythonic cross-platform file lock below is adapted
     1509            # from
     1510            # http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-python/
     1511            lock_name = base_name + '.lock'
     1512
     1513            # Try to acquire the lock, periodically.  If we time out,
     1514            # we fall back to plainly formatted documentation.
     1515            timeout = 0.5
     1516            delay = 0.05
     1517            start_time = time.time()
     1518
     1519            while True:
     1520                try:
     1521                    # This operation is atomic on platforms which
     1522                    # properly implement os.O_EXCL:
     1523                    fd_lock = os.open(lock_name, os.O_CREAT | os.O_EXCL | os.O_RDWR)
     1524                    break;
     1525                except OSError, err:
     1526                    if (err.errno != errno.EEXIST) or (time.time() - start_time >= timeout):
     1527                        plain_html = escape(html).strip()
     1528                        self.__introspect_html = '<pre class="introspection">' + plain_html + '</pre>'
     1529                        return
     1530                    time.sleep(delay)
     1531
     1532            # We've acquired the lock.  Use cached HTML or run Sphinx.
     1533            try:
     1534                open(html_name, 'r')
     1535                if verbose:
     1536                    print 'Found: %s' % html_name
     1537            except IOError:
     1538                html = html.replace('\\\\', '\\')
     1539                rst_name = base_name + '.rst'
     1540                fd_rst = open(rst_name, 'w')
     1541                fd_rst.write(html)
     1542                fd_rst.close()
     1543
     1544                # Sphinx setup.  The constructor is Sphinx(srcdir,
     1545                # confdir, outdir, doctreedir, buildername,
     1546                # confoverrides, status, warning, freshenv).
     1547                srcdir = os.path.normpath(_SAGE_INTROSPECT)
     1548
     1549                # Note: It's crucial that confdir* contains a
     1550                # customized conf.py and layout.html.  In particular,
     1551                # we've disabled index generation and told Sphinx to
     1552                # output almost exactly the HTML we display.  Sphinx
     1553                # also pickles its environment in doctreedir, but we
     1554                # force Sphinx never to load this pickle with
     1555                # freshenv=True.
     1556                confdir = os.path.join(SAGE_DOC, 'en/introspect')
     1557                doctreedir = os.path.normpath(base_name)
     1558                confoverrides = {'html_context' : {}, 'master_doc' : hash}
     1559
     1560                # To suppress output, use this:
     1561
     1562                if verbose:
     1563                    import sys
     1564                    sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, sys.stdout, sys.stderr, True)
     1565                else:
     1566                    sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, None, None, True)
     1567
     1568                # Run Sphinx. The first argument corresponds to
     1569                # sphinx-build's "write all files" -a flag, which we
     1570                # set to None.
     1571                sphinx_app.build(None, [rst_name])
     1572
     1573                # We delete .rst files, so future Sphinx runs don't
     1574                # keep track of them.  We also delete doctrees.
     1575                try:
     1576                    os.unlink(rst_name)
     1577                except OSError:
     1578                    pass
     1579                try:
     1580                    shutil.rmtree(doctreedir)
     1581                    os.unlink(doctreedir)
     1582                except OSError:
     1583                    pass
     1584
     1585                if verbose:
     1586                    print 'Built: %s' % html_name
     1587            finally:
     1588                # Contents should be flushed on close().
     1589                fd_html = open(html_name, 'r')
     1590                new_html = fd_html.read()
     1591                fd_html.close()
     1592
     1593                # We release the lock and delete the lock file.
     1594                os.close(fd_lock)
     1595                os.unlink(lock_name)
     1596
     1597                new_html = new_html.replace('<pre>', '<pre class="literal-block">')
     1598                self.__introspect_html = new_html
     1599                return
    14391600
    14401601    def introspect_html(self):
    14411602        if not self.introspect():
  • sage/server/notebook/css.py

    diff -r 748834054361 -r f18bb3d2781a sage/server/notebook/css.py
    a b  
    293293div.introspection {
    294294}
    295295
     296div.docstring {
     297  font-family:arial;
     298  background-color: #f1f1f1;
     299  color: blue;
     300  border: solid 1px black;
     301  padding:8px;
     302  margin:8px;
     303}
     304
     305pre.literal-block {
     306  background-color: #efc;
     307  color: blue;   
     308}
     309
    296310pre.introspection {
    297311  font-family: monospace;
    298312  font-size:15px;
    299   background-color: #efefef;
     313  background-color: #f1f1f1;
     314  color: blue;
    300315  border: solid 1px black;
    301316  padding:8px;
    302317  margin:8px;
     
    16351650   background-color: #990000;   
    16361651}
    16371652
     1653
     1654
     1655/* These have been scraped directly from pygment. */
     1656
     1657.hll { background-color: #ffffcc }
     1658.c { color: #408090; font-style: italic } /* Comment */
     1659.err { border: 1px solid #FF0000 } /* Error */
     1660.k { color: #007020; font-weight: bold } /* Keyword */
     1661.o { color: #666666 } /* Operator */
     1662.cm { color: #408090; font-style: italic } /* Comment.Multiline */
     1663.cp { color: #007020 } /* Comment.Preproc */
     1664.c1 { color: #408090; font-style: italic } /* Comment.Single */
     1665.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
     1666.gd { color: #A00000 } /* Generic.Deleted */
     1667.ge { font-style: italic } /* Generic.Emph */
     1668.gr { color: #FF0000 } /* Generic.Error */
     1669.gh { color: #000080; font-weight: bold } /* Generic.Heading */
     1670.gi { color: #00A000 } /* Generic.Inserted */
     1671.go { color: #303030 } /* Generic.Output */
     1672.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
     1673.gs { font-weight: bold } /* Generic.Strong */
     1674.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
     1675.gt { color: #0040D0 } /* Generic.Traceback */
     1676.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
     1677.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
     1678.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
     1679.kp { color: #007020 } /* Keyword.Pseudo */
     1680.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
     1681.kt { color: #902000 } /* Keyword.Type */
     1682.m { color: #208050 } /* Literal.Number */
     1683.s { color: #4070a0 } /* Literal.String */
     1684.na { color: #4070a0 } /* Name.Attribute */
     1685.nb { color: #007020 } /* Name.Builtin */
     1686.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
     1687.no { color: #60add5 } /* Name.Constant */
     1688.nd { color: #555555; font-weight: bold } /* Name.Decorator */
     1689.ni { color: #d55537; font-weight: bold } /* Name.Entity */
     1690.ne { color: #007020 } /* Name.Exception */
     1691.nf { color: #06287e } /* Name.Function */
     1692.nl { color: #002070; font-weight: bold } /* Name.Label */
     1693.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
     1694.nt { color: #062873; font-weight: bold } /* Name.Tag */
     1695.nv { color: #bb60d5 } /* Name.Variable */
     1696.ow { color: #007020; font-weight: bold } /* Operator.Word */
     1697.w { color: #bbbbbb } /* Text.Whitespace */
     1698.mf { color: #208050 } /* Literal.Number.Float */
     1699.mh { color: #208050 } /* Literal.Number.Hex */
     1700.mi { color: #208050 } /* Literal.Number.Integer */
     1701.mo { color: #208050 } /* Literal.Number.Oct */
     1702.sb { color: #4070a0 } /* Literal.String.Backtick */
     1703.sc { color: #4070a0 } /* Literal.String.Char */
     1704.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
     1705.s2 { color: #4070a0 } /* Literal.String.Double */
     1706.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
     1707.sh { color: #4070a0 } /* Literal.String.Heredoc */
     1708.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
     1709.sx { color: #c65d09 } /* Literal.String.Other */
     1710.sr { color: #235388 } /* Literal.String.Regex */
     1711.s1 { color: #4070a0 } /* Literal.String.Single */
     1712.ss { color: #517918 } /* Literal.String.Symbol */
     1713.bp { color: #007020 } /* Name.Builtin.Pseudo */
     1714.vc { color: #bb60d5 } /* Name.Variable.Class */
     1715.vg { color: #bb60d5 } /* Name.Variable.Global */
     1716.vi { color: #bb60d5 } /* Name.Variable.Instance */
     1717.il { color: #208050 } /* Literal.Number.Integer.Long */
     1718
     1719/* end stuff scraped from pygment */
     1720
    16381721"""
    16391722    if color == 'gmail':
    16401723        color1 = '#c3d9ff'
  • sage/server/notebook/js.py

    diff -r 748834054361 -r f18bb3d2781a sage/server/notebook/js.py
    a b  
    10171017            halt_introspection();
    10181018            return;
    10191019        }
     1020
    10201021        d.innerHTML = introspection_text;
     1022
     1023        if (contains_jsmath(introspection_text)) {
     1024            try {
     1025                jsMath.ProcessBeforeShowing(d);
     1026            } catch(e) {
     1027                text_cell.innerHTML = jsmath_font_msg + d.innerHTML;
     1028            }
     1029        }
     1030
    10211031        if(replacing)
    10221032            select_replacement_element();
    10231033    } else {
     
    30163026        cell_output.innerHTML = '';
    30173027        cell_output_nowrap.innerHTML = '';
    30183028        cell_output_html.innerHTML = introspect_html;
     3029        if (contains_jsmath(introspect_html)) {
     3030            try {
     3031                jsMath.ProcessBeforeShowing(cell_output_html);
     3032            } catch(e) {
     3033                cell_output.innerHTML = jsmath_font_msg + cell_output_html.innerHTML;
     3034            }
     3035        }
     3036
    30193037    }
    30203038}
    30213039
  • sage/server/support.py

    diff -r 748834054361 -r f18bb3d2781a sage/server/support.py
    a b  
    5353        sage.structure.sage_object.base=object_directory
    5454    sage.misc.latex.EMBEDDED_MODE = True
    5555    sage.misc.pager.EMBEDDED_MODE = True
     56    sage.misc.sageinspect.EMBEDDED_MODE = True
    5657
    5758    setup_systems(globs)
    5859    sage.misc.session.init(globs)
     
    188189    except (AttributeError, NameError, SyntaxError):
    189190        return "No object '%s' currently defined."%obj_name
    190191    s  = ''
     192    newline = "\n\n"  # blank line to start new paragraph
    191193    try:
    192194        filename = sageinspect.sage_getfile(obj)
    193195        #i = filename.find('site-packages/sage/')
    194196        #if i == -1:
    195         s += 'File:        %s\n'%filename
     197        s += '**File:** %s'%filename
     198        s += newline
    196199        #else:
    197200        #    file = filename[i+len('site-packages/sage/'):]
    198201        #    s += 'File:        <html><a href="src_browser?%s">%s</a></html>\n'%(file,file)
    199202    except TypeError:
    200203        pass
    201     s += 'Type:        %s\n'%type(obj)
    202     s += 'Definition:  %s\n'%sageinspect.sage_getdef(obj, obj_name)
    203     s += 'Docstring: \n%s\n'%sageinspect.sage_getdoc(obj, obj_name)
     204    s += '**Type:** %s'%type(obj)
     205    s += newline
     206    s += '**Definition:** %s'%sageinspect.sage_getdef(obj, obj_name)
     207    s += newline
     208    s += '**Docstring:**'
     209    s += newline
     210    s += sageinspect.sage_getdoc(obj, obj_name)
    204211    return s.rstrip()
    205212
    206213def source_code(s, globs, system='sage'):
     
    226233            return obj._sage_src_()
    227234        except:
    228235            pass
     236        newline = "\n\n"  # blank line to start new paragraph
     237        indent = "    "   # indent source code to mark it as a code block
     238
    229239        filename = sageinspect.sage_getfile(obj)
    230240        lines, lineno = sageinspect.sage_getsourcelines(obj, is_binary=False)
    231         src = ''.join(lines)
    232         src = sagedoc.format_src(src)
     241        src = indent.join(lines)
     242        src = indent + sagedoc.format_src(src)
    233243        if not lineno is None:
    234             src = "File: %s\nSource Code (starting at line %s):\n%s"%(filename, lineno, src)
    235         return src
     244            output = "**File:** %s"%filename
     245            output += newline
     246            output += "**Source Code** (starting at line %s)::"%lineno
     247            output += newline
     248            output += src
     249        return output
    236250   
    237251    except (TypeError, IndexError), msg:
    238252        print msg