diff --git a/doc/_static/test/TEST_COPYBUTTON.png b/doc/_static/test/TEST_COPYBUTTON.png
new file mode 100644
index 0000000..2787393
Binary files /dev/null and b/doc/_static/test/TEST_COPYBUTTON.png differ
diff --git a/doc/conf.py b/doc/conf.py
index 75d20c3..ba87009 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -97,6 +97,11 @@
#
# html_sidebars = {}
+# CopyButton configuration
+# copybutton_prompt_text = ">>> "
+# copybutton_only_copy_prompt_lines = False
+# copybutton_remove_prompts = False
+# copybutton_image_path = "test/TEST_COPYBUTTON.png"
# -- Options for HTMLHelp output ---------------------------------------------
diff --git a/doc/index.rst b/doc/index.rst
index e43d0a6..263750f 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -13,7 +13,7 @@ Sphinx-copybutton
Sphinx-copybutton does one thing: add little "copy" button to the right
of your code blocks. That's it! It is a lightweight wrapper around the
excellent (and also lightweight) Javascript library
-`ClipboardJS `.
+`ClipboardJS `_.
**Here's an example**
@@ -27,13 +27,20 @@ And here's a code block, note the copy button to the right!
copy me!
By default, ``sphinx-copybutton`` will remove Python prompts from
-each line that begins with them. For example, try copying the text
+each line that begins with them. If it finds lines that start with the
+prompt text, all *other* lines will not be copied.
+For example, try copying the text
below:
.. code-block:: python
>>> a = 2
>>> print(a)
+ 2
+
+ >>> b = 'wow'
+ >>> print(b)
+ wow
The text that ``sphinx-copybutton`` uses can be configured as well. See
:ref:`configure_copy_text` for more information.
@@ -70,8 +77,8 @@ extensions list. E.g.:
...
]
-When you build your site, your code blocks should now have little copy buttons to their
-right. Clicking the button will copy the code inside!
+When you build your site, your code blocks should now have little copy buttons
+to their right. Clicking the button will copy the code inside!
Customization
=============
@@ -92,52 +99,78 @@ overwrite sphinx-copybutton's behavior.
.. _configure_copy_text:
-Customize the text that is removed during copying
--------------------------------------------------
+Strip and configure input prompts for code cells
+------------------------------------------------
-By default, ``sphinx-copybutton`` will remove Python prompts (">>> ") from
-the beginning of each line. To change the text that is removed (or to remove
-no text at all), add the following configuration to your ``conf.py`` file:
+By default, ``sphinx-copybutton`` will copy the entire contents of a code
+block when the button is clicked. For many languages, it is common to
+include **input prompts** with your examples, along with the outputs from
+running the code.
-.. code:: python
+``sphinx-copybutton`` provides functionality to both
+strip input prompts, as well as *only* select lines that begin with a prompt.
+This allows users to click the button and *only* copy the input text,
+excluding the prompts and outputs.
- copybutton_skip_text = "sometexttoskip"
+To define the prompt text that you'd like removed from copied text in your code
+blocks, use the following configuration value in your ``conf.py`` file:
-Note that this text will only be removed from lines that *begin* with the text.
+.. code-block::
-Use a different copy button image
----------------------------------
+ copybutton_prompt_text = "myinputprompt"
+
+When this variable is set, ``sphinx-copybutton`` will remove the prompt from
+the beginning of any lines that start with the text you specify. In
+addition, *only* the lines that contain prompts will be copied if any are
+discovered. If no lines with prompts are found, then the full contents of
+the cell will be copied.
+
+For example, to exclude traditional Python prompts from your copied code,
+use the following configuration:
+
+.. code-block::
+
+ copybutton_prompt_text = ">>> "
-To use a different image for your copy buttons, the easiest thing to do is
-to add a small bit of javascript to your Sphinx build that points the image
-to something new. Follow these steps:
+Configure whether *only* lines with prompts are copied
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-1. Create a new javascript file in your site's static folder (e.g., `_static/js/custom.js`).
- In it, put the following code:
+By default, if sphinx-copybutton detects lines that begin with code prompts,
+it will *only* copy the text in those lines (after stripping the prompts).
+This assumes that the rest of the code block contains outputs that shouldn't
+be copied.
- .. code-block:: javascript
+To disable this behavior, use the following configuration in ``conf.py``:
- const updateCopyButtonImages = () => {
- const copybuttonimages = document.querySelectorAll('a.copybtn img')
- copybuttonimages.forEach((img, index) => {
- img.setAttribute('src', 'path-to-new-image.svg')
- })
- }
+.. code-block:: python
+
+ copybutton_only_copy_prompt_lines = False
- runWhenDOMLoaded(updateCopyButtonImages)
+In this case, all lines of the code blocks will be copied after the prompts
+are stripped.
+Configure whether the input prompts should be stripped
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-2. Add this javascript file to your `conf.py` configuration like so:
+By default, sphinx-copybutton will remove the prompt text from lines
+according to the value of ``copybutton_prompt_text``.
- .. code-block:: python
+To disable this behavior and copy the full text of lines with prompts
+(for example, if you'd like to copy *only* the lines with prompts, but not
+strip the prompts), use the following configuration in ``conf.py``:
+
+.. code-block:: python
- def setup(app):
- app.add_javascript('js/custom.js');
+ copybutton_remove_prompts = False
+
+Use a different copy button image
+---------------------------------
-This will replace the copybutton images each time the page loads!
+To use a different image for your copy buttons, do the following:
-**If you know of a better way to do this with sphinx, please don't hesitate to
-recommend something!**
+1. Place the image in the ``_static/`` folder of your site.
+2. Set the ``copybutton_image_path`` variable in your ``conf.py`` to be the
+ path to your image file, **relative to** ``_static/``.
Development
===========
diff --git a/setup.py b/setup.py
index 128aa47..9797bc9 100644
--- a/setup.py
+++ b/setup.py
@@ -33,5 +33,8 @@
'_static/copybutton.js',
'_static/copy-button.svg',
'_static/clipboard.min.js']},
- classifiers=["License :: OSI Approved :: MIT License"]
+ classifiers=["License :: OSI Approved :: MIT License"],
+ install_requires=[
+ "sphinx>=1.8"
+ ]
)
diff --git a/sphinx_copybutton/__init__.py b/sphinx_copybutton/__init__.py
index baa7fde..168aabc 100644
--- a/sphinx_copybutton/__init__.py
+++ b/sphinx_copybutton/__init__.py
@@ -7,18 +7,26 @@ def scb_static_path(app):
static_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '_static'))
app.config.html_static_path.append(static_path)
-def add_skip_text_js(app):
- skip_text = app.config['copybutton_skip_text']
- app.add_js_file(None, body="var copybuttonSkipText = '{}';".format(skip_text))
+def add_to_context(app, config):
+ # Update the global context
+ config.html_context.update({'copybutton_prompt_text': config.copybutton_prompt_text})
+ config.html_context.update({'copybutton_only_copy_prompt_lines': config.copybutton_only_copy_prompt_lines})
+ config.html_context.update({'copybutton_remove_prompts': config.copybutton_remove_prompts})
+ config.html_context.update({'copybutton_image_path': config.copybutton_image_path})
def setup(app):
print('Adding copy buttons to code blocks...')
# Add our static path
app.connect('builder-inited', scb_static_path)
- app.connect('builder-inited', add_skip_text_js)
# configuration for this tool
- app.add_config_value("copybutton_skip_text", ">>> ", "html")
+ app.add_config_value("copybutton_prompt_text", "", "html")
+ app.add_config_value("copybutton_only_copy_prompt_lines", True, "html")
+ app.add_config_value("copybutton_remove_prompts", True, "html")
+ app.add_config_value("copybutton_image_path", "copy-button.svg", "html")
+
+ # Add configuration value to the template
+ app.connect("config-inited", add_to_context)
# Add relevant code to headers
app.add_css_file('copybutton.css')
diff --git a/sphinx_copybutton/_static/copybutton.js b/sphinx_copybutton/_static/copybutton.js_t
similarity index 66%
rename from sphinx_copybutton/_static/copybutton.js
rename to sphinx_copybutton/_static/copybutton.js_t
index b79df3d..e91c792 100644
--- a/sphinx_copybutton/_static/copybutton.js
+++ b/sphinx_copybutton/_static/copybutton.js_t
@@ -65,24 +65,39 @@ const temporarilyChangeTooltip = (el, newText) => {
var copyTargetText = (trigger) => {
var target = document.querySelector(trigger.attributes['data-clipboard-target'].value);
var textContent = target.textContent.split('\n');
- // Prevent breaking of the copy functionality, for themes which don't
- // set copybuttonSkipText properly.
- if(! ("copybuttonSkipText" in window)){
- var copybuttonSkipText = ">>> ";
- console.warn(`sphinx_copybutton:
- The theme that was used to generate this document, does not support the setting for 'copybutton_skip_text',
- which is why its default of '>>> ' was used.
- Please tell the theme developers to include javascript files with the template tag 'js_tag' for sphinx>=1.8.
- Example: https://github.com/readthedocs/sphinx_rtd_theme/blob/ab7d388448258a24f8f4fa96dccb69d24f571736/sphinx_rtd_theme/layout.html#L30
- `);
- }
+ var copybuttonPromptText = '{{ copybutton_prompt_text }}'; // Inserted from config
+ var onlyCopyPromptLines = {{ copybutton_only_copy_prompt_lines | lower }}; // Inserted from config
+ var removePrompts = {{ copybutton_remove_prompts | lower }}; // Inserted from config
- textContent.forEach((line, index) => {
- if (line.startsWith(copybuttonSkipText)) {
- textContent[index] = line.slice(copybuttonSkipText.length)
+ // Text content line filtering based on prompts (if a prompt text is given)
+ if (copybuttonPromptText.length > 0) {
+ // If only copying prompt lines, remove all lines that don't start w/ prompt
+ if (onlyCopyPromptLines) {
+ linesWithPrompt = textContent.filter((line) => {
+ return line.startsWith(copybuttonPromptText) || (line.length == 0); // Keep newlines
+ });
+ // Check to make sure we have at least one non-empty line
+ var nonEmptyLines = linesWithPrompt.filter((line) => {return line.length > 0});
+ // If we detected lines w/ prompt, then overwrite textContent w/ those lines
+ if ((linesWithPrompt.length > 0) && (nonEmptyLines.length > 0)) {
+ textContent = linesWithPrompt;
+ }
+ }
+ // Remove the starting prompt from any remaining lines
+ if (removePrompts) {
+ textContent.forEach((line, index) => {
+ if (line.startsWith(copybuttonPromptText)) {
+ textContent[index] = line.slice(copybuttonPromptText.length);
+ }
+ });
}
- });
- return textContent.join('\n')
+ }
+ textContent = textContent.join('\n');
+ // Remove a trailing newline to avoid auto-running when pasting
+ if (textContent.endsWith("\n")) {
+ textContent = textContent.slice(0, -1)
+ }
+ return textContent
}
const addCopyButtonToCodeCells = () => {
@@ -102,7 +117,7 @@ const addCopyButtonToCodeCells = () => {
const clipboardButton = id =>
`
-
+
`
codeCell.insertAdjacentHTML('afterend', clipboardButton(id))
})