Skip to content

Commit 2a83aa2

Browse files
authored
Merge pull request #58 from choldgraf/template_static
directly inserting skipText into js
2 parents 105fa2b + 241fe97 commit 2a83aa2

File tree

6 files changed

+121
-57
lines changed

6 files changed

+121
-57
lines changed
611 Bytes
Loading

doc/conf.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@
9797
#
9898
# html_sidebars = {}
9999

100+
# CopyButton configuration
101+
# copybutton_prompt_text = ">>> "
102+
# copybutton_only_copy_prompt_lines = False
103+
# copybutton_remove_prompts = False
104+
# copybutton_image_path = "test/TEST_COPYBUTTON.png"
100105

101106
# -- Options for HTMLHelp output ---------------------------------------------
102107

doc/index.rst

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Sphinx-copybutton
1313
Sphinx-copybutton does one thing: add little "copy" button to the right
1414
of your code blocks. That's it! It is a lightweight wrapper around the
1515
excellent (and also lightweight) Javascript library
16-
`ClipboardJS <https://clipboardjs.com/>`.
16+
`ClipboardJS <https://clipboardjs.com/>`_.
1717

1818
**Here's an example**
1919

@@ -27,13 +27,20 @@ And here's a code block, note the copy button to the right!
2727
copy me!
2828
2929
By default, ``sphinx-copybutton`` will remove Python prompts from
30-
each line that begins with them. For example, try copying the text
30+
each line that begins with them. If it finds lines that start with the
31+
prompt text, all *other* lines will not be copied.
32+
For example, try copying the text
3133
below:
3234

3335
.. code-block:: python
3436
3537
>>> a = 2
3638
>>> print(a)
39+
2
40+
41+
>>> b = 'wow'
42+
>>> print(b)
43+
wow
3744
3845
The text that ``sphinx-copybutton`` uses can be configured as well. See
3946
:ref:`configure_copy_text` for more information.
@@ -70,8 +77,8 @@ extensions list. E.g.:
7077
...
7178
]
7279
73-
When you build your site, your code blocks should now have little copy buttons to their
74-
right. Clicking the button will copy the code inside!
80+
When you build your site, your code blocks should now have little copy buttons
81+
to their right. Clicking the button will copy the code inside!
7582

7683
Customization
7784
=============
@@ -92,52 +99,78 @@ overwrite sphinx-copybutton's behavior.
9299

93100
.. _configure_copy_text:
94101

95-
Customize the text that is removed during copying
96-
-------------------------------------------------
102+
Strip and configure input prompts for code cells
103+
------------------------------------------------
97104

98-
By default, ``sphinx-copybutton`` will remove Python prompts (">>> ") from
99-
the beginning of each line. To change the text that is removed (or to remove
100-
no text at all), add the following configuration to your ``conf.py`` file:
105+
By default, ``sphinx-copybutton`` will copy the entire contents of a code
106+
block when the button is clicked. For many languages, it is common to
107+
include **input prompts** with your examples, along with the outputs from
108+
running the code.
101109

102-
.. code:: python
110+
``sphinx-copybutton`` provides functionality to both
111+
strip input prompts, as well as *only* select lines that begin with a prompt.
112+
This allows users to click the button and *only* copy the input text,
113+
excluding the prompts and outputs.
103114

104-
copybutton_skip_text = "sometexttoskip"
115+
To define the prompt text that you'd like removed from copied text in your code
116+
blocks, use the following configuration value in your ``conf.py`` file:
105117

106-
Note that this text will only be removed from lines that *begin* with the text.
118+
.. code-block::
107119
108-
Use a different copy button image
109-
---------------------------------
120+
copybutton_prompt_text = "myinputprompt"
121+
122+
When this variable is set, ``sphinx-copybutton`` will remove the prompt from
123+
the beginning of any lines that start with the text you specify. In
124+
addition, *only* the lines that contain prompts will be copied if any are
125+
discovered. If no lines with prompts are found, then the full contents of
126+
the cell will be copied.
127+
128+
For example, to exclude traditional Python prompts from your copied code,
129+
use the following configuration:
130+
131+
.. code-block::
132+
133+
copybutton_prompt_text = ">>> "
110134
111-
To use a different image for your copy buttons, the easiest thing to do is
112-
to add a small bit of javascript to your Sphinx build that points the image
113-
to something new. Follow these steps:
135+
Configure whether *only* lines with prompts are copied
136+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114137

115-
1. Create a new javascript file in your site's static folder (e.g., `_static/js/custom.js`).
116-
In it, put the following code:
138+
By default, if sphinx-copybutton detects lines that begin with code prompts,
139+
it will *only* copy the text in those lines (after stripping the prompts).
140+
This assumes that the rest of the code block contains outputs that shouldn't
141+
be copied.
117142

118-
.. code-block:: javascript
143+
To disable this behavior, use the following configuration in ``conf.py``:
119144

120-
const updateCopyButtonImages = () => {
121-
const copybuttonimages = document.querySelectorAll('a.copybtn img')
122-
copybuttonimages.forEach((img, index) => {
123-
img.setAttribute('src', 'path-to-new-image.svg')
124-
})
125-
}
145+
.. code-block:: python
146+
147+
copybutton_only_copy_prompt_lines = False
126148
127-
runWhenDOMLoaded(updateCopyButtonImages)
149+
In this case, all lines of the code blocks will be copied after the prompts
150+
are stripped.
128151

152+
Configure whether the input prompts should be stripped
153+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129154

130-
2. Add this javascript file to your `conf.py` configuration like so:
155+
By default, sphinx-copybutton will remove the prompt text from lines
156+
according to the value of ``copybutton_prompt_text``.
131157

132-
.. code-block:: python
158+
To disable this behavior and copy the full text of lines with prompts
159+
(for example, if you'd like to copy *only* the lines with prompts, but not
160+
strip the prompts), use the following configuration in ``conf.py``:
161+
162+
.. code-block:: python
133163
134-
def setup(app):
135-
app.add_javascript('js/custom.js');
164+
copybutton_remove_prompts = False
165+
166+
Use a different copy button image
167+
---------------------------------
136168

137-
This will replace the copybutton images each time the page loads!
169+
To use a different image for your copy buttons, do the following:
138170

139-
**If you know of a better way to do this with sphinx, please don't hesitate to
140-
recommend something!**
171+
1. Place the image in the ``_static/`` folder of your site.
172+
2. Set the ``copybutton_image_path`` variable in your ``conf.py`` to be the
173+
path to your image file, **relative to** ``_static/``.
141174

142175
Development
143176
===========

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,8 @@
3333
'_static/copybutton.js',
3434
'_static/copy-button.svg',
3535
'_static/clipboard.min.js']},
36-
classifiers=["License :: OSI Approved :: MIT License"]
36+
classifiers=["License :: OSI Approved :: MIT License"],
37+
install_requires=[
38+
"sphinx>=1.8"
39+
]
3740
)

sphinx_copybutton/__init__.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@ def scb_static_path(app):
77
static_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '_static'))
88
app.config.html_static_path.append(static_path)
99

10-
def add_skip_text_js(app):
11-
skip_text = app.config['copybutton_skip_text']
12-
app.add_js_file(None, body="var copybuttonSkipText = '{}';".format(skip_text))
10+
def add_to_context(app, config):
11+
# Update the global context
12+
config.html_context.update({'copybutton_prompt_text': config.copybutton_prompt_text})
13+
config.html_context.update({'copybutton_only_copy_prompt_lines': config.copybutton_only_copy_prompt_lines})
14+
config.html_context.update({'copybutton_remove_prompts': config.copybutton_remove_prompts})
15+
config.html_context.update({'copybutton_image_path': config.copybutton_image_path})
1316

1417
def setup(app):
1518
print('Adding copy buttons to code blocks...')
1619
# Add our static path
1720
app.connect('builder-inited', scb_static_path)
18-
app.connect('builder-inited', add_skip_text_js)
1921

2022
# configuration for this tool
21-
app.add_config_value("copybutton_skip_text", ">>> ", "html")
23+
app.add_config_value("copybutton_prompt_text", "", "html")
24+
app.add_config_value("copybutton_only_copy_prompt_lines", True, "html")
25+
app.add_config_value("copybutton_remove_prompts", True, "html")
26+
app.add_config_value("copybutton_image_path", "copy-button.svg", "html")
27+
28+
# Add configuration value to the template
29+
app.connect("config-inited", add_to_context)
2230

2331
# Add relevant code to headers
2432
app.add_css_file('copybutton.css')

sphinx_copybutton/_static/copybutton.js renamed to sphinx_copybutton/_static/copybutton.js_t

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,39 @@ const temporarilyChangeTooltip = (el, newText) => {
6565
var copyTargetText = (trigger) => {
6666
var target = document.querySelector(trigger.attributes['data-clipboard-target'].value);
6767
var textContent = target.textContent.split('\n');
68-
// Prevent breaking of the copy functionality, for themes which don't
69-
// set copybuttonSkipText properly.
70-
if(! ("copybuttonSkipText" in window)){
71-
var copybuttonSkipText = ">>> ";
72-
console.warn(`sphinx_copybutton:
73-
The theme that was used to generate this document, does not support the setting for 'copybutton_skip_text',
74-
which is why its default of '>>> ' was used.
75-
Please tell the theme developers to include javascript files with the template tag 'js_tag' for sphinx>=1.8.
76-
Example: https://github.com/readthedocs/sphinx_rtd_theme/blob/ab7d388448258a24f8f4fa96dccb69d24f571736/sphinx_rtd_theme/layout.html#L30
77-
`);
78-
}
68+
var copybuttonPromptText = '{{ copybutton_prompt_text }}'; // Inserted from config
69+
var onlyCopyPromptLines = {{ copybutton_only_copy_prompt_lines | lower }}; // Inserted from config
70+
var removePrompts = {{ copybutton_remove_prompts | lower }}; // Inserted from config
7971

80-
textContent.forEach((line, index) => {
81-
if (line.startsWith(copybuttonSkipText)) {
82-
textContent[index] = line.slice(copybuttonSkipText.length)
72+
// Text content line filtering based on prompts (if a prompt text is given)
73+
if (copybuttonPromptText.length > 0) {
74+
// If only copying prompt lines, remove all lines that don't start w/ prompt
75+
if (onlyCopyPromptLines) {
76+
linesWithPrompt = textContent.filter((line) => {
77+
return line.startsWith(copybuttonPromptText) || (line.length == 0); // Keep newlines
78+
});
79+
// Check to make sure we have at least one non-empty line
80+
var nonEmptyLines = linesWithPrompt.filter((line) => {return line.length > 0});
81+
// If we detected lines w/ prompt, then overwrite textContent w/ those lines
82+
if ((linesWithPrompt.length > 0) && (nonEmptyLines.length > 0)) {
83+
textContent = linesWithPrompt;
84+
}
85+
}
86+
// Remove the starting prompt from any remaining lines
87+
if (removePrompts) {
88+
textContent.forEach((line, index) => {
89+
if (line.startsWith(copybuttonPromptText)) {
90+
textContent[index] = line.slice(copybuttonPromptText.length);
91+
}
92+
});
8393
}
84-
});
85-
return textContent.join('\n')
94+
}
95+
textContent = textContent.join('\n');
96+
// Remove a trailing newline to avoid auto-running when pasting
97+
if (textContent.endsWith("\n")) {
98+
textContent = textContent.slice(0, -1)
99+
}
100+
return textContent
86101
}
87102

88103
const addCopyButtonToCodeCells = () => {
@@ -102,7 +117,7 @@ const addCopyButtonToCodeCells = () => {
102117

103118
const clipboardButton = id =>
104119
`<a class="copybtn o-tooltip--left" style="background-color: ${pre_bg}" data-tooltip="${messages[locale]['copy']}" data-clipboard-target="#${id}">
105-
<img src="${DOCUMENTATION_OPTIONS.URL_ROOT}_static/copy-button.svg" alt="${messages[locale]['copy_to_clipboard']}">
120+
<img src="${DOCUMENTATION_OPTIONS.URL_ROOT}_static/{{ copybutton_image_path }}" alt="${messages[locale]['copy_to_clipboard']}">
106121
</a>`
107122
codeCell.insertAdjacentHTML('afterend', clipboardButton(id))
108123
})

0 commit comments

Comments
 (0)